def _find_cluster_in_org(self, cluster_name, is_org_admin_search=False): """Invoke set of all (vCD/PKS)brokers in the org to find the cluster. 'is_org_admin_search' is used here to prevent cluster creation with same cluster-name by users within org. If it is true, cluster list is filtered by the org name of the logged-in user. If cluster found: Return a tuple of (cluster and the broker instance used to find the cluster) Else: (None, None) if cluster not found. """ vcd_broker = VcdBroker(self.req_headers, self.req_spec) try: return vcd_broker.get_cluster_info(cluster_name), vcd_broker except Exception as err: LOGGER.debug(f"Get cluster info on {cluster_name} failed " f"on vCD with error: {err}") pks_ctx_list = self._create_pks_context_for_all_accounts_in_org() for pks_ctx in pks_ctx_list: pksbroker = PKSBroker(self.req_headers, self.req_spec, pks_ctx) try: return pksbroker.get_cluster_info( cluster_name=cluster_name, is_org_admin_search=is_org_admin_search), pksbroker except PksServerError as err: LOGGER.debug(f"Get cluster info on {cluster_name} failed " f"on {pks_ctx['host']} with error: {err}") return None, None
def find_cluster_in_org(self, cluster_name, is_org_admin_search=False): """Invoke vCD broker to find the cluster in the org. 'is_org_admin_search' is used here to prevent cluster creation with same cluster-name by users within org. If it is true, cluster list is filtered by the org name of the logged-in user. If cluster found: Return a tuple of (cluster and the broker instance used to find the cluster) Else: (None, None) if cluster not found. """ vcd_broker = VcdBroker(self.tenant_auth_token, self.req_spec) try: return vcd_broker.get_cluster_info(cluster_name), vcd_broker except ClusterNotFoundError as err: # If a cluster is not found, then broker_manager will # decide if it wants to raise an error or ignore it if was it just # scanning the broker to check if it can handle the cluster request # or not. LOGGER.debug(f"Get cluster info on {cluster_name}" f"on vCD failed with error: {err}") except CseDuplicateClusterError as err: LOGGER.debug(f"Get cluster info on {cluster_name}" f"on vCD failed with error: {err}") raise except Exception as err: LOGGER.debug(f"Get cluster info on {cluster_name} failed " f"on vCD with error: {err}") return None, None
def _find_cluster_in_org(self, cluster_name): """Invoke set of all (vCD/PKS)brokers in the org to find the cluster. If cluster found: Return a tuple of (cluster and the broker instance used to find the cluster) Else: (None, None) if cluster not found. """ vcd_broker = VcdBroker(self.req_headers, self.req_spec) try: return vcd_broker.get_cluster_info(cluster_name), vcd_broker except Exception as err: LOGGER.debug(f"Get cluster info on {cluster_name} failed " f"on vCD with error: {err}") pks_ctx_list = self._create_pks_context_for_all_accounts_in_org() for pks_ctx in pks_ctx_list: pksbroker = PKSBroker(self.req_headers, self.req_spec, pks_ctx) try: return pksbroker.get_cluster_info(cluster_name=cluster_name),\ pksbroker except Exception as err: LOGGER.debug(f"Get cluster info on {cluster_name} failed " f"on {pks_ctx['host']} with error: {err}") return None, None
def cluster_upgrade(request_data, op_ctx: ctx.OperationContext): """Request handler for cluster upgrade operation. data validation handled in broker :return: Dict """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.upgrade_cluster(data=request_data)
def cluster_upgrade_plan(request_data, op_ctx: ctx.OperationContext): """Request handler for cluster upgrade-plan operation. data validation handled in broker :return: List[Tuple(str, str)] """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.get_cluster_upgrade_plan(data=request_data)
def cluster_info(request_data, request_context: ctx.RequestContext): """Request handler for cluster info operation. Required data: cluster_name Optional data and default values: org_name=None, ovdc_name=None (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(request_context) return vcd_broker.get_cluster_info(data=request_data)
def cluster_config(request_data, op_ctx: ctx.OperationContext): """Request handler for cluster config operation. Required data: cluster_name Optional data and default values: org_name=None, ovdc_name=None (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.get_cluster_config(data=request_data)
def node_delete(request_data, op_ctx: ctx.OperationContext): """Request handler for node delete operation. Required data: cluster_name, node_names_list Optional data and default values: org_name=None, ovdc_name=None (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.delete_nodes(data=request_data)
def cluster_resize(request_data, op_ctx: ctx.OperationContext): """Request handler for cluster resize operation. Required data: cluster_name, num_nodes Optional data and default values: org_name=None, ovdc_name=None Conditional data and default values: network_name, rollback=True (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.resize_cluster(data=request_data)
def node_create(request_data, op_ctx: ctx.OperationContext): """Request handler for node create operation. Required data: cluster_name, network_name Optional data and default values: org_name=None, ovdc_name=None, num_nodes=1, num_cpu=None, mb_memory=None, storage_profile_name=None, template_name=default, template_revision=default, ssh_key=None, rollback=True, enable_nfs=False, (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(op_ctx) return vcd_broker.create_nodes(data=request_data)
def cluster_list(request_data, tenant_auth_token): """Request handler for cluster list operation. All (vCD/PKS) brokers in the org do 'list cluster' operation. Post-process the result returned by pks broker. Aggregate all the results into a list. Optional data and default values: org_name=None, ovdc_name=None (data validation handled in brokers) :return: List """ vcd_clusters_info = \ VcdBroker(tenant_auth_token).list_clusters(request_data) pks_clusters_info = [] if utils.is_pks_enabled(): pks_clusters_info = pks_broker_manager.list_clusters( request_data, tenant_auth_token) all_cluster_infos = vcd_clusters_info + pks_clusters_info common_cluster_properties = [ 'name', 'vdc', 'status', 'org_name', K8S_PROVIDER_KEY ] result = [] for cluster_info in all_cluster_infos: filtered_cluster_info = \ {k: cluster_info.get(k) for k in common_cluster_properties} result.append(filtered_cluster_info) return result
def cluster_create(request_data, request_context: ctx.RequestContext): """Request handler for cluster create operation. Required data: org_name, ovdc_name, cluster_name Conditional data and default values: network_name, num_nodes=2, num_cpu=None, mb_memory=None, storage_profile_name=None, template_name=default, template_revision=default, ssh_key=None, enable_nfs=False, rollback=True (data validation handled in broker) :return: Dict """ vcd_broker = VcdBroker(request_context) return vcd_broker.create_cluster(data=request_data)
def _get_broker_based_on_ctr_prov_ctx(self, ctr_prov_ctx): # If system is equipped with PKS, use the metadata on ovdc to determine # the correct broker, otherwise fallback to vCD for cluster deployment. # However if the system is enabled for PKS and has no metadata on odvc # or isn't enabled for container deployment raise appropriate # exception. if is_pks_enabled(): if ctr_prov_ctx: if ctr_prov_ctx.get(K8S_PROVIDER_KEY) == K8sProviders.PKS: return PKSBroker(self.tenant_auth_token, self.req_spec, pks_ctx=ctr_prov_ctx) elif ctr_prov_ctx.get(K8S_PROVIDER_KEY) == K8sProviders.NATIVE: return VcdBroker(self.tenant_auth_token, self.req_spec) else: return VcdBroker(self.tenant_auth_token, self.req_spec) raise CseServerError("Org VDC is not enabled for Kubernetes cluster " "deployment")
def get_broker_based_on_vdc(self): """Get the broker based on ovdc. :return: broker :rtype: container_service_extension.abstract_broker.AbstractBroker """ ovdc_name = self.req_spec.get('vdc') or \ self.req_qparams.get('vdc') org_name = self.req_spec.get('org') or \ self.req_qparams.get('org') or \ self.session.get('org') LOGGER.debug(f"org_name={org_name};vdc_name=\'{ovdc_name}\'") # Get the ovdc metadata using org and ovdc. # Create the right broker based on value of 'container_provider'. # Fall back to DefaultBroker for missing ovdc or org. if ovdc_name and org_name: ctr_prov_ctx = \ self.ovdc_cache.get_ovdc_container_provider_metadata( ovdc_name=ovdc_name, org_name=org_name, credentials_required=True, nsxt_info_required=True) LOGGER.debug( f"ovdc metadata for {ovdc_name}-{org_name}=>{ctr_prov_ctx}") if ctr_prov_ctx.get(CONTAINER_PROVIDER_KEY) == \ CtrProvType.PKS.value: return PKSBroker(self.req_headers, self.req_spec, pks_ctx=ctr_prov_ctx) elif ctr_prov_ctx.get(CONTAINER_PROVIDER_KEY) == \ CtrProvType.VCD.value: return VcdBroker(self.req_headers, self.req_spec) else: raise CseServerError(f"Vdc '{ovdc_name}' is not enabled for " "Kubernetes cluster deployment") else: # TODO() - This call should be based on a boolean flag # Specify flag in config file whether to have default # handling is required for missing ovdc or org. return VcdBroker(self.req_headers, self.req_spec)
def node_info(request_data, tenant_auth_token): """Request handler for node info operation. Required data: cluster_name, node_name Optional data and default values: org_name=None, ovdc_name=None (data validation handled in brokers) :return: Dict """ # Currently node info is a vCD only operation. return VcdBroker(tenant_auth_token).get_node_info(request_data)
def _get_broker_based_on_ctr_prov_ctx(self, ctr_prov_ctx): if ctr_prov_ctx \ and ctr_prov_ctx.get(K8S_PROVIDER_KEY) == K8sProviders.PKS: return PKSBroker(self.req_headers, self.req_spec, pks_ctx=ctr_prov_ctx) else: # TODO() - This call should be based on a boolean flag # Specify flag in config file whether to have default # handling is required for missing ovdc or org. return VcdBroker(self.req_headers, self.req_spec)
def get_broker_from_k8s_metadata(k8s_metadata, tenant_auth_token): """Get broker from ovdc k8s metadata. If PKS is not enabled, always return VcdBroker If PKS is enabled if no ovdc metadata exists or k8s provider is None, raise server error else return the broker according to ovdc k8s provider """ if utils.is_pks_enabled(): if not k8s_metadata or k8s_metadata.get( K8S_PROVIDER_KEY) == K8sProvider.NONE: # noqa: E501 raise CseServerError("Org VDC is not enabled for Kubernetes " "cluster deployment") if k8s_metadata.get(K8S_PROVIDER_KEY) == K8sProvider.PKS: return PksBroker(k8s_metadata, tenant_auth_token) if k8s_metadata.get(K8S_PROVIDER_KEY) == K8sProvider.NATIVE: return VcdBroker(tenant_auth_token) return VcdBroker(tenant_auth_token)
def _list_clusters(self): """Logic of the method is as follows. If 'ovdc' is present in the body, choose the right broker (by identifying the container_provider (vcd|pks) defined for that ovdc) to do list_clusters operation. Else Invoke set of all (vCD/PKS)brokers in the org to do list_clusters. Post-process the result returned by each broker. Aggregate all the results into one. """ if self.is_ovdc_present_in_request: broker = self.get_broker_based_on_vdc() return broker.list_clusters() else: common_cluster_properties = ('name', 'vdc', 'status', 'org_name') vcd_broker = VcdBroker(self.req_headers, self.req_spec) vcd_clusters = [] for cluster in vcd_broker.list_clusters(): vcd_cluster = { k: cluster.get(k, None) for k in common_cluster_properties } vcd_cluster[K8S_PROVIDER_KEY] = K8sProviders.NATIVE vcd_clusters.append(vcd_cluster) pks_clusters = [] pks_ctx_list = self._create_pks_context_for_all_accounts_in_org() for pks_ctx in pks_ctx_list: pks_broker = PKSBroker(self.req_headers, self.req_spec, pks_ctx) # Get all cluster information to get vdc name from # compute-profile-name for cluster in pks_broker.list_clusters(is_admin_request=True): pks_cluster = \ PKSBroker.generate_cluster_subset_with_given_keys( cluster, common_cluster_properties) pks_cluster[K8S_PROVIDER_KEY] = K8sProviders.PKS pks_clusters.append(pks_cluster) return vcd_clusters + pks_clusters
def node_delete(request_data, tenant_auth_token): """Request handler for node delete operation. Required data: cluster_name, node_names_list Optional data and default values: org_name=None, ovdc_name=None (data validation handled in brokers) :return: Dict """ # Currently node delete is a vCD only operation. # TODO remove once resize is able to scale down native clusters return VcdBroker(tenant_auth_token).delete_nodes(request_data)
def get_cluster_and_broker(request_data, tenant_auth_token, is_jwt_token): cluster_name = request_data[RequestKey.CLUSTER_NAME] vcd_broker = VcdBroker(tenant_auth_token, is_jwt_token) try: return vcd_broker.get_cluster_info(request_data), vcd_broker except ClusterNotFoundError as err: # continue searching using PksBrokers LOGGER.debug(f"{err}") except CseDuplicateClusterError as err: # fail because multiple clusters with same name exist # only case is when multiple same-name clusters exist across orgs # and sys admin tries to do a cluster operation LOGGER.debug(f"{err}") raise except Exception as err: LOGGER.error(f"Unknown error: {err}", exc_info=True) raise pks_ctx_list = create_pks_context_for_all_accounts_in_org( tenant_auth_token, is_jwt_token) for pks_ctx in pks_ctx_list: debug_msg = f"Get cluster info for cluster '{cluster_name}' " \ f"failed on host '{pks_ctx['host']}' with error: " pks_broker = PksBroker(pks_ctx, tenant_auth_token, is_jwt_token) try: return pks_broker.get_cluster_info(request_data), pks_broker except (PksClusterNotFoundError, PksServerError) as err: # continue searching using other PksBrokers LOGGER.debug(f"{debug_msg}{err}") except PksDuplicateClusterError as err: # fail because multiple clusters with same name exist LOGGER.debug(f"{debug_msg}{err}") raise except Exception as err: LOGGER.error(f"Unknown error: {err}", exc_info=True) raise # only raised if cluster was not found in VcdBroker or PksBrokers raise ClusterNotFoundError(f"Cluster '{cluster_name}' not found.")
def cluster_list(request_data, op_ctx: ctx.OperationContext): """Request handler for cluster list operation. Optional data and default values: org_name=None, ovdc_name=None (data validation handled in broker) :return: List """ vcd_broker = VcdBroker(op_ctx) vcd_clusters_info = vcd_broker.list_clusters(data=request_data) common_cluster_properties = [ 'name', 'vdc', 'status', 'org_name', 'k8s_version', K8S_PROVIDER_KEY ] result = [] for cluster_info in vcd_clusters_info: filtered_cluster_info = \ {k: cluster_info.get(k) for k in common_cluster_properties} result.append(filtered_cluster_info) return result
def _list_clusters(self): """Logic of the method is as follows. If 'ovdc' is present in the body, choose the right broker (by identifying the container_provider (vcd|pks) defined for that ovdc) to do list_clusters operation. Else Invoke set of all (vCD/PKS)brokers in the org to do list_clusters. Post-process the result returned by each broker. Aggregate all the results into one. """ if self.is_ovdc_present_in_request: broker = self.get_broker_based_on_vdc() return broker.list_clusters() else: common_cluster_properties = ('name', 'vdc', 'status') vcd_broker = VcdBroker(self.req_headers, self.req_spec) vcd_clusters = [] for cluster in vcd_broker.list_clusters(): vcd_cluster = { k: cluster.get(k, None) for k in common_cluster_properties } vcd_cluster[CONTAINER_PROVIDER_KEY] = CtrProvType.VCD.value vcd_clusters.append(vcd_cluster) pks_clusters = [] pks_ctx_list = self._create_pks_context_for_all_accounts_in_org() for pks_ctx in pks_ctx_list: pks_broker = PKSBroker(self.req_headers, self.req_spec, pks_ctx) for cluster in pks_broker.list_clusters(): pks_cluster = self._get_truncated_cluster_info( cluster, pks_broker, common_cluster_properties) pks_cluster[CONTAINER_PROVIDER_KEY] = CtrProvType.PKS.value pks_clusters.append(pks_cluster) return vcd_clusters + pks_clusters
def node_create(request_data, tenant_auth_token): """Request handler for node create operation. Required data: cluster_name, network_name Optional data and default values: org_name=None, ovdc_name=None, num_nodes=1, num_cpu=None, mb_memory=None, storage_profile_name=None, template_name=default, template_revision=default, ssh_key=None, rollback=True, enable_nfs=False, (data validation handled in brokers) :return: Dict """ # Currently node create is a vCD only operation. # Different from resize because this can create nfs nodes return VcdBroker(tenant_auth_token).create_nodes(request_data)
def invoke(self, op): """Invoke right broker(s) to perform the operation requested. Might result in further (pre/post)processing on the request/result(s). Depending on the operation requested, this method may do one or more of below mentioned points. 1. Extract and construct the relevant params for the operation. 2. Choose right broker to perform the operation/method requested. 3. Scan through available brokers to aggregate (or) filter results. :param CseOperation op: Operation to be performed by one of the brokers. :return result: result of the operation. :rtype: dict """ result = {} self.is_ovdc_present_in_request = bool( self.req_spec.get(RequestKey.OVDC_NAME)) # noqa: E501 if op == CseOperation.CLUSTER_CONFIG: cluster_spec = \ {'cluster_name': self.req_spec.get(RequestKey.CLUSTER_NAME)} result = self._get_cluster_config(**cluster_spec) elif op == CseOperation.CLUSTER_CREATE: # TODO(ClusterSpec) Create an inner class "ClusterSpec" # in abstract_broker.py and have subclasses define and use it # as instance variable. # Method 'Create_cluster' in VcdBroker and PksBroker should take # ClusterSpec either as a param (or) # read from instance variable (if needed only). cluster_spec = { 'cluster_name': self.req_spec.get(RequestKey.CLUSTER_NAME), 'vdc_name': self.req_spec.get(RequestKey.OVDC_NAME), 'org_name': self.req_spec.get(RequestKey.ORG_NAME), 'node_count': self.req_spec.get(RequestKey.NUM_WORKERS), 'storage_profile': self.req_spec.get( RequestKey.STORAGE_PROFILE_NAME), # noqa: E501 'network_name': self.req_spec.get(RequestKey.NETWORK_NAME), 'template': self.req_spec.get(RequestKey.TEMPLATE_NAME), } result = self._create_cluster(**cluster_spec) elif op == CseOperation.CLUSTER_DELETE: cluster_spec = \ {'cluster_name': self.req_spec.get(RequestKey.CLUSTER_NAME)} result = self._delete_cluster(**cluster_spec) elif op == CseOperation.CLUSTER_INFO: cluster_spec = \ {'cluster_name': self.req_spec.get(RequestKey.CLUSTER_NAME)} result = self._get_cluster_info(**cluster_spec)[0] elif op == CseOperation.CLUSTER_LIST: result = self._list_clusters() elif op == CseOperation.CLUSTER_RESIZE: cluster_spec = { 'cluster_name': self.req_spec.get(RequestKey.CLUSTER_NAME), 'node_count': self.req_spec.get(RequestKey.NUM_WORKERS) } result = self._resize_cluster(**cluster_spec) elif op == CseOperation.NODE_CREATE: # Currently node create is a vCD only operation. broker = VcdBroker(self.tenant_auth_token, self.req_spec) result = broker.create_nodes() elif op == CseOperation.NODE_DELETE: # Currently node delete is a vCD only operation. broker = VcdBroker(self.tenant_auth_token, self.req_spec) result = broker.delete_nodes() elif op == CseOperation.NODE_INFO: cluster_name = self.req_spec.get(RequestKey.CLUSTER_NAME) node_name = self.req_spec.get(RequestKey.NODE_NAME) # Currently node info is a vCD only operation. broker = VcdBroker(self.tenant_auth_token, self.req_spec) result = broker.get_node_info(cluster_name, node_name) return result
def list_clusters(self): vcd_broker = VcdBroker(self.tenant_auth_token, self.req_spec) vcd_clusters = [] for cluster in vcd_broker.list_clusters(): vcd_clusters.append(cluster) return vcd_clusters