From: Gulsum Atici Date: Tue, 27 Sep 2022 20:29:39 +0000 (+0300) Subject: Adding PaaS Service Creation X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=5fbd9a9d9cc20ecb0b49718a231327c81c2ba49d;p=osm%2Fosmclient.git Adding PaaS Service Creation Change-Id: I9aa6d236984180d6656a94fa69dd35a605f31993 Signed-off-by: Gulsum Atici --- diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index de121b1..fac267d 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -2289,9 +2289,14 @@ def nfpkg_create( @click.option("--nsd_name", prompt=True, help="name of the NS descriptor") @click.option( "--vim_account", - prompt=True, + default=None, help="default VIM account id or name for the deployment", ) +@click.option( + "--paas_account", + default=None, + help="default PaaS account id or name for the deployment", +) @click.option("--admin_status", default="ENABLED", help="administration status") @click.option( "--ssh_keys", @@ -2315,6 +2320,7 @@ def ns_create( nsd_name, ns_name, vim_account, + paas_account, admin_status, ssh_keys, config, @@ -2333,18 +2339,25 @@ def ns_create( ) with open(config_file, "r") as cf: config = cf.read() + if not (vim_account or paas_account): + raise ClientException( + 'specify "vim_account" or "paas_account", both options can not be empty' + ) + if vim_account and paas_account: + raise ClientException( + '"vim_account" and "paas_account" can not be used together, use only one of them' + ) ctx.obj.ns.create( nsd_name, ns_name, config=config, ssh_keys=ssh_keys, - account=vim_account, + vim_account=vim_account, + paas_account=paas_account, + admin_status=admin_status, wait=wait, timeout=timeout, ) - # except ClientException as e: - # print(str(e)) - # exit(1) def nst_create(ctx, filename, overwrite): diff --git a/osmclient/sol005/ns.py b/osmclient/sol005/ns.py index 00d68d6..fe3a2ba 100644 --- a/osmclient/sol005/ns.py +++ b/osmclient/sol005/ns.py @@ -40,7 +40,7 @@ class Ns(object): ) # NS '--wait' option - def _wait(self, id, wait_time, deleteFlag=False): + def _wait(self, op_id, wait_time, delete_flag=False): self._logger.debug("") # Endpoint to get operation status apiUrlStatus = "{}{}{}".format( @@ -51,11 +51,11 @@ class Ns(object): wait_time = WaitForStatus.TIMEOUT_NS_OPERATION WaitForStatus.wait_for_status( "NS", - str(id), + str(op_id), wait_time, apiUrlStatus, self._http.get2_cmd, - deleteFlag=deleteFlag, + deleteFlag=delete_flag, ) def list(self, filter=None): @@ -111,7 +111,7 @@ class Ns(object): :param config: parameters of deletion, as: autoremove: Bool (default True) timeout_ns_terminate: int - skip_terminate_primitives: Bool (default False) to not exec the terminate primitives + skip_terminate_primitives: Bool (default False) to not exec termination primitives :param wait: Make synchronous. Wait until deletion is completed: False to not wait (by default), True to wait a standard time, or int (time to wait) :return: None. Exception if fail @@ -139,138 +139,350 @@ class Ns(object): if wait and resp: resp = json.loads(resp) # For the 'delete' operation, '_id' is used - self._wait(resp.get("_id"), wait, deleteFlag=True) + self._wait(resp.get("_id"), wait, delete_flag=True) else: print("Deletion in progress") elif http_code == 204: print("Deleted") else: msg = resp or "" - # if resp: - # try: - # msg = json.loads(resp) - # except ValueError: - # msg = resp raise ClientException("failed to delete ns {} - {}".format(name, msg)) - def create( - self, - nsd_name, - nsr_name, - account, - config=None, - ssh_keys=None, - description="default description", - admin_status="ENABLED", - wait=False, - timeout=None, - ): + def _get_vim_account_id(self, vim_account: str, vim_account_dict: dict) -> str: + """Get VIM account ID. + Args: + vim_account (str): VIM account id as string + vim_account_dict (dict): A dictionary which includes vim account id + + Returns: + vim_id (str): VIM account id as string + + Raises: + NotFound Exception + """ self._logger.debug("") - self._client.get_token() - nsd = self._client.nsd.get(nsd_name) + if vim_account_dict.get(vim_account): + return vim_account_dict[vim_account] + vim = self._client.vim.get(vim_account) + if vim is None: + raise NotFound("cannot find vim account '{}'".format(vim_account)) + vim_account_dict[vim_account] = vim["_id"] + return vim["_id"] + + def _get_wim_account_id(self, wim_account: str, wim_account_dict: dict) -> str: + """Get WIM account ID. + Args: + wim_account (str): WIM account id as string + wim_account_dict (dict): A dictionary which includes wim account id - vim_account_id = {} - wim_account_id = {} - - def get_vim_account_id(vim_account): - self._logger.debug("") - if vim_account_id.get(vim_account): - return vim_account_id[vim_account] - vim = self._client.vim.get(vim_account) - if vim is None: - raise NotFound("cannot find vim account '{}'".format(vim_account)) - vim_account_id[vim_account] = vim["_id"] - return vim["_id"] - - def get_wim_account_id(wim_account): - self._logger.debug("") - # wim_account can be False (boolean) to indicate not use wim account - if not isinstance(wim_account, str): - return wim_account - if wim_account_id.get(wim_account): - return wim_account_id[wim_account] - wim = self._client.wim.get(wim_account) - if wim is None: - raise NotFound("cannot find wim account '{}'".format(wim_account)) - wim_account_id[wim_account] = wim["_id"] - return wim["_id"] - - vim_id = get_vim_account_id(account) - ns = {} - ns["nsdId"] = nsd["_id"] - ns["nsName"] = nsr_name - ns["nsDescription"] = description - ns["vimAccountId"] = vim_id - # ns['userdata'] = {} - # ns['userdata']['key1']='value1' - # ns['userdata']['key2']='value2' + Returns: + wim_id (str): WIM account id as string + + Raises: + NotFound Exception + """ + self._logger.debug("") + # wim_account can be False (boolean) to indicate not use wim account + if not isinstance(wim_account, str): + return wim_account + if wim_account_dict.get(wim_account): + return wim_account_dict[wim_account] + wim = self._client.wim.get(wim_account) + if wim is None: + raise NotFound("cannot find wim account '{}'".format(wim_account)) + wim_account_dict[wim_account] = wim["_id"] + return wim["_id"] + + def _get_paas_account_id(self, paas_account: str) -> str: + """Get PaaS account ID. + Args: + paas_account (str): PaaS account id as string + + Returns: + paas_id (str): PaaS account id as string + + Raises: + NotFound Exception + """ + self._logger.debug("") + paas = self._client.paas.get(paas_account) + if paas is None: + raise NotFound("cannot find PaaS account '{}'".format(paas_account)) + return paas["_id"] + + def _update_vnf_in_ns_config(self, ns_config: dict, vim_account_dict: dict) -> dict: + """Update vnf field in ns_config. + Args: + ns_config (dict): NS config dictionary which includes additional params + vim_account_dict (dict): A dictionary which includes vim account id + + Returns: + ns (dict): NS dictionary + """ + if "vnf" in ns_config: + for vnf in ns_config["vnf"]: + if vnf.get("vim_account"): + vnf["vimAccountId"] = self._get_vim_account_id( + vnf.pop("vim_account"), vim_account_dict + ) + return ns_config + + def _update_wim_account_in_ns( + self, ns_config: dict, wim_account_dict: dict, ns: dict + ) -> dict: + """Update WIM_account in NS dictionary. + Args: + ns_config (dict): NS config dictionary which includes additional params + wim_account_dict (dict): A dictionary which includes wim account id + ns (dict): NS dictionary which includes ns_id, ns_name, description etc. + + Returns: + ns (dict): NS dictionary + """ + if "wim_account" in ns_config: + wim_account = ns_config.pop("wim_account") + if wim_account is not None: + ns["wimAccountId"] = self._get_wim_account_id( + wim_account, wim_account_dict + ) + return ns + + def _update_vld_in_ns_config( + self, ns_config: dict, vim_account_dict: dict, wim_account_dict: dict + ) -> dict: + """Validating the additionalParamsForNs and additionalParamsForVnf in ns_config. + + Args: + ns_config (dict): NS config dictionary which includes additional params + vim_account_dict (dict): A dictionary which includes vim account id + wim_account_dict (dict): A dictionary which includes wim account id + + Returns: + ns_config (dict): NS config dictionary which includes additional params + + Raises: + ClientException + """ + if "vld" in ns_config: + if not isinstance(ns_config["vld"], list): + raise ClientException( + "Error at --config 'vld' must be a list of dictionaries" + ) + for vld in ns_config["vld"]: + if not isinstance(vld, dict): + raise ClientException( + "Error at --config 'vld' must be a list of dictionaries" + ) + if vld.get("vim-network-name"): + if isinstance(vld["vim-network-name"], dict): + vim_network_name_dict = {} + for vim_account, vim_net in vld["vim-network-name"].items(): + vim_network_name_dict[ + self._get_vim_account_id(vim_account, vim_account_dict) + ] = vim_net + vld["vim-network-name"] = vim_network_name_dict + if "wim_account" in vld and vld["wim_account"] is not None: + vld["wimAccountId"] = self._get_wim_account_id( + vld.pop("wim_account"), wim_account_dict + ) + return ns_config + + def _validate_additional_params_in_ns_config(self, ns_config: dict) -> None: + """Validating the additionalParamsForNs and additionalParamsForVnf in ns_config. + Args: + ns_config (dict): NS config dictionary which includes additional params + + Raises: + ClientException + """ + if "additionalParamsForNs" in ns_config: + if not isinstance(ns_config["additionalParamsForNs"], dict): + raise ClientException( + "Error at --config 'additionalParamsForNs' must be a dictionary" + ) + if "additionalParamsForVnf" in ns_config: + if not isinstance(ns_config["additionalParamsForVnf"], list): + raise ClientException( + "Error at --config 'additionalParamsForVnf' must be a list" + ) + for additional_param_vnf in ns_config["additionalParamsForVnf"]: + if not isinstance(additional_param_vnf, dict): + raise ClientException( + "Error at --config 'additionalParamsForVnf' items must be dictionaries" + ) + if not additional_param_vnf.get("member-vnf-index"): + raise ClientException( + "Error at --config 'additionalParamsForVnf' items must contain " + "'member-vnf-index'" + ) + + def process_ns_create_with_vim_account( + self, + vim_account: str, + nsd: dict, + nsr_name: str, + description: str, + config: dict = None, + ssh_keys: str = None, + timeout: int = None, + ) -> dict: + """Process NS create request which includes VIM Account. + Args: + vim_account (str): VIM Account id as string + nsd (dict): A dictionary which includes network service description + nsr_name (str): Network service record name + description (str): Service description + config (dict): Placeholder for additional configuration + ssh_keys (str): ssh-key file + timeout (int): Max time to wait (seconds) + + Returns: + ns (dict): Payload for ns create request + + Raises: + ClientException + """ + vim_account_dict = {} + wim_account_dict = {} + vim_id = self._get_vim_account_id(vim_account, vim_account_dict) + ns = { + "nsdId": nsd["_id"], + "nsName": nsr_name, + "nsDescription": description, + "vimAccountId": vim_id, + } if ssh_keys is not None: ns["ssh_keys"] = [] for pubkeyfile in ssh_keys.split(","): with open(pubkeyfile, "r") as f: ns["ssh_keys"].append(f.read()) + if timeout: ns["timeout_ns_deploy"] = timeout + if config: ns_config = yaml.safe_load(config) if "vim-network-name" in ns_config: ns_config["vld"] = ns_config.pop("vim-network-name") - if "vld" in ns_config: - if not isinstance(ns_config["vld"], list): - raise ClientException( - "Error at --config 'vld' must be a list of dictionaries" - ) - for vld in ns_config["vld"]: - if not isinstance(vld, dict): - raise ClientException( - "Error at --config 'vld' must be a list of dictionaries" - ) - if vld.get("vim-network-name"): - if isinstance(vld["vim-network-name"], dict): - vim_network_name_dict = {} - for vim_account, vim_net in vld["vim-network-name"].items(): - vim_network_name_dict[ - get_vim_account_id(vim_account) - ] = vim_net - vld["vim-network-name"] = vim_network_name_dict - if "wim_account" in vld and vld["wim_account"] is not None: - vld["wimAccountId"] = get_wim_account_id(vld.pop("wim_account")) - if "vnf" in ns_config: - for vnf in ns_config["vnf"]: - if vnf.get("vim_account"): - vnf["vimAccountId"] = get_vim_account_id(vnf.pop("vim_account")) - - if "additionalParamsForNs" in ns_config: - if not isinstance(ns_config["additionalParamsForNs"], dict): - raise ClientException( - "Error at --config 'additionalParamsForNs' must be a dictionary" - ) - if "additionalParamsForVnf" in ns_config: - if not isinstance(ns_config["additionalParamsForVnf"], list): - raise ClientException( - "Error at --config 'additionalParamsForVnf' must be a list" - ) - for additional_param_vnf in ns_config["additionalParamsForVnf"]: - if not isinstance(additional_param_vnf, dict): - raise ClientException( - "Error at --config 'additionalParamsForVnf' items must be dictionaries" - ) - if not additional_param_vnf.get("member-vnf-index"): - raise ClientException( - "Error at --config 'additionalParamsForVnf' items must contain " - "'member-vnf-index'" - ) - if "wim_account" in ns_config: - wim_account = ns_config.pop("wim_account") - if wim_account is not None: - ns["wimAccountId"] = get_wim_account_id(wim_account) - # rest of parameters without any transformation or checking - # "timeout_ns_deploy" - # "placement-engine" + + ns_config = self._update_vld_in_ns_config( + ns_config, vim_account_dict, wim_account_dict + ) + ns_config = self._update_vnf_in_ns_config(ns_config, vim_account_dict) + self._validate_additional_params_in_ns_config(ns_config) + ns = self._update_wim_account_in_ns(ns_config, vim_account_dict, ns) + ns.update(ns_config) + + return ns + + def process_ns_create_with_paas_account( + self, + paas_account: str, + nsd: dict, + nsr_name: str, + description: str, + config: dict = None, + timeout: int = None, + ) -> dict: + """Process NS create request which includes PaaS Account. + Args: + paas_account (str): PaaS Account id as string + nsd (dict): A dictionary which includes network service description + nsr_name (str): Network service record name + description (str): Service description + config (dict): Placeholder for additional configuration + timeout (int): Max time to wait (seconds) + + Returns: + ns (dict): Payload for ns create request + + Raises: + ClientException + """ + paas_id = self._get_paas_account_id(paas_account) + ns = { + "nsdId": nsd["_id"], + "nsName": nsr_name, + "nsDescription": description, + "paasAccountId": paas_id, + } + + if timeout: + ns["timeout_ns_deploy"] = timeout + + if config: + ns_config = yaml.safe_load(config) + self._validate_additional_params_in_ns_config(ns_config) ns.update(ns_config) - # print(yaml.safe_dump(ns)) + return ns + + def create( + self, + nsd_name: dict, + nsr_name: str, + vim_account: str = None, + paas_account: str = None, + config: dict = None, + ssh_keys: str = None, + description: str = "default description", + admin_status: str = "ENABLED", + wait: bool = False, + timeout: int = None, + ) -> str: + """NS create request which includes PaaS Account or VIM account. + Args: + nsd_name (dict): A dictionary which includes network service description + nsr_name (str): Network service record name + vim_account (str): VIM account ID as string + paas_account (str): PaaS Account id as string + config (dict): Placeholder for additional configuration + ssh_keys (str): ssh-key file + description (str): Service description + admin_status (str): Administration Status + wait (Boolean): True or False + timeout (int): Max time to wait (seconds) + + Returns: + response id (str): Response ID + + Raises: + ClientException + """ + self._logger.debug("") + + if not (vim_account or paas_account): + raise ClientException( + "Both of vim_account and paas_account options are empty." + ) + + if vim_account and paas_account: + raise ClientException( + "Both of vim_account and paas_account options are set." + ) + + self._client.get_token() + nsd = self._client.nsd.get(nsd_name) + + if vim_account: + # VIM account is provided as input parameter. + ns = self.process_ns_create_with_vim_account( + vim_account, + nsd, + nsr_name, + description, + config=config, + ssh_keys=ssh_keys, + timeout=timeout, + ) + + elif paas_account: + # PaaS account is provided as input parameter. + ns = self.process_ns_create_with_paas_account( + paas_account, nsd, nsr_name, description, config=config, timeout=timeout + ) + try: self._apiResource = "/ns_instances_content" self._apiBase = "{}{}{}".format( @@ -285,11 +497,11 @@ class Ns(object): http_code, resp = self._http.post_cmd( endpoint=self._apiBase, postfields_dict=ns ) - # print('HTTP CODE: {}'.format(http_code)) - # print('RESP: {}'.format(resp)) - # if http_code in (200, 201, 202, 204): + if resp: resp = json.loads(resp) + print(str(resp["id"])) + if not resp or "id" not in resp: raise ClientException( "unexpected response from server - {} ".format(resp) @@ -297,16 +509,9 @@ class Ns(object): if wait: # Wait for status for NS instance creation self._wait(resp.get("nslcmop_id"), wait) - print(resp["id"]) + return resp["id"] - # else: - # msg = "" - # if resp: - # try: - # msg = json.loads(resp) - # except ValueError: - # msg = resp - # raise ClientException(msg) + except ClientException as exc: message = "failed to create ns: {} nsd: {}\nerror:\n{}".format( nsr_name, nsd_name, str(exc)