def cluster_create(request_data, request_context: ctx.RequestContext): """Request handler for cluster create operation. Required data: org_name, ovdc_name, cluster_name (data validation handled in broker) :return: Dict """ _raise_error_if_pks_not_enabled() required = [RequestKey.CLUSTER_NAME] req_utils.validate_payload(request_data, required) cluster_name = request_data[RequestKey.CLUSTER_NAME] request_data['is_org_admin_search'] = True try: _get_cluster_and_broker(request_data, request_context, telemetry=False) raise ClusterAlreadyExistsError(f"Cluster {cluster_name} " f"already exists.") except ClusterNotFoundError: pass k8s_metadata = \ ovdc_utils.get_ovdc_k8s_provider_metadata( request_context.sysadmin_client, org_name=request_data[RequestKey.ORG_NAME], ovdc_name=request_data[RequestKey.OVDC_NAME], include_credentials=True, include_nsxt_info=True) broker = _get_broker_from_k8s_metadata(k8s_metadata, request_context) request_data[RequestKey.PKS_PLAN_NAME] = k8s_metadata[PKS_PLANS_KEY][0] request_data[RequestKey.PKS_EXT_HOST] = \ f"{cluster_name}.{k8s_metadata[PKS_CLUSTER_DOMAIN_KEY]}" return broker.create_cluster(data=request_data)
def cluster_create(request_data, tenant_auth_token): """Request handler for cluster create operation. Required data: org_name, ovdc_name, cluster_name Conditional data and default values: if k8s_provider is 'native': 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 brokers) :return: Dict """ required = [ RequestKey.CLUSTER_NAME ] req_utils.validate_payload(request_data, required) cluster_name = request_data[RequestKey.CLUSTER_NAME] # TODO HACK 'is_org_admin_search' is used here to prevent users from # creating clusters with the same name, including clusters in PKS # True means that the cluster list is filtered by the org name of # the logged-in user to check that there are no duplicate clusters request_data['is_org_admin_search'] = True try: broker_manager.get_cluster_and_broker(request_data, tenant_auth_token) raise ClusterAlreadyExistsError(f"Cluster {cluster_name} " f"already exists.") except ClusterNotFoundError: pass k8s_metadata = \ ovdc_utils.get_ovdc_k8s_provider_metadata( org_name=request_data[RequestKey.ORG_NAME], ovdc_name=request_data[RequestKey.OVDC_NAME], include_credentials=True, include_nsxt_info=True) if k8s_metadata.get(K8S_PROVIDER_KEY) == K8sProvider.PKS: request_data[RequestKey.PKS_PLAN_NAME] = k8s_metadata[PKS_PLANS_KEY][0] request_data[RequestKey.PKS_EXT_HOST] = \ f"{cluster_name}.{k8s_metadata[PKS_CLUSTER_DOMAIN_KEY]}" broker = broker_manager.get_broker_from_k8s_metadata(k8s_metadata, tenant_auth_token) return broker.create_cluster(request_data)
def _create_cluster(self, **cluster_spec): cluster_name = cluster_spec['cluster_name'] # '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 to check for duplicates. cluster, _ = self._find_cluster_in_org(cluster_name, is_org_admin_search=True) if not cluster: ctr_prov_ctx = self._get_ctr_prov_ctx_from_ovdc_metadata() if ctr_prov_ctx.get(K8S_PROVIDER_KEY) == K8sProviders.PKS: cluster_spec['pks_plan'] = ctr_prov_ctx[PKS_PLANS_KEY][0] cluster_spec['pks_ext_host'] = f"{cluster_name}." \ f"{ctr_prov_ctx[PKS_CLUSTER_DOMAIN_KEY]}" broker = self._get_broker_based_on_ctr_prov_ctx(ctr_prov_ctx) return broker.create_cluster(**cluster_spec) else: raise ClusterAlreadyExistsError( f"Cluster {cluster_name} already exists.")
def create_cluster_thread(self): network_name = self.req_spec.get(RequestKey.NETWORK_NAME) try: clusters = load_from_metadata(self.tenant_client, name=self.cluster_name) if len(clusters) != 0: raise ClusterAlreadyExistsError(f"Cluster {self.cluster_name} " "already exists.") org_resource = self.tenant_client.get_org_by_name( self.req_spec.get(RequestKey.ORG_NAME)) org = Org(self.tenant_client, resource=org_resource) vdc_resource = org.get_vdc(self.req_spec.get(RequestKey.OVDC_NAME)) vdc = VDC(self.tenant_client, resource=vdc_resource) template = self._get_template() self._update_task( TaskStatus.RUNNING, message=f"Creating cluster vApp {self.cluster_name}" f"({self.cluster_id})") try: vapp_resource = vdc.create_vapp( self.cluster_name, description=f"cluster {self.cluster_name}", network=network_name, fence_mode='bridged') except Exception as e: raise ClusterOperationError( "Error while creating vApp:", str(e)) self.tenant_client.get_task_monitor().wait_for_status( vapp_resource.Tasks.Task[0]) tags = {} tags['cse.cluster.id'] = self.cluster_id tags['cse.version'] = pkg_resources.require( 'container-service-extension')[0].version tags['cse.template'] = template['name'] vapp = VApp(self.tenant_client, href=vapp_resource.get('href')) for k, v in tags.items(): task = vapp.set_metadata('GENERAL', 'READWRITE', k, v) self.tenant_client.get_task_monitor().wait_for_status(task) self._update_task( TaskStatus.RUNNING, message=f"Creating master node for {self.cluster_name}" f"({self.cluster_id})") vapp.reload() server_config = get_server_runtime_config() try: add_nodes(1, template, NodeType.MASTER, server_config, self.tenant_client, org, vdc, vapp, self.req_spec) except Exception as e: raise MasterNodeCreationError( "Error while adding master node:", str(e)) self._update_task( TaskStatus.RUNNING, message=f"Initializing cluster {self.cluster_name}" f"({self.cluster_id})") vapp.reload() init_cluster(server_config, vapp, template) master_ip = get_master_ip(server_config, vapp, template) task = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip', master_ip) self.tenant_client.get_task_monitor().wait_for_status(task) if self.req_spec.get(RequestKey.NUM_WORKERS) > 0: self._update_task( TaskStatus.RUNNING, message=f"Creating " f"{self.req_spec.get(RequestKey.NUM_WORKERS)} " f"node(s) for " f"{self.cluster_name}({self.cluster_id})") try: add_nodes(self.req_spec.get(RequestKey.NUM_WORKERS), template, NodeType.WORKER, server_config, self.tenant_client, org, vdc, vapp, self.req_spec) except Exception as e: raise WorkerNodeCreationError( "Error while creating worker node:", str(e)) self._update_task( TaskStatus.RUNNING, message=f"Adding " f"{self.req_spec.get(RequestKey.NUM_WORKERS)} " f"node(s) to " f"{self.cluster_name}({self.cluster_id})") vapp.reload() join_cluster(server_config, vapp, template) if self.req_spec.get(RequestKey.ENABLE_NFS): self._update_task( TaskStatus.RUNNING, message=f"Creating NFS node for {self.cluster_name}" f"({self.cluster_id})") try: add_nodes(1, template, NodeType.NFS, server_config, self.tenant_client, org, vdc, vapp, self.req_spec) except Exception as e: raise NFSNodeCreationError( "Error while creating NFS node:", str(e)) self._update_task( TaskStatus.SUCCESS, message=f"Created cluster {self.cluster_name}" f"({self.cluster_id})") except (MasterNodeCreationError, WorkerNodeCreationError, NFSNodeCreationError, ClusterJoiningError, ClusterInitializationError, ClusterOperationError) as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) stack_trace = \ ''.join(error_obj[ERROR_MESSAGE_KEY][ERROR_STACKTRACE_KEY]) self._update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE_KEY] [ERROR_DESCRIPTION_KEY], stack_trace=stack_trace) raise e except Exception as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) stack_trace = \ ''.join(error_obj[ERROR_MESSAGE_KEY][ERROR_STACKTRACE_KEY]) self._update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE_KEY][ERROR_DESCRIPTION_KEY], # noqa: E501 stack_trace=stack_trace) finally: self._disconnect_sys_admin()
def create_cluster(self, data): """Start the cluster creation operation. Common broker function that validates data for the 'create cluster' operation and returns a dictionary with cluster detail and task information. Calls the asyncronous cluster create function that actually performs the work. The returned `result['task_href']` can be polled to get updates on task progress. Required data: cluster_name, org_name, ovdc_name, network_name Optional data and default values: num_nodes=2, num_cpu=None, mb_memory=None, storage_profile_name=None, ssh_key_filepath=None, template_name=default, template_revision=default, enable_nfs=False, rollback=True """ required = [ RequestKey.CLUSTER_NAME, RequestKey.ORG_NAME, RequestKey.OVDC_NAME, RequestKey.NETWORK_NAME ] utils.ensure_keys_in_dict(required, data, dict_name='data') cluster_name = data[RequestKey.CLUSTER_NAME] # check that cluster name is syntactically valid if not is_valid_cluster_name(cluster_name): raise CseServerError(f"Invalid cluster name '{cluster_name}'") # check that cluster name doesn't already exist try: get_cluster(self.tenant_client, cluster_name, org_name=data[RequestKey.ORG_NAME], ovdc_name=data[RequestKey.OVDC_NAME]) raise ClusterAlreadyExistsError(f"Cluster {cluster_name} " f"already exists.") except ClusterNotFoundError: pass # check that requested/default template is valid template = get_template( name=data.get(RequestKey.TEMPLATE_NAME), revision=data.get(RequestKey.TEMPLATE_REVISION)) defaults = { RequestKey.NUM_WORKERS: 2, RequestKey.NUM_CPU: None, RequestKey.MB_MEMORY: None, RequestKey.STORAGE_PROFILE_NAME: None, RequestKey.SSH_KEY_FILEPATH: None, RequestKey.TEMPLATE_NAME: template[LocalTemplateKey.NAME], RequestKey.TEMPLATE_REVISION: template[LocalTemplateKey.REVISION], RequestKey.ENABLE_NFS: False, RequestKey.ROLLBACK: True, } validated_data = {**defaults, **data} # TODO HACK default dictionary combining needs to be fixed validated_data[RequestKey.TEMPLATE_NAME] = validated_data[RequestKey.TEMPLATE_NAME] or template[LocalTemplateKey.NAME] # noqa: E501 validated_data[RequestKey.TEMPLATE_REVISION] = validated_data[RequestKey.TEMPLATE_REVISION] or template[LocalTemplateKey.REVISION] # noqa: E501 template_name = validated_data[RequestKey.TEMPLATE_NAME] template_revision = validated_data[RequestKey.TEMPLATE_REVISION] # check that requested number of worker nodes is at least more than 1 num_workers = validated_data[RequestKey.NUM_WORKERS] if num_workers < 1: raise CseServerError(f"Worker node count must be > 0 " f"(received {num_workers}).") cluster_id = str(uuid.uuid4()) # must _update_task or else self.task_resource is None # do not logout of sys admin, or else in pyvcloud's session.request() # call, session becomes None self._update_task( TaskStatus.RUNNING, message=f"Creating cluster vApp '{cluster_name}' ({cluster_id})" f" from template '{template_name}' " f"(revision {template_revision})") self._create_cluster_async( org_name=validated_data[RequestKey.ORG_NAME], ovdc_name=validated_data[RequestKey.OVDC_NAME], cluster_name=cluster_name, cluster_id=cluster_id, template_name=template_name, template_revision=template_revision, num_workers=validated_data[RequestKey.NUM_WORKERS], network_name=validated_data[RequestKey.NETWORK_NAME], num_cpu=validated_data[RequestKey.NUM_CPU], mb_memory=validated_data[RequestKey.MB_MEMORY], storage_profile_name=validated_data[RequestKey.STORAGE_PROFILE_NAME], # noqa: E501 ssh_key_filepath=validated_data[RequestKey.SSH_KEY_FILEPATH], enable_nfs=validated_data[RequestKey.ENABLE_NFS], rollback=validated_data[RequestKey.ROLLBACK]) return { 'name': cluster_name, 'cluster_id': cluster_id, 'task_href': self.task_resource.get('href') }
def create_cluster_thread(self): network_name = self.body['network'] try: clusters = load_from_metadata(self.tenant_client, name=self.cluster_name) if len(clusters) != 0: raise ClusterAlreadyExistsError(f"Cluster {self.cluster_name} " "already exists.") org_resource = self.tenant_client.get_org() org = Org(self.tenant_client, resource=org_resource) vdc_resource = org.get_vdc(self.body['vdc']) vdc = VDC(self.tenant_client, resource=vdc_resource) template = self.get_template() self.update_task(TaskStatus.RUNNING, message='Creating cluster vApp %s(%s)' % (self.cluster_name, self.cluster_id)) try: vapp_resource = vdc.create_vapp(self.cluster_name, description='cluster %s' % self.cluster_name, network=network_name, fence_mode='bridged') except Exception as e: raise ClusterOperationError('Error while creating vApp:', str(e)) self.tenant_client.get_task_monitor().wait_for_status( vapp_resource.Tasks.Task[0]) tags = {} tags['cse.cluster.id'] = self.cluster_id tags['cse.version'] = pkg_resources.require( 'container-service-extension')[0].version tags['cse.template'] = template['name'] vapp = VApp(self.tenant_client, href=vapp_resource.get('href')) for k, v in tags.items(): task = vapp.set_metadata('GENERAL', 'READWRITE', k, v) self.tenant_client.get_task_monitor().wait_for_status(task) self.update_task(TaskStatus.RUNNING, message='Creating master node for %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() server_config = get_server_runtime_config() try: add_nodes(1, template, TYPE_MASTER, server_config, self.tenant_client, org, vdc, vapp, self.body) except Exception as e: raise MasterNodeCreationError( "Error while adding master node:", str(e)) self.update_task(TaskStatus.RUNNING, message='Initializing cluster %s(%s)' % (self.cluster_name, self.cluster_id)) vapp.reload() init_cluster(server_config, vapp, template) master_ip = get_master_ip(server_config, vapp, template) task = vapp.set_metadata('GENERAL', 'READWRITE', 'cse.master.ip', master_ip) self.tenant_client.get_task_monitor().wait_for_status(task) if self.body['node_count'] > 0: self.update_task(TaskStatus.RUNNING, message='Creating %s node(s) for %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) try: add_nodes(self.body['node_count'], template, TYPE_NODE, server_config, self.tenant_client, org, vdc, vapp, self.body) except Exception as e: raise WorkerNodeCreationError( "Error while creating worker node:", str(e)) self.update_task(TaskStatus.RUNNING, message='Adding %s node(s) to %s(%s)' % (self.body['node_count'], self.cluster_name, self.cluster_id)) vapp.reload() join_cluster(server_config, vapp, template) if self.body['enable_nfs']: self.update_task(TaskStatus.RUNNING, message='Creating NFS node for %s(%s)' % (self.cluster_name, self.cluster_id)) try: add_nodes(1, template, TYPE_NFS, server_config, self.tenant_client, org, vdc, vapp, self.body) except Exception as e: raise NFSNodeCreationError( "Error while creating NFS node:", str(e)) self.update_task(TaskStatus.SUCCESS, message='Created cluster %s(%s)' % (self.cluster_name, self.cluster_id)) except (MasterNodeCreationError, WorkerNodeCreationError, NFSNodeCreationError, ClusterJoiningError, ClusterInitializationError, ClusterOperationError) as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) stack_trace = ''.join(error_obj[ERROR_MESSAGE][ERROR_STACKTRACE]) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION], stack_trace=stack_trace) raise e except Exception as e: LOGGER.error(traceback.format_exc()) error_obj = error_to_json(e) stack_trace = ''.join(error_obj[ERROR_MESSAGE][ERROR_STACKTRACE]) self.update_task( TaskStatus.ERROR, error_message=error_obj[ERROR_MESSAGE][ERROR_DESCRIPTION], stack_trace=stack_trace) finally: self._disconnect_sys_admin()