Adding PaaS Service Creation 14/12614/4
authorGulsum Atici <gulsum.atici@canonical.com>
Tue, 27 Sep 2022 20:29:39 +0000 (23:29 +0300)
committeraticig <gulsum.atici@canonical.com>
Thu, 27 Oct 2022 06:56:25 +0000 (08:56 +0200)
Change-Id: I9aa6d236984180d6656a94fa69dd35a605f31993
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
osmclient/scripts/osm.py
osmclient/sol005/ns.py

index de121b1..fac267d 100755 (executable)
@@ -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):
index 00d68d6..fe3a2ba 100644 (file)
@@ -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)