def get_cluster_config(self, data): """Get the configuration of the cluster with the given name in PKS. System administrator gets the given cluster config regardless of who is the owner of the cluster. Other users get config only on the cluster they own. :return: Configuration of the cluster. :rtype: str """ cluster_name = data[RequestKey.CLUSTER_NAME] if self.tenant_client.is_sysadmin() or \ is_org_admin(self.client_session): cluster_info = self.get_cluster_info(data) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) self._check_cluster_isolation(cluster_name, qualified_cluster_name) cluster_api = ClusterApiV1(api_client=self.client_v1) LOGGER.debug(f"Sending request to PKS: {self.pks_host_uri} to get" f" detailed configuration of cluster with name: " f"{cluster_name}") config = cluster_api.create_user(cluster_name=qualified_cluster_name) LOGGER.debug(f"Received response from PKS: {self.pks_host_uri} on " f"cluster: {cluster_name} with details: {config}") cluster_config = yaml.safe_dump(config, default_flow_style=False) return self.filter_traces_of_user_context(cluster_config)
def resize_cluster(self, **cluster_spec): """Resize the cluster of a given name to given number of worker nodes. System administrator can resize the given cluster regardless of who is the owner of the cluster. Other users can only resize the cluster they own. :param dict cluster_spec: named parameters that are required to resize cluster (cluster_name, node_count) :return: response status :rtype: dict """ cluster_name = cluster_spec['cluster_name'] if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session): cluster_info = self.get_cluster_info(cluster_name) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) self._check_cluster_isolation(cluster_name, qualified_cluster_name) cluster_spec['cluster_name'] = qualified_cluster_name result = self._resize_cluster(**cluster_spec) self._restore_original_name(result) self._filter_pks_properties(result) return result
def delete_cluster(self, cluster_name): """Delete the cluster with a given name in PKS environment. System administrator can delete the given cluster regardless of who is the owner of the cluster. Other users can only delete the cluster they own. :param str cluster_name: Name of the cluster """ if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session): cluster_info = self.get_cluster_info(cluster_name) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) result = self._delete_cluster(qualified_cluster_name) # remove cluster network isolation LOGGER.debug(f"Removing network isolation of cluster {cluster_name}.") try: cluster_network_isolater = ClusterNetworkIsolater(self.nsxt_client) cluster_network_isolater.remove_cluster_isolation( qualified_cluster_name) except Exception as err: # NSX-T oprations are idempotent so they should not cause erros # if say NSGroup is missing. But for any other exception, simply # catch them and ignore. LOGGER.debug(f"Error {err} occured while deleting cluster " f"isolation rules for cluster {cluster_name}") self._restore_original_name(result) self._filter_pks_properties(result) return result
def delete_cluster(self, data): """Delete the cluster with a given name in PKS environment. System administrator can delete the given cluster regardless of who is the owner of the cluster. Other users can only delete the cluster they own. :param str cluster_name: Name of the cluster """ cluster_name = data[RequestKey.CLUSTER_NAME] if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session): cluster_info = self._get_cluster_info(data) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) result = {} cluster_api = ClusterApi(api_client=self.client) try: LOGGER.debug( f"Sending request to PKS: {self.pks_host_uri} to delete " f"the cluster with name: {qualified_cluster_name}") cluster_api.delete_cluster(cluster_name=qualified_cluster_name) LOGGER.debug( f"PKS: {self.pks_host_uri} accepted the request to delete" f" the cluster: {qualified_cluster_name}") except ApiException as err: LOGGER.debug(f"Deleting cluster {qualified_cluster_name} failed" f" with error:\n {err}") raise PksServerError(err.status, err.body) result['name'] = qualified_cluster_name result['task_status'] = 'in progress' # remove cluster network isolation LOGGER.debug("Removing network isolation of cluster " f"{qualified_cluster_name}.") try: cluster_network_isolater = ClusterNetworkIsolater(self.nsxt_client) cluster_network_isolater.remove_cluster_isolation( qualified_cluster_name) except Exception as err: # NSX-T oprations are idempotent so they should not cause erros # if say NSGroup is missing. But for any other exception, simply # catch them and ignore. LOGGER.debug(f"Error {err} occured while deleting cluster " "isolation rules for cluster " f"{qualified_cluster_name}") return result
def _filter_clusters(self, cluster_list, **kwargs): """Filter the cluster list based on vdc, org by personae. Apply the filters in the following order of priority and return the result once the specific-persona-only filter is applied. 1. Filter clusters based on vdc for all personae. 2. Filter clusters based on org only for sysadmin. 3. Filter clusters for org admin based on visibility. 4. Filter clusters for tenant users based on ownership only. :param list cluster_list: list of clusters :return: filtered list of clusters :rtype: list TODO() These filters should be moved to either broker layer or delegated to dedicated filter class say: PksClusterFilter. """ # Apply vdc filter, if provided to all personae. if kwargs.get(RequestKey.OVDC_NAME): cluster_list = \ self._apply_vdc_filter(cluster_list, kwargs.get(RequestKey.OVDC_NAME)) # Apply org filter, if provided, for sys admin. if self.tenant_client.is_sysadmin(): org_name = kwargs.get(RequestKey.ORG_NAME) if org_name and org_name.lower() != SYSTEM_ORG_NAME.lower(): cluster_list = self._apply_org_filter(cluster_list, org_name) return cluster_list # Filter the cluster list for org admin and others. if is_org_admin(self.client_session) or kwargs.get( 'is_org_admin_search'): # noqa: E501 # TODO() - Service accounts for exclusive org does not # require the following filtering. cluster_list = [ cluster_dict for cluster_dict in cluster_list if self._is_cluster_visible_to_org_admin(cluster_dict) ] else: cluster_list = [ cluster_dict for cluster_dict in cluster_list if self._is_user_cluster_owner(cluster_dict) ] # 'is_admin_request' is a flag that is used to restrict access to # user context and other secured information on pks cluster # information. if not kwargs.get('is_admin_request'): for cluster in cluster_list: self._filter_pks_properties(cluster) return cluster_list
def resize_cluster(self, data): """Resize the cluster of a given name to given number of worker nodes. System administrator can resize the given cluster regardless of who is the owner of the cluster. Other users can only resize the cluster they own. :return: response status :rtype: dict """ cluster_name = data[RequestKey.CLUSTER_NAME] num_workers = data[RequestKey.NUM_WORKERS] if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session): cluster_info = self._get_cluster_info(data) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) self._check_cluster_isolation(cluster_name, qualified_cluster_name) result = {} cluster_api = ClusterApi(api_client=self.client) LOGGER.debug(f"Sending request to PKS:{self.pks_host_uri} to resize " f"the cluster with name: {qualified_cluster_name} to " f"{num_workers} worker nodes") resize_params = \ UpdateClusterParameters(kubernetes_worker_instances=num_workers) try: cluster_api.update_cluster(qualified_cluster_name, body=resize_params) except ApiException as err: LOGGER.debug(f"Resizing cluster {qualified_cluster_name} failed" f" with error:\n {err}") raise PksServerError(err.status, err.body) LOGGER.debug(f"PKS: {self.pks_host_uri} accepted the request to resize" f" the cluster: {qualified_cluster_name}") result['name'] = qualified_cluster_name result['task_status'] = 'in progress' self._restore_original_name(result) if not self.tenant_client.is_sysadmin(): self._filter_sensitive_pks_properties(result) return result
def _get_cluster_info(self, data): """Get the details of a cluster with a given name in PKS environment. System administrator gets the given cluster information regardless of who is the owner of the cluster. Other users get info only on the cluster they own. :param str cluster_name: Name of the cluster :return: Details of the cluster. :rtype: dict """ cluster_name = data[RequestKey.CLUSTER_NAME] # The structure of info returned by list_cluster and get_cluster is # identical, hence using list_cluster and filtering by name in memory # to retrieve info of the requested cluster. cluster_info_list = self._list_clusters(data) result = {} if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session) \ or data.get('is_org_admin_search'): filtered_cluster_info_list = [] for cluster_info in cluster_info_list: if cluster_info['name'] == cluster_name: filtered_cluster_info_list.append(cluster_info) LOGGER.debug( f"Filtered list of clusters:{filtered_cluster_info_list}") if len(filtered_cluster_info_list) > 1: raise PksDuplicateClusterError( requests.codes.bad_request, f"Multiple clusters with name '{cluster_name}' exists.") if len(filtered_cluster_info_list) == 0: raise PksServerError(requests.codes.not_found, f"cluster {cluster_name} not found.") result = filtered_cluster_info_list[0] else: qualified_cluster_name = self._append_user_id(cluster_name) for cluster_info in cluster_info_list: if cluster_info['pks_cluster_name'] == qualified_cluster_name: result = cluster_info break if not result: raise PksServerError(requests.codes.not_found, f"cluster {cluster_name} not found.") return result
def list_clusters(self, **kwargs): """Get list of clusters in PKS environment. System administrator gets all the clusters for the given service account. Other users get only those clusters which they own. :return: a list of cluster-dictionaries :rtype: list """ cluster_list = self._list_clusters() # Required for all personae for cluster in cluster_list: self._restore_original_name(cluster) # Complete list of clusters for sysadmin if self.tenant_client.is_sysadmin(): return cluster_list # Filter the list for org admin and others. if is_org_admin(self.client_session) or \ kwargs.get('is_org_admin_search'): # TODO() - Service accounts for exclusive org does not # require the following filtering. cluster_list = [ cluster_dict for cluster_dict in cluster_list if self._is_cluster_visible_to_org_admin(cluster_dict) ] else: cluster_list = [ cluster_dict for cluster_dict in cluster_list if self._is_user_cluster_owner(cluster_dict) ] # 'is_admin_request' is a flag that is used to restrict access to # user context and other secured information on pks cluster # information. if not kwargs.get('is_admin_request'): for cluster in cluster_list: self._filter_pks_properties(cluster) return cluster_list
def get_cluster_config(self, cluster_name): """Get the configuration of the cluster with the given name in PKS. System administrator gets the given cluster config regardless of who is the owner of the cluster. Other users get config only on the cluster they own. :param str cluster_name: Name of the cluster :return: Configuration of the cluster. :rtype: str """ if self.tenant_client.is_sysadmin() or \ is_org_admin(self.client_session): cluster_info = self.get_cluster_info(cluster_name) qualified_cluster_name = cluster_info['pks_cluster_name'] else: qualified_cluster_name = self._append_user_id(cluster_name) self._check_cluster_isolation(cluster_name, qualified_cluster_name) config_info = self._get_cluster_config(qualified_cluster_name) return self.filter_traces_of_user_context(config_info)
def get_cluster_info(self, data): """Get the details of a cluster with a given name in PKS environment. System administrator gets the given cluster information regardless of who is the owner of the cluster. Other users get info only on the cluster they own. :param str cluster_name: Name of the cluster :return: Details of the cluster. :rtype: dict """ cluster_name = data[RequestKey.CLUSTER_NAME] if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session) \ or data.get('is_org_admin_search'): cluster_list = self.list_clusters(data) filtered_cluster_list = \ self._filter_list_by_cluster_name(cluster_list, cluster_name) LOGGER.debug(f"filtered Cluster List:{filtered_cluster_list}") if len(filtered_cluster_list) > 1: raise PksDuplicateClusterError( requests.codes.bad_request, f"Multiple clusters with name '{cluster_name}' exists.") if len(filtered_cluster_list) == 0: raise PksServerError(requests.codes.not_found, f"cluster {cluster_name} not found.") return filtered_cluster_list[0] cluster_info = \ self._get_cluster_info(self._append_user_id(cluster_name)) self._restore_original_name(cluster_info) if not data.get('is_admin_request'): self._filter_pks_properties(cluster_info) return cluster_info
def get_cluster_info(self, cluster_name, **kwargs): """Get the details of a cluster with a given name in PKS environment. System administrator gets the given cluster information regardless of who is the owner of the cluster. Other users get info only on the cluster they own. :param str cluster_name: Name of the cluster :return: Details of the cluster. :rtype: dict """ if self.tenant_client.is_sysadmin() \ or is_org_admin(self.client_session) \ or kwargs.get('is_org_admin_search'): cluster_list = self.list_clusters( is_org_admin_search=kwargs.get('is_org_admin_search')) filtered_cluster_list = \ self._filter_list_by_cluster_name(cluster_list, cluster_name) LOGGER.debug(f"filtered Cluster List:{filtered_cluster_list}") # TODO() Sys admin may encounter multiple clusters with the same # name; in that case choosing the first one could be wrong. # Needs revisit if len(filtered_cluster_list) > 0: cluster_info = filtered_cluster_list[0] else: raise PksServerError(HTTPStatus.NOT_FOUND, f"cluster {cluster_name} not found") else: cluster_info = \ self._get_cluster_info(self._append_user_id(cluster_name)) self._restore_original_name(cluster_info) if not kwargs.get('is_admin_request'): self._filter_pks_properties(cluster_info) return cluster_info