Update vim-create and vim-update to accept config and credential files 99/11299/4 release-v11.0-start v11.0.0rc1
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 1 Nov 2021 21:04:32 +0000 (22:04 +0100)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Fri, 5 Nov 2021 13:18:05 +0000 (13:18 +0000)
vim-create will accept both a config dict and a config file, with respective
options "--config" and "--config_file". If a key is present in both, the
value in the config dict will prevail.

In addition, vim-create command will accept a new option --creds, required
for Google Cloud Platform (GCP) due to the way the authentication works in
GCP. That option is codified directly in the config dict that is sent to the
NBI, under config["credentials"]. The RO connector for GCP will receive it
and will expect those credentials in that dictionary. In the future, other
RO connectors might use a similar approach.

Finally, this change also adds the option --literal to vim-show command.

Change-Id: Ifb4c284593b171353b6c180bdc7af75e8a25dfac
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
osmclient/scripts/osm.py
osmclient/sol005/vim.py

index dd89b9d..30aa33f 100755 (executable)
@@ -94,6 +94,26 @@ def get_vim_name(vim_list, vim_id):
     return vim_name
 
 
+def create_config(config_file, json_string):
+    '''
+    Combines a YAML or JSON file with a JSON string into a Python3 structure
+    It loads the YAML or JSON file 'cfile' into a first dictionary.
+    It loads the JSON string into a second dictionary.
+    Then it updates the first dictionary with the info in the second dictionary.
+    If the field is present in both cfile and cdict, the field in cdict prevails.
+    If both cfile and cdict are None, it returns an empty dict (i.e. {})
+    '''
+    config = {}
+    if config_file:
+        with open(config_file, "r") as cf:
+            config = yaml.safe_load(cf.read())
+    if json_string:
+        cdict = yaml.safe_load(json_string)
+        for k, v in cdict.items():
+            config[k] = v
+    return config
+
+
 @click.group(
     context_settings=dict(help_option_names=["-h", "--help"], max_content_width=160)
 )
@@ -3095,18 +3115,13 @@ def pdu_delete(ctx, name, force):
 
 
 @cli_osm.command(name="vim-create", short_help="creates a new VIM account")
-@click.option("--name", prompt=True, help="Name to create datacenter")
-@click.option("--user", prompt=True, help="VIM username")
-@click.option(
-    "--password",
-    prompt=True,
-    hide_input=True,
-    confirmation_prompt=True,
-    help="VIM password",
-)
-@click.option("--auth_url", prompt=True, help="VIM url")
-@click.option("--tenant", prompt=True, help="VIM tenant name")
+@click.option("--name", required=True, help="Name to create datacenter")
+@click.option("--user", default=None, help="VIM username")
+@click.option("--password", default=None, help="VIM password")
+@click.option("--auth_url", default=None, help="VIM url")
+@click.option("--tenant", "--project", "tenant", default=None, help="VIM tenant/project name")
 @click.option("--config", default=None, help="VIM specific config parameters")
+@click.option("--config_file", default=None, help="VIM specific config parameters in YAML or JSON file")
 @click.option("--account_type", default="openstack", help="VIM type")
 @click.option("--description", default=None, help="human readable description")
 @click.option(
@@ -3128,6 +3143,7 @@ def pdu_delete(ctx, name, force):
     "until the operation is completed, or timeout",
 )
 @click.option("--vca", default=None, help="VCA to be used in this VIM account")
