From 30ac30ff81c7fcca4aaf12c8567d3b7c90a18626 Mon Sep 17 00:00:00 2001 From: Petr "Stone" Hracek Date: Jan 24 2017 09:50:08 +0000 Subject: [PATCH 1/3] 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/3] 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/3] 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 +