X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osmclient%2Fscripts%2Fosm.py;h=feb8c2f9e03f47ce5ea8bf43dd5a781a24bc7a57;hb=refs%2Ftags%2Frelease-v10.0-start;hp=603d373acc293cce71ec2c6df664e98aa90dd648;hpb=95686bbc69ded243c346f94dceb0bee567572fb7;p=osm%2Fosmclient.git diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index 603d373..feb8c2f 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -31,6 +31,7 @@ import textwrap import pkg_resources import logging from datetime import datetime +from typing import Any, Dict def wrap_text(text, width): @@ -384,7 +385,7 @@ def ns_list(ctx, filter, long): project_list = ctx.obj.project.list() try: vim_list = ctx.obj.vim.list() - except: + except Exception: vim_list = [] else: table = PrettyTable( @@ -3070,6 +3071,7 @@ def pdu_delete(ctx, name, force): help="do not return the control immediately, but keep it " "until the operation is completed, or timeout", ) +@click.option("--vca", default=None, help="VCA to be used in this VIM account") @click.pass_context def vim_create( ctx, @@ -3084,6 +3086,7 @@ def vim_create( sdn_controller, sdn_port_mapping, wait, + vca, ): """creates a new VIM account""" logger.debug("") @@ -3100,6 +3103,8 @@ def vim_create( 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: @@ -3756,7 +3761,8 @@ def sdnc_show(ctx, name): @click.option( "--k8s-nets", prompt=True, - help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"', + help='''list of VIM networks, in JSON inline format, where the cluster is + accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''', ) @click.option("--description", default=None, help="human readable description") @click.option( @@ -3812,7 +3818,8 @@ def k8scluster_add( @click.option("--vim", help="VIM target, the VIM where the cluster resides") @click.option( "--k8s-nets", - help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"', + help='''list of VIM networks, in JSON inline format, where the cluster is accessible + via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''', ) @click.option("--description", help="human readable description") @click.option( @@ -3920,7 +3927,7 @@ def k8scluster_list(ctx, filter, literal, long): ) try: vim_list = ctx.obj.vim.list() - except: + except Exception: vim_list = [] for cluster in resp: logger.debug("Cluster details: {}".format(yaml.safe_dump(cluster))) @@ -3993,6 +4000,273 @@ def k8scluster_show(ctx, name, literal): # exit(1) +########################### +# VCA operations +########################### + + +@cli_osm.command(name="vca-add", short_help="adds a VCA (Juju controller) to OSM") +@click.argument("name") +@click.option( + "--endpoints", + prompt=True, + help="Comma-separated list of IP or hostnames of the Juju controller", +) +@click.option("--user", prompt=True, help="Username with admin priviledges") +@click.option("--secret", prompt=True, help="Password of the specified username") +@click.option("--cacert", prompt=True, help="CA certificate") +@click.option( + "--lxd-cloud", + prompt=True, + help="Name of the cloud that will be used for LXD containers (LXD proxy charms)", +) +@click.option( + "--lxd-credentials", + prompt=True, + help="Name of the cloud credentialsto be used for the LXD cloud", +) +@click.option( + "--k8s-cloud", + prompt=True, + help="Name of the cloud that will be used for K8s containers (K8s proxy charms)", +) +@click.option( + "--k8s-credentials", + prompt=True, + help="Name of the cloud credentialsto be used for the K8s cloud", +) +@click.option( + "--model-config", + default={}, + help="Configuration options for the models", +) +@click.option("--description", default=None, help="human readable description") +@click.pass_context +def vca_add( + ctx, + name, + endpoints, + user, + secret, + cacert, + lxd_cloud, + lxd_credentials, + k8s_cloud, + k8s_credentials, + model_config, + description, +): + """adds a VCA to OSM + + NAME: name of the VCA + """ + check_client_version(ctx.obj, ctx.command.name) + vca = {} + vca["name"] = name + vca["endpoints"] = endpoints.split(",") + vca["user"] = user + vca["secret"] = secret + vca["cacert"] = cacert + vca["lxd-cloud"] = lxd_cloud + vca["lxd-credentials"] = lxd_credentials + vca["k8s-cloud"] = k8s_cloud + vca["k8s-credentials"] = k8s_credentials + if description: + vca["description"] = description + if model_config: + model_config = load(model_config) + vca["model-config"] = model_config + ctx.obj.vca.create(name, vca) + + +def load(data: Any): + if os.path.isfile(data): + return load_file(data) + else: + try: + return json.loads(data) + except ValueError as e: + raise ClientException(e) + + +def load_file(file_path: str) -> Dict: + content = None + with open(file_path, "r") as f: + content = f.read() + try: + return yaml.safe_load(content) + except yaml.scanner.ScannerError: + pass + try: + return json.loads(content) + except ValueError: + pass + raise ClientException(f"{file_path} must be a valid yaml or json file") + + +@cli_osm.command(name="vca-update", short_help="updates a K8s cluster") +@click.argument("name") +@click.option( + "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller" +) +@click.option("--user", help="Username with admin priviledges") +@click.option("--secret", help="Password of the specified username") +@click.option("--cacert", help="CA certificate") +@click.option( + "--lxd-cloud", + help="Name of the cloud that will be used for LXD containers (LXD proxy charms)", +) +@click.option( + "--lxd-credentials", + help="Name of the cloud credentialsto be used for the LXD cloud", +) +@click.option( + "--k8s-cloud", + help="Name of the cloud that will be used for K8s containers (K8s proxy charms)", +) +@click.option( + "--k8s-credentials", + help="Name of the cloud credentialsto be used for the K8s cloud", +) +@click.option( + "--model-config", + help="Configuration options for the models", +) +@click.option("--description", default=None, help="human readable description") +@click.pass_context +def vca_update( + ctx, + name, + endpoints, + user, + secret, + cacert, + lxd_cloud, + lxd_credentials, + k8s_cloud, + k8s_credentials, + model_config, + description, +): + """updates a K8s cluster + + NAME: name or ID of the K8s cluster + """ + check_client_version(ctx.obj, ctx.command.name) + vca = {} + vca["name"] = name + if endpoints: + vca["endpoints"] = endpoints.split(",") + if user: + vca["user"] = user + if secret: + vca["secret"] = secret + if cacert: + vca["cacert"] = cacert + if lxd_cloud: + vca["lxd-cloud"] = lxd_cloud + if lxd_credentials: + vca["lxd-credentials"] = lxd_credentials + if k8s_cloud: + vca["k8s-cloud"] = k8s_cloud + if k8s_credentials: + vca["k8s-credentials"] = k8s_credentials + if description: + vca["description"] = description + if model_config: + model_config = load(model_config) + vca["model-config"] = model_config + ctx.obj.vca.update(name, vca) + + +@cli_osm.command(name="vca-delete", short_help="deletes a K8s cluster") +@click.argument("name") +@click.option( + "--force", is_flag=True, help="forces the deletion from the DB (not recommended)" +) +@click.pass_context +def vca_delete(ctx, name, force): + """deletes a K8s cluster + + NAME: name or ID of the K8s cluster to be deleted + """ + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.vca.delete(name, force=force) + + +@cli_osm.command(name="vca-list") +@click.option( + "--filter", + default=None, + multiple=True, + help="restricts the list to the VCAs matching the filter", +) +@click.option("--literal", is_flag=True, help="print literally, no pretty table") +@click.option("--long", is_flag=True, help="get more details") +@click.pass_context +def vca_list(ctx, filter, literal, long): + """list VCAs""" + check_client_version(ctx.obj, ctx.command.name) + if filter: + filter = "&".join(filter) + resp = ctx.obj.vca.list(filter) + if literal: + print(yaml.safe_dump(resp, indent=4, default_flow_style=False)) + return + if long: + table = PrettyTable( + ["Name", "Id", "Project", "Operational State", "Detailed Status"] + ) + project_list = ctx.obj.project.list() + else: + table = PrettyTable(["Name", "Id", "Operational State"]) + for vca in resp: + logger.debug("VCA details: {}".format(yaml.safe_dump(vca))) + if long: + project_id, project_name = get_project(project_list, vca) + detailed_status = vca.get("_admin", {}).get("detailed-status", "-") + table.add_row( + [ + vca["name"], + vca["_id"], + project_name, + vca.get("_admin", {}).get("operationalState", "-"), + wrap_text(text=detailed_status, width=40), + ] + ) + else: + table.add_row( + [ + vca["name"], + vca["_id"], + vca.get("_admin", {}).get("operationalState", "-"), + ] + ) + table.align = "l" + print(table) + + +@cli_osm.command(name="vca-show", short_help="shows the details of a K8s cluster") +@click.argument("name") +@click.option("--literal", is_flag=True, help="print literally, no pretty table") +@click.pass_context +def vca_show(ctx, name, literal): + """shows the details of a K8s cluster + + NAME: name or ID of the K8s cluster + """ + # try: + resp = ctx.obj.vca.get(name) + 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()): + table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)]) + table.align = "l" + print(table) + + ########################### # Repo operations ########################### @@ -4692,6 +4966,128 @@ def ns_metric_export(ctx, ns, vnf, vdu, metric, interval): # exit(1) +################# +# Subscription operations +################# + + +@cli_osm.command( + name="subscription-create", + short_help="creates a new subscription to a specific event", +) +@click.option( + "--event_type", + # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False)) + type=click.Choice(["ns"], case_sensitive=False), + help="event type to be subscribed (for the moment, only ns is supported)", +) +@click.option("--event", default=None, help="specific yaml configuration for the event") +@click.option( + "--event_file", default=None, help="specific yaml configuration file for the event" +) +@click.pass_context +def subscription_create(ctx, event_type, event, event_file): + """creates a new subscription to a specific event""" + logger.debug("") + check_client_version(ctx.obj, ctx.command.name) + if event_file: + if event: + raise ClientException( + '"--event" option is incompatible with "--event_file" option' + ) + with open(event_file, "r") as cf: + event = cf.read() + ctx.obj.subscription.create(event_type, event) + + +@cli_osm.command(name="subscription-delete", short_help="deletes a subscription") +@click.option( + "--event_type", + # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False)) + type=click.Choice(["ns"], case_sensitive=False), + help="event type to be subscribed (for the moment, only ns is supported)", +) +@click.argument("subscription_id") +@click.option( + "--force", is_flag=True, help="forces the deletion bypassing pre-conditions" +) +@click.pass_context +def subscription_delete(ctx, event_type, subscription_id, force): + """deletes a subscription + + SUBSCRIPTION_ID: ID of the subscription to be deleted + """ + logger.debug("") + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.subscription.delete(event_type, subscription_id, force) + + +@cli_osm.command(name="subscription-list", short_help="list all subscriptions") +@click.option( + "--event_type", + # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False)) + type=click.Choice(["ns"], case_sensitive=False), + help="event type to be subscribed (for the moment, only ns is supported)", +) +@click.option( + "--filter", + default=None, + multiple=True, + help="restricts the list to the subscriptions matching the filter", +) +@click.pass_context +def subscription_list(ctx, event_type, filter): + """list all subscriptions""" + logger.debug("") + check_client_version(ctx.obj, ctx.command.name) + if filter: + filter = "&".join(filter) + resp = ctx.obj.subscription.list(event_type, filter) + table = PrettyTable(["id", "filter", "CallbackUri"]) + for sub in resp: + table.add_row( + [ + sub["_id"], + wrap_text(text=json.dumps(sub["filter"], indent=2), width=70), + sub["CallbackUri"], + ] + ) + table.align = "l" + print(table) + + +@cli_osm.command( + name="subscription-show", short_help="shows the details of a subscription" +) +@click.argument("subscription_id") +@click.option( + "--event_type", + # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False)) + type=click.Choice(["ns"], case_sensitive=False), + help="event type to be subscribed (for the moment, only ns is supported)", +) +@click.option( + "--filter", + multiple=True, + help="restricts the information to the fields in the filter", +) +@click.pass_context +def subscription_show(ctx, event_type, subscription_id, filter): + """shows the details of a subscription + + SUBSCRIPTION_ID: ID of the subscription + """ + logger.debug("") + # try: + resp = ctx.obj.subscription.get(subscription_id) + table = PrettyTable(["key", "attribute"]) + for k, v in list(resp.items()): + if not filter or k in filter: + table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)]) + table.align = "l" + print(table) + + #################### # Other operations #################### @@ -5014,6 +5410,107 @@ def vnf_scale( # exit(1) +@cli_osm.command(name="alarm-show", short_help="show alarm details") +@click.argument("uuid") +@click.pass_context +def alarm_show(ctx, uuid): + """Show alarm's detail information""" + + check_client_version(ctx.obj, ctx.command.name) + resp = ctx.obj.ns.get_alarm(uuid=uuid) + alarm_filter = [ + "uuid", + "name", + "metric", + "statistic", + "threshold", + "operation", + "ns-id", + "vnf-id", + "vdu_name", + "action", + "status", + ] + table = PrettyTable(["key", "attribute"]) + try: + # Arrange and return the response data + resp = resp.replace("ObjectId", "") + alarm = eval(resp) + for key in alarm_filter: + if key == "uuid": + value = alarm.get(key) + key = "alarm-id" + elif key == "name": + value = alarm.get(key) + key = "alarm-name" + elif key == "ns-id": + value = alarm["tags"].get("ns_id") + elif key == "vdu_name": + value = alarm["tags"].get("vdu_name") + elif key == "status": + value = alarm["alarm_status"] + else: + value = alarm[key] + table.add_row([key, wrap_text(text=json.dumps(value, indent=2), width=100)]) + table.align = "l" + print(table) + except Exception: + print(resp) + + +# List alarm +@cli_osm.command(name="alarm-list", short_help="list all alarms") +@click.option( + "--ns_id", default=None, required=False, help="List out alarm for given ns id" +) +@click.pass_context +def alarm_list(ctx, ns_id): + """list all alarm""" + + check_client_version(ctx.obj, ctx.command.name) + project_name = os.getenv("OSM_PROJECT", "admin") + resp = ctx.obj.ns.get_alarm(project_name=project_name, ns_id=ns_id) + + table = PrettyTable( + ["alarm-id", "metric", "threshold", "operation", "action", "status"] + ) + if resp: + # return the response data in a table + resp = resp.replace("ObjectId", "") + resp = eval(resp) + for alarm in resp: + table.add_row( + [ + wrap_text(text=str(alarm["uuid"]), width=38), + alarm["metric"], + alarm["threshold"], + alarm["operation"], + wrap_text(text=alarm["action"], width=25), + alarm["alarm_status"], + ] + ) + table.align = "l" + print(table) + + +# Update alarm +@cli_osm.command(name="alarm-update", short_help="Update a alarm") +@click.argument("uuid") +@click.option("--threshold", default=None, help="Alarm threshold") +@click.option("--is_enable", default=None, type=bool, help="enable or disable alarm") +@click.pass_context +def alarm_update(ctx, uuid, threshold, is_enable): + """ + Update alarm + + """ + if not threshold and is_enable is None: + raise ClientException( + "Please provide option to update i.e threshold or is_enable" + ) + ctx.obj.ns.update_alarm(uuid, threshold, is_enable) + + ############################## # Role Management Operations # ##############################