+@click.option("--creds", default=None, help="credentials file (only applycable for GCP VIM type)")
 @click.pass_context
 def vim_create(
     ctx,
@@ -3137,12 +3153,14 @@ def vim_create(
     auth_url,
     tenant,
     config,
+    config_file,
     account_type,
     description,
     sdn_controller,
     sdn_port_mapping,
     wait,
     vca,
+    creds,
 ):
     """creates a new VIM account"""
     logger.debug("")
@@ -3158,13 +3176,13 @@ def vim_create(
     vim["vim-tenant-name"] = tenant
     vim["vim-type"] = account_type
     vim["description"] = description
-    vim["config"] = config
     if vca:
         vim["vca"] = vca
-    if sdn_controller or sdn_port_mapping:
-        ctx.obj.vim.create(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
-    else:
-        ctx.obj.vim.create(name, vim, wait=wait)
+    vim_config = create_config(config_file, config)
+    if creds:
+        with open(creds, "r") as cf:
+            vim_config["credentials"] = yaml.safe_load(cf.read())
+    ctx.obj.vim.create(name, vim, vim_config, sdn_controller, sdn_port_mapping, wait=wait)
     # except ClientException as e:
     #     print(str(e))
     #     exit(1)
@@ -3178,6 +3196,7 @@ def vim_create(
 @click.option("--auth_url", help="VIM url")
 @click.option("--tenant", help="VIM tenant name")
 @click.option("--config", help="VIM specific config parameters")
+@click.option("--config_file", default=None, help="VIM specific config parameters in YAML or JSON file")
 @click.option("--account_type", help="VIM type")
 @click.option("--description", help="human readable description")
 @click.option(
@@ -3199,6 +3218,7 @@ def vim_create(
     help="do not return the control immediately, but keep it "
     "until the operation is completed, or timeout",
 )
+@click.option("--creds", default=None, help="credentials file (only applycable for GCP VIM type)")
 @click.pass_context
 def vim_update(
     ctx,
@@ -3209,11 +3229,13 @@ def vim_update(
     auth_url,
     tenant,
     config,
+    config_file,
     account_type,
     description,
     sdn_controller,
     sdn_port_mapping,
     wait,
+    creds,
 ):
     """updates a VIM account
 
@@ -3237,9 +3259,14 @@ def vim_update(
         vim["vim_type"] = account_type
     if description:
         vim["description"] = description
-    if config:
-        vim["config"] = config
-    ctx.obj.vim.update(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
+    vim_config = None
+    if config or config_file:
+        vim_config = create_config(config_file, config)
+    if creds:
+        with open(creds, "r") as cf:
+            vim_config["credentials"] = yaml.safe_load(cf.read())
+    logger.info(f"VIM: {vim}, VIM config: {vim_config}")
+    ctx.obj.vim.update(name, vim, vim_config, sdn_controller, sdn_port_mapping, wait=wait)
     # except ClientException as e:
     #     print(str(e))
     #     exit(1)
@@ -3316,6 +3343,8 @@ def vim_list(ctx, filter, long):
         if long:
             if "vim_password" in vim:
                 vim["vim_password"] = "********"
+            if "config" in vim and "credentials" in vim["config"]:
+                vim["config"]["credentials"] = "********"
             logger.debug("VIM details: {}".format(yaml.safe_dump(vim)))
             vim_state = vim["_admin"].get("operationalState", "-")
             error_details = "N/A"
@@ -3348,8 +3377,9 @@ def vim_list(ctx, filter, long):
     multiple=True,
     help="restricts the information to the fields in the filter",
 )
+@click.option("--literal", is_flag=True, help="print literally, no pretty table")
 @click.pass_context
-def vim_show(ctx, name, filter):
+def vim_show(ctx, name, filter, literal):
     """shows the details of a VIM account
 
     NAME: name or ID of the VIM account
@@ -3359,10 +3389,15 @@ def vim_show(ctx, name, filter):
     resp = ctx.obj.vim.get(name)
     if "vim_password" in resp:
         resp["vim_password"] = "********"
+    if "config" in resp and "credentials" in resp["config"]:
+        resp["config"]["credentials"] = "********"
     # except ClientException as e:
     #     print(str(e))
     #     exit(1)
 
+    if literal:
+        print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
+        return
     table = PrettyTable(["key", "attribute"])
     for k, v in list(resp.items()):
         if not filter or k in filter:
index 8b11c8d..89c2db4 100644 (file)
@@ -70,7 +70,7 @@ class Vim(object):
         return ""
 
     def create(
-        self, name, vim_access, sdn_controller=None, sdn_port_mapping=None, wait=False
+        self, name, vim_access, config={}, sdn_controller=None, sdn_port_mapping=None, wait=False
     ):
         vca_id = None
 
@@ -92,9 +92,7 @@ class Vim(object):
         vim_account = self.update_vim_account_dict(vim_account, vim_access)
         if vca_id:
             vim_account["vca"] = vca_id
-        vim_config = {}
-        if "config" in vim_access and vim_access["config"] is not None:
-            vim_config = yaml.safe_load(vim_access["config"])
+        vim_config = config
         if sdn_controller:
             sdnc = self._client.sdnc.get(sdn_controller)
             vim_config["sdn-controller"] = sdnc["_id"]
@@ -129,22 +127,20 @@ class Vim(object):
         #    raise ClientException("failed to create vim {} - {}".format(name, msg))
 
     def update(
-        self, vim_name, vim_account, sdn_controller, sdn_port_mapping, wait=False
+        self, vim_name, vim_account, config, sdn_controller, sdn_port_mapping, wait=False
     ):
         self._logger.debug("")
         self._client.get_token()
         vim = self.get(vim_name)
         vim_id_for_wait = self._get_id_for_wait(vim_name)
         vim_config = {}
-        if "config" in vim_account:
-            if vim_account.get("config") == "" and (sdn_controller or sdn_port_mapping):
+        if config is not None:
+            if not config and (sdn_controller or sdn_port_mapping):
+                # If config is empty (clearing config)
                 raise ClientException(
                     "clearing config is incompatible with updating SDN info"
                 )
-            if vim_account.get("config") == "":
-                vim_config = None
-            else:
-                vim_config = yaml.safe_load(vim_account["config"])
+            vim_config = config
         if sdn_controller == "":
             vim_config["sdn-controller"] = None
             vim_config["sdn-port-mapping"] = None
@@ -185,10 +181,10 @@ class Vim(object):
         self._logger.debug("")
         vim_account["vim_type"] = vim_access["vim-type"]
         vim_account["description"] = vim_access["description"]
-        vim_account["vim_url"] = vim_access["vim-url"]
-        vim_account["vim_user"] = vim_access["vim-username"]
-        vim_account["vim_password"] = vim_access["vim-password"]
-        vim_account["vim_tenant_name"] = vim_access["vim-tenant-name"]
+        vim_account["vim_url"] = vim_access["vim-url"] or "null"
+        vim_account["vim_user"] = vim_access["vim-username"] or "null"
+        vim_account["vim_password"] = vim_access["vim-password"] or "null"
+        vim_account["vim_tenant_name"] = vim_access["vim-tenant-name"] or "null"
         return vim_account
 
     def get_id(self, name):