diff --git a/wrapanapi/__init__.py b/wrapanapi/__init__.py index 993c24e3..2632e9c5 100644 --- a/wrapanapi/__init__.py +++ b/wrapanapi/__init__.py @@ -14,7 +14,7 @@ from .systems.scvmm import SCVMMSystem from .systems.vcloud import VmwareCloudSystem from .systems.virtualcenter import VMWareSystem -from .systems.container.rhopenshift import Openshift +from .systems.openshift import OpenshiftSystem from .entities.vm import VmState @@ -22,5 +22,5 @@ 'EC2System', 'GoogleCloudSystem', 'HawkularSystem', 'LenovoSystem', 'AzureSystem', 'NuageSystem', 'OpenstackSystem', 'OpenstackInfraSystem', 'RedfishSystem', 'RHEVMSystem', 'SCVMMSystem', - 'VmwareCloudSystem', 'VMWareSystem', 'Openshift', 'VmState' + 'VmwareCloudSystem', 'VMWareSystem', 'OpenshiftSystem', 'VmState' ] diff --git a/wrapanapi/systems/__init__.py b/wrapanapi/systems/__init__.py index 6ba6bed3..301cef46 100644 --- a/wrapanapi/systems/__init__.py +++ b/wrapanapi/systems/__init__.py @@ -13,10 +13,10 @@ from .scvmm import SCVMMSystem from .vcloud import VmwareCloudSystem from .virtualcenter import VMWareSystem -from .openshift import Openshift +from .openshift import OpenshiftSystem __all__ = [ 'EC2System', 'GoogleCloudSystem', 'HawkularSystem', 'LenovoSystem', - 'AzureSystem', 'NuageSystem', 'OpenShift', 'OpenstackSystem', 'OpenstackInfraSystem', + 'AzureSystem', 'NuageSystem', 'OpenshiftSystem', 'OpenstackSystem', 'OpenstackInfraSystem', 'RedfishSystem', 'RHEVMSystem', 'SCVMMSystem', 'VmwareCloudSystem', 'VMWareSystem' ] diff --git a/wrapanapi/systems/container/rhopenshift.py b/wrapanapi/systems/container/rhopenshift.py index 1ca3b47a..8400f134 100644 --- a/wrapanapi/systems/container/rhopenshift.py +++ b/wrapanapi/systems/container/rhopenshift.py @@ -179,13 +179,11 @@ def _connect(self): self.security_api = self.ociclient.SecurityOpenshiftIoV1Api(api_client=self.oapi_client) self.batch_api = self.kclient.BatchV1Api(api_client=self.kapi_client) # for job api - # TODO DONE def info(self): url = '{proto}://{host}:{port}'.format(proto=self.protocol, host=self.hostname, port=self.port) return "rhopenshift {}".format(url) - # TODO DONE def list_route(self, namespace=None): """Returns list of routes""" if namespace: @@ -194,7 +192,6 @@ def list_route(self, namespace=None): routes = self.o_api.list_route_for_all_namespaces().items return routes - # TODO DONE def list_image_streams(self, namespace=None): """Returns list of image streams""" if namespace: @@ -203,12 +200,10 @@ def list_image_streams(self, namespace=None): image_streams = self.o_api.list_image_stream_for_all_namespaces().items return image_streams - # TODO DONE def list_project(self): """Returns list of projects""" return self.o_api.list_project().items - # TODO DONE def list_template(self, namespace=None): """Returns list of templates""" if namespace: @@ -219,13 +214,11 @@ def list_template(self, namespace=None): # fixme: get rid of this mapping list_templates = list_template - # TODO DONE def list_image_stream_images(self): """Returns list of images (Docker registry only)""" return [item for item in self.o_api.list_image().items if item.docker_image_reference is not None] - # TODO DONE def list_deployment_config(self, namespace=None): """Returns list of deployment configs""" if namespace: @@ -234,7 +227,6 @@ def list_deployment_config(self, namespace=None): dc = self.o_api.list_deployment_config_for_all_namespaces().items return dc - # TODO DONE def list_service(self, namespace=None): """Returns list of services.""" if namespace: @@ -243,7 +235,6 @@ def list_service(self, namespace=None): svc = self.k_api.list_service_for_all_namespaces().items return svc - # TODO DONE def list_replication_controller(self, namespace=None): """Returns list of replication controllers""" if namespace: @@ -252,13 +243,11 @@ def list_replication_controller(self, namespace=None): rc = self.k_api.list_replication_controller_for_all_namespaces().items return rc - # TODO DONE def list_node(self): """Returns list of nodes""" nodes = self.k_api.list_node().items return nodes - # TODO DONE def cluster_info(self): """Returns information about the cluster - number of CPUs and memory in GB""" aggregate_cpu, aggregate_mem = 0, 0 @@ -269,13 +258,11 @@ def cluster_info(self): return {'cpu': aggregate_cpu, 'memory': aggregate_mem} - # TODO DONE def list_persistent_volume(self): """Returns list of persistent volumes""" pv = self.k_api.list_persistent_volume().items return pv - # TODO DONE def list_pods(self, namespace=None): """Returns list of container groups (pods). If project_name is passed, only the pods under the selected project will be returned""" @@ -285,7 +272,6 @@ def list_pods(self, namespace=None): pods = self.k_api.list_pod_for_all_namespaces().items return pods - # TODO DONE def list_container(self, namespace=None): """Returns list of containers (derived from pods) If project_name is passed, only the containers under the selected project will be returned @@ -293,7 +279,6 @@ def list_container(self, namespace=None): pods = self.list_pods(namespace=namespace) return [pod.spec.containers for pod in pods] - # TODO DONE def list_image_id(self, namespace=None): """Returns list of unique image ids (derived from pods)""" pods = self.list_pods(namespace=namespace) @@ -303,7 +288,6 @@ def list_image_id(self, namespace=None): statuses.append(status) return sorted(set([status.image_id for status in statuses])) - # TODO DONE def list_image_registry(self, namespace=None): """Returns list of image registries (derived from pods)""" pods = self.list_pods(namespace=namespace) @@ -314,7 +298,6 @@ def list_image_registry(self, namespace=None): # returns only the image registry name, without the port number in case of local registry return sorted(set([status.image.split('/')[0].split(':')[0] for status in statuses])) - # TODO DONE def expose_db_ip(self, namespace): """Creates special service in appliance project (namespace) which makes internal appliance db be available outside. @@ -330,7 +313,6 @@ def expose_db_ip(self, namespace): return self.get_ip_address(namespace) - # TODO DONE def deploy_template(self, template, tags=None, password='smartvm', **kwargs): """Deploy a VM from a template @@ -471,7 +453,6 @@ def deploy_template(self, template, tags=None, password='smartvm', **kwargs): # todo: return and print all failed pod details raise - # TODO DONE def create_template_entities(self, namespace, entities): """Creates entities from openshift template. @@ -497,7 +478,6 @@ def create_template_entities(self, namespace, entities): else: self.logger.error("some entity %s isn't present in entity creation list", entity) - # TODO DONE def start_vm(self, vm_name): """Starts a vm. @@ -512,7 +492,6 @@ def start_vm(self, vm_name): else: raise ValueError("Project with name {n} doesn't exist".format(n=vm_name)) - # TODO DONE def stop_vm(self, vm_name): """Stops a vm. @@ -527,7 +506,6 @@ def stop_vm(self, vm_name): else: raise ValueError("Project with name {n} doesn't exist".format(n=vm_name)) - # TODO DONE def delete_vm(self, vm_name): """Deletes a vm. @@ -539,7 +517,6 @@ def delete_vm(self, vm_name): self.delete_project(name=vm_name) return True - # TODO DONE def does_vm_exist(self, vm_name): """Does VM exist? @@ -549,7 +526,6 @@ def does_vm_exist(self, vm_name): """ return self.does_project_exist(vm_name) - # TODO DONE @staticmethod def _update_template_parameters(template, **params): """Updates openshift template parameters. @@ -577,7 +553,6 @@ def _update_template_parameters(template, **params): template.parameters = new_parameters return template - # TODO DONE def process_template(self, name, namespace, parameters=None): """Implements template processing mechanism similar to `oc process`. @@ -594,7 +569,6 @@ def process_template(self, name, namespace, parameters=None): return self.process_raw_template(body=raw_data, namespace=namespace, parameters=parameters) - # TODO DONE def process_raw_template(self, body, namespace, parameters=None): """Implements template processing mechanism similar to `oc process`. It does two functions @@ -623,7 +597,6 @@ def process_raw_template(self, body, namespace, parameters=None): processed_template = self.ociclient.V1Template(**updated_data) return processed_template.objects - # TODO DONE def rename_structure(self, struct): """Fixes inconsistency in input/output data of openshift python client methods @@ -653,7 +626,6 @@ def rename_structure(self, struct): else: return struct - # TODO DONE def create_config_map(self, namespace, **kwargs): """Creates ConfigMap entity using REST API. @@ -669,7 +641,6 @@ def create_config_map(self, namespace, **kwargs): self.wait_config_map_exist(namespace=namespace, name=conf_map_name) return output - # TODO DONE def replace_config_map(self, namespace, **kwargs): """Replace ConfigMap entity using REST API. @@ -686,7 +657,6 @@ def replace_config_map(self, namespace, **kwargs): body=conf_map) return output - # TODO DONE def create_stateful_set(self, namespace, **kwargs): """Creates StatefulSet entity using REST API. @@ -703,8 +673,6 @@ def create_stateful_set(self, namespace, **kwargs): self.wait_stateful_set_exist(namespace=namespace, name=st_name) return output - - # TODO DONE def create_service(self, namespace, **kwargs): """Creates Service entity using REST API. @@ -720,7 +688,6 @@ def create_service(self, namespace, **kwargs): self.wait_service_exist(namespace=namespace, name=service_name) return output - # TODO DONE def create_endpoints(self, namespace, **kwargs): """Creates Endpoints entity using REST API. @@ -736,7 +703,6 @@ def create_endpoints(self, namespace, **kwargs): self.wait_endpoints_exist(namespace=namespace, name=endpoints_name) return output - # TODO DONE def create_route(self, namespace, **kwargs): """Creates Route entity using REST API. @@ -752,7 +718,6 @@ def create_route(self, namespace, **kwargs): self.wait_route_exist(namespace=namespace, name=route_name) return output - # TODO DONE def create_service_account(self, namespace, **kwargs): """Creates Service Account entity using REST API. @@ -768,7 +733,6 @@ def create_service_account(self, namespace, **kwargs): self.wait_service_account_exist(namespace=namespace, name=sa_name) return output - # TODO DONE def create_role_binding(self, namespace, **kwargs): """Creates RoleBinding entity using REST API. @@ -794,7 +758,6 @@ def create_role_binding(self, namespace, **kwargs): self.wait_role_binding_exist(namespace=namespace, name=role_binding_name) return output - # TODO DONE def create_image_stream(self, namespace, **kwargs): """Creates Image Stream entity using REST API. @@ -810,7 +773,6 @@ def create_image_stream(self, namespace, **kwargs): self.wait_image_stream_exist(namespace=namespace, name=is_name) return output - # TODO DONE def create_secret(self, namespace, **kwargs): """Creates Secret entity using REST API. @@ -826,7 +788,6 @@ def create_secret(self, namespace, **kwargs): self.wait_secret_exist(namespace=namespace, name=secret_name) return output - # TODO DONE def create_deployment_config(self, namespace, **kwargs): """Creates Deployment Config entity using REST API. @@ -843,7 +804,6 @@ def create_deployment_config(self, namespace, **kwargs): name=dc_name) return output - # TODO DONE def create_persistent_volume_claim(self, namespace, **kwargs): """Creates Persistent Volume Claim entity using REST API. @@ -861,7 +821,6 @@ def create_persistent_volume_claim(self, namespace, **kwargs): name=pv_claim_name) return output - # TODO DONE def create_project(self, name, description=None): """Creates Project(namespace) using REST API. @@ -879,7 +838,6 @@ def create_project(self, name, description=None): self.wait_project_exist(name=name) return output - # TODO DONE def run_job(self, namespace, body): """Creates job from passed template, runs it and waits for the job to be accomplished @@ -894,7 +852,6 @@ def run_job(self, namespace, body): return self.wait_job_finished(namespace, job_name) - # TODO DONE def wait_job_finished(self, namespace, name, wait='15m'): """Waits for job to accomplish @@ -914,7 +871,6 @@ def job_wait_accomplished(): return False return wait_for(job_wait_accomplished, num_sec=wait)[0] - # TODO DONE def wait_persistent_volume_claim_status(self, namespace, name, status, wait='1m'): """Waits until pvc gets some particular status. For example: Bound. @@ -936,7 +892,6 @@ def pvc_wait_status(): return wait_for(pvc_wait_status, num_sec=wait)[0] - # TODO DONE def wait_project_exist(self, name, wait=60): """Checks whether Project exists within some time. @@ -948,7 +903,6 @@ def wait_project_exist(self, name, wait=60): return wait_for(self._does_exist, num_sec=wait, func_kwargs={'func': self.o_api.read_project, 'name': name})[0] - # TODO DONE def wait_config_map_exist(self, namespace, name, wait=60): """Checks whether Config Map exists within some time. @@ -962,7 +916,7 @@ def wait_config_map_exist(self, namespace, name, wait=60): func_kwargs={'func': self.k_api.read_namespaced_config_map, 'name': name, 'namespace': namespace})[0] - # TODO DONE + def wait_stateful_set_exist(self, namespace, name, wait=900): """Checks whether StatefulSet exists within some time. @@ -979,7 +933,6 @@ def wait_stateful_set_exist(self, namespace, name, wait=900): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_service_exist(self, namespace, name, wait=60): """Checks whether Service exists within some time. @@ -994,7 +947,6 @@ def wait_service_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_endpoints_exist(self, namespace, name, wait=60): """Checks whether Endpoints exists within some time. @@ -1009,7 +961,6 @@ def wait_endpoints_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_route_exist(self, namespace, name, wait=60): """Checks whether Route exists within some time. @@ -1024,7 +975,6 @@ def wait_route_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_service_account_exist(self, namespace, name, wait=60): """Checks whether Service Account exists within some time. @@ -1039,7 +989,6 @@ def wait_service_account_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_image_stream_exist(self, namespace, name, wait=60): """Checks whether Image Stream exists within some time. @@ -1054,7 +1003,6 @@ def wait_image_stream_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_role_binding_exist(self, namespace, name, wait=60): """Checks whether RoleBinding exists within some time. @@ -1070,7 +1018,6 @@ def wait_role_binding_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_secret_exist(self, namespace, name, wait=90): """Checks whether Secret exists within some time. @@ -1085,7 +1032,6 @@ def wait_secret_exist(self, namespace, name, wait=90): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_persistent_volume_claim_exist(self, namespace, name, wait=60): """Checks whether Persistent Volume Claim exists within some time. @@ -1100,7 +1046,6 @@ def wait_persistent_volume_claim_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_deployment_config_exist(self, namespace, name, wait=600): """Checks whether Deployment Config exists within some time. @@ -1116,7 +1061,6 @@ def wait_deployment_config_exist(self, namespace, name, wait=600): 'name': name, 'namespace': namespace})[0] - # TODO DONE def wait_template_exist(self, namespace, name, wait=60): """Checks whether Template exists within some time. @@ -1131,7 +1075,6 @@ def wait_template_exist(self, namespace, name, wait=60): 'name': name, 'namespace': namespace})[0] - # TODO DONE def _does_exist(self, func, **kwargs): try: func(**kwargs) @@ -1140,7 +1083,6 @@ def _does_exist(self, func, **kwargs): self.logger.info("ApiException occurred %s, it looks like obj doesn't exist", e) return False - # TODO DONE def _restore_missing_project_role_bindings(self, namespace): """Fixes one of issues in Openshift REST API create project doesn't add necessary roles to default sa, probably bug, this is workaround @@ -1195,7 +1137,6 @@ def _restore_missing_project_role_bindings(self, namespace): metadata=role_binding_name) auth_api.create_namespaced_role_binding(namespace=namespace, body=puller_role_binding) - # TODO DONE def delete_project(self, name, wait=300): """Removes project(namespace) and all entities in it. @@ -1214,7 +1155,6 @@ def delete_project(self, name, wait=300): raise TimedOutError('project {n} was not removed within {w} sec'.format(n=name, w=wait)) - # TODO DONE def scale_entity(self, namespace, name, replicas, wait=60): """Allows to scale up/down entities. One of cases when this is necessary is emulation of stopping/starting appliance @@ -1255,12 +1195,10 @@ def check_scale_value(): self.logger.info("scaling entity %s to %s replicas", name, replicas) wait_for(check_scale_value, num_sec=wait, fail_condition=lambda val: val != replicas) - # TODO DONE def get_project_by_name(self, project_name): """Returns only the selected Project object""" return next(proj for proj in self.list_project() if proj.metadata.name == project_name) - # TODO DONE def get_scc(self, name): """Returns Security Context Constraint by name @@ -1270,7 +1208,6 @@ def get_scc(self, name): """ return self.security_api.read_security_context_constraints(name) - # TODO DONE def create_scc(self, body): """Creates Security Context Constraint from passed structure. Main aim is to create scc from read and parsed yaml file. @@ -1286,7 +1223,6 @@ def create_scc(self, body): scc = self.ociclient.V1SecurityContextConstraints(**raw_scc) return self.security_api.create_security_context_constraints(body=scc) - # TODO DONE def append_sa_to_scc(self, scc_name, namespace, sa): """Appends Service Account to respective Security Constraint @@ -1313,7 +1249,6 @@ def append_sa_to_scc(self, scc_name, namespace, sa): return self.security_api.patch_security_context_constraints(name=scc_name, body=update_scc_cmd) - # TODO DONE def remove_sa_from_scc(self, scc_name, namespace, sa): """Removes Service Account from respective Security Constraint @@ -1338,7 +1273,6 @@ def remove_sa_from_scc(self, scc_name, namespace, sa): return self.security_api.patch_security_context_constraints(name=scc_name, body=update_scc_cmd) - # TODO DONE def is_vm_running(self, vm_name, running_pods=()): """Emulates check is vm(appliance) up and running @@ -1360,7 +1294,6 @@ def is_vm_running(self, vm_name, running_pods=()): # todo: check url is available + db is accessable return True - # TODO DONE def list_deployment_config_names(self, namespace): """Extracts and returns list of Deployment Config names @@ -1371,7 +1304,6 @@ def list_deployment_config_names(self, namespace): dcs = self.o_api.list_namespaced_deployment_config(namespace=namespace) return [dc.metadata.name for dc in dcs.items] - # TODO DONE def list_stateful_set_names(self, namespace): """Returns list of Stateful Set names @@ -1383,7 +1315,6 @@ def list_stateful_set_names(self, namespace): sts = st_api.list_namespaced_stateful_set(namespace=namespace) return [st.metadata.name for st in sts.items] - # TODO DONE def is_deployment_config(self, namespace, name): """Checks whether passed name belongs to deployment configs in appropriate namespace @@ -1394,7 +1325,6 @@ def is_deployment_config(self, namespace, name): """ return name in self.list_deployment_config_names(namespace=namespace) - # TODO DONE def is_stateful_set(self, namespace, name): """Checks whether passed name belongs to Stateful Sets in appropriate namespace @@ -1405,7 +1335,6 @@ def is_stateful_set(self, namespace, name): """ return name in self.list_stateful_set_names(namespace=namespace) - # TODO DONE def does_project_exist(self, name): """Checks whether Project exists. @@ -1415,7 +1344,6 @@ def does_project_exist(self, name): """ return self._does_exist(func=self.o_api.read_project, name=name) - # TODO DONE def is_vm_stopped(self, vm_name): """Check whether vm isn't running. There is no such state stopped for vm in openshift therefore @@ -1431,7 +1359,6 @@ def is_vm_stopped(self, vm_name): "running: {}").format([pod.metadata.name for pod in pods])) return not bool(pods) - # TODO DONE def wait_vm_running(self, vm_name, num_sec=900): """Checks whether all project pods are in ready state. @@ -1443,7 +1370,6 @@ def wait_vm_running(self, vm_name, num_sec=900): wait_for(self.is_vm_running, [vm_name], num_sec=num_sec) return True - # TODO DONE def wait_vm_stopped(self, vm_name, num_sec=600): """Checks whether all project pods are stopped. @@ -1455,7 +1381,6 @@ def wait_vm_stopped(self, vm_name, num_sec=600): wait_for(self.is_vm_stopped, [vm_name], num_sec=num_sec) return True - # TODO DONE def current_ip_address(self, vm_name): """Tries to retrieve project's external ip @@ -1470,7 +1395,6 @@ def current_ip_address(self, vm_name): except Exception: return None - # TODO DONE def is_vm_suspended(self, vm_name): """There is no such state in openshift @@ -1480,7 +1404,6 @@ def is_vm_suspended(self, vm_name): """ return False - # TODO DONE def in_steady_state(self, vm_name): """Return whether the specified virtual machine is in steady state @@ -1492,12 +1415,10 @@ def in_steady_state(self, vm_name): or self.is_vm_stopped(vm_name) or self.is_vm_suspended(vm_name)) - # TODO DONE @property def can_rename(self): return hasattr(self, "rename_vm") - # TODO DONE def list_project_names(self): """Obtains project names @@ -1508,7 +1429,6 @@ def list_project_names(self): list_vms = list_vm = list_project_names - # TODO DONE def get_appliance_version(self, vm_name): """Returns appliance version if it is possible @@ -1526,7 +1446,6 @@ def get_appliance_version(self, vm_name): except ValueError: return None - # TODO DONE def delete_template(self, template_name, namespace='openshift'): """Deletes template @@ -1539,17 +1458,14 @@ def delete_template(self, template_name, namespace='openshift'): return self.o_api.delete_namespaced_template(name=template_name, namespace=namespace, body=options) - # TODO DONE def get_meta_value(self, instance, key): raise NotImplementedError( 'Provider {} does not implement get_meta_value'.format(type(self).__name__)) - # TODO DONE def set_meta_value(self, instance, key): raise NotImplementedError( 'Provider {} does not implement get_meta_value'.format(type(self).__name__)) - # TODO DONE def vm_status(self, vm_name): """Returns current vm/appliance state @@ -1561,7 +1477,6 @@ def vm_status(self, vm_name): raise ValueError("Vm {} doesn't exist".format(vm_name)) return 'up' if self.is_vm_running(vm_name) else 'down' - # TODO DONE def vm_creation_time(self, vm_name): """Returns time when vm/appliance was created @@ -1575,13 +1490,11 @@ def vm_creation_time(self, vm_name): project = next(proj for proj in projects if proj.metadata.name == vm_name) return project.metadata.creation_timestamp - # TODO DONE @staticmethod def _progress_log_callback(logger, source, destination, progress): logger.info("Provisioning progress {}->{}: {}".format( source, destination, str(progress))) - # TODO DONE def vm_hardware_configuration(self, vm_name): """Collects project's cpu and ram usage @@ -1611,7 +1524,6 @@ def vm_hardware_configuration(self, vm_name): hw_config['ram'] += ram return hw_config - # TODO DONE def usage_and_quota(self): installed_ram = 0 installed_cpu = 0 @@ -1629,7 +1541,6 @@ def usage_and_quota(self): 'cpu_limit': None, } - # TODO DONE def get_required_pods(self, vm_name): """Provides list of pods which should be present in appliance @@ -1643,7 +1554,6 @@ def get_required_pods(self, vm_name): else: return self.required_project_pods - # TODO DONE def get_ip_address(self, vm_name, timeout=600): """ Returns the IP address for the selected appliance. @@ -1662,11 +1572,9 @@ def get_ip_address(self, vm_name, timeout=600): ip_address = None return ip_address - # TODO DONE def disconnect(self): pass - # TODO DONE def get_appliance_tags(self, name): """Returns appliance tags stored in appropriate config map if it exists. @@ -1681,7 +1589,6 @@ def get_appliance_tags(self, name): except ApiException: return {} - # TODO DONE def get_appliance_url(self, name): """Returns appliance url assigned by Openshift @@ -1695,7 +1602,6 @@ def get_appliance_url(self, name): except (ApiException, IndexError): return None - # TODO DONE def get_appliance_uuid(self, name): """Returns appliance uuid assigned by Openshift @@ -1705,7 +1611,6 @@ def get_appliance_uuid(self, name): """ return self.get_project_by_name(name).metadata.uid - # TODO DONE def is_appliance(self, name): """Checks whether passed vm/project is appliance @@ -1715,7 +1620,6 @@ def is_appliance(self, name): """ return bool(self.get_appliance_tags(name)) - # TODO DONE def find_job_pods(self, namespace, name): """Finds and returns all remaining job pods @@ -1730,7 +1634,6 @@ def find_job_pods(self, namespace, name): pods.append(pod) return pods - # TODO DONE def read_pod_log(self, namespace, name): """Reads and returns pod log diff --git a/wrapanapi/systems/openshift.py b/wrapanapi/systems/openshift.py index b8698dc4..de355385 100644 --- a/wrapanapi/systems/openshift.py +++ b/wrapanapi/systems/openshift.py @@ -1,6 +1,5 @@ from __future__ import absolute_import -import re import copy import json import string @@ -13,14 +12,13 @@ import six from cached_property import cached_property from kubernetes import client as kubeclient -from kubernetes import config as kubeclientconfig from openshift.dynamic import DynamicClient from kubernetes.client.rest import ApiException from miq_version import TemplateName, Version from openshift import client as ociclient from wait_for import TimedOutError, wait_for -from wrapanapi.entities import (Template, TemplateMixin, Vm, VmMixin, VmState, ProjectMixin, +from wrapanapi.entities import (Template, Vm, VmMixin, VmState, ProjectMixin, Project) from wrapanapi.systems.base import System @@ -115,7 +113,7 @@ def _get_state(self): pods = self.system.list_pods(namespace=self.name) states = [] for pod in pods: - states.append(pod.state) + states.append(pod.state) if len(set(states)) == 1: return states[0] @@ -235,10 +233,14 @@ def namespace(self): @property def ip(self): - ipv4_re = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' + # TODO JUWATTS + # ipv4_re = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' self.refresh() try: return self.raw.status.podIP + if not re.match(ipv4_re, ip_address) or ip_address == '127.0.0.1': + ip_address = None + return ip_address except (AttributeError): # AttributeError: vm doesn't have an ip address yet return None @@ -586,8 +588,9 @@ def deploy(self, tags=None, password='smartvm', **kwargs): # todo: return and print all failed pod details raise + @reconnect(unauthenticated_error_handler) -class Openshift(System, VmMixin, ProjectMixin): +class OpenshiftSystem(System, VmMixin, ProjectMixin): _stats_available = { 'num_container': lambda self: len(self.list_containers()), @@ -643,7 +646,7 @@ class Openshift(System, VmMixin, ProjectMixin): def __init__(self, hostname, protocol="https", port=8443, debug=False, verify_ssl=False, **kwargs): - super(Openshift, self).__init__(kwargs) + super(OpenshiftSystem, self).__init__(kwargs) self.hostname = hostname self.protocol = protocol self.port = port @@ -670,18 +673,18 @@ def _k8s_client_connect(self): url = '{proto}://{host}:{port}'.format(proto=self.protocol, host=self.hostname, port=self.port) - aConfiguration = kubeclient.Configuration() + k8_configuration = kubeclient.Configuration() - aConfiguration.host = url + k8_configuration.host = url # Security part. - aConfiguration.verify_ssl = self.verify_ssl - aConfiguration.ssl_ca_cert = self.ssl_ca_cert + k8_configuration.verify_ssl = self.verify_ssl + k8_configuration.ssl_ca_cert = self.ssl_ca_cert - aConfiguration.api_key = {"authorization": "Bearer " + aToken} + k8_configuration.api_key = {"authorization": "Bearer " + aToken} # Create a ApiClient with our config - return kubeclient.ApiClient(aConfiguration) + return kubeclient.ApiClient(k8_configuration) # def _connect(self): # @@ -799,6 +802,15 @@ def can_suspend(self): def can_pause(self): return False + @staticmethod + def _progress_log_callback(logger, source, destination, progress): + logger.info("Provisioning progress {}->{}: {}".format( + source, destination, str(progress))) + + @property + def can_rename(self): + return hasattr(self, "rename_vm") + def _does_exist(self, func, **kwargs): try: func(**kwargs) @@ -923,7 +935,6 @@ def get_pod(self, name, namespace=None): return Pod(system=self, name=pod.metadata.name, namespace=pod.metadata.namespace, raw=pod) - def create_vm(self, name, **kwargs): raise NotImplementedError('This function has not yet been implemented.') @@ -942,7 +953,6 @@ def list_pods(self, namespace=None): Pod(system=self, name=pod.metadata.name, namespace=pod.metadata.namespace, raw=pod) for pod in self.v1_pod.get(namespace=namespace).items] - def wait_project_exist(self, name, wait=60): """Checks whether Project exists within some time. @@ -1613,26 +1623,6 @@ def is_vm_running(self, vm_name, running_pods=()): # todo: check url is available + db is accessable return True - def is_deployment_config(self, namespace, name): - """Checks whether passed name belongs to deployment configs in appropriate namespace - - Args: - namespace: project(namespace) name - name: entity name - Return: True/False - """ - return name in self.list_deployment_config_names(namespace=namespace) - - def is_stateful_set(self, namespace, name): - """Checks whether passed name belongs to Stateful Sets in appropriate namespace - - Args: - namespace: project(namespace) name - name: entity name - Return: True/False - """ - return name in self.list_stateful_set_names(namespace=namespace) - def is_vm_stopped(self, vm_name): """Check whether vm isn't running. There is no such state stopped for vm in openshift therefore @@ -1679,10 +1669,6 @@ def is_vm_suspended(self, vm_name): """ return False - @property - def can_rename(self): - return hasattr(self, "rename_vm") - def get_appliance_version(self, vm_name): """Returns appliance version if it is possible @@ -1731,11 +1717,6 @@ def vm_creation_time(self, vm_name): project = self.v1_project.get(vm_name) return project.raw.metadata.creation_timestamp - @staticmethod - def _progress_log_callback(logger, source, destination, progress): - logger.info("Provisioning progress {}->{}: {}".format( - source, destination, str(progress))) - def vm_hardware_configuration(self, vm_name): """Collects project's cpu and ram usage @@ -1795,24 +1776,6 @@ def get_required_pods(self, vm_name): else: return self.required_project_pods - def get_ip_address(self, vm_name, timeout=600): - """ Returns the IP address for the selected appliance. - - Args: - vm_name: The name of the vm to obtain the IP for. - timeout: The IP address wait timeout. - Returns: A string containing the first found IP that isn't the device. - """ - try: - ip_address, tc = wait_for(lambda: self.current_ip_address(vm_name), - fail_condition=None, - delay=5, - num_sec=timeout, - message="get_ip_address from openshift") - except TimedOutError: - ip_address = None - return ip_address - def disconnect(self): pass @@ -1973,7 +1936,6 @@ def delete_template(self, template_name, namespace='openshift'): options = self.kclient.V1DeleteOptions() return self.v1_template.delete(name=template_name, namespace=namespace, body=options) - def scale_entity(self, namespace, name, replicas, wait=60): """Allows to scale up/down entities. One of cases when this is necessary is emulation of stopping/starting appliance @@ -2014,19 +1976,16 @@ def check_scale_value(): self.logger.info("scaling entity %s to %s replicas", name, replicas) wait_for(check_scale_value, num_sec=wait, fail_condition=lambda val: val != replicas) - # def run_command(self, namespace, name, cmd, **kwargs): - # """Connects to pod and tries to run - # - # Args: - # namespace: (str) project name - # name: (str) pod name - # cmd: (list) command to run - # Return: command output - # """ - # # there are some limitations and this code isn't robust enough due to - # # https://github.com/kubernetes-client/python/issues/58 - # return self.v1_pod.exec.post(namespace=namespace, name=name, - # command=cmd, - # stdout=True, - # stderr=True, - # **kwargs) \ No newline at end of file + def run_command(self, namespace, name, cmd, **kwargs): + """Connects to pod and tries to run + + Args: + namespace: (str) project name + name: (str) pod name + cmd: (list) command to run + Return: command output + """ + # there are some limitations and this code isn't robust enough due to + # https://github.com/kubernetes-client/python/issues/58 + return self.v1_pod.exec.post(namespace=namespace, name=name, command=cmd, stdout=True, + stderr=True, **kwargs)