From 30ac30ff81c7fcca4aaf12c8567d3b7c90a18626 Mon Sep 17 00:00:00 2001 From: Petr "Stone" Hracek Date: Jan 24 2017 09:50:08 +0000 Subject: [PATCH 1/4] Script for OpenShift template generation. Signed-off-by: Petr "Stone" Hracek --- diff --git a/build_oc_template.py b/build_oc_template.py new file mode 100755 index 0000000..1fd9e86 --- /dev/null +++ b/build_oc_template.py @@ -0,0 +1,197 @@ +#!/bin/python + +from __future__ import absolute_import +from __future__ import print_function + +import sys +import os +import ast +import yaml +import argparse +import tempfile +import shutil +import re + +from dockerfile_parse import DockerfileParser + +# Dockerfile path +DOCKERFILE = "Dockerfile" + +EXPOSE = "EXPOSE" +VOLUME = "VOLUME" +LABEL = "LABEL" +ENV = "ENV" + +# OpenShift template +OPENSHIFT_TEMPLATE = "openshift-template.yml" + + +def get_string(value): + return ast.literal_eval(value) + + +class OpenShiftTemplateGenerator(object): + """ + Class generates an OpenShift template + It requires openshift-template.yml file. + """ + + docker_file = None + oc_template = None + + def __init__(self, args=None): + self.dir = os.getcwd() + self.docker_image = args.image + if args.dockerfile is None: + self.dockerfile = 'Dockerfile' + else: + self.dockerfile = os.path.join(self.dir, args.dockerfile) + + def _get_files(self): + if not os.path.exists(self.dockerfile): + print("Dockerfile %s does not exists." % self.dockerfile) + return + for f in os.listdir(self.dir): + if os.path.isdir(os.path.join(self.dir, f)): + continue + file_name = os.path.join(self.dir, f) + if f == OPENSHIFT_TEMPLATE: + self.oc_template = file_name + + def _get_expose(self, value): + return value.split() + + def _get_env(self, value): + return value.split(" ") + + def _get_volume(self, value): + return get_string(value) + + def _get_labels(self, value): + labels = re.sub('\s\s+', ';', value).split(';') + label_dict = {l.split('=')[0]: l.split('=')[1] for l in labels} + return label_dict + + def _get_docker_tags(self): + tmp_dir = tempfile.mkdtemp() + if os.path.isdir(tmp_dir): + shutil.rmtree(tmp_dir) + os.makedirs(tmp_dir) + shutil.copyfile(self.dockerfile, os.path.join(tmp_dir, "Dockerfile")) + dfp = DockerfileParser(path=tmp_dir) + docker_dict = {} + inst = "instruction" + allowed_tags = [ENV, EXPOSE, VOLUME, LABEL] + functions = {ENV: self._get_env, + EXPOSE: self._get_expose, + VOLUME: self._get_volume, + LABEL: self._get_labels} + + for struct in dfp.structure: + key = struct[inst] + val = struct["value"] + if key in allowed_tags: + if key == LABEL: + if key not in docker_dict: + docker_dict[key] = {} + docker_dict[key].update(functions[key](val)) + else: + if key not in docker_dict: + docker_dict[key] = [] + docker_dict[key].extend(functions[key](val)) + + shutil.rmtree(tmp_dir) + return docker_dict + + def _load_oc_template(self, docker_dict): + templ = {} + with open(self.oc_template, 'r') as f: + try: + templ = yaml.load(f) + except yaml.YAMLError as exc: + print(exc) + return + labels = templ['metadata']['annotation'] + try: + labels['description'] = docker_dict[LABEL]['description'] + labels['tags'] = docker_dict[LABEL]['io.openshift.tags'] + except KeyError: + labels['description'] = "EMPTY_DESCRIPTION" + labels['tags'] = 'EMPTY_TAGS' + labels['template'] = self.docker_image + templ['metadata']['name'] = self.docker_image + for obj in templ['objects']: + obj['spec']['dockerImageRepository'] = self.docker_image + obj['metadata']['name'] = self.docker_image + ports_list = [] + for p in docker_dict[EXPOSE]: + ports_list.append({'containerPort': int(p)}) + volume_list = [] + volume_names = [] + env_list = [] + if docker_dict[VOLUME]: + for p in docker_dict[VOLUME]: + volume_list.append({'mountPath': p, + 'name': 'name-' + os.path.basename(p)}) + volume_names.append({'name': 'name-' + os.path.basename(p), + 'emptyDir': {} + }) + if docker_dict[ENV]: + for e in docker_dict[ENV]: + key, val = e.split('=') + env_list.append({'name': key, + 'value': val}) + if 'template' in obj['spec']: + obj['spec']['template']['metadata']['labels']['name'] = self.docker_image + containers = obj['spec']['template']['spec']['containers'][0] + if env_list: + containers['env'] = env_list + if ports_list: + containers['ports'] = ports_list + if volume_list: + containers['volumeMounts'] = volume_list + obj['spec']['template']['spec']['volumes'] = volume_names + containers['name'] = self.docker_image + containers['image'] = self.docker_image + + if 'triggers' in obj['spec']: + for trig in obj['spec']['triggers']: + trig['imageChangeParams']['containerNames'] = [self.docker_image] + trig['imageChangeParams']['from']['name'] = self.docker_image + ":latest" + + tmp_dir = tempfile.mkdtemp() + if os.path.isdir(tmp_dir): + shutil.rmtree(tmp_dir) + os.makedirs(tmp_dir) + tmp_file = os.path.join(tmp_dir, os.path.basename(self.oc_template)) + with open(tmp_file, 'w') as f: + try: + yaml.safe_dump(templ, f, default_flow_style=False) + print("OpenShift template is generated here: %s" % (tmp_file)) + except yaml.YAMLError as exc: + print(exc) + + def run(self): + self._get_files() + docker_dict = self._get_docker_tags() + self._load_oc_template(docker_dict) + + +def main(): + parser = argparse.ArgumentParser(description="Creates an OpenShift template YAML file.") + parser.add_argument( + "image", + metavar='IMAGE', + help="docker image name", + ) + parser.add_argument( + "--dockerfile", + help="Specify Dockerfile name. Default is Dockerfile." + ) + args = parser.parse_args() + otg = OpenShiftTemplateGenerator(args) + otg.run() + + +if __name__ == "__main__": + sys.exit(main()) From 5fa901a362d5721073e78da01d9905160e9cffa4 Mon Sep 17 00:00:00 2001 From: Petr "Stone" Hracek Date: Feb 07 2017 12:15:17 +0000 Subject: [PATCH 2/4] Created module under modularity package Signed-off-by: Petr "Stone" Hracek --- diff --git a/build_oc_template.py b/build_oc_template.py index 1fd9e86..e61f904 100755 --- a/build_oc_template.py +++ b/build_oc_template.py @@ -1,197 +1,8 @@ #!/bin/python -from __future__ import absolute_import -from __future__ import print_function - import sys -import os -import ast -import yaml -import argparse -import tempfile -import shutil -import re - -from dockerfile_parse import DockerfileParser - -# Dockerfile path -DOCKERFILE = "Dockerfile" - -EXPOSE = "EXPOSE" -VOLUME = "VOLUME" -LABEL = "LABEL" -ENV = "ENV" - -# OpenShift template -OPENSHIFT_TEMPLATE = "openshift-template.yml" - - -def get_string(value): - return ast.literal_eval(value) - - -class OpenShiftTemplateGenerator(object): - """ - Class generates an OpenShift template - It requires openshift-template.yml file. - """ - - docker_file = None - oc_template = None - - def __init__(self, args=None): - self.dir = os.getcwd() - self.docker_image = args.image - if args.dockerfile is None: - self.dockerfile = 'Dockerfile' - else: - self.dockerfile = os.path.join(self.dir, args.dockerfile) - - def _get_files(self): - if not os.path.exists(self.dockerfile): - print("Dockerfile %s does not exists." % self.dockerfile) - return - for f in os.listdir(self.dir): - if os.path.isdir(os.path.join(self.dir, f)): - continue - file_name = os.path.join(self.dir, f) - if f == OPENSHIFT_TEMPLATE: - self.oc_template = file_name - - def _get_expose(self, value): - return value.split() - - def _get_env(self, value): - return value.split(" ") - - def _get_volume(self, value): - return get_string(value) - - def _get_labels(self, value): - labels = re.sub('\s\s+', ';', value).split(';') - label_dict = {l.split('=')[0]: l.split('=')[1] for l in labels} - return label_dict - - def _get_docker_tags(self): - tmp_dir = tempfile.mkdtemp() - if os.path.isdir(tmp_dir): - shutil.rmtree(tmp_dir) - os.makedirs(tmp_dir) - shutil.copyfile(self.dockerfile, os.path.join(tmp_dir, "Dockerfile")) - dfp = DockerfileParser(path=tmp_dir) - docker_dict = {} - inst = "instruction" - allowed_tags = [ENV, EXPOSE, VOLUME, LABEL] - functions = {ENV: self._get_env, - EXPOSE: self._get_expose, - VOLUME: self._get_volume, - LABEL: self._get_labels} - - for struct in dfp.structure: - key = struct[inst] - val = struct["value"] - if key in allowed_tags: - if key == LABEL: - if key not in docker_dict: - docker_dict[key] = {} - docker_dict[key].update(functions[key](val)) - else: - if key not in docker_dict: - docker_dict[key] = [] - docker_dict[key].extend(functions[key](val)) - - shutil.rmtree(tmp_dir) - return docker_dict - - def _load_oc_template(self, docker_dict): - templ = {} - with open(self.oc_template, 'r') as f: - try: - templ = yaml.load(f) - except yaml.YAMLError as exc: - print(exc) - return - labels = templ['metadata']['annotation'] - try: - labels['description'] = docker_dict[LABEL]['description'] - labels['tags'] = docker_dict[LABEL]['io.openshift.tags'] - except KeyError: - labels['description'] = "EMPTY_DESCRIPTION" - labels['tags'] = 'EMPTY_TAGS' - labels['template'] = self.docker_image - templ['metadata']['name'] = self.docker_image - for obj in templ['objects']: - obj['spec']['dockerImageRepository'] = self.docker_image - obj['metadata']['name'] = self.docker_image - ports_list = [] - for p in docker_dict[EXPOSE]: - ports_list.append({'containerPort': int(p)}) - volume_list = [] - volume_names = [] - env_list = [] - if docker_dict[VOLUME]: - for p in docker_dict[VOLUME]: - volume_list.append({'mountPath': p, - 'name': 'name-' + os.path.basename(p)}) - volume_names.append({'name': 'name-' + os.path.basename(p), - 'emptyDir': {} - }) - if docker_dict[ENV]: - for e in docker_dict[ENV]: - key, val = e.split('=') - env_list.append({'name': key, - 'value': val}) - if 'template' in obj['spec']: - obj['spec']['template']['metadata']['labels']['name'] = self.docker_image - containers = obj['spec']['template']['spec']['containers'][0] - if env_list: - containers['env'] = env_list - if ports_list: - containers['ports'] = ports_list - if volume_list: - containers['volumeMounts'] = volume_list - obj['spec']['template']['spec']['volumes'] = volume_names - containers['name'] = self.docker_image - containers['image'] = self.docker_image - - if 'triggers' in obj['spec']: - for trig in obj['spec']['triggers']: - trig['imageChangeParams']['containerNames'] = [self.docker_image] - trig['imageChangeParams']['from']['name'] = self.docker_image + ":latest" - - tmp_dir = tempfile.mkdtemp() - if os.path.isdir(tmp_dir): - shutil.rmtree(tmp_dir) - os.makedirs(tmp_dir) - tmp_file = os.path.join(tmp_dir, os.path.basename(self.oc_template)) - with open(tmp_file, 'w') as f: - try: - yaml.safe_dump(templ, f, default_flow_style=False) - print("OpenShift template is generated here: %s" % (tmp_file)) - except yaml.YAMLError as exc: - print(exc) - - def run(self): - self._get_files() - docker_dict = self._get_docker_tags() - self._load_oc_template(docker_dict) - - -def main(): - parser = argparse.ArgumentParser(description="Creates an OpenShift template YAML file.") - parser.add_argument( - "image", - metavar='IMAGE', - help="docker image name", - ) - parser.add_argument( - "--dockerfile", - help="Specify Dockerfile name. Default is Dockerfile." - ) - args = parser.parse_args() - otg = OpenShiftTemplateGenerator(args) - otg.run() +from modularity.cli import CliHelper if __name__ == "__main__": - sys.exit(main()) + sys.exit(CliHelper.run()) diff --git a/modularity/__init__.py b/modularity/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/modularity/__init__.py diff --git a/modularity/__init__.pyc b/modularity/__init__.pyc new file mode 100644 index 0000000..0cc4b00 Binary files /dev/null and b/modularity/__init__.pyc differ diff --git a/modularity/cli.py b/modularity/cli.py new file mode 100644 index 0000000..b758551 --- /dev/null +++ b/modularity/cli.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# + +import sys +import argparse + +from modularity.oc_template import OpenShiftTemplateGenerator + + +class CLI(object): + """ Class for processing data from commandline """ + + @staticmethod + def build_parser(): + parser = argparse.ArgumentParser(description="Creates an OpenShift template YAML file.") + parser.add_argument( + "image", + metavar='IMAGE', + help="docker image name (like NAME or docker.io/USER/NAME)", + ) + parser.add_argument( + "--dockerfile", + help="Specify Dockerfile name. Default is Dockerfile." + ) + return parser + + def __init__(self, args=None): + self.parser = CLI.build_parser() + self.args = self.parser.parse_args(args) + + def __getattr__(self, name): + try: + return getattr(self.args, name) + except AttributeError: + return object.__getattribute__(self, name) + + +class CliHelper(object): + + @staticmethod + def run(): + try: + cli = CLI(sys.argv[1:]) + otg = OpenShiftTemplateGenerator(cli) + otg.run() + except KeyboardInterrupt: + print('\nInterrupted by user') + except Exception as e: + print('\n%s', e) + sys.exit(1) diff --git a/modularity/cli.pyc b/modularity/cli.pyc new file mode 100644 index 0000000..2e1cc0f Binary files /dev/null and b/modularity/cli.pyc differ diff --git a/modularity/oc_template.py b/modularity/oc_template.py new file mode 100644 index 0000000..ba757d6 --- /dev/null +++ b/modularity/oc_template.py @@ -0,0 +1,210 @@ +from __future__ import absolute_import +from __future__ import print_function + +import os +import ast +import yaml +import tempfile +import shutil +import re + +from dockerfile_parse import DockerfileParser + +# Dockerfile path +DOCKERFILE = "Dockerfile" + +EXPOSE = "EXPOSE" +VOLUME = "VOLUME" +LABEL = "LABEL" +ENV = "ENV" + +# OpenShift template +OPENSHIFT_TEMPLATE = "openshift-template.yml" + + +def get_string(value): + return ast.literal_eval(value) + + +class OpenShiftTemplateGenerator(object): + """ + Class generates an OpenShift template + It requires openshift-template.yml file. + """ + + docker_file = None + oc_template = None + docker_dict = {} + + def __init__(self, args=None, dir_name=None): + if dir_name is None: + self.dir = os.getcwd() + else: + self.dir = dir_name + self.docker_image = args.image + if args.dockerfile is None: + self.dockerfile = 'Dockerfile' + else: + self.dockerfile = os.path.join(self.dir, args.dockerfile) + + def _get_files(self): + if not os.path.exists(self.dockerfile): + print("Dockerfile %s does not exists." % self.dockerfile) + return + for f in os.listdir(self.dir): + if os.path.isdir(os.path.join(self.dir, f)): + continue + file_name = os.path.join(self.dir, f) + if f == OPENSHIFT_TEMPLATE: + self.oc_template = file_name + + def _get_expose(self, value): + return value.split() + + def _get_env(self, value): + return value.split(" ") + + def _get_volume(self, value): + return get_string(value) + + def _get_label(self, value): + labels = re.sub('\s\s+', ';', value).split(';') + label_dict = {l.split('=')[0]: l.split('=')[1] for l in labels} + return label_dict + + def _get_docker_tags(self): + tmp_dir = tempfile.mkdtemp() + if os.path.isdir(tmp_dir): + shutil.rmtree(tmp_dir) + os.makedirs(tmp_dir) + shutil.copyfile(self.dockerfile, os.path.join(tmp_dir, "Dockerfile")) + dfp = DockerfileParser(path=tmp_dir) + inst = "instruction" + allowed_tags = [ENV, EXPOSE, VOLUME, LABEL] + functions = {ENV: self._get_env, + EXPOSE: self._get_expose, + VOLUME: self._get_volume, + LABEL: self._get_label} + + for struct in dfp.structure: + key = struct[inst] + val = struct["value"] + if key in allowed_tags: + if key == LABEL: + if key not in self.docker_dict: + self.docker_dict[key] = {} + self.docker_dict[key].update(functions[key](val)) + else: + if key not in self.docker_dict: + self.docker_dict[key] = [] + ret_val = functions[key](val) + for v in ret_val: + if v not in self.docker_dict[key]: + self.docker_dict[key].append(v) + + shutil.rmtree(tmp_dir) + + def _load_oc_template(self): + with open(self.oc_template, 'r') as f: + try: + templ = yaml.load(f) + except yaml.YAMLError as exc: + print(exc) + return + return templ + + def _get_labels(self, templ): + try: + labels = templ['metadata']['annotation'] + except KeyError: + labels = {} + try: + labels['description'] = self.docker_dict[LABEL]['description'] + labels['tags'] = self.docker_dict[LABEL]['io.openshift.tags'] + except KeyError: + labels['description'] = "EMPTY_DESCRIPTION" + labels['tags'] = 'EMPTY_TAGS' + labels['template'] = self.docker_image + return labels + + def _get_docker_volumes(self): + volume_list = [] + volume_names = [] + if 'VOLUME' in self.docker_dict and self.docker_dict[VOLUME]: + for p in self.docker_dict[VOLUME]: + volume_list.append({'mountPath': p, + 'name': 'name' + p.replace('/', '-')}) + volume_names.append({'name': 'name' + p.replace('/', '-'), + 'emptyDir': {} + }) + return volume_list, volume_names + + def _get_docker_env(self): + env_list = [] + if 'ENV' in self.docker_dict and self.docker_dict[ENV]: + for e in self.docker_dict[ENV]: + key, val = e.split('=') + env_list.append({'name': key, + 'value': val}) + return env_list + + def _get_docker_expose(self): + ports_list = [] + + for p in self.docker_dict[EXPOSE]: + ports_list.append({'containerPort': int(p)}) + return ports_list + + def write_oc_template(self, templ): + tmp_dir = tempfile.mkdtemp() + if os.path.isdir(tmp_dir): + shutil.rmtree(tmp_dir) + os.makedirs(tmp_dir) + tmp_file = os.path.join(tmp_dir, os.path.basename(self.oc_template)) + with open(tmp_file, 'w') as f: + try: + yaml.safe_dump(templ, f, default_flow_style=False) + print("OpenShift template is generated here: %s" % (tmp_file)) + except yaml.YAMLError as exc: + print(exc) + + def generate_oc_template(self): + templ = self._load_oc_template() + + if self.docker_dict: + labels = self._get_labels(templ) + volume_list, volume_names = self._get_docker_volumes() + env_list = self._get_docker_env() + ports_list = self._get_docker_expose() + templ['metadata']['name'] = self.docker_image + templ['metadata']['annotation'] = labels + for obj in templ['objects']: + obj['spec']['dockerImageRepository'] = self.docker_image + obj['metadata']['name'] = self.docker_image + if 'template' in obj['spec']: + obj['spec']['template']['metadata']['labels']['name'] = self.docker_image + containers = obj['spec']['template']['spec']['containers'][0] + if env_list: + containers['env'] = env_list + if ports_list: + containers['ports'] = ports_list + if volume_list: + containers['volumeMounts'] = volume_list + obj['spec']['template']['spec']['volumes'] = volume_names + containers['name'] = self.docker_image + containers['image'] = self.docker_image + + if 'triggers' in obj['spec']: + for trig in obj['spec']['triggers']: + trig['imageChangeParams']['containerNames'] = [self.docker_image] + trig['imageChangeParams']['from']['name'] = self.docker_image + ":latest" + + return templ + + def run(self): + self._get_files() + self._get_docker_tags() + tmpl = self._load_oc_template(self.docker_dict) + self.write_oc_template(tmpl) + + diff --git a/modularity/oc_template.pyc b/modularity/oc_template.pyc new file mode 100644 index 0000000..7118588 Binary files /dev/null and b/modularity/oc_template.pyc differ diff --git a/tests/.cache/v/cache/lastfailed b/tests/.cache/v/cache/lastfailed new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/tests/.cache/v/cache/lastfailed @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/__init__.pyc b/tests/__init__.pyc new file mode 100644 index 0000000..43de833 Binary files /dev/null and b/tests/__init__.pyc differ diff --git a/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc b/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc new file mode 100644 index 0000000..0b8e47b Binary files /dev/null and b/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc differ diff --git a/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc b/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc new file mode 100644 index 0000000..8f5055b Binary files /dev/null and b/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc differ diff --git a/tests/files/Dockerfile b/tests/files/Dockerfile new file mode 100644 index 0000000..4f7883a --- /dev/null +++ b/tests/files/Dockerfile @@ -0,0 +1,30 @@ +FROM fedora:25 + +RUN dnf install -y --setopt=tsflags=nodocs && \ + dnf -y clean all + +LABEL summary="Testing Summary." \ + version="1.0" \ + description="DESCRIPTION." \ + io.k8s.description="IO_K8S_DESCRIPTION." \ + io.k8s.display-name="IO_K8S_DISPLAY_NAME." \ + io.openshift.expose-services="1234:EXPOSE_SERVICES" \ + io.openshift.tags="TAGS" + +MAINTAINER "Foo Bar" + +ENV POSTFIX_SMTP_PORT=10025 + +ADD files /files + + +EXPOSE 1234 2345 +EXPOSE 6789 + +# Postfix UID based from Fedora +# USER 89 + +VOLUME ['/var/log', '/var/spool/log'] +VOLUME ['/var/spool/mail'] + +CMD ["/files/start.sh"] \ No newline at end of file diff --git a/tests/files/openshift-template.yml b/tests/files/openshift-template.yml new file mode 100644 index 0000000..955d0d0 --- /dev/null +++ b/tests/files/openshift-template.yml @@ -0,0 +1,61 @@ +--- +kind: Template # Link https://docs.openshift.org/latest/dev_guide/templates.html +apiVersion: v1 +metadata: + name: #specify-template-name +labels: + template: #label. Prefer the same as metadata:name + description: #description of your template + tags: #optional: can be tagged for quick finding in OpenShift +objects: + - kind: ImageStream + apiVersion: v1 + metadata: + name: #name of you docker image + spec: + dockerImageRepository: # specify docker image. Either name in your docker repository or reference to github.io + # example: helloworld:latest which is visible from your `docker images` command + # example: docker.io/fedora:latest + tags: + - name: latest + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: # name of your DeploymentConfig. I would prefer to use the same as Template + spec: + strategy: + type: Rolling + triggers: + - type: ImageChange + imageChangeParams: + automatic: true + containerNames: + - # Name of your container image. Taken from kind:ImageStream:name + from: + kind: ImageStreamTag + name: # Specify what version do you need. Usually the latest like fedora:latest + # Another one + # kind: DockerImage + # name: openshift/python-35-centos7:latest + replicas: 1 + template: + metadata: + labels: + name: # I would prefer to use the same as template:metadata:name + spec: + containers: # Container specification + - env: # This is a list + - name: REDIS_PASSWORD + value: #define a value like ${REDIS_PASSWORD} + name: # Name. Use the same as ImageStream + image: # Use the same as kind:ImageStream:spec:dockerImageRepository + imagePullPolicy: Never # Never means, user will care about it. Deleting means, Update the image automaticaly + ports: # List ports which are used within a container on which service is listening. + - containerPort: #Port1 + - containerPort: #Port2 + volumeMounts: # Can be repeated several times + - mountPath: #Specify mount point on the container + name: #Unique name which will be used in kind:DeploymentConfig:spec:template:spec:volumes + volumes: # Can be repeated + - name: # The same as in template:spec:containers:volumeMounts:name + emptyDir: #If you want to persist data, specify dir on your host system. Once container is down, your data will be in the directory. If you don't need it skip it. # For more information see https://docs.openshift.org/latest/dev_guide/persistent_volumes.html diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..9cce04f --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# + +from modularity.cli import CLI + + +class TestCLI(object): + """ + The test suite is used for testing CLI class + """ + def test_cli_unit(self): + """Function tests cli class with all arguments""" + conf = {'dockerfile': 'Dockerfile.testing', + 'image': 'Testing_image'} + arguments = ['--dockerfile', 'Dockerfile.testing', + 'Testing_image'] + cli = CLI(arguments) + for key, value in cli.args.__dict__.items(): + assert cli.args.__dict__[key] == conf[key] diff --git a/tests/test_oc_template.py b/tests/test_oc_template.py new file mode 100644 index 0000000..d13534d --- /dev/null +++ b/tests/test_oc_template.py @@ -0,0 +1,129 @@ +# - *- coding: utf-8 -*- + + +import pytest +import tempfile +import shutil +import os +import six + +from modularity.cli import CLI +from modularity.oc_template import OpenShiftTemplateGenerator +from modularity.oc_template import VOLUME, ENV, EXPOSE, LABEL + + +class TestOCTemplate(object): + ostg = None + WORKING_DIR = '' + TESTS_DIR = os.path.dirname(__file__) + docker_tags = {} + + def setup(self): + self.WORKING_DIR = tempfile.mkdtemp(prefix="ostg-") + arguments = ['--dockerfile', 'Dockerfile', 'docker_image'] + cli = CLI(arguments) + self.ostg = OpenShiftTemplateGenerator(cli, self.WORKING_DIR) + for f in ['Dockerfile', 'openshift-template.yml']: + shutil.copy(os.path.join(os.path.dirname(__file__), + 'files', + f), + self.WORKING_DIR) + os.chdir(self.WORKING_DIR) + self.ostg._get_files() + self.docker_tags = self.ostg._get_docker_tags() + + def teardown(self): + os.chdir(self.TESTS_DIR) + shutil.rmtree(self.WORKING_DIR) + + def test_oc_check_docker_tags(self): + expected_tags = {VOLUME: ['/var/log', '/var/spool/log', '/var/spool/mail'], + EXPOSE: ['1234', '2345', '6789'], + LABEL: {u'io.k8s.description': '"IO_K8S_DESCRIPTION."', + 'version': '"1.0"', + 'description': '"DESCRIPTION."', + 'io.openshift.expose-services': '"1234:EXPOSE_SERVICES"', + 'io.k8s.display-name': '"IO_K8S_DISPLAY_NAME."', + 'io.openshift.tags': '"TAGS"', + 'summary': '"Testing Summary."'}} + for key, value in six.iteritems(self.ostg.docker_dict): + if key in expected_tags: + assert value == expected_tags[key] + + def test_oc_template_generation(self): + tmpl = self.ostg._load_oc_template() + assert True + + def test_docker_volumes(self): + expected_volume_list = [{'mountPath': '/var/log', 'name': 'name-var-log'}, + {'mountPath': '/var/spool/log', 'name': 'name-var-spool-log'}, + {'mountPath': '/var/spool/mail', 'name': 'name-var-spool-mail'}] + expected_volume_names = [{'emptyDir': {}, 'name': 'name-var-log'}, + {'emptyDir': {}, 'name': 'name-var-spool-log'}, + {'emptyDir': {}, 'name': 'name-var-spool-mail'}] + volume_list, volume_names = self.ostg._get_docker_volumes() + assert volume_list == expected_volume_list + assert volume_names == expected_volume_names + + def test_docker_env(self): + expected_env_list = [{'name': 'POSTFIX_SMTP_PORT', 'value': '10025'}] + env_list = self.ostg._get_docker_env() + assert env_list == expected_env_list + + def test_docker_expose(self): + expected_expose_list = [{'containerPort': 1234}, + {'containerPort': 2345}, + {'containerPort': 6789}] + expose_list = self.ostg._get_docker_expose() + assert expose_list == expected_expose_list + + def test_generate_oc(self): + expected_tmpl = {'apiVersion': 'v1', + 'kind': 'Template', + 'labels': {'description': None, 'tags': None, 'template': None}, + 'metadata': {'annotation': {'description': u'"DESCRIPTION."', + 'tags': u'"TAGS"', + 'template': 'docker_image'}, + 'name': 'docker_image'}, + 'objects': [{'apiVersion': 'v1', + 'kind': 'ImageStream', + 'metadata': {'name': 'docker_image'}, + 'spec': {'dockerImageRepository': 'docker_image'}, + 'tags': [{'name': 'latest'}]}, + {'apiVersion': 'v1', + 'kind': 'DeploymentConfig', + 'metadata': {'name': 'docker_image'}, + 'spec': {'dockerImageRepository': 'docker_image', + 'replicas': 1, + 'strategy': {'type': 'Rolling'}, + 'template': {'metadata': {'labels': {'name': 'docker_image'}}, + 'spec': {'containers': [{'env': [{'name': u'POSTFIX_SMTP_PORT', + 'value': u'10025'}], + 'image': 'docker_image', + 'imagePullPolicy': 'Never', + 'name': 'docker_image', + 'ports': [{'containerPort': 1234}, + {'containerPort': 2345}, + {'containerPort': 6789}], + 'volumeMounts': [{'mountPath': '/var/log', + 'name': 'name-var-log'}, + {'mountPath': '/var/spool/log', + 'name': 'name-var-spool-log'}, + {'mountPath': '/var/spool/mail', + 'name': 'name-var-spool-mail'}]}], + 'volumes': [{'emptyDir': {}, + 'name': 'name-var-log'}, + {'emptyDir': {}, + 'name': 'name-var-spool-log'}, + {'emptyDir': {}, + 'name': 'name-var-spool-mail'}]}}, + 'triggers': [{'imageChangeParams': {'automatic': True, + 'containerNames': ['docker_image'], + 'from': {'kind': 'ImageStreamTag', + 'name': 'docker_image:latest'}}, + 'type': 'ImageChange'}] + } + }] + } + tmpl = self.ostg.generate_oc_template() + assert tmpl == expected_tmpl \ No newline at end of file From 34679514bcc4da43b5be6a52a1f74df9e365e2ac Mon Sep 17 00:00:00 2001 From: Petr "Stone" Hracek Date: Feb 07 2017 12:45:47 +0000 Subject: [PATCH 3/4] Add gitignore and more tests for build_oc_template Signed-off-by: Petr "Stone" Hracek --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..83f1996 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +*.py[cod] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 + +# Installer logs +pip-log.txt + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject +.spyderproject +.idea +..rej +.spyderworkspace +.cache + diff --git a/modularity/oc_template.py b/modularity/oc_template.py index ba757d6..1133335 100644 --- a/modularity/oc_template.py +++ b/modularity/oc_template.py @@ -168,14 +168,15 @@ class OpenShiftTemplateGenerator(object): except yaml.YAMLError as exc: print(exc) - def generate_oc_template(self): - templ = self._load_oc_template() - + def get_docker_directives(self, templ): if self.docker_dict: labels = self._get_labels(templ) volume_list, volume_names = self._get_docker_volumes() env_list = self._get_docker_env() ports_list = self._get_docker_expose() + return labels, volume_list, volume_names, env_list, ports_list + + def generate_oc_template(self, templ, labels, volume_list, volume_names, env_list, ports_list): templ['metadata']['name'] = self.docker_image templ['metadata']['annotation'] = labels for obj in templ['objects']: @@ -204,7 +205,8 @@ class OpenShiftTemplateGenerator(object): def run(self): self._get_files() self._get_docker_tags() - tmpl = self._load_oc_template(self.docker_dict) + templ = self._load_oc_template() + tmpl = self.generate_oc_template(templ, *self.get_docker_directives(templ)) self.write_oc_template(tmpl) diff --git a/modularity/oc_template.pyc b/modularity/oc_template.pyc deleted file mode 100644 index 7118588..0000000 Binary files a/modularity/oc_template.pyc and /dev/null differ diff --git a/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc b/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc deleted file mode 100644 index 8f5055b..0000000 Binary files a/tests/__pycache__/test_oc_template.cpython-27-PYTEST.pyc and /dev/null differ diff --git a/tests/test_oc_template.py b/tests/test_oc_template.py index d13534d..a004d98 100644 --- a/tests/test_oc_template.py +++ b/tests/test_oc_template.py @@ -125,5 +125,66 @@ class TestOCTemplate(object): } }] } - tmpl = self.ostg.generate_oc_template() - assert tmpl == expected_tmpl \ No newline at end of file + templ = self.ostg._load_oc_template() + (args) = self.ostg.get_docker_directives(templ) + tmpl = self.ostg.generate_oc_template(templ, *args) + assert tmpl == expected_tmpl + + def test_missing_annotation(self): + expected_tmpl = {'apiVersion': 'v1', + 'kind': 'Template', + 'labels': {'description': None, 'tags': None, 'template': None}, + 'metadata': {'annotation': {'tags': u'"TAGS"', + 'template': 'docker_image'}, + 'name': 'docker_image'}, + 'objects': [{'apiVersion': 'v1', + 'kind': 'ImageStream', + 'metadata': {'name': 'docker_image'}, + 'spec': {'dockerImageRepository': 'docker_image'}, + 'tags': [{'name': 'latest'}]}, + {'apiVersion': 'v1', + 'kind': 'DeploymentConfig', + 'metadata': {'name': 'docker_image'}, + 'spec': {'dockerImageRepository': 'docker_image', + 'replicas': 1, + 'strategy': {'type': 'Rolling'}, + 'template': {'metadata': {'labels': {'name': 'docker_image'}}, + 'spec': {'containers': [{'env': [{'name': u'POSTFIX_SMTP_PORT', + 'value': u'10025'}], + 'image': 'docker_image', + 'imagePullPolicy': 'Never', + 'name': 'docker_image', + 'ports': [{'containerPort': 1234}, + {'containerPort': 2345}, + {'containerPort': 6789}], + 'volumeMounts': [{'mountPath': '/var/log', + 'name': 'name-var-log'}, + {'mountPath': '/var/spool/log', + 'name': 'name-var-spool-log'}, + {'mountPath': '/var/spool/mail', + 'name': 'name-var-spool-mail'}]}], + 'volumes': [{'emptyDir': {}, + 'name': 'name-var-log'}, + {'emptyDir': {}, + 'name': 'name-var-spool-log'}, + {'emptyDir': {}, + 'name': 'name-var-spool-mail'}]}}, + 'triggers': [{'imageChangeParams': {'automatic': True, + 'containerNames': ['docker_image'], + 'from': {'kind': 'ImageStreamTag', + 'name': 'docker_image:latest'}}, + 'type': 'ImageChange'}] + } + }] + } + templ = self.ostg._load_oc_template() + labels, volume_list, volume_names, env_list, ports_list = self.ostg.get_docker_directives(templ) + del labels['description'] + tmpl = self.ostg.generate_oc_template(templ, + labels, + volume_list, + volume_names, + env_list, + ports_list) + assert tmpl == expected_tmpl + From 32ac15ba12a7de5ed3bc98ba720a6221305478e6 Mon Sep 17 00:00:00 2001 From: Petr "Stone" Hracek Date: Mar 17 2017 11:36:48 +0000 Subject: [PATCH 4/4] Several fixes. Signed-off-by: Petr "Stone" Hracek --- diff --git a/.gitignore b/.gitignore index 83f1996..8d09458 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ pip-log.txt .spyderworkspace .cache +tests/openshift-template.yml \ No newline at end of file diff --git a/README.md b/README.md index e69de29..8588bcc 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,33 @@ +# Modularity-tools + +## Requirements +Following packages are required: + * python2-pytest + +## build_oc_template.py + +The tool is used for generation OpenShift template from Dockerfile and from [https://github.com/container-images/container-image-template/blob/master/openshift-template.yml](openshift-template.yml) already prepared by Modularity team. +As Dockerfile as openshift-template.yml have to exist in the directory. + +### How to use build_oc_template.py +Run the command with following parameters: + + `./build_oc_template.py --dockerfile IMAGENAME` + + where parameters mean: + * dockerfile ... means full path to Dockerfile + * IMAGENAME ... means image name in register. Can be taken from command `docker images` or from some other registry. + +The output of **build_oc_template.py** command is OpenShift template stored in temporary directory + +Example usage: +```bash + ./build_oc_template.py --dockerfile ~/work/programming/container-images/debugging-tools/Dockerfile registry.fedoraproject.org/debugging-tools +/home/phracek/work/programming/container-images/debugging-tools/Dockerfile + OpenShift template is generated here: /tmp/tmpM0teUC/openshift-template.yml +``` +### How to run tests for build_oc_template.py + +In order to run tests, run command: + +`py.test-2.7 tests/` \ No newline at end of file diff --git a/modularity/__init__.pyc b/modularity/__init__.pyc deleted file mode 100644 index 0cc4b00..0000000 Binary files a/modularity/__init__.pyc and /dev/null differ diff --git a/modularity/cli.py b/modularity/cli.py index b758551..6d3350b 100644 --- a/modularity/cli.py +++ b/modularity/cli.py @@ -45,6 +45,6 @@ class CliHelper(object): otg.run() except KeyboardInterrupt: print('\nInterrupted by user') - except Exception as e: - print('\n%s', e) - sys.exit(1) + # except Exception as e: + # print(e) + # sys.exit(1) diff --git a/modularity/cli.pyc b/modularity/cli.pyc deleted file mode 100644 index 2e1cc0f..0000000 Binary files a/modularity/cli.pyc and /dev/null differ diff --git a/modularity/oc_template.py b/modularity/oc_template.py index 1133335..6311447 100644 --- a/modularity/oc_template.py +++ b/modularity/oc_template.py @@ -17,6 +17,7 @@ EXPOSE = "EXPOSE" VOLUME = "VOLUME" LABEL = "LABEL" ENV = "ENV" +PORTS = "PORTS" # OpenShift template OPENSHIFT_TEMPLATE = "openshift-template.yml" @@ -32,7 +33,7 @@ class OpenShiftTemplateGenerator(object): It requires openshift-template.yml file. """ - docker_file = None + dockerfile = None oc_template = None docker_dict = {} @@ -46,11 +47,32 @@ class OpenShiftTemplateGenerator(object): self.dockerfile = 'Dockerfile' else: self.dockerfile = os.path.join(self.dir, args.dockerfile) + self.docker_dict = {} - def _get_files(self): + def _exist_docker_file(self): + """ + Function checks if docker file exists + :return: True if exists + """ if not os.path.exists(self.dockerfile): - print("Dockerfile %s does not exists." % self.dockerfile) - return + print("Dockerfile has to exists in the %s directory." % self.dir) + return False + return True + + def _exist_openshift_template(self): + """ + Function checks if openshift template exists + :return: True if exists + """ + if self.oc_template is None: + print("%s has to exists in the %s directory." % (OPENSHIFT_TEMPLATE, self.dir)) + return False + return True + + def _get_openshift_template(self): + """ + Function sets openshift template. + """ for f in os.listdir(self.dir): if os.path.isdir(os.path.join(self.dir, f)): continue @@ -59,20 +81,39 @@ class OpenShiftTemplateGenerator(object): self.oc_template = file_name def _get_expose(self, value): + """Function returns exposes as field""" return value.split() def _get_env(self, value): + """Function gets env as field""" return value.split(" ") def _get_volume(self, value): + """Function evaluates a value and returns as string.""" return get_string(value) def _get_label(self, value): + """ + Function returns label from Docker file + except INSTALL, UNINSTALL and RUN label used by atomic. + :param value: row from Dockerfile + :return: label_dict + """ + untracked_values = ['INSTALL', 'UNINSTALL', 'RUN'] + if [f for f in untracked_values if value.startswith(f)]: + return None labels = re.sub('\s\s+', ';', value).split(';') + labels = [l.replace('"', '') for l in labels] label_dict = {l.split('=')[0]: l.split('=')[1] for l in labels} return label_dict def _get_docker_tags(self): + """ + Function analyses dockerfile and extracts + ENV, VOLUME, EXPOSE and LABEL directives. + """ + if not self._exist_docker_file(): + return tmp_dir = tempfile.mkdtemp() if os.path.isdir(tmp_dir): shutil.rmtree(tmp_dir) @@ -93,7 +134,9 @@ class OpenShiftTemplateGenerator(object): if key == LABEL: if key not in self.docker_dict: self.docker_dict[key] = {} - self.docker_dict[key].update(functions[key](val)) + value = functions[key](val) + if value is not None: + self.docker_dict[key].update(value) else: if key not in self.docker_dict: self.docker_dict[key] = [] @@ -105,32 +148,59 @@ class OpenShiftTemplateGenerator(object): shutil.rmtree(tmp_dir) def _load_oc_template(self): + """ + Function loads openshift template + :return: YAML dictionary + """ + if not self._exist_openshift_template(): + return None with open(self.oc_template, 'r') as f: try: templ = yaml.load(f) except yaml.YAMLError as exc: print(exc) - return + raise return templ def _get_labels(self, templ): + labels = None try: - labels = templ['metadata']['annotation'] + labels = templ['metadata']['labels'] except KeyError: labels = {} + raise_exception = False try: labels['description'] = self.docker_dict[LABEL]['description'] + except KeyError: + print("Label Description is missing in Dockerfile. It is mandatory.") + raise_exception = True + try: labels['tags'] = self.docker_dict[LABEL]['io.openshift.tags'] except KeyError: - labels['description'] = "EMPTY_DESCRIPTION" - labels['tags'] = 'EMPTY_TAGS' + print('Label tags is missing in Dockerfile. It is mandatory.') + raise_exception = True + if raise_exception: + raise KeyError labels['template'] = self.docker_image return labels + def _get_docker_labels(self): + """ + Function returns docker labels + :return: label dictionary + """ + if LABEL in self.docker_dict and self.docker_dict[LABEL]: + return self.docker_dict[LABEL] + return None + def _get_docker_volumes(self): + """ + Function returns docker volumes and labels + :return: volume list, volume names + """ volume_list = [] volume_names = [] - if 'VOLUME' in self.docker_dict and self.docker_dict[VOLUME]: + if VOLUME in self.docker_dict and self.docker_dict[VOLUME]: for p in self.docker_dict[VOLUME]: volume_list.append({'mountPath': p, 'name': 'name' + p.replace('/', '-')}) @@ -140,8 +210,12 @@ class OpenShiftTemplateGenerator(object): return volume_list, volume_names def _get_docker_env(self): + """ + Function return docker ENV directives + :return: list of ENV variables + """ env_list = [] - if 'ENV' in self.docker_dict and self.docker_dict[ENV]: + if ENV in self.docker_dict and self.docker_dict[ENV]: for e in self.docker_dict[ENV]: key, val = e.split('=') env_list.append({'name': key, @@ -149,13 +223,22 @@ class OpenShiftTemplateGenerator(object): return env_list def _get_docker_expose(self): + """ + Function return docker EXPOSE directives + :return: list of PORTS + """ ports_list = [] - - for p in self.docker_dict[EXPOSE]: - ports_list.append({'containerPort': int(p)}) + if EXPOSE in self.docker_dict and self.docker_dict[EXPOSE]: + for p in self.docker_dict[EXPOSE]: + ports_list.append({'containerPort': int(p)}) return ports_list def write_oc_template(self, templ): + """ + Function writes a YAML dictionary into template + :param templ: YAML template with all data + :return: + """ tmp_dir = tempfile.mkdtemp() if os.path.isdir(tmp_dir): shutil.rmtree(tmp_dir) @@ -167,8 +250,15 @@ class OpenShiftTemplateGenerator(object): print("OpenShift template is generated here: %s" % (tmp_file)) except yaml.YAMLError as exc: print(exc) + raise def get_docker_directives(self, templ): + """ + Function collects all directives + :param templ: + :return: label_list, volume_list, volume_names, env_list, ports_list + """ + labels = volume_list = volume_names = env_list = ports_list = None if self.docker_dict: labels = self._get_labels(templ) volume_list, volume_names = self._get_docker_volumes() @@ -177,8 +267,18 @@ class OpenShiftTemplateGenerator(object): return labels, volume_list, volume_names, env_list, ports_list def generate_oc_template(self, templ, labels, volume_list, volume_names, env_list, ports_list): + """ + Function fulfills template with data taken from Dockerfile. + :param templ: YAML openshift templates + :param labels: list of labels + :param volume_list: volume list + :param volume_names: volume names + :param env_list: env list + :param ports_list: port list + :return: template with all data + """ templ['metadata']['name'] = self.docker_image - templ['metadata']['annotation'] = labels + templ['metadata']['labels'] = labels for obj in templ['objects']: obj['spec']['dockerImageRepository'] = self.docker_image obj['metadata']['name'] = self.docker_image @@ -186,12 +286,19 @@ class OpenShiftTemplateGenerator(object): obj['spec']['template']['metadata']['labels']['name'] = self.docker_image containers = obj['spec']['template']['spec']['containers'][0] if env_list: - containers['env'] = env_list + containers["env"] = env_list + else: + containers.pop("env") if ports_list: - containers['ports'] = ports_list + containers["ports"] = ports_list + else: + containers.pop("ports") if volume_list: containers['volumeMounts'] = volume_list obj['spec']['template']['spec']['volumes'] = volume_names + else: + containers.pop('volumeMounts') + obj['spec']['template']['spec'].pop('volumes') containers['name'] = self.docker_image containers['image'] = self.docker_image @@ -203,10 +310,19 @@ class OpenShiftTemplateGenerator(object): return templ def run(self): - self._get_files() + """ + Main function + :return: + """ + self._get_openshift_template() + if not self._exist_docker_file() or not self._exist_openshift_template(): + return 1 self._get_docker_tags() templ = self._load_oc_template() - tmpl = self.generate_oc_template(templ, *self.get_docker_directives(templ)) + try: + tmpl = self.generate_oc_template(templ, *self.get_docker_directives(templ)) + except KeyError: + return 1 self.write_oc_template(tmpl) diff --git a/tests/__init__.pyc b/tests/__init__.pyc deleted file mode 100644 index 43de833..0000000 Binary files a/tests/__init__.pyc and /dev/null differ diff --git a/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc b/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc deleted file mode 100644 index 0b8e47b..0000000 Binary files a/tests/__pycache__/test_cli.cpython-27-PYTEST.pyc and /dev/null differ diff --git a/tests/test_oc_template.py b/tests/test_oc_template.py index a004d98..38b777a 100644 --- a/tests/test_oc_template.py +++ b/tests/test_oc_template.py @@ -6,12 +6,23 @@ import tempfile import shutil import os import six +import urllib from modularity.cli import CLI from modularity.oc_template import OpenShiftTemplateGenerator from modularity.oc_template import VOLUME, ENV, EXPOSE, LABEL +def init_oc_template_generator(dockerfile, image_name, working_dir): + arguments = ['--dockerfile', dockerfile, image_name] + cli = CLI(arguments) + ostg = OpenShiftTemplateGenerator(cli, working_dir) + oc_template = urllib.URLopener() + oc_template.retrieve('https://raw.githubusercontent.com/container-images/container-image-template/master/openshift-template.yml', + os.path.join(os.path.dirname(__file__), 'openshift-template.yml')) + return ostg + + class TestOCTemplate(object): ostg = None WORKING_DIR = '' @@ -20,16 +31,11 @@ class TestOCTemplate(object): def setup(self): self.WORKING_DIR = tempfile.mkdtemp(prefix="ostg-") - arguments = ['--dockerfile', 'Dockerfile', 'docker_image'] - cli = CLI(arguments) - self.ostg = OpenShiftTemplateGenerator(cli, self.WORKING_DIR) - for f in ['Dockerfile', 'openshift-template.yml']: - shutil.copy(os.path.join(os.path.dirname(__file__), - 'files', - f), - self.WORKING_DIR) + self.ostg = init_oc_template_generator(os.path.join(self. TESTS_DIR, 'files', 'Dockerfile'), + 'docker_image', + self.TESTS_DIR) os.chdir(self.WORKING_DIR) - self.ostg._get_files() + self.ostg._get_openshift_template() self.docker_tags = self.ostg._get_docker_tags() def teardown(self): @@ -38,17 +44,82 @@ class TestOCTemplate(object): def test_oc_check_docker_tags(self): expected_tags = {VOLUME: ['/var/log', '/var/spool/log', '/var/spool/mail'], + ENV: ['POSTFIX_SMTP_PORT=10025'], EXPOSE: ['1234', '2345', '6789'], - LABEL: {u'io.k8s.description': '"IO_K8S_DESCRIPTION."', - 'version': '"1.0"', - 'description': '"DESCRIPTION."', - 'io.openshift.expose-services': '"1234:EXPOSE_SERVICES"', - 'io.k8s.display-name': '"IO_K8S_DISPLAY_NAME."', - 'io.openshift.tags': '"TAGS"', - 'summary': '"Testing Summary."'}} + LABEL: {u'io.k8s.description': u'IO_K8S_DESCRIPTION.', + u'version': u'1.0', + u'description': u'DESCRIPTION.', + u'io.openshift.expose-services': u'1234:EXPOSE_SERVICES', + u'io.k8s.display-name': u'IO_K8S_DISPLAY_NAME.', + u'io.openshift.tags': u'TAGS', + u'summary': u'Testing Summary.'}} for key, value in six.iteritems(self.ostg.docker_dict): if key in expected_tags: assert value == expected_tags[key] + else: + print(key) + assert False + + def test_check_missing_exposes(self): + expected_tags = {VOLUME: ['/var/log', '/var/spool/log', '/var/spool/mail'], + ENV: ['POSTFIX_SMTP_PORT=10025'], + LABEL: {'io.k8s.description': 'IO_K8S_DESCRIPTION.', + 'version': '1.0', + 'description': 'DESCRIPTION.', + 'io.openshift.expose-services': '1234:EXPOSE_SERVICES', + 'io.k8s.display-name': 'IO_K8S_DISPLAY_NAME.', + 'io.openshift.tags': 'TAGS', + 'summary': 'Testing Summary.'}} + self.ostg.docker_dict.pop('EXPOSE') + for key, value in six.iteritems(self.ostg.docker_dict): + if key in expected_tags: + assert value == expected_tags[key] + else: + print(key) + assert False + + def test_check_missing_labels(self): + expected_tags = {VOLUME: ['/var/log', '/var/spool/log', '/var/spool/mail'], + EXPOSE: ['1234', '2345', '6789'], + ENV: ['POSTFIX_SMTP_PORT=10025'] + } + self.ostg.docker_dict.pop('LABEL') + for key, value in six.iteritems(self.ostg.docker_dict): + if key in expected_tags: + assert value == expected_tags[key] + else: + assert False + + def test_check_missing_some_labels(self): + expected_tags = {VOLUME: ['/var/log', '/var/spool/log', '/var/spool/mail'], + ENV: ['POSTFIX_SMTP_PORT=10025'], + EXPOSE: ['1234', '2345', '6789'], + LABEL: {u'io.k8s.description': 'IO_K8S_DESCRIPTION.', + 'version': '1.0', + 'description': 'DESCRIPTION.', + 'io.openshift.tags': 'TAGS', + 'summary': 'Testing Summary.'}} + self.ostg.docker_dict['LABEL'].pop('io.openshift.expose-services') + self.ostg.docker_dict['LABEL'].pop('io.k8s.display-name') + for key, value in six.iteritems(self.ostg.docker_dict): + if key in expected_tags: + assert value == expected_tags[key] + else: + print(key) + assert False + + def test_check_missing_all(self): + expected_tags = {} + self.ostg.docker_dict.pop('LABEL') + self.ostg.docker_dict.pop('VOLUME') + self.ostg.docker_dict.pop('ENV') + self.ostg.docker_dict.pop('EXPOSE') + for key, value in six.iteritems(self.ostg.docker_dict): + if key in expected_tags: + assert value == expected_tags[key] + else: + print(key) + assert False def test_oc_template_generation(self): tmpl = self.ostg._load_oc_template() @@ -80,11 +151,10 @@ class TestOCTemplate(object): def test_generate_oc(self): expected_tmpl = {'apiVersion': 'v1', 'kind': 'Template', - 'labels': {'description': None, 'tags': None, 'template': None}, - 'metadata': {'annotation': {'description': u'"DESCRIPTION."', - 'tags': u'"TAGS"', - 'template': 'docker_image'}, - 'name': 'docker_image'}, + 'metadata': {'name': 'docker_image', + 'labels': {'description': u'DESCRIPTION.', 'tags': u'TAGS', + 'template': 'docker_image'}, + }, 'objects': [{'apiVersion': 'v1', 'kind': 'ImageStream', 'metadata': {'name': 'docker_image'}, @@ -133,9 +203,8 @@ class TestOCTemplate(object): def test_missing_annotation(self): expected_tmpl = {'apiVersion': 'v1', 'kind': 'Template', - 'labels': {'description': None, 'tags': None, 'template': None}, - 'metadata': {'annotation': {'tags': u'"TAGS"', - 'template': 'docker_image'}, + 'metadata': {'labels': {'tags': u'TAGS', + 'template': 'docker_image'}, 'name': 'docker_image'}, 'objects': [{'apiVersion': 'v1', 'kind': 'ImageStream', @@ -188,3 +257,48 @@ class TestOCTemplate(object): ports_list) assert tmpl == expected_tmpl + + +class TestCockpitDockerFromDistGit(object): + ostg = None + WORKING_DIR = '' + TESTS_DIR = os.path.dirname(__file__) + docker_tags = {} + cockpit_name = None + + def setup(self): + self.WORKING_DIR = tempfile.mkdtemp(prefix="ostg-") + self.cockpit_name = 'Dockerfile-Cockpit' + docker = urllib.URLopener() + docker.retrieve('http://pkgs.fedoraproject.org/cgit/docker/cockpit.git/plain/Dockerfile', + os.path.join(os.path.dirname(__file__), self.cockpit_name)) + self.ostg = init_oc_template_generator(self.cockpit_name, + 'docker_image', + self.TESTS_DIR) + self.ostg._get_openshift_template() + self.ostg._get_docker_tags() + + def test_cockit_env(self): + expected_env = [{'name': u'VERSION', + 'value': u'125'}, + {'name': u'RELEASE', + 'value': u'1.6'} + ] + assert expected_env == self.ostg._get_docker_env() + + def test_cockit_label(self): + expected_label = {u'Architecture': u'x86_64', + u'BZComponent': u'cockpit', + u'Name': u'$FGC/cockpit', + u'Release': u'$RELEASE.$DISTTAG', + u'Version': u'$VERSION'} + assert expected_label == self.ostg._get_docker_labels() + + def test_cockit_volume(self): + expected_volume = ([],[]) + assert expected_volume == self.ostg._get_docker_volumes() + + def teardown(self): + os.chdir(self.TESTS_DIR) + os.unlink(self.cockpit_name) + shutil.rmtree(self.WORKING_DIR)