Newer
Older
#!/usr/bin/env python3
"""
Script to create a Docker image from a Dune module
"""
import os
import sys
import string
import shutil
import argparse
import subprocess
from util.moduleinfo import getModuleFile
from util.moduleinfo import extractModuleInfos
# require python 3
if sys.version_info[0] < 3:
sys.exit("\nERROR: Python3 required")
def substituteAndWrite(template, target, mapping):
"""substitute content from template and write to target"""
if not os.path.exists(template):
sys.exit("Template file '" + template + "' could not be found")
with open(target, "w") as targetFile:
with open(template) as tmp:
raw = string.Template(tmp.read())
targetFile.write(raw.substitute(**mapping))
if __name__ == "__main__":
# input argument parser
parser = argparse.ArgumentParser(
description="Create a docker image for a given module and install script."
)
parser.add_argument("-m", "--modulepath", required=True, help="the path to the your module")
parser.add_argument(
"-i", "--installScript", required=True, help="Specify the installation script"
)
parser.add_argument(
"-t", "--templateFolder", required=False, help="Specify the folder with the template files"
)
args = vars(parser.parse_args())
# get information on the module
modulePath = os.path.abspath(args["modulepath"])
modInfo = extractModuleInfos(getModuleFile(modulePath), ["Module", "Maintainer"])
moduleName = modInfo["Module"]
moduleMaintainer = modInfo["Maintainer"]
dockerTag = moduleName.lower() # docker only supports lower case
# get folder with the template files
templateFolder = args["templateFolder"]
if not templateFolder:
templateFolder = os.path.join(__file__, "../dumux/docker")
print(f"Folder with template files not given. Defaulting to '{templateFolder}'.")
if not os.path.exists(templateFolder):
sys.exit(f"Template folder {templateFolder} could not be found")
print("*" * 54)
print("\n-- Creating a Docker image for module " + moduleName + " --\n")
print("*" * 54)
if os.path.exists("docker"):
print(
"\nA docker folder already exists. " "Continue anyway? - will be overwritten - [y/N]\n"
)
delete = input()
shutil.rmtree("docker")
print("--> Deleted old docker folder.")
else:
sys.exit("Abort.")
os.mkdir("docker")
print("--> Created the folder 'docker'.")
# copy install script into docker folder and make it executable
installScriptPath = args["installScript"]
installScriptName = os.path.split(installScriptPath)[1]
installScript = os.path.join(os.path.join(os.getcwd(), "docker"), installScriptName)
shutil.copy(installScriptPath, installScript)
os.system(f"chmod +x {installScript}")
print(
f"--> Using install script: {installScript} "
f"to install dependencies for module {moduleName}."
# write setpermissions helper script
substituteAndWrite(
template=os.path.join(templateFolder, "setpermissions.sh.template"),
target=os.path.join(os.getcwd(), "docker/setpermissions.sh"),
mapping={},
)
print("--> Created permission helper script for easier container setup.")
# write welcome message file
substituteAndWrite(
template=os.path.join(templateFolder, "WELCOME.template"),
target=os.path.join(os.getcwd(), "docker/WELCOME"),
mapping={"modName": moduleName, "modFolder": moduleName},
)
print("--> Created welcome message displayed on Docker container startup.")
# write readme file
substituteAndWrite(
template=os.path.join(templateFolder, "README.md.template"),
target=os.path.join(os.getcwd(), "docker/README.md"),
mapping={"modName": moduleName, "dockerTag": dockerTag},
)
print("--> Created README.md on how to use the docker image.")
# write helper file for container spin-up (make it executable after creation)
dockerScript = os.path.join(os.getcwd(), f"docker/docker_{dockerTag}.sh")
substituteAndWrite(
template=os.path.join(templateFolder, "docker.sh.template"),
target=dockerScript,
mapping={"dockerTag": dockerTag},
)
os.system("chmod +x " + dockerScript)
print("--> Created helper script to spin up the docker container.")
# write the docker file
substituteAndWrite(
template=os.path.join(templateFolder, "Dockerfile.template"),
target=os.path.join(os.getcwd(), "docker/Dockerfile"),
mapping={
"modName": moduleName,
"modMaintainer": moduleMaintainer,
"dockerTag": dockerTag,
"instScript": installScriptName,
},
)
print("--> Created Dockerfile. You can adapt it to your needs.")
print()
print("Do you want to directly build the Docker image? [y/N]")
build = input()
print("Building Docker image... this may take several minutes.")
try:
os.chdir("docker")
subprocess.run(
["docker", "build", "-f", "Dockerfile", "-t", dockerTag, "."], check=True
)
os.chdir("../")
except subprocess.CalledProcessError:
os.chdir("../")
sys.exit("ERROR: docker image build failed")
print(
"",
f"Successfully built image: {dockerTag}. ",
"Have a look at docker/README.md.",
"Check the container by running "
f"'docker run -it {dockerTag} /bin/bash' in the same "
"directory as the Dockerfile, and try using the convenience script "
f"docker_{dockerTag}.sh",
"See docker/README.md for more information.",
else:
print(
"You can build your Docker image later by running "
f"'docker build -f Dockerfile -t {dockerTag}' "
"from within the folder 'docker' that was created by this script, "
"and in which you should find the 'Dockerfile'."
)