"""
This module generates a Dockerfile for use with light chutes.
"""
import platform
import re
from io import BytesIO
[docs]class Dockerfile(object):
requiredFields = ["image", "command"]
def __init__(self, service):
"""
service: Service object containing configuration for the image.
"""
self.service = service
[docs] def getBytesIO(self):
"""
Geterate a Dockerfile and return as a BytesIO object.
"""
data = self.getString()
return BytesIO(data.encode("utf-8"))
[docs] def getString(self):
"""
Generate a Dockerfile as a multi-line string.
"""
# Required fields for generating Dockerfile.
# Developer tells us what language pack to use and what command to run.
language = self.service.image
command = self.service.command
# Extra build options.
build = self.service.build
image_source = build.get("image_source", "paradrop")
image_version = build.get("image_version", "latest")
packages = build.get("packages", [])
as_root = self.service.requests.get("as-root", False)
# Example base image: paradrop/node-x86_64:latest
from_image = "{}/{}-{}:{}".format(image_source, language,
platform.machine(), image_version)
if isinstance(command, basestring):
cmd_string = command
elif isinstance(command, list):
cmd_string = "[{}]".format(",".join(
"\"{}\"".format(v) for v in command))
else:
raise Exception("command must be either a string or list of strings")
dockerfile = "FROM {}\n".format(from_image)
if len(packages) > 0:
# The base images set up an unprivileged user, paradrop. We will
# need to run as root to install packages, though.
dockerfile += "USER root\n"
dockerfile += "RUN apt-get update && apt-get install -y {}\n".format(
" ".join(packages))
# Drop back to user paradrop after installing packages.
if not as_root:
dockerfile += "USER paradrop\n"
elif as_root:
# No packages to install but run as root.
dockerfile += "USER root\n"
dockerfile += "CMD {}\n".format(cmd_string)
return dockerfile
[docs] def isValid(self):
"""
Check if configuration is valid.
Returns a tuple (True/False, None or str).
"""
# Check required fields.
for field in Dockerfile.requiredFields:
if getattr(self.service, field, None) is None:
return (False, "Missing required field {}".format(field))
command = self.service.command
if not isinstance(command, basestring) and not isinstance(command, list):
return (False, "Command must be either a string or list of strings")
packages = self.service.build.get("packages", [])
if not isinstance(packages, list):
return (False, "Packages must be specified as a list")
for pkg in packages:
if re.search(r"\s", pkg):
return (False, "Package name ({}) contains whitespace".format(pkg))
return (True, None)
[docs] def writeFile(self, path):
"""
Generate Dockerfile and write to a file.
"""
data = self.getString()
with open(path, "w") as output:
output.write(data)