X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osmclient%2Fscripts%2Fosm.py;h=2d9a231fdc384098546cd811ab7b2a839dd13cf1;hb=refs%2Fchanges%2F91%2F12191%2F2;hp=3ce02df0d5ad89f0df166546d64db046c7090f7f;hpb=0a3cee20d28824aeca5ef5afce2b83bdb31222d6;p=osm%2Fosmclient.git diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index 3ce02df..2d9a231 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -21,6 +21,7 @@ OSM shell/cli import click from osmclient import client from osmclient.common.exceptions import ClientException, NotFound +from osmclient.common.utils import validate_uuid4 from prettytable import PrettyTable import yaml import json @@ -3878,6 +3879,24 @@ def sdnc_show(ctx, name): 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( + "--init-helm2/--skip-helm2", + required=False, + default=True, + help="Initialize helm v2", +) +@click.option( + "--init-helm3/--skip-helm3", + required=False, + default=True, + help="Initialize helm v3", +) +@click.option( + "--init-jujubundle/--skip-jujubundle", + required=False, + default=True, + help="Initialize juju-bundle", +) @click.option("--description", default=None, help="human readable description") @click.option( "--namespace", @@ -3905,7 +3924,7 @@ def sdnc_show(ctx, name): # help='do not return the control immediately, but keep it until the operation is completed, or timeout') @click.pass_context def k8scluster_add( - ctx, name, creds, version, vim, k8s_nets, description, namespace, wait, cni + ctx, name, creds, version, vim, k8s_nets, init_helm2, init_helm3, init_jujubundle, description, namespace, wait, cni ): """adds a K8s cluster to OSM @@ -3920,6 +3939,10 @@ def k8scluster_add( cluster["k8s_version"] = version cluster["vim_account"] = vim cluster["nets"] = yaml.safe_load(k8s_nets) + if not (init_helm2 and init_jujubundle and init_helm3): + cluster["deployment_methods"] = {"helm-chart": init_helm2, + "juju-bundle": init_jujubundle, + "helm-chart-v3": init_helm3} if description: cluster["description"] = description if namespace: @@ -4049,6 +4072,7 @@ def k8scluster_list(ctx, filter, literal, long): "Version", "VIM", "K8s-nets", + "Deployment methods", "Operational State", "Op. state (details)", "Description", @@ -4086,6 +4110,7 @@ def k8scluster_list(ctx, filter, literal, long): cluster["k8s_version"], vim_info, json.dumps(cluster["nets"]), + json.dumps(cluster["deployment_methods"]), cluster["_admin"]["operationalState"], op_state_details, trunc_text(cluster.get("description") or "", 40), @@ -5611,6 +5636,277 @@ def update(ctx, ns_name, updatetype, config, timeout, wait): ctx.obj.ns.update(ns_name, op_data, wait=wait) +def iterator_split(iterator, separators): + """ + Splits a tuple or list into several lists whenever a separator is found + For instance, the following tuple will be separated with the separator "--vnf" as follows. + From: + ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1", "--vnf", "B", "--cause", "cause_B", ... + "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", "--vdu", "vdu_B1", "--count_index", "2") + To: + [ + ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1"), + ("--vnf", "B", "--cause", "cause_B", "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", ... + "--vdu", "vdu_B1", "--count_index", "2") + ] + + Returns as many lists as separators are found + """ + logger.debug("") + if iterator[0] not in separators: + raise ClientException(f"Expected one of {separators}. Received: {iterator[0]}.") + list_of_lists = [] + first = 0 + for i in range(len(iterator)): + if iterator[i] in separators: + if i == first: + continue + if (i - first < 2): + raise ClientException(f"Expected at least one argument after separator (possible separators: {separators}).") + list_of_lists.append(list(iterator[first:i])) + first = i + if ((len(iterator) - first) < 2): + raise ClientException(f"Expected at least one argument after separator (possible separators: {separators}).") + else: + list_of_lists.append(list(iterator[first:len(iterator)])) + # logger.debug(f"List of lists: {list_of_lists}") + return list_of_lists + + +def process_common_heal_params(heal_vnf_dict, args): + logger.debug("") + current_item = "vnf" + i = 0 + while i < len(args): + if args[i] == "--cause": + if (i+1 >= len(args)) or args[i+1].startswith("--"): + raise ClientException("No cause was provided after --cause") + heal_vnf_dict["cause"] = args[i+1] + i = i + 2 + continue + if args[i] == "--run-day1": + if current_item == "vnf": + if "additionalParams" not in heal_vnf_dict: + heal_vnf_dict["additionalParams"] = {} + heal_vnf_dict["additionalParams"]["run-day1"] = True + else: + # if current_item == "vdu" + heal_vnf_dict["additionalParams"]["vdu"][-1]["run-day1"] = True + i = i + 1 + continue + if args[i] == "--vdu": + if "additionalParams" not in heal_vnf_dict: + heal_vnf_dict["additionalParams"] = {} + heal_vnf_dict["additionalParams"]["vdu"] = [] + if (i+1 >= len(args)) or args[i+1].startswith("--"): + raise ClientException("No VDU ID was provided after --vdu") + heal_vnf_dict["additionalParams"]["vdu"].append({"vdu-id": args[i+1]}) + current_item = "vdu" + i = i + 2 + continue + if args[i] == "--count-index": + if current_item == "vnf": + raise ClientException("Option --count-index only applies to VDU, not to VNF") + if (i+1 >= len(args)) or args[i+1].startswith("--"): + raise ClientException("No count index was provided after --count-index") + heal_vnf_dict["additionalParams"]["vdu"][-1]["count-index"] = int(args[i+1]) + i = i + 2 + continue + i = i + 1 + return + + +def process_ns_heal_params(ctx, param, value): + """ + Processes the params in the command ns-heal + Click does not allow advanced patterns for positional options like this: + --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf" + --vdu several_volumes-VM + --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf" + --vdu mgmtVM --count-index 1 --run-day1 + --vdu mgmtVM --count-index 2 + + It returns the dictionary with all the params stored in ctx.params["heal_params"] + """ + logger.debug("") + # logger.debug(f"Args: {value}") + if param.name != "args": + raise ClientException(f"Unexpected param: {param.name}") + # Split the tuple "value" by "--vnf" + vnfs = iterator_split(value, ["--vnf"]) + logger.debug(f"VNFs: {vnfs}") + heal_dict = {} + heal_dict["healVnfData"] = [] + for vnf in vnfs: + # logger.debug(f"VNF: {vnf}") + heal_vnf = {} + if vnf[1].startswith("--"): + raise ClientException("Expected a VNF_ID after --vnf") + heal_vnf["vnfInstanceId"] = vnf[1] + process_common_heal_params(heal_vnf, vnf[2:]) + heal_dict["healVnfData"].append(heal_vnf) + ctx.params["heal_params"] = heal_dict + return + + +@cli_osm.command( + name="ns-heal", + short_help="heals (recreates) VNFs or VDUs of a NS instance", + context_settings=dict(ignore_unknown_options=True,) +) +@click.argument("ns_name") +@click.argument( + 'args', + nargs=-1, + type=click.UNPROCESSED, + callback=process_ns_heal_params, +) +@click.option( + "--timeout", + type=int, + default=None, + help="timeout in seconds" +) +@click.option( + "--wait", + default=False, + is_flag=True, + help="do not return the control immediately, but keep it until the operation is completed, or timeout", +) +@click.pass_context +def ns_heal( + ctx, + ns_name, + args, + heal_params, + timeout, + wait +): + """heals (recreates) VNFs or VDUs of a NS instance + + NS_NAME: name or ID of the NS instance + + \b + Options: + --vnf TEXT VNF instance ID or VNF id in the NS [required] + --cause TEXT human readable cause of the healing + --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU + --vdu TEXT vdu-id + --count-index INTEGER count-index + + \b + Example: + osm ns-heal NS_NAME|NS_ID --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf" + --vdu several_volumes-VM + --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf" + --vdu mgmtVM --count-index 1 --run-day1 + --vdu mgmtVM --count-index 2 + """ + logger.debug("") + heal_dict = ctx.params["heal_params"] + logger.debug(f"Heal dict:\n{yaml.safe_dump(heal_dict)}") + # replace VNF id in the NS by the VNF instance ID + for vnf in heal_dict["healVnfData"]: + vnf_id = vnf["vnfInstanceId"] + if not validate_uuid4(vnf_id): + vnf_filter = f"member-vnf-index-ref={vnf_id}" + vnf_list = ctx.obj.vnf.list(ns=ns_name, filter=vnf_filter) + if len(vnf_list) == 0: + raise ClientException(f"No VNF found in NS {ns_name} with filter {vnf_filter}") + elif len(vnf_list) == 1: + vnf["vnfInstanceId"] = vnf_list[0]["_id"] + else: + raise ClientException(f"More than 1 VNF found in NS {ns_name} with filter {vnf_filter}") + logger.debug(f"Heal dict:\n{yaml.safe_dump(heal_dict)}") + check_client_version(ctx.obj, ctx.command.name) + ctx.obj.ns.heal(ns_name, heal_dict, wait, timeout) + exit(0) + + +def process_vnf_heal_params(ctx, param, value): + """ + Processes the params in the command vnf-heal + Click does not allow advanced patterns for positional options like this: + --vdu mgmtVM --count-index 1 --run-day1 --vdu mgmtVM --count-index 2 + + It returns the dictionary with all the params stored in ctx.params["heal_params"] + """ + logger.debug("") + # logger.debug(f"Args: {value}") + if param.name != "args": + raise ClientException(f"Unexpected param: {param.name}") + # Split the tuple "value" by "--vnf" + vnf = value + heal_dict = {} + heal_dict["healVnfData"] = [] + logger.debug(f"VNF: {vnf}") + heal_vnf = {"vnfInstanceId": "id_to_be_substituted"} + process_common_heal_params(heal_vnf, vnf) + heal_dict["healVnfData"].append(heal_vnf) + ctx.params["heal_params"] = heal_dict + return + + +@cli_osm.command( + name="vnf-heal", + short_help="heals (recreates) a VNF instance or the VDUs of a VNF instance", + context_settings=dict(ignore_unknown_options=True,) +) +@click.argument("vnf_name") +@click.argument( + 'args', + nargs=-1, + type=click.UNPROCESSED, + callback=process_vnf_heal_params, +) +@click.option( + "--timeout", + type=int, + default=None, + help="timeout in seconds" +) +@click.option( + "--wait", + default=False, + is_flag=True, + help="do not return the control immediately, but keep it until the operation is completed, or timeout", +) +@click.pass_context +def vnf_heal2( + ctx, + vnf_name, + args, + heal_params, + timeout, + wait, +): + """heals (recreates) a VNF instance or the VDUs of a VNF instance + + VNF_NAME: name or ID of the VNF instance + + \b + Options: + --cause TEXT human readable cause of the healing of the VNF + --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU + --vdu TEXT vdu-id + --count-index INTEGER count-index + + \b + Example: + osm vnf-heal VNF_INSTANCE_ID --vdu mgmtVM --count-index 1 --run-day1 + --vdu mgmtVM --count-index 2 + """ + logger.debug("") + heal_dict = ctx.params["heal_params"] + heal_dict["healVnfData"][-1]["vnfInstanceId"] = vnf_name + logger.debug(f"Heal dict:\n{yaml.safe_dump(heal_dict)}") + check_client_version(ctx.obj, ctx.command.name) + vnfr = ctx.obj.vnf.get(vnf_name) + ns_id = vnfr["nsr-id-ref"] + ctx.obj.ns.heal(ns_id, heal_dict, wait, timeout) + exit(0) + + @cli_osm.command(name="alarm-show", short_help="show alarm details") @click.argument("uuid") @click.pass_context @@ -5635,8 +5931,7 @@ def alarm_show(ctx, uuid): table = PrettyTable(["key", "attribute"]) try: # Arrange and return the response data - resp = resp.replace("ObjectId", "") - alarm = eval(resp) + alarm = resp.replace("ObjectId", "") for key in alarm_filter: if key == "uuid": value = alarm.get(key) @@ -5678,7 +5973,6 @@ def alarm_list(ctx, ns_id): if resp: # return the response data in a table resp = resp.replace("ObjectId", "") - resp = eval(resp) for alarm in resp: table.add_row( [