summaryrefslogtreecommitdiffstats
path: root/roles/lib_openshift/src
diff options
context:
space:
mode:
Diffstat (limited to 'roles/lib_openshift/src')
-rw-r--r--roles/lib_openshift/src/ansible/oc_adm_registry.py47
-rw-r--r--roles/lib_openshift/src/ansible/oc_adm_router.py67
-rw-r--r--roles/lib_openshift/src/class/oc_adm_registry.py399
-rw-r--r--roles/lib_openshift/src/class/oc_adm_router.py453
-rw-r--r--roles/lib_openshift/src/doc/registry192
-rw-r--r--roles/lib_openshift/src/doc/router217
-rw-r--r--roles/lib_openshift/src/lib/deploymentconfig.py2
-rw-r--r--roles/lib_openshift/src/lib/replicationcontroller.py7
-rw-r--r--roles/lib_openshift/src/lib/rolebinding.py289
-rw-r--r--roles/lib_openshift/src/lib/secret.py2
-rw-r--r--roles/lib_openshift/src/lib/serviceaccount.py2
-rw-r--r--roles/lib_openshift/src/lib/volume.py37
-rw-r--r--roles/lib_openshift/src/sources.yml30
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oadm_manage_node.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_env.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_label.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_process.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_route.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_scale.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_secret.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_service.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_serviceaccount.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_serviceaccount_secret.py0
-rwxr-xr-x[-rw-r--r--]roles/lib_openshift/src/test/unit/test_oc_version.py0
24 files changed, 1740 insertions, 4 deletions
diff --git a/roles/lib_openshift/src/ansible/oc_adm_registry.py b/roles/lib_openshift/src/ansible/oc_adm_registry.py
new file mode 100644
index 000000000..a49b84589
--- /dev/null
+++ b/roles/lib_openshift/src/ansible/oc_adm_registry.py
@@ -0,0 +1,47 @@
+# pylint: skip-file
+# flake8: noqa
+
+def main():
+ '''
+ ansible oc module for registry
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ state=dict(default='present', type='str',
+ choices=['present', 'absent']),
+ debug=dict(default=False, type='bool'),
+ namespace=dict(default='default', type='str'),
+ name=dict(default=None, required=True, type='str'),
+
+ kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+ images=dict(default=None, type='str'),
+ latest_images=dict(default=False, type='bool'),
+ labels=dict(default=None, type='list'),
+ ports=dict(default=['5000'], type='list'),
+ replicas=dict(default=1, type='int'),
+ selector=dict(default=None, type='str'),
+ service_account=dict(default='registry', type='str'),
+ mount_host=dict(default=None, type='str'),
+ volume_mounts=dict(default=None, type='list'),
+ env_vars=dict(default=None, type='dict'),
+ edits=dict(default=None, type='list'),
+ enforce_quota=dict(default=False, type='bool'),
+ force=dict(default=False, type='bool'),
+ daemonset=dict(default=False, type='bool'),
+ tls_key=dict(default=None, type='str'),
+ tls_certificate=dict(default=None, type='str'),
+ ),
+
+ supports_check_mode=True,
+ )
+
+ results = Registry.run_ansible(module.params, module.check_mode)
+ if 'failed' in results:
+ module.fail_json(**results)
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/roles/lib_openshift/src/ansible/oc_adm_router.py b/roles/lib_openshift/src/ansible/oc_adm_router.py
new file mode 100644
index 000000000..48c9f0ec1
--- /dev/null
+++ b/roles/lib_openshift/src/ansible/oc_adm_router.py
@@ -0,0 +1,67 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+def main():
+ '''
+ ansible oc module for router
+ '''
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ state=dict(default='present', type='str',
+ choices=['present', 'absent']),
+ debug=dict(default=False, type='bool'),
+ namespace=dict(default='default', type='str'),
+ name=dict(default='router', type='str'),
+
+ kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'),
+ default_cert=dict(default=None, type='str'),
+ cert_file=dict(default=None, type='str'),
+ key_file=dict(default=None, type='str'),
+ images=dict(default=None, type='str'), #'openshift3/ose-${component}:${version}'
+ latest_images=dict(default=False, type='bool'),
+ labels=dict(default=None, type='list'),
+ ports=dict(default=['80:80', '443:443'], type='list'),
+ replicas=dict(default=1, type='int'),
+ selector=dict(default=None, type='str'),
+ service_account=dict(default='router', type='str'),
+ router_type=dict(default='haproxy-router', type='str'),
+ host_network=dict(default=True, type='bool'),
+ # external host options
+ external_host=dict(default=None, type='str'),
+ external_host_vserver=dict(default=None, type='str'),
+ external_host_insecure=dict(default=False, type='bool'),
+ external_host_partition_path=dict(default=None, type='str'),
+ external_host_username=dict(default=None, type='str'),
+ external_host_password=dict(default=None, type='str'),
+ external_host_private_key=dict(default=None, type='str'),
+ # Metrics
+ expose_metrics=dict(default=False, type='bool'),
+ metrics_image=dict(default=None, type='str'),
+ # Stats
+ stats_user=dict(default=None, type='str'),
+ stats_password=dict(default=None, type='str'),
+ stats_port=dict(default=1936, type='int'),
+ # extra
+ cacert_file=dict(default=None, type='str'),
+ # edits
+ edits=dict(default=[], type='list'),
+ ),
+ mutually_exclusive=[["router_type", "images"],
+ ["key_file", "default_cert"],
+ ["cert_file", "default_cert"],
+ ],
+
+ supports_check_mode=True,
+ )
+ results = Router.run_ansible(module.params, module.check_mode)
+
+ if 'failed' in results:
+ module.fail_json(**results)
+
+ module.exit_json(**results)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/roles/lib_openshift/src/class/oc_adm_registry.py b/roles/lib_openshift/src/class/oc_adm_registry.py
new file mode 100644
index 000000000..8cb7aea31
--- /dev/null
+++ b/roles/lib_openshift/src/class/oc_adm_registry.py
@@ -0,0 +1,399 @@
+# pylint: skip-file
+# flake8: noqa
+
+class RegistryException(Exception):
+ ''' Registry Exception Class '''
+ pass
+
+
+class RegistryConfig(OpenShiftCLIConfig):
+ ''' RegistryConfig is a DTO for the registry. '''
+ def __init__(self, rname, namespace, kubeconfig, registry_options):
+ super(RegistryConfig, self).__init__(rname, namespace, kubeconfig, registry_options)
+
+
+class Registry(OpenShiftCLI):
+ ''' Class to wrap the oc command line tools '''
+
+ volume_mount_path = 'spec.template.spec.containers[0].volumeMounts'
+ volume_path = 'spec.template.spec.volumes'
+ env_path = 'spec.template.spec.containers[0].env'
+
+ def __init__(self,
+ registry_config,
+ verbose=False):
+ ''' Constructor for Registry
+
+ a registry consists of 3 or more parts
+ - dc/docker-registry
+ - svc/docker-registry
+
+ Parameters:
+ :registry_config:
+ :verbose:
+ '''
+ super(Registry, self).__init__(registry_config.namespace, registry_config.kubeconfig, verbose)
+ self.version = OCVersion(registry_config.kubeconfig, verbose)
+ self.svc_ip = None
+ self.portal_ip = None
+ self.config = registry_config
+ self.verbose = verbose
+ self.registry_parts = [{'kind': 'dc', 'name': self.config.name},
+ {'kind': 'svc', 'name': self.config.name},
+ ]
+
+ self.__prepared_registry = None
+ self.volume_mounts = []
+ self.volumes = []
+ if self.config.config_options['volume_mounts']['value']:
+ for volume in self.config.config_options['volume_mounts']['value']:
+ volume_info = {'secret_name': volume.get('secret_name', None),
+ 'name': volume.get('name', None),
+ 'type': volume.get('type', None),
+ 'path': volume.get('path', None),
+ 'claimName': volume.get('claim_name', None),
+ 'claimSize': volume.get('claim_size', None),
+ }
+
+ vol, vol_mount = Volume.create_volume_structure(volume_info)
+ self.volumes.append(vol)
+ self.volume_mounts.append(vol_mount)
+
+ self.dconfig = None
+ self.svc = None
+
+ @property
+ def deploymentconfig(self):
+ ''' deploymentconfig property '''
+ return self.dconfig
+
+ @deploymentconfig.setter
+ def deploymentconfig(self, config):
+ ''' setter for deploymentconfig property '''
+ self.dconfig = config
+
+ @property
+ def service(self):
+ ''' service property '''
+ return self.svc
+
+ @service.setter
+ def service(self, config):
+ ''' setter for service property '''
+ self.svc = config
+
+ @property
+ def prepared_registry(self):
+ ''' prepared_registry property '''
+ if not self.__prepared_registry:
+ results = self.prepare_registry()
+ if not results:
+ raise RegistryException('Could not perform registry preparation.')
+ self.__prepared_registry = results
+
+ return self.__prepared_registry
+
+ @prepared_registry.setter
+ def prepared_registry(self, data):
+ ''' setter method for prepared_registry attribute '''
+ self.__prepared_registry = data
+
+ def get(self):
+ ''' return the self.registry_parts '''
+ self.deploymentconfig = None
+ self.service = None
+
+ rval = 0
+ for part in self.registry_parts:
+ result = self._get(part['kind'], rname=part['name'])
+ if result['returncode'] == 0 and part['kind'] == 'dc':
+ self.deploymentconfig = DeploymentConfig(result['results'][0])
+ elif result['returncode'] == 0 and part['kind'] == 'svc':
+ self.service = Yedit(content=result['results'][0])
+
+ if result['returncode'] != 0:
+ rval = result['returncode']
+
+
+ return {'returncode': rval, 'deploymentconfig': self.deploymentconfig, 'service': self.service}
+
+ def exists(self):
+ '''does the object exist?'''
+ self.get()
+ if self.deploymentconfig or self.service:
+ return True
+
+ return False
+
+ def delete(self, complete=True):
+ '''return all pods '''
+ parts = []
+ for part in self.registry_parts:
+ if not complete and part['kind'] == 'svc':
+ continue
+ parts.append(self._delete(part['kind'], part['name']))
+
+ # Clean up returned results
+ rval = 0
+ for part in parts:
+ # pylint: disable=invalid-sequence-index
+ if 'returncode' in part and part['returncode'] != 0:
+ rval = part['returncode']
+
+ return {'returncode': rval, 'results': parts}
+
+ def prepare_registry(self):
+ ''' prepare a registry for instantiation '''
+ options = self.config.to_option_list()
+
+ cmd = ['registry', '-n', self.config.namespace]
+ cmd.extend(options)
+ cmd.extend(['--dry-run=True', '-o', 'json'])
+
+ results = self.openshift_cmd(cmd, oadm=True, output=True, output_type='json')
+ # probably need to parse this
+ # pylint thinks results is a string
+ # pylint: disable=no-member
+ if results['returncode'] != 0 and results['results'].has_key('items'):
+ return results
+
+ service = None
+ deploymentconfig = None
+ # pylint: disable=invalid-sequence-index
+ for res in results['results']['items']:
+ if res['kind'] == 'DeploymentConfig':
+ deploymentconfig = DeploymentConfig(res)
+ elif res['kind'] == 'Service':
+ service = Service(res)
+
+ # Verify we got a service and a deploymentconfig
+ if not service or not deploymentconfig:
+ return results
+
+ # results will need to get parsed here and modifications added
+ deploymentconfig = DeploymentConfig(self.add_modifications(deploymentconfig))
+
+ # modify service ip
+ if self.svc_ip:
+ service.put('spec.clusterIP', self.svc_ip)
+ if self.portal_ip:
+ service.put('spec.portalIP', self.portal_ip)
+
+ # need to create the service and the deploymentconfig
+ service_file = Utils.create_tmp_file_from_contents('service', service.yaml_dict)
+ deployment_file = Utils.create_tmp_file_from_contents('deploymentconfig', deploymentconfig.yaml_dict)
+
+ return {"service": service,
+ "service_file": service_file,
+ "service_update": False,
+ "deployment": deploymentconfig,
+ "deployment_file": deployment_file,
+ "deployment_update": False}
+
+ def create(self):
+ '''Create a registry'''
+ results = []
+ for config_file in ['deployment_file', 'service_file']:
+ results.append(self._create(self.prepared_registry[config_file]))
+
+ # Clean up returned results
+ rval = 0
+ for result in results:
+ # pylint: disable=invalid-sequence-index
+ if 'returncode' in result and result['returncode'] != 0:
+ rval = result['returncode']
+
+ return {'returncode': rval, 'results': results}
+
+ def update(self):
+ '''run update for the registry. This performs a delete and then create '''
+ # Store the current service IP
+ if self.service:
+ svcip = self.service.get('spec.clusterIP')
+ if svcip:
+ self.svc_ip = svcip
+ portip = self.service.get('spec.portalIP')
+ if portip:
+ self.portal_ip = portip
+
+ results = []
+ if self.prepared_registry['deployment_update']:
+ results.append(self._replace(self.prepared_registry['deployment_file']))
+ if self.prepared_registry['service_update']:
+ results.append(self._replace(self.prepared_registry['service_file']))
+
+ # Clean up returned results
+ rval = 0
+ for result in results:
+ if result['returncode'] != 0:
+ rval = result['returncode']
+
+ return {'returncode': rval, 'results': results}
+
+ def add_modifications(self, deploymentconfig):
+ ''' update a deployment config with changes '''
+ # Currently we know that our deployment of a registry requires a few extra modifications
+ # Modification 1
+ # we need specific environment variables to be set
+ for key, value in self.config.config_options['env_vars']['value'].items():
+ if not deploymentconfig.exists_env_key(key):
+ deploymentconfig.add_env_value(key, value)
+ else:
+ deploymentconfig.update_env_var(key, value)
+
+ # Modification 2
+ # we need specific volume variables to be set
+ for volume in self.volumes:
+ deploymentconfig.update_volume(volume)
+
+ for vol_mount in self.volume_mounts:
+ deploymentconfig.update_volume_mount(vol_mount)
+
+ # Modification 3
+ # Edits
+ edit_results = []
+ for edit in self.config.config_options['edits'].get('value', []):
+ if edit['action'] == 'put':
+ edit_results.append(deploymentconfig.put(edit['key'],
+ edit['value']))
+ if edit['action'] == 'update':
+ edit_results.append(deploymentconfig.update(edit['key'],
+ edit['value'],
+ edit.get('index', None),
+ edit.get('curr_value', None)))
+ if edit['action'] == 'append':
+ edit_results.append(deploymentconfig.append(edit['key'],
+ edit['value']))
+
+ if edit_results and not any([res[0] for res in edit_results]):
+ return None
+
+ return deploymentconfig.yaml_dict
+
+ def needs_update(self):
+ ''' check to see if we need to update '''
+ if not self.service or not self.deploymentconfig:
+ return True
+
+ exclude_list = ['clusterIP', 'portalIP', 'type', 'protocol']
+ if not Utils.check_def_equal(self.prepared_registry['service'].yaml_dict,
+ self.service.yaml_dict,
+ exclude_list,
+ debug=self.verbose):
+ self.prepared_registry['service_update'] = True
+
+ exclude_list = ['dnsPolicy',
+ 'terminationGracePeriodSeconds',
+ 'restartPolicy', 'timeoutSeconds',
+ 'livenessProbe', 'readinessProbe',
+ 'terminationMessagePath',
+ 'securityContext',
+ 'imagePullPolicy',
+ 'protocol', # ports.portocol: TCP
+ 'type', # strategy: {'type': 'rolling'}
+ 'defaultMode', # added on secrets
+ 'activeDeadlineSeconds', # added in 1.5 for timeouts
+ ]
+
+ if not Utils.check_def_equal(self.prepared_registry['deployment'].yaml_dict,
+ self.deploymentconfig.yaml_dict,
+ exclude_list,
+ debug=self.verbose):
+ self.prepared_registry['deployment_update'] = True
+
+ return self.prepared_registry['deployment_update'] or self.prepared_registry['service_update'] or False
+
+ # In the future, we would like to break out each ansible state into a function.
+ # pylint: disable=too-many-branches,too-many-return-statements
+ @staticmethod
+ def run_ansible(params, check_mode):
+ '''run idempotent ansible code'''
+
+ rconfig = RegistryConfig(params['name'],
+ params['namespace'],
+ params['kubeconfig'],
+ {'images': {'value': params['images'], 'include': True},
+ 'latest_images': {'value': params['latest_images'], 'include': True},
+ 'labels': {'value': params['labels'], 'include': True},
+ 'ports': {'value': ','.join(params['ports']), 'include': True},
+ 'replicas': {'value': params['replicas'], 'include': True},
+ 'selector': {'value': params['selector'], 'include': True},
+ 'service_account': {'value': params['service_account'], 'include': True},
+ 'mount_host': {'value': params['mount_host'], 'include': True},
+ 'env_vars': {'value': params['env_vars'], 'include': False},
+ 'volume_mounts': {'value': params['volume_mounts'], 'include': False},
+ 'edits': {'value': params['edits'], 'include': False},
+ 'enforce_quota': {'value': params['enforce_quota'], 'include': True},
+ 'daemonset': {'value': params['daemonset'], 'include': True},
+ 'tls_key': {'value': params['tls_key'], 'include': True},
+ 'tls_certificate': {'value': params['tls_certificate'], 'include': True},
+ })
+
+
+ ocregistry = Registry(rconfig, params['debug'])
+
+ api_rval = ocregistry.get()
+
+ state = params['state']
+ ########
+ # get
+ ########
+ if state == 'list':
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': False, 'results': api_rval, 'state': state}
+
+ ########
+ # Delete
+ ########
+ if state == 'absent':
+ if not ocregistry.exists():
+ return {'changed': False, 'state': state}
+
+ if check_mode:
+ return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a delete.'}
+
+ # Unsure as to why this is angry with the return type.
+ # pylint: disable=redefined-variable-type
+ api_rval = ocregistry.delete()
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': True, 'results': api_rval, 'state': state}
+
+ if state == 'present':
+ ########
+ # Create
+ ########
+ if not ocregistry.exists():
+
+ if check_mode:
+ return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a create.'}
+
+ api_rval = ocregistry.create()
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': True, 'results': api_rval, 'state': state}
+
+ ########
+ # Update
+ ########
+ if not params['force'] and not ocregistry.needs_update():
+ return {'changed': False, 'state': state}
+
+ if check_mode:
+ return {'changed': True, 'msg': 'CHECK_MODE: Would have performed an update.'}
+
+ api_rval = ocregistry.update()
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': True, 'results': api_rval, 'state': state}
+
+ return {'failed': True, 'msg': 'Unknown state passed. %s' % state}
diff --git a/roles/lib_openshift/src/class/oc_adm_router.py b/roles/lib_openshift/src/class/oc_adm_router.py
new file mode 100644
index 000000000..9d61cfdf2
--- /dev/null
+++ b/roles/lib_openshift/src/class/oc_adm_router.py
@@ -0,0 +1,453 @@
+# pylint: skip-file
+# flake8: noqa
+
+
+class RouterException(Exception):
+ ''' Router exception'''
+ pass
+
+
+class RouterConfig(OpenShiftCLIConfig):
+ ''' RouterConfig is a DTO for the router. '''
+ def __init__(self, rname, namespace, kubeconfig, router_options):
+ super(RouterConfig, self).__init__(rname, namespace, kubeconfig, router_options)
+
+
+class Router(OpenShiftCLI):
+ ''' Class to wrap the oc command line tools '''
+ def __init__(self,
+ router_config,
+ verbose=False):
+ ''' Constructor for OpenshiftOC
+
+ a router consists of 3 or more parts
+ - dc/router
+ - svc/router
+ - sa/router
+ - secret/router-certs
+ - clusterrolebinding/router-router-role
+ '''
+ super(Router, self).__init__('default', router_config.kubeconfig, verbose)
+ self.config = router_config
+ self.verbose = verbose
+ self.router_parts = [{'kind': 'dc', 'name': self.config.name},
+ {'kind': 'svc', 'name': self.config.name},
+ {'kind': 'sa', 'name': self.config.config_options['service_account']['value']},
+ {'kind': 'secret', 'name': self.config.name + '-certs'},
+ {'kind': 'clusterrolebinding', 'name': 'router-' + self.config.name + '-role'},
+ ]
+
+ self.__prepared_router = None
+ self.dconfig = None
+ self.svc = None
+ self._secret = None
+ self._serviceaccount = None
+ self._rolebinding = None
+
+ @property
+ def prepared_router(self):
+ ''' property for the prepared router'''
+ if self.__prepared_router is None:
+ results = self._prepare_router()
+ if not results:
+ raise RouterException('Could not perform router preparation')
+ self.__prepared_router = results
+
+ return self.__prepared_router
+
+ @prepared_router.setter
+ def prepared_router(self, obj):
+ '''setter for the prepared_router'''
+ self.__prepared_router = obj
+
+ @property
+ def deploymentconfig(self):
+ ''' property deploymentconfig'''
+ return self.dconfig
+
+ @deploymentconfig.setter
+ def deploymentconfig(self, config):
+ ''' setter for property deploymentconfig '''
+ self.dconfig = config
+
+ @property
+ def service(self):
+ ''' property for service '''
+ return self.svc
+
+ @service.setter
+ def service(self, config):
+ ''' setter for property service '''
+ self.svc = config
+
+ @property
+ def secret(self):
+ ''' property secret '''
+ return self._secret
+
+ @secret.setter
+ def secret(self, config):
+ ''' setter for property secret '''
+ self._secret = config
+
+ @property
+ def serviceaccount(self):
+ ''' property for serviceaccount '''
+ return self._serviceaccount
+
+ @serviceaccount.setter
+ def serviceaccount(self, config):
+ ''' setter for property serviceaccount '''
+ self._serviceaccount = config
+
+ @property
+ def rolebinding(self):
+ ''' property rolebinding '''
+ return self._rolebinding
+
+ @rolebinding.setter
+ def rolebinding(self, config):
+ ''' setter for property rolebinding '''
+ self._rolebinding = config
+
+ def get(self):
+ ''' return the self.router_parts '''
+ self.service = None
+ self.deploymentconfig = None
+ self.serviceaccount = None
+ self.secret = None
+ self.rolebinding = None
+ for part in self.router_parts:
+ result = self._get(part['kind'], rname=part['name'])
+ if result['returncode'] == 0 and part['kind'] == 'dc':
+ self.deploymentconfig = DeploymentConfig(result['results'][0])
+ elif result['returncode'] == 0 and part['kind'] == 'svc':
+ self.service = Service(content=result['results'][0])
+ elif result['returncode'] == 0 and part['kind'] == 'sa':
+ self.serviceaccount = ServiceAccount(content=result['results'][0])
+ elif result['returncode'] == 0 and part['kind'] == 'secret':
+ self.secret = Secret(content=result['results'][0])
+ elif result['returncode'] == 0 and part['kind'] == 'clusterrolebinding':
+ self.rolebinding = RoleBinding(content=result['results'][0])
+
+ return {'deploymentconfig': self.deploymentconfig,
+ 'service': self.service,
+ 'serviceaccount': self.serviceaccount,
+ 'secret': self.secret,
+ 'clusterrolebinding': self.rolebinding,
+ }
+
+ def exists(self):
+ '''return a whether svc or dc exists '''
+ if self.deploymentconfig and self.service and self.secret and self.serviceaccount:
+ return True
+
+ return False
+
+ def delete(self):
+ '''return all pods '''
+ parts = []
+ for part in self.router_parts:
+ parts.append(self._delete(part['kind'], part['name']))
+
+ rval = 0
+ for part in parts:
+ if part['returncode'] != 0 and not 'already exist' in part['stderr']:
+ rval = part['returncode']
+
+ return {'returncode': rval, 'results': parts}
+
+ def add_modifications(self, deploymentconfig):
+ '''modify the deployment config'''
+ # We want modifications in the form of edits coming in from the module.
+ # Let's apply these here
+ edit_results = []
+ for edit in self.config.config_options['edits'].get('value', []):
+ if edit['action'] == 'put':
+ edit_results.append(deploymentconfig.put(edit['key'],
+ edit['value']))
+ if edit['action'] == 'update':
+ edit_results.append(deploymentconfig.update(edit['key'],
+ edit['value'],
+ edit.get('index', None),
+ edit.get('curr_value', None)))
+ if edit['action'] == 'append':
+ edit_results.append(deploymentconfig.append(edit['key'],
+ edit['value']))
+
+ if edit_results and not any([res[0] for res in edit_results]):
+ return None
+
+ return deploymentconfig
+
+ def _prepare_router(self):
+ '''prepare router for instantiation'''
+ # We need to create the pem file
+ if self.config.config_options['default_cert']['value'] is None:
+ router_pem = '/tmp/router.pem'
+ with open(router_pem, 'w') as rfd:
+ rfd.write(open(self.config.config_options['cert_file']['value']).read())
+ rfd.write(open(self.config.config_options['key_file']['value']).read())
+ if self.config.config_options['cacert_file']['value'] and \
+ os.path.exists(self.config.config_options['cacert_file']['value']):
+ rfd.write(open(self.config.config_options['cacert_file']['value']).read())
+
+ atexit.register(Utils.cleanup, [router_pem])
+ self.config.config_options['default_cert']['value'] = router_pem
+
+ options = self.config.to_option_list()
+
+ cmd = ['router', self.config.name, '-n', self.config.namespace]
+ cmd.extend(options)
+ cmd.extend(['--dry-run=True', '-o', 'json'])
+
+ results = self.openshift_cmd(cmd, oadm=True, output=True, output_type='json')
+
+ # pylint: disable=no-member
+ if results['returncode'] != 0 and 'items' in results['results']:
+ return results
+
+ oc_objects = {'DeploymentConfig': {'obj': None, 'path': None, 'update': False},
+ 'Secret': {'obj': None, 'path': None, 'update': False},
+ 'ServiceAccount': {'obj': None, 'path': None, 'update': False},
+ 'ClusterRoleBinding': {'obj': None, 'path': None, 'update': False},
+ 'Service': {'obj': None, 'path': None, 'update': False},
+ }
+ # pylint: disable=invalid-sequence-index
+ for res in results['results']['items']:
+ if res['kind'] == 'DeploymentConfig':
+ oc_objects['DeploymentConfig']['obj'] = DeploymentConfig(res)
+ elif res['kind'] == 'Service':
+ oc_objects['Service']['obj'] = Service(res)
+ elif res['kind'] == 'ServiceAccount':
+ oc_objects['ServiceAccount']['obj'] = ServiceAccount(res)
+ elif res['kind'] == 'Secret':
+ oc_objects['Secret']['obj'] = Secret(res)
+ elif res['kind'] == 'ClusterRoleBinding':
+ oc_objects['ClusterRoleBinding']['obj'] = RoleBinding(res)
+
+ # Currently only deploymentconfig needs updating
+ # Verify we got a deploymentconfig
+ if not oc_objects['DeploymentConfig']['obj']:
+ return results
+
+ # add modifications added
+ oc_objects['DeploymentConfig']['obj'] = self.add_modifications(oc_objects['DeploymentConfig']['obj'])
+
+ for oc_type, oc_data in oc_objects.items():
+ oc_data['path'] = Utils.create_tmp_file_from_contents(oc_type, oc_data['obj'].yaml_dict)
+
+ return oc_objects
+
+ def create(self):
+ '''Create a deploymentconfig '''
+ results = []
+
+ # pylint: disable=no-member
+ for _, oc_data in self.prepared_router.items():
+ results.append(self._create(oc_data['path']))
+
+ rval = 0
+ for result in results:
+ if result['returncode'] != 0 and not 'already exist' in result['stderr']:
+ rval = result['returncode']
+
+ return {'returncode': rval, 'results': results}
+
+ def update(self):
+ '''run update for the router. This performs a replace'''
+ results = []
+
+ # pylint: disable=no-member
+ for _, oc_data in self.prepared_router.items():
+ if oc_data['update']:
+ results.append(self._replace(oc_data['path']))
+
+ rval = 0
+ for result in results:
+ if result['returncode'] != 0:
+ rval = result['returncode']
+
+ return {'returncode': rval, 'results': results}
+
+ # pylint: disable=too-many-return-statements,too-many-branches
+ def needs_update(self):
+ ''' check to see if we need to update '''
+ if not self.deploymentconfig or not self.service or not self.serviceaccount or not self.secret:
+ return True
+
+ # ServiceAccount:
+ # Need to determine changes from the pregenerated ones from the original
+ # Since these are auto generated, we can skip
+ skip = ['secrets', 'imagePullSecrets']
+ if not Utils.check_def_equal(self.prepared_router['ServiceAccount']['obj'].yaml_dict,
+ self.serviceaccount.yaml_dict,
+ skip_keys=skip,
+ debug=self.verbose):
+ self.prepared_router['ServiceAccount']['update'] = True
+
+ # Secret:
+ # See if one was generated from our dry-run and verify it if needed
+ if self.prepared_router['Secret']['obj']:
+ if not self.secret:
+ self.prepared_router['Secret']['update'] = True
+
+ if not Utils.check_def_equal(self.prepared_router['Secret']['obj'].yaml_dict,
+ self.secret.yaml_dict,
+ skip_keys=skip,
+ debug=self.verbose):
+ self.prepared_router['Secret']['update'] = True
+
+ # Service:
+ # Fix the ports to have protocol=TCP
+ for port in self.prepared_router['Service']['obj'].get('spec.ports'):
+ port['protocol'] = 'TCP'
+
+ skip = ['portalIP', 'clusterIP', 'sessionAffinity', 'type']
+ if not Utils.check_def_equal(self.prepared_router['Service']['obj'].yaml_dict,
+ self.service.yaml_dict,
+ skip_keys=skip,
+ debug=self.verbose):
+ self.prepared_router['Service']['update'] = True
+
+ # DeploymentConfig:
+ # Router needs some exceptions.
+ # We do not want to check the autogenerated password for stats admin
+ if not self.config.config_options['stats_password']['value']:
+ for idx, env_var in enumerate(self.prepared_router['DeploymentConfig']['obj'].get(\
+ 'spec.template.spec.containers[0].env') or []):
+ if env_var['name'] == 'STATS_PASSWORD':
+ env_var['value'] = \
+ self.deploymentconfig.get('spec.template.spec.containers[0].env[%s].value' % idx)
+ break
+
+ # dry-run doesn't add the protocol to the ports section. We will manually do that.
+ for idx, port in enumerate(self.prepared_router['DeploymentConfig']['obj'].get(\
+ 'spec.template.spec.containers[0].ports') or []):
+ if not 'protocol' in port:
+ port['protocol'] = 'TCP'
+
+ # These are different when generating
+ skip = ['dnsPolicy',
+ 'terminationGracePeriodSeconds',
+ 'restartPolicy', 'timeoutSeconds',
+ 'livenessProbe', 'readinessProbe',
+ 'terminationMessagePath', 'hostPort',
+ 'defaultMode',
+ ]
+
+ if not Utils.check_def_equal(self.prepared_router['DeploymentConfig']['obj'].yaml_dict,
+ self.deploymentconfig.yaml_dict,
+ skip_keys=skip,
+ debug=self.verbose):
+ self.prepared_router['DeploymentConfig']['update'] = True
+
+ # Check if any of the parts need updating, if so, return True
+ # else, no need to update
+ # pylint: disable=no-member
+ return any([self.prepared_router[oc_type]['update'] for oc_type in self.prepared_router.keys()])
+
+ @staticmethod
+ def run_ansible(params, check_mode):
+ '''run ansible idempotent code'''
+
+ rconfig = RouterConfig(params['name'],
+ params['namespace'],
+ params['kubeconfig'],
+ {'default_cert': {'value': params['default_cert'], 'include': True},
+ 'cert_file': {'value': params['cert_file'], 'include': False},
+ 'key_file': {'value': params['key_file'], 'include': False},
+ 'images': {'value': params['images'], 'include': True},
+ 'latest_images': {'value': params['latest_images'], 'include': True},
+ 'labels': {'value': params['labels'], 'include': True},
+ 'ports': {'value': ','.join(params['ports']), 'include': True},
+ 'replicas': {'value': params['replicas'], 'include': True},
+ 'selector': {'value': params['selector'], 'include': True},
+ 'service_account': {'value': params['service_account'], 'include': True},
+ 'router_type': {'value': params['router_type'], 'include': False},
+ 'host_network': {'value': params['host_network'], 'include': True},
+ 'external_host': {'value': params['external_host'], 'include': True},
+ 'external_host_vserver': {'value': params['external_host_vserver'],
+ 'include': True},
+ 'external_host_insecure': {'value': params['external_host_insecure'],
+ 'include': True},
+ 'external_host_partition_path': {'value': params['external_host_partition_path'],
+ 'include': True},
+ 'external_host_username': {'value': params['external_host_username'],
+ 'include': True},
+ 'external_host_password': {'value': params['external_host_password'],
+ 'include': True},
+ 'external_host_private_key': {'value': params['external_host_private_key'],
+ 'include': True},
+ 'expose_metrics': {'value': params['expose_metrics'], 'include': True},
+ 'metrics_image': {'value': params['metrics_image'], 'include': True},
+ 'stats_user': {'value': params['stats_user'], 'include': True},
+ 'stats_password': {'value': params['stats_password'], 'include': True},
+ 'stats_port': {'value': params['stats_port'], 'include': True},
+ # extra
+ 'cacert_file': {'value': params['cacert_file'], 'include': False},
+ # edits
+ 'edits': {'value': params['edits'], 'include': False},
+ })
+
+
+ state = params['state']
+
+ ocrouter = Router(rconfig, verbose=params['debug'])
+
+ api_rval = ocrouter.get()
+
+ ########
+ # get
+ ########
+ if state == 'list':
+ return {'changed': False, 'results': api_rval, 'state': state}
+
+ ########
+ # Delete
+ ########
+ if state == 'absent':
+ if not ocrouter.exists():
+ return {'changed': False, 'state': state}
+
+ if check_mode:
+ return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a delete.'}
+
+ # In case of delete we return a list of each object
+ # that represents a router and its result in a list
+ # pylint: disable=redefined-variable-type
+ api_rval = ocrouter.delete()
+
+ return {'changed': True, 'results': api_rval, 'state': state}
+
+ if state == 'present':
+ ########
+ # Create
+ ########
+ if not ocrouter.exists():
+
+ if check_mode:
+ return {'changed': True, 'msg': 'CHECK_MODE: Would have performed a create.'}
+
+ api_rval = ocrouter.create()
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': True, 'results': api_rval, 'state': state}
+
+ ########
+ # Update
+ ########
+ if not ocrouter.needs_update():
+ return {'changed': False, 'state': state}
+
+ if check_mode:
+ return {'changed': False, 'msg': 'CHECK_MODE: Would have performed an update.'}
+
+ api_rval = ocrouter.update()
+
+ if api_rval['returncode'] != 0:
+ return {'failed': True, 'msg': api_rval}
+
+ return {'changed': True, 'results': api_rval, 'state': state}
diff --git a/roles/lib_openshift/src/doc/registry b/roles/lib_openshift/src/doc/registry
new file mode 100644
index 000000000..ebc714b7a
--- /dev/null
+++ b/roles/lib_openshift/src/doc/registry
@@ -0,0 +1,192 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_adm_registry
+short_description: Module to manage openshift registry
+description:
+ - Manage openshift registry programmatically.
+options:
+ state:
+ description:
+ - The desired action when managing openshift registry
+ - present - update or create the registry
+ - absent - tear down the registry service and deploymentconfig
+ - list - returns the current representiation of a registry
+ required: false
+ default: False
+ aliases: []
+ kubeconfig:
+ description:
+ - The path for the kubeconfig file to use for authentication
+ required: false
+ default: /etc/origin/master/admin.kubeconfig
+ aliases: []
+ debug:
+ description:
+ - Turn on debug output.
+ required: false
+ default: False
+ aliases: []
+ name:
+ description:
+ - The name of the registry
+ required: false
+ default: None
+ aliases: []
+ namespace:
+ description:
+ - The selector when filtering on node labels
+ required: false
+ default: None
+ aliases: []
+ images:
+ description:
+ - The image to base this registry on - ${component} will be replaced with --type
+ required: 'openshift3/ose-${component}:${version}'
+ default: None
+ aliases: []
+ latest_images:
+ description:
+ - If true, attempt to use the latest image for the registry instead of the latest release.
+ required: false
+ default: False
+ aliases: []
+ labels:
+ description:
+ - A set of labels to uniquely identify the registry and its components.
+ required: false
+ default: None
+ aliases: []
+ enforce_quota:
+ description:
+ - If set, the registry will refuse to write blobs if they exceed quota limits
+ required: False
+ default: False
+ aliases: []
+ mount_host:
+ description:
+ - If set, the registry volume will be created as a host-mount at this path.
+ required: False
+ default: False
+ aliases: []
+ ports:
+ description:
+ - A comma delimited list of ports or port pairs to expose on the registry pod. The default is set for 5000.
+ required: False
+ default: [5000]
+ aliases: []
+ replicas:
+ description:
+ - The replication factor of the registry; commonly 2 when high availability is desired.
+ required: False
+ default: 1
+ aliases: []
+ selector:
+ description:
+ - Selector used to filter nodes on deployment. Used to run registries on a specific set of nodes.
+ required: False
+ default: None
+ aliases: []
+ service_account:
+ description:
+ - Name of the service account to use to run the registry pod.
+ required: False
+ default: 'registry'
+ aliases: []
+ tls_certificate:
+ description:
+ - An optional path to a PEM encoded certificate (which may contain the private key) for serving over TLS
+ required: false
+ default: None
+ aliases: []
+ tls_key:
+ description:
+ - An optional path to a PEM encoded private key for serving over TLS
+ required: false
+ default: None
+ aliases: []
+ volume_mounts:
+ description:
+ - The volume mounts for the registry.
+ required: false
+ default: None
+ aliases: []
+ daemonset:
+ description:
+ - Use a daemonset instead of a deployment config.
+ required: false
+ default: False
+ aliases: []
+ edits:
+ description:
+ - A list of modifications to make on the deploymentconfig
+ required: false
+ default: None
+ aliases: []
+ env_vars:
+ description:
+ - A dictionary of modifications to make on the deploymentconfig. e.g. FOO: BAR
+ required: false
+ default: None
+ aliases: []
+ force:
+ description:
+ - Force a registry update.
+ required: false
+ default: False
+ aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment: []
+'''
+
+EXAMPLES = '''
+- name: create a secure registry
+ oc_adm_registry:
+ name: docker-registry
+ service_account: registry
+ replicas: 2
+ namespace: default
+ selector: type=infra
+ images: "registry.ops.openshift.com/openshift3/ose-${component}:${version}"
+ env_vars:
+ REGISTRY_CONFIGURATION_PATH: /etc/registryconfig/config.yml
+ REGISTRY_HTTP_TLS_CERTIFICATE: /etc/secrets/registry.crt
+ REGISTRY_HTTP_TLS_KEY: /etc/secrets/registry.key
+ REGISTRY_HTTP_SECRET: supersecret
+ volume_mounts:
+ - path: /etc/secrets
+ name: dockercerts
+ type: secret
+ secret_name: registry-secret
+ - path: /etc/registryconfig
+ name: dockersecrets
+ type: secret
+ secret_name: docker-registry-config
+ edits:
+ - key: spec.template.spec.containers[0].livenessProbe.httpGet.scheme
+ value: HTTPS
+ action: put
+ - key: spec.template.spec.containers[0].readinessProbe.httpGet.scheme
+ value: HTTPS
+ action: put
+ - key: spec.strategy.rollingParams
+ value:
+ intervalSeconds: 1
+ maxSurge: 50%
+ maxUnavailable: 50%
+ timeoutSeconds: 600
+ updatePeriodSeconds: 1
+ action: put
+ - key: spec.template.spec.containers[0].resources.limits.memory
+ value: 2G
+ action: update
+ - key: spec.template.spec.containers[0].resources.requests.memory
+ value: 1G
+ action: update
+
+ register: registryout
+
+'''
diff --git a/roles/lib_openshift/src/doc/router b/roles/lib_openshift/src/doc/router
new file mode 100644
index 000000000..ed46e03a0
--- /dev/null
+++ b/roles/lib_openshift/src/doc/router
@@ -0,0 +1,217 @@
+# flake8: noqa
+# pylint: skip-file
+
+DOCUMENTATION = '''
+---
+module: oc_adm_router
+short_description: Module to manage openshift router
+description:
+ - Manage openshift router programmatically.
+options:
+ state:
+ description:
+ - Whether to create or delete the router
+ - present - create the router
+ - absent - remove the router
+ - list - return the current representation of a router
+ required: false
+ default: present
+ choices:
+ - present
+ - absent
+ aliases: []
+ kubeconfig:
+ description:
+ - The path for the kubeconfig file to use for authentication
+ required: false
+ default: /etc/origin/master/admin.kubeconfig
+ aliases: []
+ debug:
+ description:
+ - Turn on debug output.
+ required: false
+ default: False
+ aliases: []
+ name:
+ description:
+ - The name of the router
+ required: false
+ default: router
+ aliases: []
+ namespace:
+ description:
+ - The namespace where to manage the router.
+ required: false
+ default: default
+ aliases: []
+ images:
+ description:
+ - The image to base this router on - ${component} will be replaced with --type
+ required: 'openshift3/ose-${component}:${version}'
+ default: None
+ aliases: []
+ latest_images:
+ description:
+ - If true, attempt to use the latest image for the registry instead of the latest release.
+ required: false
+ default: False
+ aliases: []
+ labels:
+ description:
+ - A set of labels to uniquely identify the registry and its components.
+ required: false
+ default: None
+ aliases: []
+ ports:
+ description:
+ - A list of strings in the 'port:port' format
+ required: False
+ default:
+ - 80:80
+ - 443:443
+ aliases: []
+ replicas:
+ description:
+ - The replication factor of the registry; commonly 2 when high availability is desired.
+ required: False
+ default: 1
+ aliases: []
+ selector:
+ description:
+ - Selector used to filter nodes on deployment. Used to run routers on a specific set of nodes.
+ required: False
+ default: None
+ aliases: []
+ service_account:
+ description:
+ - Name of the service account to use to run the router pod.
+ required: False
+ default: router
+ aliases: []
+ router_type:
+ description:
+ - The router image to use - if you specify --images this flag may be ignored.
+ required: false
+ default: haproxy-router
+ aliases: []
+ external_host:
+ description:
+ - If the underlying router implementation connects with an external host, this is the external host's hostname.
+ required: false
+ default: None
+ aliases: []
+ external_host_vserver:
+ description:
+ - If the underlying router implementation uses virtual servers, this is the name of the virtual server for HTTP connections.
+ required: false
+ default: None
+ aliases: []
+ external_host_insecure:
+ description:
+ - If the underlying router implementation connects with an external host
+ - over a secure connection, this causes the router to skip strict certificate verification with the external host.
+ required: false
+ default: False
+ aliases: []
+ external_host_partition_path:
+ description:
+ - If the underlying router implementation uses partitions for control boundaries, this is the path to use for that partition.
+ required: false
+ default: None
+ aliases: []
+ external_host_username:
+ description:
+ - If the underlying router implementation connects with an external host, this is the username for authenticating with the external host.
+ required: false
+ default: None
+ aliases: []
+ external_host_password:
+ description:
+ - If the underlying router implementation connects with an external host, this is the password for authenticating with the external host.
+ required: false
+ default: None
+ aliases: []
+ external_host_private_key:
+ description:
+ - If the underlying router implementation requires an SSH private key, this is the path to the private key file.
+ required: false
+ default: None
+ aliases: []
+ expose_metrics:
+ description:
+ - This is a hint to run an extra container in the pod to expose metrics - the image
+ - will either be set depending on the router implementation or provided with --metrics-image.
+ required: false
+ default: False
+ aliases: []
+ metrics_image:
+ description:
+ - If expose_metrics is specified this is the image to use to run a sidecar container
+ - in the pod exposing metrics. If not set and --expose-metrics is true the image will
+ - depend on router implementation.
+ required: false
+ default: None
+ aliases: []
+author:
+- "Kenny Woodson <kwoodson@redhat.com>"
+extends_documentation_fragment:
+- There are some exceptions to note when doing the idempotency in this module.
+- The strategy is to use the oc adm router command to generate a default
+- configuration when creating or updating a router. Often times there
+- differences from the generated template and what is in memory in openshift.
+- We make exceptions to not check these specific values when comparing objects.
+- Here are a list of exceptions:
+- - DeploymentConfig:
+ - dnsPolicy
+ - terminationGracePeriodSeconds
+ - restartPolicy
+ - timeoutSeconds
+ - livenessProbe
+ - readinessProbe
+ - terminationMessagePath
+ - hostPort
+ - defaultMode
+ - Service:
+ - portalIP
+ - clusterIP
+ - sessionAffinity
+ - type
+ - ServiceAccount:
+ - secrets
+ - imagePullSecrets
+'''
+
+EXAMPLES = '''
+- name: create routers
+ oc_adm_router:
+ name: router
+ service_account: router
+ replicas: 2
+ namespace: default
+ selector: type=infra
+ cert_file: /etc/origin/master/named_certificates/router.crt
+ key_file: /etc/origin/master/named_certificates/router.key
+ cacert_file: /etc/origin/master/named_certificates/router.ca
+ edits:
+ - key: spec.strategy.rollingParams
+ value:
+ intervalSeconds: 1
+ maxSurge: 50%
+ maxUnavailable: 50%
+ timeoutSeconds: 600
+ updatePeriodSeconds: 1
+ action: put
+ - key: spec.template.spec.containers[0].resources.limits.memory
+ value: 2G
+ action: put
+ - key: spec.template.spec.containers[0].resources.requests.memory
+ value: 1G
+ action: put
+ - key: spec.template.spec.containers[0].env
+ value:
+ name: EXTENDED_VALIDATION
+ value: 'false'
+ action: update
+ register: router_out
+ run_once: True
+'''
diff --git a/roles/lib_openshift/src/lib/deploymentconfig.py b/roles/lib_openshift/src/lib/deploymentconfig.py
index e060d3707..f10c6bb8b 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
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 1ba78ddd5..622290aa8 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'] = {}
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..84ef1f705
--- /dev/null
+++ b/roles/lib_openshift/src/lib/volume.py
@@ -0,0 +1,37 @@
+# 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']}
+ if volume_info['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_info['type'] == 'emptydir':
+ volume['emptyDir'] = {}
+ volume_mount = {'mountPath': volume_info['path'],
+ 'name': volume_info['name']}
+ elif volume_info['type'] == 'pvc':
+ volume['persistentVolumeClaim'] = {}
+ volume['persistentVolumeClaim']['claimName'] = volume_info['claimName']
+ volume['persistentVolumeClaim']['claimSize'] = volume_info['claimSize']
+ elif volume_info['type'] == 'hostpath':
+ volume['hostPath'] = {}
+ volume['hostPath']['path'] = volume_info['path']
+
+ return (volume, volume_mount)
diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml
index 091aaef2e..fca1f4818 100644
--- a/roles/lib_openshift/src/sources.yml
+++ b/roles/lib_openshift/src/sources.yml
@@ -9,6 +9,36 @@ oadm_manage_node.py:
- class/oadm_manage_node.py
- ansible/oadm_manage_node.py
+oc_adm_registry.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/registry
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- lib/deploymentconfig.py
+- lib/secret.py
+- lib/service.py
+- lib/volume.py
+- class/oc_version.py
+- class/oc_adm_registry.py
+- ansible/oc_adm_registry.py
+
+oc_adm_router.py:
+- doc/generated
+- doc/license
+- lib/import.py
+- doc/router
+- ../../lib_utils/src/class/yedit.py
+- lib/base.py
+- lib/service.py
+- lib/deploymentconfig.py
+- lib/serviceaccount.py
+- lib/secret.py
+- lib/rolebinding.py
+- class/oc_adm_router.py
+- ansible/oc_adm_router.py
+
oc_edit.py:
- doc/generated
- doc/license
diff --git a/roles/lib_openshift/src/test/unit/test_oadm_manage_node.py b/roles/lib_openshift/src/test/unit/test_oadm_manage_node.py
index b0786dfac..b0786dfac 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oadm_manage_node.py
+++ b/roles/lib_openshift/src/test/unit/test_oadm_manage_node.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_env.py b/roles/lib_openshift/src/test/unit/test_oc_env.py
index 15bd7e464..15bd7e464 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_env.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_env.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_label.py b/roles/lib_openshift/src/test/unit/test_oc_label.py
index 3176987b0..3176987b0 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_label.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_label.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_process.py b/roles/lib_openshift/src/test/unit/test_oc_process.py
index 450ff7071..450ff7071 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_process.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_process.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_route.py b/roles/lib_openshift/src/test/unit/test_oc_route.py
index 361b61f4b..361b61f4b 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_route.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_route.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_scale.py b/roles/lib_openshift/src/test/unit/test_oc_scale.py
index f15eb164d..f15eb164d 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_scale.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_scale.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_secret.py b/roles/lib_openshift/src/test/unit/test_oc_secret.py
index 645aac82b..645aac82b 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_secret.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_secret.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_service.py b/roles/lib_openshift/src/test/unit/test_oc_service.py
index 4a845e9f3..4a845e9f3 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_service.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_service.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_serviceaccount.py b/roles/lib_openshift/src/test/unit/test_oc_serviceaccount.py
index 256b569eb..256b569eb 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_serviceaccount.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_serviceaccount.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_serviceaccount_secret.py b/roles/lib_openshift/src/test/unit/test_oc_serviceaccount_secret.py
index 213c581aa..213c581aa 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_serviceaccount_secret.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_serviceaccount_secret.py
diff --git a/roles/lib_openshift/src/test/unit/test_oc_version.py b/roles/lib_openshift/src/test/unit/test_oc_version.py
index 67dea415b..67dea415b 100644..100755
--- a/roles/lib_openshift/src/test/unit/test_oc_version.py
+++ b/roles/lib_openshift/src/test/unit/test_oc_version.py