From e7c24981a7021176e68ee87998c86d21e87f548e Mon Sep 17 00:00:00 2001 From: garciadeblas Date: Mon, 1 Nov 2021 22:04:32 +0100 Subject: [PATCH] Update vim-create and vim-update to accept config and credential files 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 --- osmclient/scripts/osm.py | 75 +++++++++++++++++++++++++++++----------- osmclient/sol005/vim.py | 26 ++++++-------- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index dd89b9d..30aa33f 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -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: diff --git a/osmclient/sol005/vim.py b/osmclient/sol005/vim.py index 8b11c8d..89c2db4 100644 --- a/osmclient/sol005/vim.py +++ b/osmclient/sol005/vim.py @@ -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): -- 2.25.1