diff options
Diffstat (limited to 'roles/lib_openshift/src/lib')
-rw-r--r-- | roles/lib_openshift/src/lib/base.py | 64 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/deploymentconfig.py | 15 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/import.py | 7 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/replicationcontroller.py | 7 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/rolebinding.py | 289 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/secret.py | 5 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/service.py | 5 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/serviceaccount.py | 2 | ||||
-rw-r--r-- | roles/lib_openshift/src/lib/volume.py | 38 |
9 files changed, 412 insertions, 20 deletions
diff --git a/roles/lib_openshift/src/lib/base.py b/roles/lib_openshift/src/lib/base.py index a895b40b3..d037074a5 100644 --- a/roles/lib_openshift/src/lib/base.py +++ b/roles/lib_openshift/src/lib/base.py @@ -9,6 +9,32 @@ class OpenShiftCLIError(Exception): pass +ADDITIONAL_PATH_LOOKUPS = ['/usr/local/bin', os.path.expanduser('~/bin')] + + +def locate_oc_binary(): + ''' Find and return oc binary file ''' + # https://github.com/openshift/openshift-ansible/issues/3410 + # oc can be in /usr/local/bin in some cases, but that may not + # be in $PATH due to ansible/sudo + paths = os.environ.get("PATH", os.defpath).split(os.pathsep) + ADDITIONAL_PATH_LOOKUPS + + oc_binary = 'oc' + + # Use shutil.which if it is available, otherwise fallback to a naive path search + try: + which_result = shutil.which(oc_binary, path=os.pathsep.join(paths)) + if which_result is not None: + oc_binary = which_result + except AttributeError: + for path in paths: + if os.path.exists(os.path.join(path, oc_binary)): + oc_binary = os.path.join(path, oc_binary) + break + + return oc_binary + + # pylint: disable=too-few-public-methods class OpenShiftCLI(object): ''' Class to wrap the command line tools ''' @@ -22,6 +48,7 @@ class OpenShiftCLI(object): self.verbose = verbose self.kubeconfig = Utils.create_tmpfile_copy(kubeconfig) self.all_namespaces = all_namespaces + self.oc_binary = locate_oc_binary() # Pylint allows only 5 arguments to be passed. # pylint: disable=too-many-arguments @@ -218,24 +245,23 @@ class OpenShiftCLI(object): stdout, stderr = proc.communicate(input_data) - return proc.returncode, stdout, stderr + return proc.returncode, stdout.decode(), stderr.decode() # pylint: disable=too-many-arguments,too-many-branches def openshift_cmd(self, cmd, oadm=False, output=False, output_type='json', input_data=None): '''Base command for oc ''' - cmds = [] + cmds = [self.oc_binary] + if oadm: - cmds = ['oadm'] - else: - cmds = ['oc'] + cmds.append('adm') + + cmds.extend(cmd) if self.all_namespaces: cmds.extend(['--all-namespaces']) elif self.namespace is not None and self.namespace.lower() not in ['none', 'emtpy']: # E501 cmds.extend(['-n', self.namespace]) - cmds.extend(cmd) - rval = {} results = '' err = None @@ -243,7 +269,10 @@ class OpenShiftCLI(object): if self.verbose: print(' '.join(cmds)) - returncode, stdout, stderr = self._run(cmds, input_data) + try: + returncode, stdout, stderr = self._run(cmds, input_data) + except OSError as ex: + returncode, stdout, stderr = 1, '', 'Failed to execute {}: {}'.format(subprocess.list2cmdline(cmds), ex) rval = {"returncode": returncode, "results": results, @@ -295,7 +324,13 @@ class Utils(object): tmp = Utils.create_tmpfile(prefix=rname) if ftype == 'yaml': - Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper)) + # AUDIT:no-member makes sense here due to ruamel.YAML/PyYAML usage + # pylint: disable=no-member + if hasattr(yaml, 'RoundTripDumper'): + Utils._write(tmp, yaml.dump(data, Dumper=yaml.RoundTripDumper)) + else: + Utils._write(tmp, yaml.safe_dump(data, default_flow_style=False)) + elif ftype == 'json': Utils._write(tmp, json.dumps(data)) else: @@ -377,7 +412,12 @@ class Utils(object): contents = sfd.read() if sfile_type == 'yaml': - contents = yaml.load(contents, yaml.RoundTripLoader) + # AUDIT:no-member makes sense here due to ruamel.YAML/PyYAML usage + # pylint: disable=no-member + if hasattr(yaml, 'RoundTripLoader'): + contents = yaml.load(contents, yaml.RoundTripLoader) + else: + contents = yaml.safe_load(contents) elif sfile_type == 'json': contents = json.loads(contents) @@ -483,8 +523,8 @@ class Utils(object): elif value != user_def[key]: if debug: print('value should be identical') - print(value) print(user_def[key]) + print(value) return False # recurse on a dictionary @@ -504,8 +544,8 @@ class Utils(object): if api_values != user_values: if debug: print("keys are not equal in dict") - print(api_values) print(user_values) + print(api_values) return False result = Utils.check_def_equal(user_def[key], value, skip_keys=skip_keys, debug=debug) diff --git a/roles/lib_openshift/src/lib/deploymentconfig.py b/roles/lib_openshift/src/lib/deploymentconfig.py index e060d3707..0549bba84 100644 --- a/roles/lib_openshift/src/lib/deploymentconfig.py +++ b/roles/lib_openshift/src/lib/deploymentconfig.py @@ -4,7 +4,7 @@ # pylint: disable=too-many-public-methods class DeploymentConfig(Yedit): - ''' Class to wrap the oc command line tools ''' + ''' Class to model an openshift DeploymentConfig''' default_deployment_config = ''' apiVersion: v1 kind: DeploymentConfig @@ -68,7 +68,6 @@ spec: super(DeploymentConfig, self).__init__(content=content) - # pylint: disable=no-member def add_env_value(self, key, value): ''' add key, value pair to env array ''' rval = False @@ -106,6 +105,18 @@ spec: return False + def get_env_var(self, key): + '''return a environment variables ''' + results = self.get(DeploymentConfig.env_path) or [] + if not results: + return None + + for env_var in results: + if env_var['name'] == key: + return env_var + + return None + def get_env_vars(self): '''return a environment variables ''' return self.get(DeploymentConfig.env_path) or [] diff --git a/roles/lib_openshift/src/lib/import.py b/roles/lib_openshift/src/lib/import.py index 6344c1a54..a79297898 100644 --- a/roles/lib_openshift/src/lib/import.py +++ b/roles/lib_openshift/src/lib/import.py @@ -7,6 +7,7 @@ from __future__ import print_function import atexit +import copy import json import os import re @@ -14,5 +15,9 @@ import shutil import subprocess import tempfile # pylint: disable=import-error -import ruamel.yaml as yaml +try: + import ruamel.yaml as yaml +except ImportError: + import yaml + from ansible.module_utils.basic import AnsibleModule diff --git a/roles/lib_openshift/src/lib/replicationcontroller.py b/roles/lib_openshift/src/lib/replicationcontroller.py index ae585a986..8bcc1e3cc 100644 --- a/roles/lib_openshift/src/lib/replicationcontroller.py +++ b/roles/lib_openshift/src/lib/replicationcontroller.py @@ -4,7 +4,12 @@ # pylint: disable=too-many-public-methods class ReplicationController(DeploymentConfig): - ''' Class to wrap the oc command line tools ''' + ''' Class to model a replicationcontroller openshift object. + + Currently we are modeled after a deployment config since they + are very similar. In the future, when the need arises we + will add functionality to this class. + ''' replicas_path = "spec.replicas" env_path = "spec.template.spec.containers[0].env" volumes_path = "spec.template.spec.volumes" diff --git a/roles/lib_openshift/src/lib/rolebinding.py b/roles/lib_openshift/src/lib/rolebinding.py new file mode 100644 index 000000000..69629f9f5 --- /dev/null +++ b/roles/lib_openshift/src/lib/rolebinding.py @@ -0,0 +1,289 @@ +# pylint: skip-file +# flake8: noqa + +# pylint: disable=too-many-instance-attributes +class RoleBindingConfig(object): + ''' Handle rolebinding config ''' + # pylint: disable=too-many-arguments + def __init__(self, + name, + namespace, + kubeconfig, + group_names=None, + role_ref=None, + subjects=None, + usernames=None): + ''' constructor for handling rolebinding options ''' + self.kubeconfig = kubeconfig + self.name = name + self.namespace = namespace + self.group_names = group_names + self.role_ref = role_ref + self.subjects = subjects + self.usernames = usernames + self.data = {} + + self.create_dict() + + def create_dict(self): + ''' create a default rolebinding as a dict ''' + self.data['apiVersion'] = 'v1' + self.data['kind'] = 'RoleBinding' + self.data['groupNames'] = self.group_names + self.data['metadata']['name'] = self.name + self.data['metadata']['namespace'] = self.namespace + + self.data['roleRef'] = self.role_ref + self.data['subjects'] = self.subjects + self.data['userNames'] = self.usernames + + +# pylint: disable=too-many-instance-attributes,too-many-public-methods +class RoleBinding(Yedit): + ''' Class to model a rolebinding openshift object''' + group_names_path = "groupNames" + role_ref_path = "roleRef" + subjects_path = "subjects" + user_names_path = "userNames" + + kind = 'RoleBinding' + + def __init__(self, content): + '''RoleBinding constructor''' + super(RoleBinding, self).__init__(content=content) + self._subjects = None + self._role_ref = None + self._group_names = None + self._user_names = None + + @property + def subjects(self): + ''' subjects property ''' + if self._subjects is None: + self._subjects = self.get_subjects() + return self._subjects + + @subjects.setter + def subjects(self, data): + ''' subjects property setter''' + self._subjects = data + + @property + def role_ref(self): + ''' role_ref property ''' + if self._role_ref is None: + self._role_ref = self.get_role_ref() + return self._role_ref + + @role_ref.setter + def role_ref(self, data): + ''' role_ref property setter''' + self._role_ref = data + + @property + def group_names(self): + ''' group_names property ''' + if self._group_names is None: + self._group_names = self.get_group_names() + return self._group_names + + @group_names.setter + def group_names(self, data): + ''' group_names property setter''' + self._group_names = data + + @property + def user_names(self): + ''' user_names property ''' + if self._user_names is None: + self._user_names = self.get_user_names() + return self._user_names + + @user_names.setter + def user_names(self, data): + ''' user_names property setter''' + self._user_names = data + + def get_group_names(self): + ''' return groupNames ''' + return self.get(RoleBinding.group_names_path) or [] + + def get_user_names(self): + ''' return usernames ''' + return self.get(RoleBinding.user_names_path) or [] + + def get_role_ref(self): + ''' return role_ref ''' + return self.get(RoleBinding.role_ref_path) or {} + + def get_subjects(self): + ''' return subjects ''' + return self.get(RoleBinding.subjects_path) or [] + + #### ADD ##### + def add_subject(self, inc_subject): + ''' add a subject ''' + if self.subjects: + # pylint: disable=no-member + self.subjects.append(inc_subject) + else: + self.put(RoleBinding.subjects_path, [inc_subject]) + + return True + + def add_role_ref(self, inc_role_ref): + ''' add a role_ref ''' + if not self.role_ref: + self.put(RoleBinding.role_ref_path, {"name": inc_role_ref}) + return True + + return False + + def add_group_names(self, inc_group_names): + ''' add a group_names ''' + if self.group_names: + # pylint: disable=no-member + self.group_names.append(inc_group_names) + else: + self.put(RoleBinding.group_names_path, [inc_group_names]) + + return True + + def add_user_name(self, inc_user_name): + ''' add a username ''' + if self.user_names: + # pylint: disable=no-member + self.user_names.append(inc_user_name) + else: + self.put(RoleBinding.user_names_path, [inc_user_name]) + + return True + + #### /ADD ##### + + #### Remove ##### + def remove_subject(self, inc_subject): + ''' remove a subject ''' + try: + # pylint: disable=no-member + self.subjects.remove(inc_subject) + except ValueError as _: + return False + + return True + + def remove_role_ref(self, inc_role_ref): + ''' remove a role_ref ''' + if self.role_ref and self.role_ref['name'] == inc_role_ref: + del self.role_ref['name'] + return True + + return False + + def remove_group_name(self, inc_group_name): + ''' remove a groupname ''' + try: + # pylint: disable=no-member + self.group_names.remove(inc_group_name) + except ValueError as _: + return False + + return True + + def remove_user_name(self, inc_user_name): + ''' remove a username ''' + try: + # pylint: disable=no-member + self.user_names.remove(inc_user_name) + except ValueError as _: + return False + + return True + + #### /REMOVE ##### + + #### UPDATE ##### + def update_subject(self, inc_subject): + ''' update a subject ''' + try: + # pylint: disable=no-member + index = self.subjects.index(inc_subject) + except ValueError as _: + return self.add_subject(inc_subject) + + self.subjects[index] = inc_subject + + return True + + def update_group_name(self, inc_group_name): + ''' update a groupname ''' + try: + # pylint: disable=no-member + index = self.group_names.index(inc_group_name) + except ValueError as _: + return self.add_group_names(inc_group_name) + + self.group_names[index] = inc_group_name + + return True + + def update_user_name(self, inc_user_name): + ''' update a username ''' + try: + # pylint: disable=no-member + index = self.user_names.index(inc_user_name) + except ValueError as _: + return self.add_user_name(inc_user_name) + + self.user_names[index] = inc_user_name + + return True + + def update_role_ref(self, inc_role_ref): + ''' update a role_ref ''' + self.role_ref['name'] = inc_role_ref + + return True + + #### /UPDATE ##### + + #### FIND #### + def find_subject(self, inc_subject): + ''' find a subject ''' + index = None + try: + # pylint: disable=no-member + index = self.subjects.index(inc_subject) + except ValueError as _: + return index + + return index + + def find_group_name(self, inc_group_name): + ''' find a group_name ''' + index = None + try: + # pylint: disable=no-member + index = self.group_names.index(inc_group_name) + except ValueError as _: + return index + + return index + + def find_user_name(self, inc_user_name): + ''' find a user_name ''' + index = None + try: + # pylint: disable=no-member + index = self.user_names.index(inc_user_name) + except ValueError as _: + return index + + return index + + def find_role_ref(self, inc_role_ref): + ''' find a user_name ''' + if self.role_ref and self.role_ref['name'] == inc_role_ref['name']: + return self.role_ref + + return None diff --git a/roles/lib_openshift/src/lib/secret.py b/roles/lib_openshift/src/lib/secret.py index 39bf3c33a..75c32e8b1 100644 --- a/roles/lib_openshift/src/lib/secret.py +++ b/roles/lib_openshift/src/lib/secret.py @@ -20,7 +20,7 @@ class SecretConfig(object): self.create_dict() def create_dict(self): - ''' return a secret as a dict ''' + ''' assign the correct properties for a secret dict ''' self.data['apiVersion'] = 'v1' self.data['kind'] = 'Secret' self.data['metadata'] = {} @@ -90,8 +90,7 @@ class Secret(Yedit): def update_secret(self, key, value): ''' update a secret''' - # pylint: disable=no-member - if self.secrets.has_key(key): + if key in self.secrets: self.secrets[key] = value else: self.add_secret(key, value) diff --git a/roles/lib_openshift/src/lib/service.py b/roles/lib_openshift/src/lib/service.py index ffe27da47..eef568779 100644 --- a/roles/lib_openshift/src/lib/service.py +++ b/roles/lib_openshift/src/lib/service.py @@ -67,6 +67,7 @@ class Service(Yedit): port_path = "spec.ports" portal_ip = "spec.portalIP" cluster_ip = "spec.clusterIP" + selector_path = 'spec.selector' kind = 'Service' def __init__(self, content): @@ -77,6 +78,10 @@ class Service(Yedit): ''' get a list of ports ''' return self.get(Service.port_path) or [] + def get_selector(self): + ''' get the service selector''' + return self.get(Service.selector_path) or {} + def add_ports(self, inc_ports): ''' add a port object to the ports list ''' if not isinstance(inc_ports, list): diff --git a/roles/lib_openshift/src/lib/serviceaccount.py b/roles/lib_openshift/src/lib/serviceaccount.py index 47a55757e..50c104d44 100644 --- a/roles/lib_openshift/src/lib/serviceaccount.py +++ b/roles/lib_openshift/src/lib/serviceaccount.py @@ -18,7 +18,7 @@ class ServiceAccountConfig(object): self.create_dict() def create_dict(self): - ''' return a properly structured volume ''' + ''' instantiate a properly structured volume ''' self.data['apiVersion'] = 'v1' self.data['kind'] = 'ServiceAccount' self.data['metadata'] = {} diff --git a/roles/lib_openshift/src/lib/volume.py b/roles/lib_openshift/src/lib/volume.py new file mode 100644 index 000000000..e0abb1d1b --- /dev/null +++ b/roles/lib_openshift/src/lib/volume.py @@ -0,0 +1,38 @@ +# pylint: skip-file +# flake8: noqa + +class Volume(object): + ''' Class to model an openshift volume object''' + volume_mounts_path = {"pod": "spec.containers[0].volumeMounts", + "dc": "spec.template.spec.containers[0].volumeMounts", + "rc": "spec.template.spec.containers[0].volumeMounts", + } + volumes_path = {"pod": "spec.volumes", + "dc": "spec.template.spec.volumes", + "rc": "spec.template.spec.volumes", + } + + @staticmethod + def create_volume_structure(volume_info): + ''' return a properly structured volume ''' + volume_mount = None + volume = {'name': volume_info['name']} + volume_type = volume_info['type'].lower() + if volume_type == 'secret': + volume['secret'] = {} + volume[volume_info['type']] = {'secretName': volume_info['secret_name']} + volume_mount = {'mountPath': volume_info['path'], + 'name': volume_info['name']} + elif volume_type == 'emptydir': + volume['emptyDir'] = {} + volume_mount = {'mountPath': volume_info['path'], + 'name': volume_info['name']} + elif volume_type == 'pvc' or volume_type == 'persistentvolumeclaim': + volume['persistentVolumeClaim'] = {} + volume['persistentVolumeClaim']['claimName'] = volume_info['claimName'] + volume['persistentVolumeClaim']['claimSize'] = volume_info['claimSize'] + elif volume_type == 'hostpath': + volume['hostPath'] = {} + volume['hostPath']['path'] = volume_info['path'] + + return (volume, volume_mount) |