1 # Copyright 2017-2018 Sandvine
2 # Copyright 2018 Telefonica
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
22 from osmclient
import client
23 from osmclient
.common
.exceptions
import ClientException
, NotFound
24 from osmclient
.common
.utils
import validate_uuid4
25 from prettytable
import PrettyTable
34 from datetime
import datetime
35 from typing
import Any
, Dict
38 def wrap_text(text
, width
):
39 wrapper
= textwrap
.TextWrapper(width
=width
)
40 lines
= text
.splitlines()
41 return "\n".join(map(wrapper
.fill
, lines
))
44 def trunc_text(text
, length
):
45 if len(text
) > length
:
46 return text
[: (length
- 3)] + "..."
51 def check_client_version(obj
, what
, version
="sol005"):
53 Checks the version of the client object and raises error if it not the expected.
55 :param obj: the client object
56 :what: the function or command under evaluation (used when an error is raised)
58 :raises ClientError: if the specified version does not match the client version
61 fullclassname
= obj
.__module
__ + "." + obj
.__class
__.__name
__
62 message
= 'The following commands or options are only supported with the option "--sol005": {}'.format(
66 message
= 'The following commands or options are not supported when using option "--sol005": {}'.format(
69 if fullclassname
!= "osmclient.{}.client.Client".format(version
):
70 raise ClientException(message
)
74 def get_project(project_list
, item
):
75 # project_list = ctx.obj.project.list()
76 item_project_list
= item
.get("_admin", {}).get("projects_read")
80 for p1
in item_project_list
:
82 for p2
in project_list
:
83 if p2
["_id"] == project_id
:
84 project_name
= p2
["name"]
85 return project_id
, project_name
86 return project_id
, project_name
89 def get_vim_name(vim_list
, vim_id
):
92 if v
["uuid"] == vim_id
:
98 def create_config(config_file
, json_string
):
100 Combines a YAML or JSON file with a JSON string into a Python3 structure
101 It loads the YAML or JSON file 'cfile' into a first dictionary.
102 It loads the JSON string into a second dictionary.
103 Then it updates the first dictionary with the info in the second dictionary.
104 If the field is present in both cfile and cdict, the field in cdict prevails.
105 If both cfile and cdict are None, it returns an empty dict (i.e. {})
109 with
open(config_file
, "r") as cf
:
110 config
= yaml
.safe_load(cf
.read())
112 cdict
= yaml
.safe_load(json_string
)
113 for k
, v
in cdict
.items():
119 context_settings
=dict(help_option_names
=["-h", "--help"], max_content_width
=160)
124 envvar
="OSM_HOSTNAME",
125 help="hostname of server. " + "Also can set OSM_HOSTNAME in environment",
127 # @click.option('--sol005/--no-sol005',
129 # envvar='OSM_SOL005',
130 # help='Use ETSI NFV SOL005 API (default) or the previous SO API. ' +
131 # 'Also can set OSM_SOL005 in environment')
136 help="user (defaults to admin). " + "Also can set OSM_USER in environment",
141 envvar
="OSM_PASSWORD",
142 help="password (defaults to admin). " + "Also can set OSM_PASSWORD in environment",
147 envvar
="OSM_PROJECT",
148 help="project (defaults to admin). " + "Also can set OSM_PROJECT in environment",
154 help="increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)",
156 @click.option("--all-projects", default
=None, is_flag
=True, help="include all projects")
158 "--public/--no-public",
160 help="flag for public items (packages, instances, VIM accounts, etc.)",
163 "--project-domain-name",
164 "project_domain_name",
166 envvar
="OSM_PROJECT_DOMAIN_NAME",
167 help="project domain name for keystone authentication (default to None). "
168 + "Also can set OSM_PROJECT_DOMAIN_NAME in environment",
171 "--user-domain-name",
174 envvar
="OSM_USER_DOMAIN_NAME",
175 help="user domain name for keystone authentication (default to None). "
176 + "Also can set OSM_USER_DOMAIN_NAME in environment",
178 # @click.option('--so-port',
180 # envvar='OSM_SO_PORT',
181 # help='hostname of server. ' +
182 # 'Also can set OSM_SO_PORT in environment')
183 # @click.option('--so-project',
185 # envvar='OSM_SO_PROJECT',
186 # help='Project Name in SO. ' +
187 # 'Also can set OSM_SO_PROJECT in environment')
188 # @click.option('--ro-hostname',
190 # envvar='OSM_RO_HOSTNAME',
191 # help='hostname of RO server. ' +
192 # 'Also can set OSM_RO_HOSTNAME in environment')
193 # @click.option('--ro-port',
195 # envvar='OSM_RO_PORT',
196 # help='hostname of RO server. ' +
197 # 'Also can set OSM_RO_PORT in environment')
199 def cli_osm(ctx
, **kwargs
):
201 hostname
= kwargs
.pop("hostname", None)
205 "either hostname option or OSM_HOSTNAME "
206 + "environment variable needs to be specified"
211 kwargs
= {k
: v
for k
, v
in kwargs
.items() if v
is not None}
212 # if so_port is not None:
213 # kwargs['so_port']=so_port
214 # if so_project is not None:
215 # kwargs['so_project']=so_project
216 # if ro_hostname is not None:
217 # kwargs['ro_host']=ro_hostname
218 # if ro_port is not None:
219 # kwargs['ro_port']=ro_port
220 sol005
= os
.getenv("OSM_SOL005", True)
221 # if user is not None:
222 # kwargs['user']=user
223 # if password is not None:
224 # kwargs['password']=password
225 # if project is not None:
226 # kwargs['project']=project
228 # kwargs['all_projects']=all_projects
229 # if public is not None:
230 # kwargs['public']=public
231 ctx
.obj
= client
.Client(host
=hostname
, sol005
=sol005
, **kwargs
)
232 logger
= logging
.getLogger("osmclient")
240 @cli_osm.command(name
="ns-list", short_help
="list all NS instances")
245 help="restricts the list to the NS instances matching the filter.",
250 help="get more details of the NS (project, vim, deployment status, configuration status.",
253 def ns_list(ctx
, filter, long):
254 """list all NS instances
258 --filter filterExpr Restricts the list to the NS instances matching the filter
261 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
262 concatenated using the "&" character:
265 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
266 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
267 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
269 value := scalar value
273 * zero or more occurrences
274 ? zero or one occurrence
275 [] grouping of expressions to be used with ? and *
276 "" quotation marks for marking string constants
280 "AttrName" is the name of one attribute in the data type that defines the representation
281 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
282 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
283 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
284 entries, it means that the operator "op" is applied to the attribute addressed by the last
285 <attrName> entry included in the concatenation. All simple filter expressions are combined
286 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
287 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
288 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
289 prefix". If an attribute referenced in an expression is an array, an object that contains a
290 corresponding array shall be considered to match the expression if any of the elements in the
291 array matches all expressions that have the same attribute prefix.
295 --filter admin-status=ENABLED
296 --filter nsd-ref=<NSD_NAME>
297 --filter nsd.vendor=<VENDOR>
298 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
299 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
302 def summarize_deployment_status(status_dict
):
309 net_list
= status_dict
.get("nets", [])
312 if net
["status"] not in status_nets
:
313 status_nets
[net
["status"]] = 1
315 status_nets
[net
["status"]] += 1
317 for k
, v
in status_nets
.items():
318 message
+= "{}:{},".format(k
, v
)
319 message
+= "TOTAL:{}".format(n_nets
)
320 summary
+= "{}".format(message
)
325 vnf_list
= status_dict
["vnfs"]
327 member_vnf_index
= vnf
["member_vnf_index"]
328 if member_vnf_index
not in status_vnfs
:
329 status_vnfs
[member_vnf_index
] = {}
330 for vm
in vnf
["vms"]:
332 if vm
["status"] not in status_vms
:
333 status_vms
[vm
["status"]] = 1
335 status_vms
[vm
["status"]] += 1
336 if vm
["status"] not in status_vnfs
[member_vnf_index
]:
337 status_vnfs
[member_vnf_index
][vm
["status"]] = 1
339 status_vnfs
[member_vnf_index
][vm
["status"]] += 1
341 for k
, v
in status_vms
.items():
342 message
+= "{}:{},".format(k
, v
)
343 message
+= "TOTAL:{}".format(n_vms
)
344 summary
+= "\n{}".format(message
)
346 for k
, v
in status_vnfs
.items():
348 message
= "\n {} VMs: ".format(k
)
349 for k2
, v2
in v
.items():
350 message
+= "{}:{},".format(k2
, v2
)
352 message
+= "TOTAL:{}".format(total
)
356 def summarize_config_status(ee_list
):
364 if ee
["elementType"] not in status_ee
:
365 status_ee
[ee
["elementType"]] = {}
366 status_ee
[ee
["elementType"]][ee
["status"]] = 1
368 if ee
["status"] in status_ee
[ee
["elementType"]]:
369 status_ee
[ee
["elementType"]][ee
["status"]] += 1
371 status_ee
[ee
["elementType"]][ee
["status"]] = 1
372 for elementType
in ["KDU", "VDU", "PDU", "VNF", "NS"]:
373 if elementType
in status_ee
:
376 for k
, v
in status_ee
[elementType
].items():
377 message
+= "{}:{},".format(k
, v
)
379 message
+= "TOTAL:{}\n".format(total
)
380 summary
+= "{}: {}".format(elementType
, message
)
381 summary
+= "TOTAL Exec. Env.: {}".format(n_ee
)
386 check_client_version(ctx
.obj
, "--filter")
387 filter = "&".join(filter)
388 resp
= ctx
.obj
.ns
.list(filter)
390 resp
= ctx
.obj
.ns
.list()
403 "configuration status",
406 project_list
= ctx
.obj
.project
.list()
408 vim_list
= ctx
.obj
.vim
.list()
423 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
424 if fullclassname
== "osmclient.sol005.client.Client":
426 logger
.debug("NS info: {}".format(nsr
))
427 nsr_name
= nsr
["name"]
429 date
= datetime
.fromtimestamp(nsr
["create-time"]).strftime(
432 ns_state
= nsr
.get("nsState", nsr
["_admin"]["nsState"])
434 deployment_status
= summarize_deployment_status(
435 nsr
.get("deploymentStatus")
437 config_status
= summarize_config_status(nsr
.get("configurationStatus"))
438 project_id
, project_name
= get_project(project_list
, nsr
)
439 # project = '{} ({})'.format(project_name, project_id)
440 project
= project_name
441 vim_id
= nsr
.get("datacenter")
442 vim_name
= get_vim_name(vim_list
, vim_id
)
444 # vim = '{} ({})'.format(vim_name, vim_id)
446 if "currentOperation" in nsr
:
447 current_operation
= "{} ({})".format(
448 nsr
["currentOperation"], nsr
["currentOperationID"]
451 current_operation
= "{} ({})".format(
452 nsr
["_admin"].get("current-operation", "-"),
453 nsr
["_admin"]["nslcmop"],
455 error_details
= "N/A"
458 or ns_state
== "DEGRADED"
459 or ("currentOperation" not in nsr
and nsr
.get("errorDescription"))
461 error_details
= "{}\nDetail: {}".format(
462 nsr
["errorDescription"], nsr
["errorDetail"]
465 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
466 nsr
= nsopdata
["nsr:nsr"]
467 nsr_name
= nsr
["name-ref"]
468 nsr_id
= nsr
["ns-instance-config-ref"]
471 deployment_status
= (
472 nsr
["operational-status"]
473 if "operational-status" in nsr
476 ns_state
= deployment_status
477 config_status
= nsr
.get("config-status", "Not found")
478 current_operation
= "Unknown"
479 error_details
= nsr
.get("detailed-status", "Not found")
480 if config_status
== "config_not_needed":
481 config_status
= "configured (no charms)"
491 wrap_text(text
=error_details
, width
=40),
506 wrap_text(text
=error_details
, width
=40),
511 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
513 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
517 def nsd_list(ctx
, filter, long):
520 check_client_version(ctx
.obj
, "--filter")
521 filter = "&".join(filter)
522 resp
= ctx
.obj
.nsd
.list(filter)
524 resp
= ctx
.obj
.nsd
.list()
525 # print(yaml.safe_dump(resp))
526 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
527 if fullclassname
== "osmclient.sol005.client.Client":
541 table
= PrettyTable(["nsd name", "id"])
543 name
= nsd
.get("id", "-")
545 onb_state
= nsd
["_admin"].get("onboardingState", "-")
546 op_state
= nsd
["_admin"].get("operationalState", "-")
547 usage_state
= nsd
["_admin"].get("usageState", "-")
548 date
= datetime
.fromtimestamp(nsd
["_admin"]["created"]).strftime(
551 last_update
= datetime
.fromtimestamp(
552 nsd
["_admin"]["modified"]
553 ).strftime("%Y-%m-%dT%H:%M:%S")
566 table
.add_row([name
, nsd
["_id"]])
568 table
= PrettyTable(["nsd name", "id"])
570 table
.add_row([nsd
["name"], nsd
["id"]])
575 @cli_osm.command(name
="nsd-list", short_help
="list all NS packages")
580 help="restricts the list to the NSD/NSpkg matching the filter",
582 @click.option("--long", is_flag
=True, help="get more details")
584 def nsd_list1(ctx
, filter, long):
585 """list all NSD/NS pkg in the system"""
587 nsd_list(ctx
, filter, long)
590 @cli_osm.command(name
="nspkg-list", short_help
="list all NS packages")
595 help="restricts the list to the NSD/NSpkg matching the filter",
597 @click.option("--long", is_flag
=True, help="get more details")
599 def nsd_list2(ctx
, filter, long):
600 """list all NS packages"""
602 nsd_list(ctx
, filter, long)
605 def pkg_repo_list(ctx
, pkgtype
, filter, repo
, long):
606 resp
= ctx
.obj
.osmrepo
.pkg_list(pkgtype
, filter, repo
)
609 ["nfpkg name", "vendor", "version", "latest", "description", "repository"]
612 table
= PrettyTable(["nfpkg name", "repository"])
614 name
= vnfd
.get("id", vnfd
.get("name", "-"))
615 repository
= vnfd
.get("repository")
617 vendor
= vnfd
.get("provider", vnfd
.get("vendor"))
618 version
= vnfd
.get("version")
619 description
= vnfd
.get("description")
620 latest
= vnfd
.get("latest")
621 table
.add_row([name
, vendor
, version
, latest
, description
, repository
])
623 table
.add_row([name
, repository
])
628 def vnfd_list(ctx
, nf_type
, filter, long):
631 check_client_version(ctx
.obj
, "--nf_type")
633 check_client_version(ctx
.obj
, "--filter")
635 filter = "&".join(filter)
638 nf_filter
= "_admin.type=vnfd"
639 elif nf_type
== "pnf":
640 nf_filter
= "_admin.type=pnfd"
641 elif nf_type
== "hnf":
642 nf_filter
= "_admin.type=hnfd"
644 raise ClientException(
645 'wrong value for "--nf_type" option, allowed values: vnf, pnf, hnf'
648 filter = "{}&{}".format(nf_filter
, filter)
652 resp
= ctx
.obj
.vnfd
.list(filter)
654 resp
= ctx
.obj
.vnfd
.list()
655 # print(yaml.safe_dump(resp))
656 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
657 if fullclassname
== "osmclient.sol005.client.Client":
674 table
= PrettyTable(["nfpkg name", "id", "desc type"])
676 name
= vnfd
.get("id", vnfd
.get("name", "-"))
677 descriptor_type
= "sol006" if "product-name" in vnfd
else "rel8"
679 onb_state
= vnfd
["_admin"].get("onboardingState", "-")
680 op_state
= vnfd
["_admin"].get("operationalState", "-")
681 vendor
= vnfd
.get("provider", vnfd
.get("vendor"))
682 version
= vnfd
.get("version")
683 usage_state
= vnfd
["_admin"].get("usageState", "-")
684 date
= datetime
.fromtimestamp(vnfd
["_admin"]["created"]).strftime(
687 last_update
= datetime
.fromtimestamp(
688 vnfd
["_admin"]["modified"]
689 ).strftime("%Y-%m-%dT%H:%M:%S")
705 table
.add_row([name
, vnfd
["_id"], descriptor_type
])
707 table
= PrettyTable(["nfpkg name", "id"])
709 table
.add_row([vnfd
["name"], vnfd
["id"]])
714 @cli_osm.command(name
="vnfd-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
715 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
720 help="restricts the list to the NF pkg matching the filter",
722 @click.option("--long", is_flag
=True, help="get more details")
724 def vnfd_list1(ctx
, nf_type
, filter, long):
725 """list all xNF packages (VNF, HNF, PNF)"""
727 vnfd_list(ctx
, nf_type
, filter, long)
730 @cli_osm.command(name
="vnfpkg-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
731 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
736 help="restricts the list to the NFpkg matching the filter",
738 @click.option("--long", is_flag
=True, help="get more details")
740 def vnfd_list2(ctx
, nf_type
, filter, long):
741 """list all xNF packages (VNF, HNF, PNF)"""
743 vnfd_list(ctx
, nf_type
, filter, long)
746 @cli_osm.command(name
="nfpkg-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
747 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
752 help="restricts the list to the NFpkg matching the filter",
754 @click.option("--long", is_flag
=True, help="get more details")
756 def nfpkg_list(ctx
, nf_type
, filter, long):
757 """list all xNF packages (VNF, HNF, PNF)"""
760 check_client_version(ctx
.obj
, ctx
.command
.name
)
761 vnfd_list(ctx
, nf_type
, filter, long)
762 # except ClientException as e:
768 name
="vnfpkg-repo-list", short_help
="list all xNF from OSM repositories"
774 help="restricts the list to the NFpkg matching the filter",
777 "--repo", default
=None, help="restricts the list to a particular OSM repository"
779 @click.option("--long", is_flag
=True, help="get more details")
781 def nfpkg_repo_list1(ctx
, filter, repo
, long):
782 """list xNF packages from OSM repositories"""
784 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
788 name
="nfpkg-repo-list", short_help
="list all xNF from OSM repositories"
794 help="restricts the list to the NFpkg matching the filter",
797 "--repo", default
=None, help="restricts the list to a particular OSM repository"
799 @click.option("--long", is_flag
=True, help="get more details")
801 def nfpkg_repo_list2(ctx
, filter, repo
, long):
802 """list xNF packages from OSM repositories"""
804 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
807 def vnf_list(ctx
, ns
, filter, long):
811 check_client_version(ctx
.obj
, "--ns")
813 filter = "&".join(filter)
814 check_client_version(ctx
.obj
, "--filter")
815 resp
= ctx
.obj
.vnf
.list(ns
, filter)
817 resp
= ctx
.obj
.vnf
.list()
818 # except ClientException as e:
821 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
822 if fullclassname
== "osmclient.sol005.client.Client":
844 table
= PrettyTable(field_names
)
846 name
= vnfr
["name"] if "name" in vnfr
else "-"
851 vnfr
["member-vnf-index-ref"],
853 vnfr
["vim-account-id"],
857 date
= datetime
.fromtimestamp(vnfr
["_admin"]["created"]).strftime(
860 last_update
= datetime
.fromtimestamp(
861 vnfr
["_admin"]["modified"]
862 ).strftime("%Y-%m-%dT%H:%M:%S")
863 new_row
.extend([date
, last_update
])
864 table
.add_row(new_row
)
866 table
= PrettyTable(["vnf name", "id", "operational status", "config status"])
868 if "mgmt-interface" not in vnfr
:
869 vnfr
["mgmt-interface"] = {}
870 vnfr
["mgmt-interface"]["ip-address"] = None
875 vnfr
["operational-status"],
876 vnfr
["config-status"],
883 @cli_osm.command(name
="vnf-list", short_help
="list all NF instances")
885 "--ns", default
=None, help="NS instance id or name to restrict the NF list"
891 help="restricts the list to the NF instances matching the filter.",
893 @click.option("--long", is_flag
=True, help="get more details")
895 def vnf_list1(ctx
, ns
, filter, long):
896 """list all NF instances"""
898 vnf_list(ctx
, ns
, filter, long)
901 @cli_osm.command(name
="nsd-repo-list", short_help
="list all NS from OSM repositories")
906 help="restricts the list to the NS matching the filter",
909 "--repo", default
=None, help="restricts the list to a particular OSM repository"
911 @click.option("--long", is_flag
=True, help="get more details")
913 def nspkg_repo_list(ctx
, filter, repo
, long):
914 """list xNF packages from OSM repositories"""
916 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
919 @cli_osm.command(name
="nspkg-repo-list", short_help
="list all NS from OSM repositories")
924 help="restricts the list to the NS matching the filter",
927 "--repo", default
=None, help="restricts the list to a particular OSM repository"
929 @click.option("--long", is_flag
=True, help="get more details")
931 def nspkg_repo_list2(ctx
, filter, repo
, long):
932 """list xNF packages from OSM repositories"""
934 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
937 @cli_osm.command(name
="nf-list", short_help
="list all NF instances")
939 "--ns", default
=None, help="NS instance id or name to restrict the NF list"
945 help="restricts the list to the NF instances matching the filter.",
947 @click.option("--long", is_flag
=True, help="get more details")
949 def nf_list(ctx
, ns
, filter, long):
950 """list all NF instances
954 --ns TEXT NS instance id or name to restrict the VNF list
955 --filter filterExpr Restricts the list to the VNF instances matching the filter
958 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
959 concatenated using the "&" character:
962 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
963 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
964 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
966 value := scalar value
970 * zero or more occurrences
971 ? zero or one occurrence
972 [] grouping of expressions to be used with ? and *
973 "" quotation marks for marking string constants
977 "AttrName" is the name of one attribute in the data type that defines the representation
978 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
979 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
980 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
981 entries, it means that the operator "op" is applied to the attribute addressed by the last
982 <attrName> entry included in the concatenation. All simple filter expressions are combined
983 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
984 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
985 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
986 prefix". If an attribute referenced in an expression is an array, an object that contains a
987 corresponding array shall be considered to match the expression if any of the elements in the
988 array matches all expressions that have the same attribute prefix.
992 --filter vim-account-id=<VIM_ACCOUNT_ID>
993 --filter vnfd-ref=<VNFD_NAME>
994 --filter vdur.ip-address=<IP_ADDRESS>
995 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
998 vnf_list(ctx
, ns
, filter, long)
1002 name
="ns-op-list", short_help
="shows the history of operations over a NS instance"
1004 @click.argument("name")
1006 "--long", is_flag
=True, help="get more details of the NS operation (date, )."
1009 def ns_op_list(ctx
, name
, long):
1010 """shows the history of operations over a NS instance
1012 NAME: name or ID of the NS instance
1015 def formatParams(params
):
1016 if params
["lcmOperationType"] == "instantiate":
1017 params
.pop("nsDescription")
1018 params
.pop("nsName")
1020 params
.pop("nsr_id")
1021 elif params
["lcmOperationType"] == "action":
1022 params
.pop("primitive")
1023 params
.pop("lcmOperationType")
1024 params
.pop("nsInstanceId")
1029 check_client_version(ctx
.obj
, ctx
.command
.name
)
1030 resp
= ctx
.obj
.ns
.list_op(name
)
1031 # except ClientException as e:
1036 table
= PrettyTable(
1049 table
= PrettyTable(
1050 ["id", "operation", "action_name", "status", "date", "detail"]
1053 # print(yaml.safe_dump(resp))
1056 if op
["lcmOperationType"] == "action":
1057 action_name
= op
["operationParams"]["primitive"]
1059 if op
["operationState"] == "PROCESSING":
1060 if op
["queuePosition"] is not None and op
["queuePosition"] > 0:
1061 detail
= "In queue. Current position: {}".format(op
["queuePosition"])
1062 elif op
["lcmOperationType"] in ("instantiate", "terminate"):
1064 detail
= op
["stage"]
1065 elif op
["operationState"] in ("FAILED", "FAILED_TEMP"):
1066 detail
= op
.get("errorMessage", "-")
1067 date
= datetime
.fromtimestamp(op
["startTime"]).strftime("%Y-%m-%dT%H:%M:%S")
1068 last_update
= datetime
.fromtimestamp(op
["statusEnteredTime"]).strftime(
1075 op
["lcmOperationType"],
1078 text
=json
.dumps(formatParams(op
["operationParams"]), indent
=2),
1081 op
["operationState"],
1084 wrap_text(text
=detail
, width
=50),
1091 op
["lcmOperationType"],
1093 op
["operationState"],
1095 wrap_text(text
=detail
or "", width
=50),
1102 def nsi_list(ctx
, filter):
1103 """list all Network Slice Instances"""
1106 check_client_version(ctx
.obj
, ctx
.command
.name
)
1108 filter = "&".join(filter)
1109 resp
= ctx
.obj
.nsi
.list(filter)
1110 # except ClientException as e:
1113 table
= PrettyTable(
1115 "netslice instance name",
1117 "operational status",
1123 nsi_name
= nsi
["name"]
1126 nsi
["operational-status"] if "operational-status" in nsi
else "Not found"
1128 configstatus
= nsi
["config-status"] if "config-status" in nsi
else "Not found"
1130 nsi
["detailed-status"] if "detailed-status" in nsi
else "Not found"
1132 if configstatus
== "config_not_needed":
1133 configstatus
= "configured (no charms)"
1134 table
.add_row([nsi_name
, nsi_id
, opstatus
, configstatus
, detailed_status
])
1139 @cli_osm.command(name
="nsi-list", short_help
="list all Network Slice Instances (NSI)")
1144 help="restricts the list to the Network Slice Instances matching the filter",
1147 def nsi_list1(ctx
, filter):
1148 """list all Network Slice Instances (NSI)"""
1150 nsi_list(ctx
, filter)
1154 name
="netslice-instance-list", short_help
="list all Network Slice Instances (NSI)"
1160 help="restricts the list to the Network Slice Instances matching the filter",
1163 def nsi_list2(ctx
, filter):
1164 """list all Network Slice Instances (NSI)"""
1166 nsi_list(ctx
, filter)
1169 def nst_list(ctx
, filter):
1172 check_client_version(ctx
.obj
, ctx
.command
.name
)
1174 filter = "&".join(filter)
1175 resp
= ctx
.obj
.nst
.list(filter)
1176 # except ClientException as e:
1179 # print(yaml.safe_dump(resp))
1180 table
= PrettyTable(["nst name", "id"])
1182 name
= nst
["name"] if "name" in nst
else "-"
1183 table
.add_row([name
, nst
["_id"]])
1188 @cli_osm.command(name
="nst-list", short_help
="list all Network Slice Templates (NST)")
1193 help="restricts the list to the NST matching the filter",
1196 def nst_list1(ctx
, filter):
1197 """list all Network Slice Templates (NST) in the system"""
1199 nst_list(ctx
, filter)
1203 name
="netslice-template-list", short_help
="list all Network Slice Templates (NST)"
1209 help="restricts the list to the NST matching the filter",
1212 def nst_list2(ctx
, filter):
1213 """list all Network Slice Templates (NST) in the system"""
1215 nst_list(ctx
, filter)
1218 def nsi_op_list(ctx
, name
):
1221 check_client_version(ctx
.obj
, ctx
.command
.name
)
1222 resp
= ctx
.obj
.nsi
.list_op(name
)
1223 # except ClientException as e:
1226 table
= PrettyTable(["id", "operation", "status"])
1228 table
.add_row([op
["id"], op
["lcmOperationType"], op
["operationState"]])
1235 short_help
="shows the history of operations over a Network Slice Instance (NSI)",
1237 @click.argument("name")
1239 def nsi_op_list1(ctx
, name
):
1240 """shows the history of operations over a Network Slice Instance (NSI)
1242 NAME: name or ID of the Network Slice Instance
1245 nsi_op_list(ctx
, name
)
1249 name
="netslice-instance-op-list",
1250 short_help
="shows the history of operations over a Network Slice Instance (NSI)",
1252 @click.argument("name")
1254 def nsi_op_list2(ctx
, name
):
1255 """shows the history of operations over a Network Slice Instance (NSI)
1257 NAME: name or ID of the Network Slice Instance
1260 nsi_op_list(ctx
, name
)
1263 @cli_osm.command(name
="pdu-list", short_help
="list all Physical Deployment Units (PDU)")
1268 help="restricts the list to the Physical Deployment Units matching the filter",
1271 def pdu_list(ctx
, filter):
1272 """list all Physical Deployment Units (PDU)"""
1275 check_client_version(ctx
.obj
, ctx
.command
.name
)
1277 filter = "&".join(filter)
1278 resp
= ctx
.obj
.pdu
.list(filter)
1279 # except ClientException as e:
1282 table
= PrettyTable(["pdu name", "id", "type", "mgmt ip address"])
1284 pdu_name
= pdu
["name"]
1286 pdu_type
= pdu
["type"]
1287 pdu_ipaddress
= "None"
1288 for iface
in pdu
["interfaces"]:
1290 pdu_ipaddress
= iface
["ip-address"]
1292 table
.add_row([pdu_name
, pdu_id
, pdu_type
, pdu_ipaddress
])
1297 ####################
1299 ####################
1302 def nsd_show(ctx
, name
, literal
):
1305 resp
= ctx
.obj
.nsd
.get(name
)
1306 # resp = ctx.obj.nsd.get_individual(name)
1307 # except ClientException as e:
1312 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1315 table
= PrettyTable(["field", "value"])
1316 for k
, v
in list(resp
.items()):
1317 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1322 @cli_osm.command(name
="nsd-show", short_help
="shows the details of a NS package")
1323 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1324 @click.argument("name")
1326 def nsd_show1(ctx
, name
, literal
):
1327 """shows the content of a NSD
1329 NAME: name or ID of the NSD/NSpkg
1332 nsd_show(ctx
, name
, literal
)
1335 @cli_osm.command(name
="nspkg-show", short_help
="shows the details of a NS package")
1336 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1337 @click.argument("name")
1339 def nsd_show2(ctx
, name
, literal
):
1340 """shows the content of a NSD
1342 NAME: name or ID of the NSD/NSpkg
1345 nsd_show(ctx
, name
, literal
)
1348 def vnfd_show(ctx
, name
, literal
):
1351 resp
= ctx
.obj
.vnfd
.get(name
)
1352 # resp = ctx.obj.vnfd.get_individual(name)
1353 # except ClientException as e:
1358 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1361 table
= PrettyTable(["field", "value"])
1362 for k
, v
in list(resp
.items()):
1363 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1368 def pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
):
1371 filter = "&".join(filter)
1373 resp
= ctx
.obj
.osmrepo
.pkg_get(pkgtype
, name
, repo
, version
, filter)
1376 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1379 catalog
= pkgtype
+ "-catalog"
1380 full_catalog
= pkgtype
+ ":" + catalog
1381 if resp
.get(catalog
):
1382 resp
= resp
.pop(catalog
)[pkgtype
][0]
1383 elif resp
.get(full_catalog
):
1384 resp
= resp
.pop(full_catalog
)[pkgtype
][0]
1386 table
= PrettyTable(["field", "value"])
1387 for k
, v
in list(resp
.items()):
1388 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1393 @cli_osm.command(name
="vnfd-show", short_help
="shows the details of a NF package")
1394 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1395 @click.argument("name")
1397 def vnfd_show1(ctx
, name
, literal
):
1398 """shows the content of a VNFD
1400 NAME: name or ID of the VNFD/VNFpkg
1403 vnfd_show(ctx
, name
, literal
)
1406 @cli_osm.command(name
="vnfpkg-show", short_help
="shows the details of a NF package")
1407 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1408 @click.argument("name")
1410 def vnfd_show2(ctx
, name
, literal
):
1411 """shows the content of a VNFD
1413 NAME: name or ID of the VNFD/VNFpkg
1416 vnfd_show(ctx
, name
, literal
)
1420 name
="vnfpkg-repo-show",
1421 short_help
="shows the details of a NF package in an OSM repository",
1423 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1424 @click.option("--repo", required
=True, help="Repository name")
1425 @click.argument("name")
1426 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1427 @click.option("--version", default
="latest", help="package version")
1429 def vnfd_show3(ctx
, name
, repo
, version
, literal
=None, filter=None):
1430 """shows the content of a VNFD in a repository
1432 NAME: name or ID of the VNFD/VNFpkg
1435 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1439 name
="nsd-repo-show",
1440 short_help
="shows the details of a NS package in an OSM repository",
1442 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1443 @click.option("--repo", required
=True, help="Repository name")
1444 @click.argument("name")
1445 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1446 @click.option("--version", default
="latest", help="package version")
1448 def nsd_repo_show(ctx
, name
, repo
, version
, literal
=None, filter=None):
1449 """shows the content of a VNFD in a repository
1451 NAME: name or ID of the VNFD/VNFpkg
1454 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1458 name
="nspkg-repo-show",
1459 short_help
="shows the details of a NS package in an OSM repository",
1461 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1462 @click.option("--repo", required
=True, help="Repository name")
1463 @click.argument("name")
1464 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1465 @click.option("--version", default
="latest", help="package version")
1467 def nsd_repo_show2(ctx
, name
, repo
, version
, literal
=None, filter=None):
1468 """shows the content of a VNFD in a repository
1470 NAME: name or ID of the VNFD/VNFpkg
1473 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1476 @cli_osm.command(name
="nfpkg-show", short_help
="shows the details of a NF package")
1477 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1478 @click.argument("name")
1480 def nfpkg_show(ctx
, name
, literal
):
1481 """shows the content of a NF Descriptor
1483 NAME: name or ID of the NFpkg
1486 vnfd_show(ctx
, name
, literal
)
1490 name
="nfpkg-repo-show",
1491 short_help
="shows the details of a NF package in an OSM repository",
1493 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1494 @click.option("--repo", required
=True, help="Repository name")
1495 @click.argument("name")
1496 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1497 @click.option("--version", default
="latest", help="package version")
1499 def vnfd_show4(ctx
, name
, repo
, version
, literal
=None, filter=None):
1500 """shows the content of a VNFD in a repository
1502 NAME: name or ID of the VNFD/VNFpkg
1505 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1508 @cli_osm.command(name
="ns-show", short_help
="shows the info of a NS instance")
1509 @click.argument("name")
1510 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1514 help="restricts the information to the fields in the filter",
1517 def ns_show(ctx
, name
, literal
, filter):
1518 """shows the info of a NS instance
1520 NAME: name or ID of the NS instance
1524 ns
= ctx
.obj
.ns
.get(name
)
1525 # except ClientException as e:
1530 print(yaml
.safe_dump(ns
, indent
=4, default_flow_style
=False))
1533 table
= PrettyTable(["field", "value"])
1535 for k
, v
in list(ns
.items()):
1536 if not filter or k
in filter:
1537 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1539 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
1540 if fullclassname
!= "osmclient.sol005.client.Client":
1541 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
1542 nsr_optdata
= nsopdata
["nsr:nsr"]
1543 for k
, v
in list(nsr_optdata
.items()):
1544 if not filter or k
in filter:
1545 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), width
=100)])
1550 @cli_osm.command(name
="vnf-show", short_help
="shows the info of a VNF instance")
1551 @click.argument("name")
1552 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1556 help="restricts the information to the fields in the filter",
1558 @click.option("--kdu", default
=None, help="KDU name (whose status will be shown)")
1560 def vnf_show(ctx
, name
, literal
, filter, kdu
):
1561 """shows the info of a VNF instance
1563 NAME: name or ID of the VNF instance
1566 def print_kdu_status(op_info_status
):
1567 """print KDU status properly formatted"""
1569 op_status
= yaml
.safe_load(op_info_status
)
1571 "namespace" in op_status
1572 and "info" in op_status
1573 and "last_deployed" in op_status
["info"]
1574 and "status" in op_status
["info"]
1575 and "code" in op_status
["info"]["status"]
1576 and "resources" in op_status
["info"]["status"]
1577 and "seconds" in op_status
["info"]["last_deployed"]
1579 last_deployed_time
= datetime
.fromtimestamp(
1580 op_status
["info"]["last_deployed"]["seconds"]
1581 ).strftime("%a %b %d %I:%M:%S %Y")
1582 print("LAST DEPLOYED: {}".format(last_deployed_time
))
1583 print("NAMESPACE: {}".format(op_status
["namespace"]))
1584 status_code
= "UNKNOWN"
1585 if op_status
["info"]["status"]["code"] == 1:
1586 status_code
= "DEPLOYED"
1587 print("STATUS: {}".format(status_code
))
1590 print(op_status
["info"]["status"]["resources"])
1591 if "notes" in op_status
["info"]["status"]:
1593 print(op_status
["info"]["status"]["notes"])
1595 print(op_info_status
)
1597 print(op_info_status
)
1602 raise ClientException(
1603 '"--literal" option is incompatible with "--kdu" option'
1606 raise ClientException(
1607 '"--filter" option is incompatible with "--kdu" option'
1611 check_client_version(ctx
.obj
, ctx
.command
.name
)
1612 resp
= ctx
.obj
.vnf
.get(name
)
1615 ns_id
= resp
["nsr-id-ref"]
1617 op_data
["member_vnf_index"] = resp
["member-vnf-index-ref"]
1618 op_data
["kdu_name"] = kdu
1619 op_data
["primitive"] = "status"
1620 op_data
["primitive_params"] = {}
1621 op_id
= ctx
.obj
.ns
.exec_op(ns_id
, op_name
="action", op_data
=op_data
, wait
=False)
1624 op_info
= ctx
.obj
.ns
.get_op(op_id
)
1625 if op_info
["operationState"] == "COMPLETED":
1626 print_kdu_status(op_info
["detailed-status"])
1630 print("Could not determine KDU status")
1634 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1637 table
= PrettyTable(["field", "value"])
1638 for k
, v
in list(resp
.items()):
1639 if not filter or k
in filter:
1640 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1643 # except ClientException as e:
1648 # @cli_osm.command(name='vnf-monitoring-show')
1649 # @click.argument('vnf_name')
1650 # @click.pass_context
1651 # def vnf_monitoring_show(ctx, vnf_name):
1653 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1654 # resp = ctx.obj.vnf.get_monitoring(vnf_name)
1655 # except ClientException as e:
1659 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1660 # if resp is not None:
1661 # for monitor in resp:
1665 # monitor['value-integer'],
1666 # monitor['units']])
1671 # @cli_osm.command(name='ns-monitoring-show')
1672 # @click.argument('ns_name')
1673 # @click.pass_context
1674 # def ns_monitoring_show(ctx, ns_name):
1676 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1677 # resp = ctx.obj.ns.get_monitoring(ns_name)
1678 # except ClientException as e:
1682 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1683 # for key, val in list(resp.items()):
1684 # for monitor in val:
1688 # monitor['value-integer'],
1689 # monitor['units']])
1694 @cli_osm.command(name
="ns-op-show", short_help
="shows the info of a NS operation")
1695 @click.argument("id")
1699 help="restricts the information to the fields in the filter",
1701 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1703 def ns_op_show(ctx
, id, filter, literal
):
1704 """shows the detailed info of a NS operation
1706 ID: operation identifier
1710 check_client_version(ctx
.obj
, ctx
.command
.name
)
1711 op_info
= ctx
.obj
.ns
.get_op(id)
1712 # except ClientException as e:
1717 print(yaml
.safe_dump(op_info
, indent
=4, default_flow_style
=False))
1720 table
= PrettyTable(["field", "value"])
1721 for k
, v
in list(op_info
.items()):
1722 if not filter or k
in filter:
1723 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1728 def nst_show(ctx
, name
, literal
):
1731 check_client_version(ctx
.obj
, ctx
.command
.name
)
1732 resp
= ctx
.obj
.nst
.get(name
)
1733 # resp = ctx.obj.nst.get_individual(name)
1734 # except ClientException as e:
1739 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1742 table
= PrettyTable(["field", "value"])
1743 for k
, v
in list(resp
.items()):
1744 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1750 name
="nst-show", short_help
="shows the content of a Network Slice Template (NST)"
1752 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1753 @click.argument("name")
1755 def nst_show1(ctx
, name
, literal
):
1756 """shows the content of a Network Slice Template (NST)
1758 NAME: name or ID of the NST
1761 nst_show(ctx
, name
, literal
)
1765 name
="netslice-template-show",
1766 short_help
="shows the content of a Network Slice Template (NST)",
1768 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1769 @click.argument("name")
1771 def nst_show2(ctx
, name
, literal
):
1772 """shows the content of a Network Slice Template (NST)
1774 NAME: name or ID of the NST
1777 nst_show(ctx
, name
, literal
)
1780 def nsi_show(ctx
, name
, literal
, filter):
1783 check_client_version(ctx
.obj
, ctx
.command
.name
)
1784 nsi
= ctx
.obj
.nsi
.get(name
)
1785 # except ClientException as e:
1790 print(yaml
.safe_dump(nsi
, indent
=4, default_flow_style
=False))
1793 table
= PrettyTable(["field", "value"])
1795 for k
, v
in list(nsi
.items()):
1796 if not filter or k
in filter:
1797 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1804 name
="nsi-show", short_help
="shows the content of a Network Slice Instance (NSI)"
1806 @click.argument("name")
1807 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1811 help="restricts the information to the fields in the filter",
1814 def nsi_show1(ctx
, name
, literal
, filter):
1815 """shows the content of a Network Slice Instance (NSI)
1817 NAME: name or ID of the Network Slice Instance
1820 nsi_show(ctx
, name
, literal
, filter)
1824 name
="netslice-instance-show",
1825 short_help
="shows the content of a Network Slice Instance (NSI)",
1827 @click.argument("name")
1828 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1832 help="restricts the information to the fields in the filter",
1835 def nsi_show2(ctx
, name
, literal
, filter):
1836 """shows the content of a Network Slice Instance (NSI)
1838 NAME: name or ID of the Network Slice Instance
1841 nsi_show(ctx
, name
, literal
, filter)
1844 def nsi_op_show(ctx
, id, filter):
1847 check_client_version(ctx
.obj
, ctx
.command
.name
)
1848 op_info
= ctx
.obj
.nsi
.get_op(id)
1849 # except ClientException as e:
1853 table
= PrettyTable(["field", "value"])
1854 for k
, v
in list(op_info
.items()):
1855 if not filter or k
in filter:
1856 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1863 short_help
="shows the info of an operation over a Network Slice Instance(NSI)",
1865 @click.argument("id")
1869 help="restricts the information to the fields in the filter",
1872 def nsi_op_show1(ctx
, id, filter):
1873 """shows the info of an operation over a Network Slice Instance(NSI)
1875 ID: operation identifier
1878 nsi_op_show(ctx
, id, filter)
1882 name
="netslice-instance-op-show",
1883 short_help
="shows the info of an operation over a Network Slice Instance(NSI)",
1885 @click.argument("id")
1889 help="restricts the information to the fields in the filter",
1892 def nsi_op_show2(ctx
, id, filter):
1893 """shows the info of an operation over a Network Slice Instance(NSI)
1895 ID: operation identifier
1898 nsi_op_show(ctx
, id, filter)
1902 name
="pdu-show", short_help
="shows the content of a Physical Deployment Unit (PDU)"
1904 @click.argument("name")
1905 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1909 help="restricts the information to the fields in the filter",
1912 def pdu_show(ctx
, name
, literal
, filter):
1913 """shows the content of a Physical Deployment Unit (PDU)
1915 NAME: name or ID of the PDU
1919 check_client_version(ctx
.obj
, ctx
.command
.name
)
1920 pdu
= ctx
.obj
.pdu
.get(name
)
1921 # except ClientException as e:
1926 print(yaml
.safe_dump(pdu
, indent
=4, default_flow_style
=False))
1929 table
= PrettyTable(["field", "value"])
1931 for k
, v
in list(pdu
.items()):
1932 if not filter or k
in filter:
1933 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1939 ####################
1941 ####################
1944 def nsd_create(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
1947 check_client_version(ctx
.obj
, ctx
.command
.name
)
1949 filename
= ctx
.obj
.osmrepo
.get_pkg("ns", filename
, repo
, vendor
, version
)
1950 ctx
.obj
.nsd
.create(filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1951 # except ClientException as e:
1956 @cli_osm.command(name
="nsd-create", short_help
="creates a new NSD/NSpkg")
1957 @click.argument("filename")
1961 default
=None, # hidden=True,
1962 help="Deprecated. Use override",
1968 help="overrides fields in descriptor, format: "
1969 '"key1.key2...=value[;key3...=value;...]"',
1972 "--skip-charm-build",
1975 help="The charm will not be compiled, it is assumed to already exist",
1977 @click.option("--repo", default
=None, help="[repository]: Repository name")
1978 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
1982 help="[repository]: filter by version. Default: latest",
1985 def nsd_create1(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
1986 """onboards a new NSpkg (alias of nspkg-create) (TO BE DEPRECATED)
1989 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
1990 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
1991 If FILENAME is an NF Package folder, it is built and then onboarded.
1997 overwrite
=overwrite
,
1998 skip_charm_build
=skip_charm_build
,
2005 @cli_osm.command(name
="nspkg-create", short_help
="creates a new NSD/NSpkg")
2006 @click.argument("filename")
2010 default
=None, # hidden=True,
2011 help="Deprecated. Use override",
2017 help="overrides fields in descriptor, format: "
2018 '"key1.key2...=value[;key3...=value;...]"',
2021 "--skip-charm-build",
2024 help="The charm will not be compiled, it is assumed to already exist",
2026 @click.option("--repo", default
=None, help="[repository]: Repository name")
2027 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2031 help="[repository]: filter by version. Default: latest",
2034 def nsd_pkg_create(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
2035 """onboards a new NSpkg
2037 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2038 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2039 If FILENAME is an NF Package folder, it is built and then onboarded.
2045 overwrite
=overwrite
,
2046 skip_charm_build
=skip_charm_build
,
2067 check_client_version(ctx
.obj
, ctx
.command
.name
)
2069 filename
= ctx
.obj
.osmrepo
.get_pkg("vnf", filename
, repo
, vendor
, version
)
2070 ctx
.obj
.vnfd
.create(
2072 overwrite
=overwrite
,
2073 skip_charm_build
=skip_charm_build
,
2074 override_epa
=override_epa
,
2075 override_nonepa
=override_nonepa
,
2076 override_paravirt
=override_paravirt
,
2078 # except ClientException as e:
2083 @cli_osm.command(name
="vnfd-create", short_help
="creates a new VNFD/VNFpkg")
2084 @click.argument("filename")
2086 "--overwrite", "overwrite", default
=None, help="overwrite deprecated, use override"
2092 help="overrides fields in descriptor, format: "
2093 '"key1.key2...=value[;key3...=value;...]"',
2096 "--skip-charm-build",
2099 help="The charm will not be compiled, it is assumed to already exist",
2106 help="adds guest-epa parameters to all VDU",
2109 "--override-nonepa",
2113 help="removes all guest-epa parameters from all VDU",
2116 "--override-paravirt",
2120 help="overrides all VDU interfaces to PARAVIRT",
2122 @click.option("--repo", default
=None, help="[repository]: Repository name")
2123 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2127 help="[repository]: filter by version. Default: latest",
2142 """creates a new VNFD/VNFpkg
2144 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2145 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2146 If FILENAME is an NF Package folder, it is built and then onboarded.
2152 overwrite
=overwrite
,
2153 skip_charm_build
=skip_charm_build
,
2154 override_epa
=override_epa
,
2155 override_nonepa
=override_nonepa
,
2156 override_paravirt
=override_paravirt
,
2163 @cli_osm.command(name
="vnfpkg-create", short_help
="creates a new VNFD/VNFpkg")
2164 @click.argument("filename")
2168 default
=None, # hidden=True,
2169 help="Deprecated. Use override",
2175 help="overrides fields in descriptor, format: "
2176 '"key1.key2...=value[;key3...=value;...]"',
2179 "--skip-charm-build",
2182 help="The charm will not be compiled, it is assumed to already exist",
2189 help="adds guest-epa parameters to all VDU",
2192 "--override-nonepa",
2196 help="removes all guest-epa parameters from all VDU",
2199 "--override-paravirt",
2203 help="overrides all VDU interfaces to PARAVIRT",
2205 @click.option("--repo", default
=None, help="[repository]: Repository name")
2206 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2210 help="[repository]: filter by version. Default: latest",
2225 """creates a new VNFD/VNFpkg
2227 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2228 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2229 If FILENAME is an NF Package folder, it is built and then onboarded.
2235 overwrite
=overwrite
,
2236 skip_charm_build
=skip_charm_build
,
2237 override_epa
=override_epa
,
2238 override_nonepa
=override_nonepa
,
2239 override_paravirt
=override_paravirt
,
2246 @cli_osm.command(name
="nfpkg-create", short_help
="creates a new NFpkg")
2247 @click.argument("filename")
2251 default
=None, # hidden=True,
2252 help="Deprecated. Use override",
2258 help="overrides fields in descriptor, format: "
2259 '"key1.key2...=value[;key3...=value;...]"',
2262 "--skip-charm-build",
2265 help="The charm will not be compiled, it is assumed to already exist",
2272 help="adds guest-epa parameters to all VDU",
2275 "--override-nonepa",
2279 help="removes all guest-epa parameters from all VDU",
2282 "--override-paravirt",
2286 help="overrides all VDU interfaces to PARAVIRT",
2288 @click.option("--repo", default
=None, help="[repository]: Repository name")
2289 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2293 help="[repository]: filter by version. Default: latest",
2308 """creates a new NFpkg
2311 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2312 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2313 If FILENAME is an NF Package folder, it is built and then onboarded.
2319 overwrite
=overwrite
,
2320 skip_charm_build
=skip_charm_build
,
2321 override_epa
=override_epa
,
2322 override_nonepa
=override_nonepa
,
2323 override_paravirt
=override_paravirt
,
2330 @cli_osm.command(name
="ns-create", short_help
="creates a new Network Service instance")
2331 @click.option("--ns_name", prompt
=True, help="name of the NS instance")
2332 @click.option("--nsd_name", prompt
=True, help="name of the NS descriptor")
2336 help="default VIM account id or name for the deployment",
2338 @click.option("--admin_status", default
="ENABLED", help="administration status")
2342 help="comma separated list of public key files to inject to vnfs",
2344 @click.option("--config", default
=None, help="ns specific yaml configuration")
2345 @click.option("--config_file", default
=None, help="ns specific yaml configuration file")
2351 help="do not return the control immediately, but keep it "
2352 "until the operation is completed, or timeout",
2354 @click.option("--timeout", default
=None, help="ns deployment timeout")
2368 """creates a new NS instance"""
2372 check_client_version(ctx
.obj
, "--config_file")
2374 raise ClientException(
2375 '"--config" option is incompatible with "--config_file" option'
2377 with
open(config_file
, "r") as cf
:
2384 account
=vim_account
,
2388 # except ClientException as e:
2393 def nst_create(ctx
, filename
, overwrite
):
2396 check_client_version(ctx
.obj
, ctx
.command
.name
)
2397 ctx
.obj
.nst
.create(filename
, overwrite
)
2398 # except ClientException as e:
2404 name
="nst-create", short_help
="creates a new Network Slice Template (NST)"
2406 @click.argument("filename")
2410 default
=None, # hidden=True,
2411 help="Deprecated. Use override",
2417 help="overrides fields in descriptor, format: "
2418 '"key1.key2...=value[;key3...=value;...]"',
2421 def nst_create1(ctx
, filename
, overwrite
):
2422 """creates a new Network Slice Template (NST)
2424 FILENAME: NST package folder, NST yaml file or NSTpkg tar.gz file
2427 nst_create(ctx
, filename
, overwrite
)
2431 name
="netslice-template-create",
2432 short_help
="creates a new Network Slice Template (NST)",
2434 @click.argument("filename")
2438 default
=None, # hidden=True,
2439 help="Deprecated. Use override",
2445 help="overrides fields in descriptor, format: "
2446 '"key1.key2...=value[;key3...=value;...]"',
2449 def nst_create2(ctx
, filename
, overwrite
):
2450 """creates a new Network Slice Template (NST)
2452 FILENAME: NST yaml file or NSTpkg tar.gz file
2455 nst_create(ctx
, filename
, overwrite
)
2459 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2461 """creates a new Network Slice Instance (NSI)"""
2464 check_client_version(ctx
.obj
, ctx
.command
.name
)
2467 raise ClientException(
2468 '"--config" option is incompatible with "--config_file" option'
2470 with
open(config_file
, "r") as cf
:
2477 account
=vim_account
,
2480 # except ClientException as e:
2485 @cli_osm.command(name
="nsi-create", short_help
="creates a new Network Slice Instance")
2486 @click.option("--nsi_name", prompt
=True, help="name of the Network Slice Instance")
2487 @click.option("--nst_name", prompt
=True, help="name of the Network Slice Template")
2491 help="default VIM account id or name for the deployment",
2494 "--ssh_keys", default
=None, help="comma separated list of keys to inject to vnfs"
2499 help="Netslice specific yaml configuration:\n"
2500 "netslice_subnet: [\n"
2501 "id: TEXT, vim_account: TEXT,\n"
2502 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2503 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n"
2504 "additionalParamsForNsi: {param: value, ...}\n"
2505 "additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n"
2507 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2510 "--config_file", default
=None, help="nsi specific yaml configuration file"
2517 help="do not return the control immediately, but keep it "
2518 "until the operation is completed, or timeout",
2522 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2524 """creates a new Network Slice Instance (NSI)"""
2527 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
2532 name
="netslice-instance-create", short_help
="creates a new Network Slice Instance"
2534 @click.option("--nsi_name", prompt
=True, help="name of the Network Slice Instance")
2535 @click.option("--nst_name", prompt
=True, help="name of the Network Slice Template")
2539 help="default VIM account id or name for the deployment",
2542 "--ssh_keys", default
=None, help="comma separated list of keys to inject to vnfs"
2547 help="Netslice specific yaml configuration:\n"
2548 "netslice_subnet: [\n"
2549 "id: TEXT, vim_account: TEXT,\n"
2550 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2551 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]"
2553 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2556 "--config_file", default
=None, help="nsi specific yaml configuration file"
2563 help="do not return the control immediately, but keep it "
2564 "until the operation is completed, or timeout",
2568 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2570 """creates a new Network Slice Instance (NSI)"""
2573 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
2578 name
="pdu-create", short_help
="adds a new Physical Deployment Unit to the catalog"
2580 @click.option("--name", help="name of the Physical Deployment Unit")
2581 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2584 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2585 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2588 @click.option("--description", help="human readable description")
2591 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2592 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2593 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2597 "--descriptor_file",
2599 help="PDU descriptor file (as an alternative to using the other arguments)",
2603 ctx
, name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2605 """creates a new Physical Deployment Unit (PDU)"""
2608 check_client_version(ctx
.obj
, ctx
.command
.name
)
2610 pdu
= create_pdu_dictionary(
2611 name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2613 ctx
.obj
.pdu
.create(pdu
)
2616 ########################
2617 # UPDATE PDU operation #
2618 ########################
2622 name
="pdu-update", short_help
="updates a Physical Deployment Unit to the catalog"
2624 @click.argument("name")
2625 @click.option("--newname", help="New name for the Physical Deployment Unit")
2626 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2629 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2630 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2633 @click.option("--description", help="human readable description")
2636 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2637 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2638 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2642 "--descriptor_file",
2644 help="PDU descriptor file (as an alternative to using the other arguments)",
2648 ctx
, name
, newname
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2650 """Updates a new Physical Deployment Unit (PDU)"""
2653 check_client_version(ctx
.obj
, ctx
.command
.name
)
2660 pdu
= create_pdu_dictionary(
2661 newname
, pdu_type
, interface
, description
, vim_account
, descriptor_file
, update
2663 ctx
.obj
.pdu
.update(name
, pdu
)
2666 def create_pdu_dictionary(
2667 name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
, update
=False
2673 if not descriptor_file
:
2676 raise ClientException(
2677 'in absence of descriptor file, option "--name" is mandatory'
2680 raise ClientException(
2681 'in absence of descriptor file, option "--pdu_type" is mandatory'
2684 raise ClientException(
2685 'in absence of descriptor file, option "--interface" is mandatory (at least once)'
2688 raise ClientException(
2689 'in absence of descriptor file, option "--vim_account" is mandatory (at least once)'
2692 with
open(descriptor_file
, "r") as df
:
2693 pdu
= yaml
.safe_load(df
.read())
2697 pdu
["type"] = pdu_type
2699 pdu
["description"] = description
2701 pdu
["vim_accounts"] = vim_account
2704 for iface
in interface
:
2705 new_iface
= {k
: v
for k
, v
in [i
.split("=") for i
in iface
.split(",")]}
2706 new_iface
["mgmt"] = new_iface
.get("mgmt", "false").lower() == "true"
2707 ifaces_list
.append(new_iface
)
2708 pdu
["interfaces"] = ifaces_list
2712 ####################
2714 ####################
2717 def nsd_update(ctx
, name
, content
):
2720 check_client_version(ctx
.obj
, ctx
.command
.name
)
2721 ctx
.obj
.nsd
.update(name
, content
)
2722 # except ClientException as e:
2727 @cli_osm.command(name
="nsd-update", short_help
="updates a NSD/NSpkg")
2728 @click.argument("name")
2732 help="filename with the NSD/NSpkg replacing the current one",
2735 def nsd_update1(ctx
, name
, content
):
2736 """updates a NSD/NSpkg
2738 NAME: name or ID of the NSD/NSpkg
2741 nsd_update(ctx
, name
, content
)
2744 @cli_osm.command(name
="nspkg-update", short_help
="updates a NSD/NSpkg")
2745 @click.argument("name")
2749 help="filename with the NSD/NSpkg replacing the current one",
2752 def nsd_update2(ctx
, name
, content
):
2753 """updates a NSD/NSpkg
2755 NAME: name or ID of the NSD/NSpkg
2758 nsd_update(ctx
, name
, content
)
2761 def vnfd_update(ctx
, name
, content
):
2764 check_client_version(ctx
.obj
, ctx
.command
.name
)
2765 ctx
.obj
.vnfd
.update(name
, content
)
2766 # except ClientException as e:
2771 @cli_osm.command(name
="vnfd-update", short_help
="updates a new VNFD/VNFpkg")
2772 @click.argument("name")
2776 help="filename with the VNFD/VNFpkg replacing the current one",
2779 def vnfd_update1(ctx
, name
, content
):
2780 """updates a VNFD/VNFpkg
2782 NAME: name or ID of the VNFD/VNFpkg
2785 vnfd_update(ctx
, name
, content
)
2788 @cli_osm.command(name
="vnfpkg-update", short_help
="updates a VNFD/VNFpkg")
2789 @click.argument("name")
2793 help="filename with the VNFD/VNFpkg replacing the current one",
2796 def vnfd_update2(ctx
, name
, content
):
2797 """updates a VNFD/VNFpkg
2799 NAME: VNFD yaml file or VNFpkg tar.gz file
2802 vnfd_update(ctx
, name
, content
)
2805 @cli_osm.command(name
="nfpkg-update", short_help
="updates a NFpkg")
2806 @click.argument("name")
2808 "--content", default
=None, help="filename with the NFpkg replacing the current one"
2811 def nfpkg_update(ctx
, name
, content
):
2814 NAME: NF Descriptor yaml file or NFpkg tar.gz file
2817 vnfd_update(ctx
, name
, content
)
2820 def nst_update(ctx
, name
, content
):
2823 check_client_version(ctx
.obj
, ctx
.command
.name
)
2824 ctx
.obj
.nst
.update(name
, content
)
2825 # except ClientException as e:
2830 @cli_osm.command(name
="nst-update", short_help
="updates a Network Slice Template (NST)")
2831 @click.argument("name")
2835 help="filename with the NST/NSTpkg replacing the current one",
2838 def nst_update1(ctx
, name
, content
):
2839 """updates a Network Slice Template (NST)
2841 NAME: name or ID of the NSD/NSpkg
2844 nst_update(ctx
, name
, content
)
2848 name
="netslice-template-update", short_help
="updates a Network Slice Template (NST)"
2850 @click.argument("name")
2854 help="filename with the NST/NSTpkg replacing the current one",
2857 def nst_update2(ctx
, name
, content
):
2858 """updates a Network Slice Template (NST)
2860 NAME: name or ID of the NSD/NSpkg
2863 nst_update(ctx
, name
, content
)
2866 ####################
2868 ####################
2871 def nsd_delete(ctx
, name
, force
):
2875 ctx
.obj
.nsd
.delete(name
)
2877 check_client_version(ctx
.obj
, "--force")
2878 ctx
.obj
.nsd
.delete(name
, force
)
2879 # except ClientException as e:
2884 @cli_osm.command(name
="nsd-delete", short_help
="deletes a NSD/NSpkg")
2885 @click.argument("name")
2887 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2890 def nsd_delete1(ctx
, name
, force
):
2891 """deletes a NSD/NSpkg
2893 NAME: name or ID of the NSD/NSpkg to be deleted
2896 nsd_delete(ctx
, name
, force
)
2899 @cli_osm.command(name
="nspkg-delete", short_help
="deletes a NSD/NSpkg")
2900 @click.argument("name")
2902 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2905 def nsd_delete2(ctx
, name
, force
):
2906 """deletes a NSD/NSpkg
2908 NAME: name or ID of the NSD/NSpkg to be deleted
2911 nsd_delete(ctx
, name
, force
)
2914 def vnfd_delete(ctx
, name
, force
):
2918 ctx
.obj
.vnfd
.delete(name
)
2920 check_client_version(ctx
.obj
, "--force")
2921 ctx
.obj
.vnfd
.delete(name
, force
)
2922 # except ClientException as e:
2927 @cli_osm.command(name
="vnfd-delete", short_help
="deletes a VNFD/VNFpkg")
2928 @click.argument("name")
2930 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2933 def vnfd_delete1(ctx
, name
, force
):
2934 """deletes a VNFD/VNFpkg
2936 NAME: name or ID of the VNFD/VNFpkg to be deleted
2939 vnfd_delete(ctx
, name
, force
)
2942 @cli_osm.command(name
="vnfpkg-delete", short_help
="deletes a VNFD/VNFpkg")
2943 @click.argument("name")
2945 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2948 def vnfd_delete2(ctx
, name
, force
):
2949 """deletes a VNFD/VNFpkg
2951 NAME: name or ID of the VNFD/VNFpkg to be deleted
2954 vnfd_delete(ctx
, name
, force
)
2957 @cli_osm.command(name
="nfpkg-delete", short_help
="deletes a NFpkg")
2958 @click.argument("name")
2960 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2963 def nfpkg_delete(ctx
, name
, force
):
2966 NAME: name or ID of the NFpkg to be deleted
2969 vnfd_delete(ctx
, name
, force
)
2972 @cli_osm.command(name
="ns-delete", short_help
="deletes a NS instance")
2973 @click.argument("name")
2975 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2980 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
2981 "600, skip_terminate_primitives: True}'",
2988 help="do not return the control immediately, but keep it "
2989 "until the operation is completed, or timeout",
2992 def ns_delete(ctx
, name
, force
, config
, wait
):
2993 """deletes a NS instance
2995 NAME: name or ID of the NS instance to be deleted
3000 ctx
.obj
.ns
.delete(name
, config
=config
, wait
=wait
)
3002 check_client_version(ctx
.obj
, "--force")
3003 ctx
.obj
.ns
.delete(name
, force
, config
=config
, wait
=wait
)
3004 # except ClientException as e:
3009 def nst_delete(ctx
, name
, force
):
3012 check_client_version(ctx
.obj
, ctx
.command
.name
)
3013 ctx
.obj
.nst
.delete(name
, force
)
3014 # except ClientException as e:
3019 @cli_osm.command(name
="nst-delete", short_help
="deletes a Network Slice Template (NST)")
3020 @click.argument("name")
3022 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3025 def nst_delete1(ctx
, name
, force
):
3026 """deletes a Network Slice Template (NST)
3028 NAME: name or ID of the NST/NSTpkg to be deleted
3031 nst_delete(ctx
, name
, force
)
3035 name
="netslice-template-delete", short_help
="deletes a Network Slice Template (NST)"
3037 @click.argument("name")
3039 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3042 def nst_delete2(ctx
, name
, force
):
3043 """deletes a Network Slice Template (NST)
3045 NAME: name or ID of the NST/NSTpkg to be deleted
3048 nst_delete(ctx
, name
, force
)
3051 def nsi_delete(ctx
, name
, force
, wait
):
3054 check_client_version(ctx
.obj
, ctx
.command
.name
)
3055 ctx
.obj
.nsi
.delete(name
, force
, wait
=wait
)
3056 # except ClientException as e:
3061 @cli_osm.command(name
="nsi-delete", short_help
="deletes a Network Slice Instance (NSI)")
3062 @click.argument("name")
3064 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3071 help="do not return the control immediately, but keep it "
3072 "until the operation is completed, or timeout",
3075 def nsi_delete1(ctx
, name
, force
, wait
):
3076 """deletes a Network Slice Instance (NSI)
3078 NAME: name or ID of the Network Slice instance to be deleted
3081 nsi_delete(ctx
, name
, force
, wait
=wait
)
3085 name
="netslice-instance-delete", short_help
="deletes a Network Slice Instance (NSI)"
3087 @click.argument("name")
3089 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3092 def nsi_delete2(ctx
, name
, force
, wait
):
3093 """deletes a Network Slice Instance (NSI)
3095 NAME: name or ID of the Network Slice instance to be deleted
3098 nsi_delete(ctx
, name
, force
, wait
=wait
)
3102 name
="pdu-delete", short_help
="deletes a Physical Deployment Unit (PDU)"
3104 @click.argument("name")
3106 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3109 def pdu_delete(ctx
, name
, force
):
3110 """deletes a Physical Deployment Unit (PDU)
3112 NAME: name or ID of the PDU to be deleted
3116 check_client_version(ctx
.obj
, ctx
.command
.name
)
3117 ctx
.obj
.pdu
.delete(name
, force
)
3118 # except ClientException as e:
3128 @cli_osm.command(name
="vim-create", short_help
="creates a new VIM account")
3129 @click.option("--name", required
=True, help="Name to create datacenter")
3130 @click.option("--user", default
=None, help="VIM username")
3131 @click.option("--password", default
=None, help="VIM password")
3132 @click.option("--auth_url", default
=None, help="VIM url")
3133 @click.option("--tenant", "--project", "tenant", default
=None, help="VIM tenant/project name")
3134 @click.option("--config", default
=None, help="VIM specific config parameters")
3135 @click.option("--config_file", default
=None, help="VIM specific config parameters in YAML or JSON file")
3136 @click.option("--account_type", default
="openstack", help="VIM type")
3137 @click.option("--description", default
=None, help="human readable description")
3141 help="Name or id of the SDN controller associated to this VIM account",
3144 "--sdn_port_mapping",
3146 help="File describing the port mapping between compute nodes' ports and switch ports",
3153 help="do not return the control immediately, but keep it "
3154 "until the operation is completed, or timeout",
3156 @click.option("--vca", default
=None, help="VCA to be used in this VIM account")
3157 @click.option("--creds", default
=None, help="credentials file (only applycable for GCP VIM type)")
3158 @click.option("--prometheus_config_file", default
=None, help="Prometheus configuration to get VIM data")
3176 prometheus_config_file
3178 """creates a new VIM account"""
3182 check_client_version(ctx
.obj
, "--sdn_controller")
3183 if sdn_port_mapping
:
3184 check_client_version(ctx
.obj
, "--sdn_port_mapping")
3186 if prometheus_config_file
:
3187 with
open(prometheus_config_file
) as prometheus_file
:
3188 prometheus_config_dict
= json
.load(prometheus_file
)
3189 vim
["prometheus-config"] = prometheus_config_dict
3191 vim
["vim-username"] = user
3192 vim
["vim-password"] = password
3193 vim
["vim-url"] = auth_url
3194 vim
["vim-tenant-name"] = tenant
3195 vim
["vim-type"] = account_type
3196 vim
["description"] = description
3199 vim_config
= create_config(config_file
, config
)
3201 with
open(creds
, "r") as cf
:
3202 vim_config
["credentials"] = yaml
.safe_load(cf
.read())
3203 ctx
.obj
.vim
.create(name
, vim
, vim_config
, sdn_controller
, sdn_port_mapping
, wait
=wait
)
3204 # except ClientException as e:
3209 @cli_osm.command(name
="vim-update", short_help
="updates a VIM account")
3210 @click.argument("name")
3211 @click.option("--newname", help="New name for the VIM account")
3212 @click.option("--user", help="VIM username")
3213 @click.option("--password", help="VIM password")
3214 @click.option("--auth_url", help="VIM url")
3215 @click.option("--tenant", help="VIM tenant name")
3216 @click.option("--config", help="VIM specific config parameters")
3217 @click.option("--config_file", default
=None, help="VIM specific config parameters in YAML or JSON file")
3218 @click.option("--account_type", help="VIM type")
3219 @click.option("--description", help="human readable description")
3223 help="Name or id of the SDN controller to be associated with this VIM"
3224 "account. Use empty string to disassociate",
3227 "--sdn_port_mapping",
3229 help="File describing the port mapping between compute nodes' ports and switch ports",
3236 help="do not return the control immediately, but keep it "
3237 "until the operation is completed, or timeout",
3239 @click.option("--creds", default
=None, help="credentials file (only applycable for GCP VIM type)")
3240 @click.option("--prometheus_config_file", default
=None, help="Prometheus configuration to get VIM data")
3258 prometheus_config_file
3260 """updates a VIM account
3262 NAME: name or ID of the VIM account
3266 check_client_version(ctx
.obj
, ctx
.command
.name
)
3269 vim
["name"] = newname
3271 vim
["vim_user"] = user
3273 vim
["vim_password"] = password
3275 vim
["vim_url"] = auth_url
3277 vim
["vim-tenant-name"] = tenant
3279 vim
["vim_type"] = account_type
3281 vim
["description"] = description
3283 if config
or config_file
:
3284 vim_config
= create_config(config_file
, config
)
3286 with
open(creds
, "r") as cf
:
3287 vim_config
["credentials"] = yaml
.safe_load(cf
.read())
3288 if prometheus_config_file
:
3289 with
open(prometheus_config_file
) as prometheus_file
:
3290 prometheus_config_dict
= json
.load(prometheus_file
)
3291 vim
["prometheus-config"] = prometheus_config_dict
3292 logger
.info(f
"VIM: {vim}, VIM config: {vim_config}")
3293 ctx
.obj
.vim
.update(name
, vim
, vim_config
, sdn_controller
, sdn_port_mapping
, wait
=wait
)
3294 # except ClientException as e:
3299 @cli_osm.command(name
="vim-delete", short_help
="deletes a VIM account")
3300 @click.argument("name")
3302 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3309 help="do not return the control immediately, but keep it "
3310 "until the operation is completed, or timeout",
3313 def vim_delete(ctx
, name
, force
, wait
):
3314 """deletes a VIM account
3316 NAME: name or ID of the VIM account to be deleted
3321 ctx
.obj
.vim
.delete(name
, wait
=wait
)
3323 check_client_version(ctx
.obj
, "--force")
3324 ctx
.obj
.vim
.delete(name
, force
, wait
=wait
)
3325 # except ClientException as e:
3330 @cli_osm.command(name
="vim-list", short_help
="list all VIM accounts")
3331 # @click.option('--ro_update/--no_ro_update',
3333 # help='update list from RO')
3338 help="restricts the list to the VIM accounts matching the filter",
3343 help="get more details of the NS (project, vim, deployment status, configuration status.",
3346 def vim_list(ctx
, filter, long):
3347 """list all VIM accounts"""
3350 filter = "&".join(filter)
3351 check_client_version(ctx
.obj
, "--filter")
3353 # check_client_version(ctx.obj, '--ro_update', 'v1')
3354 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
3355 if fullclassname
== "osmclient.sol005.client.Client":
3356 resp
= ctx
.obj
.vim
.list(filter)
3358 # resp = ctx.obj.vim.list(ro_update)
3360 table
= PrettyTable(
3361 ["vim name", "uuid", "project", "operational state", "error details"]
3363 project_list
= ctx
.obj
.project
.list()
3365 table
= PrettyTable(["vim name", "uuid", "operational state"])
3368 if "vim_password" in vim
:
3369 vim
["vim_password"] = "********"
3370 if "config" in vim
and "credentials" in vim
["config"]:
3371 vim
["config"]["credentials"] = "********"
3372 logger
.debug("VIM details: {}".format(yaml
.safe_dump(vim
)))
3373 vim_state
= vim
["_admin"].get("operationalState", "-")
3374 error_details
= "N/A"
3375 if vim_state
== "ERROR":
3376 error_details
= vim
["_admin"].get("detailed-status", "Not found")
3377 project_id
, project_name
= get_project(project_list
, vim
)
3378 # project_info = '{} ({})'.format(project_name, project_id)
3379 project_info
= project_name
3386 wrap_text(text
=error_details
, width
=80),
3391 [vim
["name"], vim
["uuid"], vim
["_admin"].get("operationalState", "-")]
3397 @cli_osm.command(name
="vim-show", short_help
="shows the details of a VIM account")
3398 @click.argument("name")
3402 help="restricts the information to the fields in the filter",
3404 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
3406 def vim_show(ctx
, name
, filter, literal
):
3407 """shows the details of a VIM account
3409 NAME: name or ID of the VIM account
3413 resp
= ctx
.obj
.vim
.get(name
)
3414 if "vim_password" in resp
:
3415 resp
["vim_password"] = "********"
3416 if "config" in resp
and "credentials" in resp
["config"]:
3417 resp
["config"]["credentials"] = "********"
3418 # except ClientException as e:
3423 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
3425 table
= PrettyTable(["key", "attribute"])
3426 for k
, v
in list(resp
.items()):
3427 if not filter or k
in filter:
3428 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
3433 ####################
3435 ####################
3438 @cli_osm.command(name
="wim-create", short_help
="creates a new WIM account")
3439 @click.option("--name", prompt
=True, help="Name for the WIM account")
3440 @click.option("--user", help="WIM username")
3441 @click.option("--password", help="WIM password")
3442 @click.option("--url", prompt
=True, help="WIM url")
3443 # @click.option('--tenant',
3444 # help='wIM tenant name')
3445 @click.option("--config", default
=None, help="WIM specific config parameters")
3446 @click.option("--wim_type", help="WIM type")
3447 @click.option("--description", default
=None, help="human readable description")
3449 "--wim_port_mapping",
3451 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3452 "(WAN service endpoint id and info)",
3459 help="do not return the control immediately, but keep it "
3460 "until the operation is completed, or timeout",
3476 """creates a new WIM account"""
3479 check_client_version(ctx
.obj
, ctx
.command
.name
)
3480 # if sdn_controller:
3481 # check_client_version(ctx.obj, '--sdn_controller')
3482 # if sdn_port_mapping:
3483 # check_client_version(ctx.obj, '--sdn_port_mapping')
3488 wim
["password"] = password
3490 wim
["wim_url"] = url
3491 # if tenant: wim['tenant'] = tenant
3492 wim
["wim_type"] = wim_type
3494 wim
["description"] = description
3496 wim
["config"] = config
3497 ctx
.obj
.wim
.create(name
, wim
, wim_port_mapping
, wait
=wait
)
3498 # except ClientException as e:
3503 @cli_osm.command(name
="wim-update", short_help
="updates a WIM account")
3504 @click.argument("name")
3505 @click.option("--newname", help="New name for the WIM account")
3506 @click.option("--user", help="WIM username")
3507 @click.option("--password", help="WIM password")
3508 @click.option("--url", help="WIM url")
3509 @click.option("--config", help="WIM specific config parameters")
3510 @click.option("--wim_type", help="WIM type")
3511 @click.option("--description", help="human readable description")
3513 "--wim_port_mapping",
3515 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3516 "(WAN service endpoint id and info)",
3523 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3539 """updates a WIM account
3541 NAME: name or ID of the WIM account
3545 check_client_version(ctx
.obj
, ctx
.command
.name
)
3548 wim
["name"] = newname
3552 wim
["password"] = password
3555 # if tenant: wim['tenant'] = tenant
3557 wim
["wim_type"] = wim_type
3559 wim
["description"] = description
3561 wim
["config"] = config
3562 ctx
.obj
.wim
.update(name
, wim
, wim_port_mapping
, wait
=wait
)
3563 # except ClientException as e:
3568 @cli_osm.command(name
="wim-delete", short_help
="deletes a WIM account")
3569 @click.argument("name")
3571 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3578 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3581 def wim_delete(ctx
, name
, force
, wait
):
3582 """deletes a WIM account
3584 NAME: name or ID of the WIM account to be deleted
3588 check_client_version(ctx
.obj
, ctx
.command
.name
)
3589 ctx
.obj
.wim
.delete(name
, force
, wait
=wait
)
3590 # except ClientException as e:
3595 @cli_osm.command(name
="wim-list", short_help
="list all WIM accounts")
3600 help="restricts the list to the WIM accounts matching the filter",
3603 def wim_list(ctx
, filter):
3604 """list all WIM accounts"""
3607 check_client_version(ctx
.obj
, ctx
.command
.name
)
3609 filter = "&".join(filter)
3610 resp
= ctx
.obj
.wim
.list(filter)
3611 table
= PrettyTable(["wim name", "uuid"])
3613 table
.add_row([wim
["name"], wim
["uuid"]])
3616 # except ClientException as e:
3621 @cli_osm.command(name
="wim-show", short_help
="shows the details of a WIM account")
3622 @click.argument("name")
3624 def wim_show(ctx
, name
):
3625 """shows the details of a WIM account
3627 NAME: name or ID of the WIM account
3631 check_client_version(ctx
.obj
, ctx
.command
.name
)
3632 resp
= ctx
.obj
.wim
.get(name
)
3633 if "password" in resp
:
3634 resp
["wim_password"] = "********"
3635 # except ClientException as e:
3639 table
= PrettyTable(["key", "attribute"])
3640 for k
, v
in list(resp
.items()):
3641 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3646 ####################
3647 # SDN controller operations
3648 ####################
3651 @cli_osm.command(name
="sdnc-create", short_help
="creates a new SDN controller")
3652 @click.option("--name", prompt
=True, help="Name to create sdn controller")
3653 @click.option("--type", prompt
=True, help="SDN controller type")
3655 "--sdn_controller_version", # hidden=True,
3656 help="Deprecated. Use --config {version: sdn_controller_version}",
3658 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3659 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True,
3660 @click.option("--port", help="Deprecated. Use --url") # hidden=True,
3662 "--switch_dpid", help="Deprecated. Use --config {switch_id: DPID}" # hidden=True,
3666 help="Extra information for SDN in yaml format, as {switch_id: identity used for the plugin (e.g. DPID: "
3667 "Openflow Datapath ID), version: version}",
3669 @click.option("--user", help="SDN controller username")
3673 confirmation_prompt
=True,
3674 help="SDN controller password",
3676 @click.option("--description", default
=None, help="human readable description")
3682 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3685 def sdnc_create(ctx
, **kwargs
):
3686 """creates a new SDN controller"""
3691 if kwargs
[x
] and x
not in ("wait", "ip_address", "port", "switch_dpid")
3693 if kwargs
.get("port"):
3694 print("option '--port' is deprecated, use '--url' instead")
3695 sdncontroller
["port"] = int(kwargs
["port"])
3696 if kwargs
.get("ip_address"):
3697 print("option '--ip_address' is deprecated, use '--url' instead")
3698 sdncontroller
["ip"] = kwargs
["ip_address"]
3699 if kwargs
.get("switch_dpid"):
3701 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3703 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
3704 if kwargs
.get("sdn_controller_version"):
3706 "option '--sdn_controller_version' is deprecated, use '--config={version: SDN_CONTROLLER_VERSION}'"
3710 check_client_version(ctx
.obj
, ctx
.command
.name
)
3711 ctx
.obj
.sdnc
.create(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
3712 # except ClientException as e:
3717 @cli_osm.command(name
="sdnc-update", short_help
="updates an SDN controller")
3718 @click.argument("name")
3719 @click.option("--newname", help="New name for the SDN controller")
3720 @click.option("--description", default
=None, help="human readable description")
3721 @click.option("--type", help="SDN controller type")
3722 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3725 help="Extra information for SDN in yaml format, as "
3726 "{switch_id: identity used for the plugin (e.g. DPID: "
3727 "Openflow Datapath ID), version: version}",
3729 @click.option("--user", help="SDN controller username")
3730 @click.option("--password", help="SDN controller password")
3731 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True
3732 @click.option("--port", help="Deprecated. Use --url") # hidden=True
3734 "--switch_dpid", help="Deprecated. Use --config {switch_dpid: DPID}"
3737 "--sdn_controller_version", help="Deprecated. Use --config {version: VERSION}"
3744 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3747 def sdnc_update(ctx
, **kwargs
):
3748 """updates an SDN controller
3750 NAME: name or ID of the SDN controller
3757 and x
not in ("wait", "ip_address", "port", "switch_dpid", "new_name")
3759 if kwargs
.get("newname"):
3760 sdncontroller
["name"] = kwargs
["newname"]
3761 if kwargs
.get("port"):
3762 print("option '--port' is deprecated, use '--url' instead")
3763 sdncontroller
["port"] = int(kwargs
["port"])
3764 if kwargs
.get("ip_address"):
3765 print("option '--ip_address' is deprecated, use '--url' instead")
3766 sdncontroller
["ip"] = kwargs
["ip_address"]
3767 if kwargs
.get("switch_dpid"):
3769 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3771 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
3772 if kwargs
.get("sdn_controller_version"):
3774 "option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
3779 check_client_version(ctx
.obj
, ctx
.command
.name
)
3780 ctx
.obj
.sdnc
.update(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
3781 # except ClientException as e:
3786 @cli_osm.command(name
="sdnc-delete", short_help
="deletes an SDN controller")
3787 @click.argument("name")
3789 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3796 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3799 def sdnc_delete(ctx
, name
, force
, wait
):
3800 """deletes an SDN controller
3802 NAME: name or ID of the SDN controller to be deleted
3806 check_client_version(ctx
.obj
, ctx
.command
.name
)
3807 ctx
.obj
.sdnc
.delete(name
, force
, wait
=wait
)
3808 # except ClientException as e:
3813 @cli_osm.command(name
="sdnc-list", short_help
="list all SDN controllers")
3818 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'",
3821 def sdnc_list(ctx
, filter):
3822 """list all SDN controllers"""
3825 check_client_version(ctx
.obj
, ctx
.command
.name
)
3827 filter = "&".join(filter)
3828 resp
= ctx
.obj
.sdnc
.list(filter)
3829 # except ClientException as e:
3832 table
= PrettyTable(["sdnc name", "id"])
3834 table
.add_row([sdnc
["name"], sdnc
["_id"]])
3839 @cli_osm.command(name
="sdnc-show", short_help
="shows the details of an SDN controller")
3840 @click.argument("name")
3842 def sdnc_show(ctx
, name
):
3843 """shows the details of an SDN controller
3845 NAME: name or ID of the SDN controller
3849 check_client_version(ctx
.obj
, ctx
.command
.name
)
3850 resp
= ctx
.obj
.sdnc
.get(name
)
3851 # except ClientException as e:
3855 table
= PrettyTable(["key", "attribute"])
3856 for k
, v
in list(resp
.items()):
3857 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3862 ###########################
3863 # K8s cluster operations
3864 ###########################
3867 @cli_osm.command(name
="k8scluster-add", short_help
="adds a K8s cluster to OSM")
3868 @click.argument("name")
3870 "--creds", prompt
=True, help="credentials file, i.e. a valid `.kube/config` file"
3872 @click.option("--version", prompt
=True, help="Kubernetes version")
3874 "--vim", prompt
=True, help="VIM target, the VIM where the cluster resides"
3879 help='''list of VIM networks, in JSON inline format, where the cluster is
3880 accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3883 "--init-helm2/--skip-helm2",
3886 help="Initialize helm v2",
3889 "--init-helm3/--skip-helm3",
3892 help="Initialize helm v3",
3895 "--init-jujubundle/--skip-jujubundle",
3898 help="Initialize juju-bundle",
3900 @click.option("--description", default
=None, help="human readable description")
3903 default
="kube-system",
3904 help="namespace to be used for its operation, defaults to `kube-system`",
3911 help="do not return the control immediately, but keep it "
3912 "until the operation is completed, or timeout",
3917 help="list of CNI plugins, in JSON inline format, used in the cluster",
3919 # @click.option('--skip-init',
3921 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
3922 # @click.option('--wait',
3924 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3927 ctx
, name
, creds
, version
, vim
, k8s_nets
, init_helm2
, init_helm3
, init_jujubundle
, description
, namespace
, wait
, cni
3929 """adds a K8s cluster to OSM
3931 NAME: name of the K8s cluster
3934 check_client_version(ctx
.obj
, ctx
.command
.name
)
3936 cluster
["name"] = name
3937 with
open(creds
, "r") as cf
:
3938 cluster
["credentials"] = yaml
.safe_load(cf
.read())
3939 cluster
["k8s_version"] = version
3940 cluster
["vim_account"] = vim
3941 cluster
["nets"] = yaml
.safe_load(k8s_nets
)
3942 if not (init_helm2
and init_jujubundle
and init_helm3
):
3943 cluster
["deployment_methods"] = {"helm-chart": init_helm2
,
3944 "juju-bundle": init_jujubundle
,
3945 "helm-chart-v3": init_helm3
}
3947 cluster
["description"] = description
3949 cluster
["namespace"] = namespace
3951 cluster
["cni"] = yaml
.safe_load(cni
)
3952 ctx
.obj
.k8scluster
.create(name
, cluster
, wait
)
3953 # except ClientException as e:
3958 @cli_osm.command(name
="k8scluster-update", short_help
="updates a K8s cluster")
3959 @click.argument("name")
3960 @click.option("--newname", help="New name for the K8s cluster")
3961 @click.option("--creds", help="credentials file, i.e. a valid `.kube/config` file")
3962 @click.option("--version", help="Kubernetes version")
3963 @click.option("--vim", help="VIM target, the VIM where the cluster resides")
3966 help='''list of VIM networks, in JSON inline format, where the cluster is accessible
3967 via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3969 @click.option("--description", help="human readable description")
3972 help="namespace to be used for its operation, defaults to `kube-system`",
3979 help="do not return the control immediately, but keep it "
3980 "until the operation is completed, or timeout",
3983 "--cni", help="list of CNI plugins, in JSON inline format, used in the cluster"
3986 def k8scluster_update(
3987 ctx
, name
, newname
, creds
, version
, vim
, k8s_nets
, description
, namespace
, wait
, cni
3989 """updates a K8s cluster
3991 NAME: name or ID of the K8s cluster
3994 check_client_version(ctx
.obj
, ctx
.command
.name
)
3997 cluster
["name"] = newname
3999 with
open(creds
, "r") as cf
:
4000 cluster
["credentials"] = yaml
.safe_load(cf
.read())
4002 cluster
["k8s_version"] = version
4004 cluster
["vim_account"] = vim
4006 cluster
["nets"] = yaml
.safe_load(k8s_nets
)
4008 cluster
["description"] = description
4010 cluster
["namespace"] = namespace
4012 cluster
["cni"] = yaml
.safe_load(cni
)
4013 ctx
.obj
.k8scluster
.update(name
, cluster
, wait
)
4014 # except ClientException as e:
4019 @cli_osm.command(name
="k8scluster-delete", short_help
="deletes a K8s cluster")
4020 @click.argument("name")
4022 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4029 help="do not return the control immediately, but keep it "
4030 "until the operation is completed, or timeout",
4033 def k8scluster_delete(ctx
, name
, force
, wait
):
4034 """deletes a K8s cluster
4036 NAME: name or ID of the K8s cluster to be deleted
4039 check_client_version(ctx
.obj
, ctx
.command
.name
)
4040 ctx
.obj
.k8scluster
.delete(name
, force
, wait
)
4041 # except ClientException as e:
4046 @cli_osm.command(name
="k8scluster-list")
4051 help="restricts the list to the K8s clusters matching the filter",
4053 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4054 @click.option("--long", is_flag
=True, help="get more details")
4056 def k8scluster_list(ctx
, filter, literal
, long):
4057 """list all K8s clusters"""
4059 check_client_version(ctx
.obj
, ctx
.command
.name
)
4061 filter = "&".join(filter)
4062 resp
= ctx
.obj
.k8scluster
.list(filter)
4064 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4067 table
= PrettyTable(
4075 "Deployment methods",
4076 "Operational State",
4077 "Op. state (details)",
4082 project_list
= ctx
.obj
.project
.list()
4084 table
= PrettyTable(
4085 ["Name", "Id", "VIM", "Operational State", "Op. state details"]
4088 vim_list
= ctx
.obj
.vim
.list()
4091 for cluster
in resp
:
4092 logger
.debug("Cluster details: {}".format(yaml
.safe_dump(cluster
)))
4093 vim_name
= get_vim_name(vim_list
, cluster
["vim_account"])
4094 # vim_info = '{} ({})'.format(vim_name,cluster['vim_account'])
4096 op_state_details
= "Helm: {}\nJuju: {}".format(
4097 cluster
["_admin"].get("helm-chart", {}).get("operationalState", "-"),
4098 cluster
["_admin"].get("juju-bundle", {}).get("operationalState", "-"),
4101 project_id
, project_name
= get_project(project_list
, cluster
)
4102 # project_info = '{} ({})'.format(project_name, project_id)
4103 project_info
= project_name
4104 detailed_status
= cluster
["_admin"].get("detailed-status", "-")
4110 cluster
["k8s_version"],
4112 json
.dumps(cluster
["nets"]),
4113 json
.dumps(cluster
["deployment_methods"]),
4114 cluster
["_admin"]["operationalState"],
4116 trunc_text(cluster
.get("description") or "", 40),
4117 wrap_text(text
=detailed_status
, width
=40),
4126 cluster
["_admin"]["operationalState"],
4132 # except ClientException as e:
4138 name
="k8scluster-show", short_help
="shows the details of a K8s cluster"
4140 @click.argument("name")
4141 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4143 def k8scluster_show(ctx
, name
, literal
):
4144 """shows the details of a K8s cluster
4146 NAME: name or ID of the K8s cluster
4149 resp
= ctx
.obj
.k8scluster
.get(name
)
4151 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4153 table
= PrettyTable(["key", "attribute"])
4154 for k
, v
in list(resp
.items()):
4155 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
4158 # except ClientException as e:
4163 ###########################
4165 ###########################
4168 @cli_osm.command(name
="vca-add", short_help
="adds a VCA (Juju controller) to OSM")
4169 @click.argument("name")
4173 help="Comma-separated list of IP or hostnames of the Juju controller",
4175 @click.option("--user", prompt
=True, help="Username with admin priviledges")
4176 @click.option("--secret", prompt
=True, help="Password of the specified username")
4177 @click.option("--cacert", prompt
=True, help="CA certificate")
4181 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4184 "--lxd-credentials",
4186 help="Name of the cloud credentialsto be used for the LXD cloud",
4191 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4194 "--k8s-credentials",
4196 help="Name of the cloud credentialsto be used for the K8s cloud",
4201 help="Configuration options for the models",
4203 @click.option("--description", default
=None, help="human readable description")
4219 """adds a VCA to OSM
4221 NAME: name of the VCA
4223 check_client_version(ctx
.obj
, ctx
.command
.name
)
4226 vca
["endpoints"] = endpoints
.split(",")
4228 vca
["secret"] = secret
4229 vca
["cacert"] = cacert
4230 vca
["lxd-cloud"] = lxd_cloud
4231 vca
["lxd-credentials"] = lxd_credentials
4232 vca
["k8s-cloud"] = k8s_cloud
4233 vca
["k8s-credentials"] = k8s_credentials
4235 vca
["description"] = description
4237 model_config
= load(model_config
)
4238 vca
["model-config"] = model_config
4239 ctx
.obj
.vca
.create(name
, vca
)
4242 def load(data
: Any
):
4243 if os
.path
.isfile(data
):
4244 return load_file(data
)
4247 return json
.loads(data
)
4248 except ValueError as e
:
4249 raise ClientException(e
)
4252 def load_file(file_path
: str) -> Dict
:
4254 with
open(file_path
, "r") as f
:
4257 return yaml
.safe_load(content
)
4258 except yaml
.scanner
.ScannerError
:
4261 return json
.loads(content
)
4264 raise ClientException(f
"{file_path} must be a valid yaml or json file")
4267 @cli_osm.command(name
="vca-update", short_help
="updates a K8s cluster")
4268 @click.argument("name")
4270 "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
4272 @click.option("--user", help="Username with admin priviledges")
4273 @click.option("--secret", help="Password of the specified username")
4274 @click.option("--cacert", help="CA certificate")
4277 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4280 "--lxd-credentials",
4281 help="Name of the cloud credentialsto be used for the LXD cloud",
4285 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4288 "--k8s-credentials",
4289 help="Name of the cloud credentialsto be used for the K8s cloud",
4293 help="Configuration options for the models",
4295 @click.option("--description", default
=None, help="human readable description")
4311 """updates a K8s cluster
4313 NAME: name or ID of the K8s cluster
4315 check_client_version(ctx
.obj
, ctx
.command
.name
)
4319 vca
["endpoints"] = endpoints
.split(",")
4323 vca
["secret"] = secret
4325 vca
["cacert"] = cacert
4327 vca
["lxd-cloud"] = lxd_cloud
4329 vca
["lxd-credentials"] = lxd_credentials
4331 vca
["k8s-cloud"] = k8s_cloud
4333 vca
["k8s-credentials"] = k8s_credentials
4335 vca
["description"] = description
4337 model_config
= load(model_config
)
4338 vca
["model-config"] = model_config
4339 ctx
.obj
.vca
.update(name
, vca
)
4342 @cli_osm.command(name
="vca-delete", short_help
="deletes a K8s cluster")
4343 @click.argument("name")
4345 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4348 def vca_delete(ctx
, name
, force
):
4349 """deletes a K8s cluster
4351 NAME: name or ID of the K8s cluster to be deleted
4353 check_client_version(ctx
.obj
, ctx
.command
.name
)
4354 ctx
.obj
.vca
.delete(name
, force
=force
)
4357 @cli_osm.command(name
="vca-list")
4362 help="restricts the list to the VCAs matching the filter",
4364 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4365 @click.option("--long", is_flag
=True, help="get more details")
4367 def vca_list(ctx
, filter, literal
, long):
4369 check_client_version(ctx
.obj
, ctx
.command
.name
)
4371 filter = "&".join(filter)
4372 resp
= ctx
.obj
.vca
.list(filter)
4374 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4377 table
= PrettyTable(
4378 ["Name", "Id", "Project", "Operational State", "Detailed Status"]
4380 project_list
= ctx
.obj
.project
.list()
4382 table
= PrettyTable(["Name", "Id", "Operational State"])
4384 logger
.debug("VCA details: {}".format(yaml
.safe_dump(vca
)))
4386 project_id
, project_name
= get_project(project_list
, vca
)
4387 detailed_status
= vca
.get("_admin", {}).get("detailed-status", "-")
4393 vca
.get("_admin", {}).get("operationalState", "-"),
4394 wrap_text(text
=detailed_status
, width
=40),
4402 vca
.get("_admin", {}).get("operationalState", "-"),
4409 @cli_osm.command(name
="vca-show", short_help
="shows the details of a K8s cluster")
4410 @click.argument("name")
4411 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4413 def vca_show(ctx
, name
, literal
):
4414 """shows the details of a K8s cluster
4416 NAME: name or ID of the K8s cluster
4419 resp
= ctx
.obj
.vca
.get(name
)
4421 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4423 table
= PrettyTable(["key", "attribute"])
4424 for k
, v
in list(resp
.items()):
4425 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
4430 ###########################
4432 ###########################
4435 @cli_osm.command(name
="repo-add", short_help
="adds a repo to OSM")
4436 @click.argument("name")
4437 @click.argument("uri")
4440 type=click
.Choice(["helm-chart", "juju-bundle", "osm"]),
4442 help="type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles, osm for OSM Repositories)",
4444 @click.option("--description", default
=None, help="human readable description")
4446 "--user", default
=None, help="OSM repository: The username of the OSM repository"
4451 help="OSM repository: The password of the OSM repository",
4453 # @click.option('--wait',
4455 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4457 def repo_add(ctx
, **kwargs
):
4458 """adds a repo to OSM
4460 NAME: name of the repo
4461 URI: URI of the repo
4464 kwargs
= {k
: v
for k
, v
in kwargs
.items() if v
is not None}
4466 repo
["url"] = repo
.pop("uri")
4467 if repo
["type"] in ["helm-chart", "juju-bundle"]:
4468 ctx
.obj
.repo
.create(repo
["name"], repo
)
4470 ctx
.obj
.osmrepo
.create(repo
["name"], repo
)
4471 # except ClientException as e:
4476 @cli_osm.command(name
="repo-update", short_help
="updates a repo in OSM")
4477 @click.argument("name")
4478 @click.option("--newname", help="New name for the repo")
4479 @click.option("--uri", help="URI of the repo")
4480 @click.option("--description", help="human readable description")
4481 # @click.option('--wait',
4483 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4485 def repo_update(ctx
, name
, newname
, uri
, description
):
4486 """updates a repo in OSM
4488 NAME: name of the repo
4491 check_client_version(ctx
.obj
, ctx
.command
.name
)
4494 repo
["name"] = newname
4498 repo
["description"] = description
4500 ctx
.obj
.repo
.update(name
, repo
)
4502 ctx
.obj
.osmrepo
.update(name
, repo
)
4504 # except ClientException as e:
4510 name
="repo-index", short_help
="Index a repository from a folder with artifacts"
4513 "--origin", default
=".", help="origin path where the artifacts are located"
4516 "--destination", default
=".", help="destination path where the index is deployed"
4519 def repo_index(ctx
, origin
, destination
):
4520 """Index a repository
4522 NAME: name or ID of the repo to be deleted
4524 check_client_version(ctx
.obj
, ctx
.command
.name
)
4525 ctx
.obj
.osmrepo
.repo_index(origin
, destination
)
4528 @cli_osm.command(name
="repo-delete", short_help
="deletes a repo")
4529 @click.argument("name")
4531 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4533 # @click.option('--wait',
4535 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4537 def repo_delete(ctx
, name
, force
):
4540 NAME: name or ID of the repo to be deleted
4544 ctx
.obj
.repo
.delete(name
, force
=force
)
4546 ctx
.obj
.osmrepo
.delete(name
, force
=force
)
4547 # except ClientException as e:
4552 @cli_osm.command(name
="repo-list")
4557 help="restricts the list to the repos matching the filter",
4559 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4561 def repo_list(ctx
, filter, literal
):
4562 """list all repos"""
4565 check_client_version(ctx
.obj
, ctx
.command
.name
)
4567 filter = "&".join(filter)
4568 resp
= ctx
.obj
.repo
.list(filter)
4569 resp
+= ctx
.obj
.osmrepo
.list(filter)
4571 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4573 table
= PrettyTable(["Name", "Id", "Type", "URI", "Description"])
4575 # cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
4582 trunc_text(repo
.get("description") or "", 40),
4588 # except ClientException as e:
4593 @cli_osm.command(name
="repo-show", short_help
="shows the details of a repo")
4594 @click.argument("name")
4595 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4597 def repo_show(ctx
, name
, literal
):
4598 """shows the details of a repo
4600 NAME: name or ID of the repo
4603 resp
= ctx
.obj
.repo
.get(name
)
4605 resp
= ctx
.obj
.osmrepo
.get(name
)
4609 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4611 table
= PrettyTable(["key", "attribute"])
4613 for k
, v
in list(resp
.items()):
4614 table
.add_row([k
, json
.dumps(v
, indent
=2)])
4618 # except ClientException as e:
4623 ####################
4624 # Project mgmt operations
4625 ####################
4628 @cli_osm.command(name
="project-create", short_help
="creates a new project")
4629 @click.argument("name")
4630 # @click.option('--description',
4631 # default='no description',
4632 # help='human readable description')
4633 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
4639 help="provide quotas. Can be used several times: 'quota1=number[,quota2=number,...]'. Quotas can be one "
4640 "of vnfds, nsds, nsts, pdus, nsrs, nsis, vim_accounts, wim_accounts, sdns, k8sclusters, k8srepos",
4643 def project_create(ctx
, name
, domain_name
, quotas
):
4644 """Creates a new project
4646 NAME: name of the project
4647 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
4648 QUOTAS: set quotas for the project
4651 project
= {"name": name
}
4653 project
["domain_name"] = domain_name
4654 quotas_dict
= _process_project_quotas(quotas
)
4656 project
["quotas"] = quotas_dict
4659 check_client_version(ctx
.obj
, ctx
.command
.name
)
4660 ctx
.obj
.project
.create(name
, project
)
4661 # except ClientException as e:
4666 def _process_project_quotas(quota_list
):
4671 for quota
in quota_list
:
4672 for single_quota
in quota
.split(","):
4673 k
, v
= single_quota
.split("=")
4674 quotas_dict
[k
] = None if v
in ("None", "null", "") else int(v
)
4675 except (ValueError, TypeError):
4676 raise ClientException(
4677 "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
4682 @cli_osm.command(name
="project-delete", short_help
="deletes a project")
4683 @click.argument("name")
4684 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4686 def project_delete(ctx
, name
):
4687 """deletes a project
4689 NAME: name or ID of the project to be deleted
4693 check_client_version(ctx
.obj
, ctx
.command
.name
)
4694 ctx
.obj
.project
.delete(name
)
4695 # except ClientException as e:
4700 @cli_osm.command(name
="project-list", short_help
="list all projects")
4705 help="restricts the list to the projects matching the filter",
4708 def project_list(ctx
, filter):
4709 """list all projects"""
4712 check_client_version(ctx
.obj
, ctx
.command
.name
)
4714 filter = "&".join(filter)
4715 resp
= ctx
.obj
.project
.list(filter)
4716 # except ClientException as e:
4719 table
= PrettyTable(["name", "id"])
4721 table
.add_row([proj
["name"], proj
["_id"]])
4726 @cli_osm.command(name
="project-show", short_help
="shows the details of a project")
4727 @click.argument("name")
4729 def project_show(ctx
, name
):
4730 """shows the details of a project
4732 NAME: name or ID of the project
4736 check_client_version(ctx
.obj
, ctx
.command
.name
)
4737 resp
= ctx
.obj
.project
.get(name
)
4738 # except ClientException as e:
4742 table
= PrettyTable(["key", "attribute"])
4743 for k
, v
in resp
.items():
4744 table
.add_row([k
, json
.dumps(v
, indent
=2)])
4750 name
="project-update", short_help
="updates a project (only the name can be updated)"
4752 @click.argument("project")
4753 @click.option("--name", default
=None, help="new name for the project")
4759 help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
4760 "(use empty to reset quota to default",
4763 def project_update(ctx
, project
, name
, quotas
):
4765 Update a project name
4768 :param project: id or name of the project to modify
4769 :param name: new name for the project
4770 :param quotas: change quotas of the project
4774 project_changes
= {}
4776 project_changes
["name"] = name
4777 quotas_dict
= _process_project_quotas(quotas
)
4779 project_changes
["quotas"] = quotas_dict
4782 check_client_version(ctx
.obj
, ctx
.command
.name
)
4783 ctx
.obj
.project
.update(project
, project_changes
)
4784 # except ClientException as e:
4788 ####################
4789 # User mgmt operations
4790 ####################
4793 @cli_osm.command(name
="user-create", short_help
="creates a new user")
4794 @click.argument("username")
4799 confirmation_prompt
=True,
4800 help="user password",
4804 # prompt="Comma separate list of projects",
4806 callback
=lambda ctx
, param
, value
: "".join(value
).split(",")
4807 if all(len(x
) == 1 for x
in value
)
4809 help="list of project ids that the user belongs to",
4812 "--project-role-mappings",
4813 "project_role_mappings",
4816 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4818 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
4820 def user_create(ctx
, username
, password
, projects
, project_role_mappings
, domain_name
):
4821 """Creates a new user
4824 USERNAME: name of the user
4825 PASSWORD: password of the user
4826 PROJECTS: projects assigned to user (internal only)
4827 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
4828 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
4832 user
["username"] = username
4833 user
["password"] = password
4834 user
["projects"] = projects
4835 user
["project_role_mappings"] = project_role_mappings
4837 user
["domain_name"] = domain_name
4840 check_client_version(ctx
.obj
, ctx
.command
.name
)
4841 ctx
.obj
.user
.create(username
, user
)
4842 # except ClientException as e:
4847 @cli_osm.command(name
="user-update", short_help
="updates user information")
4848 @click.argument("username")
4853 # confirmation_prompt=True,
4854 help="user password",
4856 @click.option("--set-username", "set_username", default
=None, help="change username")
4862 help="create/replace the roles for this project: 'project,role1[,role2,...]'",
4869 help="removes project from user: 'project'",
4872 "--add-project-role",
4876 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4879 "--remove-project-role",
4880 "remove_project_role",
4883 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4886 "--change_password",
4888 help="user's current password"
4893 help="user's new password to update in expiry condition"
4904 remove_project_role
,
4908 """Update a user information
4911 USERNAME: name of the user
4912 PASSWORD: new password
4913 SET_USERNAME: new username
4914 SET_PROJECT: creating mappings for project/role(s)
4915 REMOVE_PROJECT: deleting mappings for project/role(s)
4916 ADD_PROJECT_ROLE: adding mappings for project/role(s)
4917 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
4918 CHANGE_PASSWORD: user's current password to change
4919 NEW_PASSWORD: user's new password to update in expiry condition
4923 user
["password"] = password
4924 user
["username"] = set_username
4925 user
["set-project"] = set_project
4926 user
["remove-project"] = remove_project
4927 user
["add-project-role"] = add_project_role
4928 user
["remove-project-role"] = remove_project_role
4929 user
["change_password"] = change_password
4930 user
["new_password"] = new_password
4933 check_client_version(ctx
.obj
, ctx
.command
.name
)
4934 if not user
.get("change_password"):
4935 ctx
.obj
.user
.update(username
, user
)
4937 ctx
.obj
.user
.update(username
, user
, pwd_change
=True)
4938 # except ClientException as e:
4943 @cli_osm.command(name
="user-delete", short_help
="deletes a user")
4944 @click.argument("name")
4945 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4947 def user_delete(ctx
, name
):
4951 NAME: name or ID of the user to be deleted
4955 check_client_version(ctx
.obj
, ctx
.command
.name
)
4956 ctx
.obj
.user
.delete(name
)
4957 # except ClientException as e:
4962 @cli_osm.command(name
="user-list", short_help
="list all users")
4967 help="restricts the list to the users matching the filter",
4970 def user_list(ctx
, filter):
4971 """list all users"""
4973 check_client_version(ctx
.obj
, ctx
.command
.name
)
4975 filter = "&".join(filter)
4976 resp
= ctx
.obj
.user
.list(filter)
4977 # except ClientException as e:
4980 table
= PrettyTable(["name", "id"])
4982 table
.add_row([user
["username"], user
["_id"]])
4987 @cli_osm.command(name
="user-show", short_help
="shows the details of a user")
4988 @click.argument("name")
4990 def user_show(ctx
, name
):
4991 """shows the details of a user
4993 NAME: name or ID of the user
4997 check_client_version(ctx
.obj
, ctx
.command
.name
)
4998 resp
= ctx
.obj
.user
.get(name
)
4999 if "password" in resp
:
5000 resp
["password"] = "********"
5001 # except ClientException as e:
5005 table
= PrettyTable(["key", "attribute"])
5006 for k
, v
in resp
.items():
5007 table
.add_row([k
, json
.dumps(v
, indent
=2)])
5012 ####################
5013 # Fault Management operations
5014 ####################
5017 @cli_osm.command(name
="ns-alarm-create")
5018 @click.argument("name")
5019 @click.option("--ns", prompt
=True, help="NS instance id or name")
5021 "--vnf", prompt
=True, help="VNF name (VNF member index as declared in the NSD)"
5023 @click.option("--vdu", prompt
=True, help="VDU name (VDU name as declared in the VNFD)")
5024 @click.option("--metric", prompt
=True, help="Name of the metric (e.g. cpu_utilization)")
5028 help="severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)",
5031 "--threshold_value",
5033 help="threshold value that, when crossed, an alarm is triggered",
5036 "--threshold_operator",
5038 help="threshold operator describing the comparison (GE, LE, GT, LT, EQ)",
5043 help="statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)",
5046 def ns_alarm_create(
5058 """creates a new alarm for a NS instance"""
5059 # TODO: Check how to validate threshold_value.
5060 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
5063 ns_instance
= ctx
.obj
.ns
.get(ns
)
5065 alarm
["alarm_name"] = name
5066 alarm
["ns_id"] = ns_instance
["_id"]
5067 alarm
["correlation_id"] = ns_instance
["_id"]
5068 alarm
["vnf_member_index"] = vnf
5069 alarm
["vdu_name"] = vdu
5070 alarm
["metric_name"] = metric
5071 alarm
["severity"] = severity
5072 alarm
["threshold_value"] = int(threshold_value
)
5073 alarm
["operation"] = threshold_operator
5074 alarm
["statistic"] = statistic
5075 check_client_version(ctx
.obj
, ctx
.command
.name
)
5076 ctx
.obj
.ns
.create_alarm(alarm
)
5077 # except ClientException as e:
5082 # @cli_osm.command(name='ns-alarm-delete')
5083 # @click.argument('name')
5084 # @click.pass_context
5085 # def ns_alarm_delete(ctx, name):
5086 # """deletes an alarm
5088 # NAME: name of the alarm to be deleted
5091 # check_client_version(ctx.obj, ctx.command.name)
5092 # ctx.obj.ns.delete_alarm(name)
5093 # except ClientException as e:
5098 ####################
5099 # Performance Management operations
5100 ####################
5104 name
="ns-metric-export",
5105 short_help
="exports a metric to the internal OSM bus, which can be read by other apps",
5107 @click.option("--ns", prompt
=True, help="NS instance id or name")
5109 "--vnf", prompt
=True, help="VNF name (VNF member index as declared in the NSD)"
5111 @click.option("--vdu", prompt
=True, help="VDU name (VDU name as declared in the VNFD)")
5112 @click.option("--metric", prompt
=True, help="name of the metric (e.g. cpu_utilization)")
5113 # @click.option('--period', default='1w',
5114 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
5116 "--interval", help="periodic interval (seconds) to export metrics continuously"
5119 def ns_metric_export(ctx
, ns
, vnf
, vdu
, metric
, interval
):
5120 """exports a metric to the internal OSM bus, which can be read by other apps"""
5121 # TODO: Check how to validate interval.
5122 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
5125 ns_instance
= ctx
.obj
.ns
.get(ns
)
5127 metric_data
["ns_id"] = ns_instance
["_id"]
5128 metric_data
["correlation_id"] = ns_instance
["_id"]
5129 metric_data
["vnf_member_index"] = vnf
5130 metric_data
["vdu_name"] = vdu
5131 metric_data
["metric_name"] = metric
5132 metric_data
["collection_unit"] = "WEEK"
5133 metric_data
["collection_period"] = 1
5134 check_client_version(ctx
.obj
, ctx
.command
.name
)
5136 print("{}".format(ctx
.obj
.ns
.export_metric(metric_data
)))
5140 print("{} {}".format(ctx
.obj
.ns
.export_metric(metric_data
), i
))
5141 time
.sleep(int(interval
))
5143 # except ClientException as e:
5149 # Subscription operations
5154 name
="subscription-create",
5155 short_help
="creates a new subscription to a specific event",
5159 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5160 type=click
.Choice(["ns"], case_sensitive
=False),
5161 help="event type to be subscribed (for the moment, only ns is supported)",
5163 @click.option("--event", default
=None, help="specific yaml configuration for the event")
5165 "--event_file", default
=None, help="specific yaml configuration file for the event"
5168 def subscription_create(ctx
, event_type
, event
, event_file
):
5169 """creates a new subscription to a specific event"""
5171 check_client_version(ctx
.obj
, ctx
.command
.name
)
5174 raise ClientException(
5175 '"--event" option is incompatible with "--event_file" option'
5177 with
open(event_file
, "r") as cf
:
5179 ctx
.obj
.subscription
.create(event_type
, event
)
5182 @cli_osm.command(name
="subscription-delete", short_help
="deletes a subscription")
5185 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5186 type=click
.Choice(["ns"], case_sensitive
=False),
5187 help="event type to be subscribed (for the moment, only ns is supported)",
5189 @click.argument("subscription_id")
5191 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
5194 def subscription_delete(ctx
, event_type
, subscription_id
, force
):
5195 """deletes a subscription
5197 SUBSCRIPTION_ID: ID of the subscription to be deleted
5200 check_client_version(ctx
.obj
, ctx
.command
.name
)
5201 ctx
.obj
.subscription
.delete(event_type
, subscription_id
, force
)
5204 @cli_osm.command(name
="subscription-list", short_help
="list all subscriptions")
5207 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5208 type=click
.Choice(["ns"], case_sensitive
=False),
5209 help="event type to be subscribed (for the moment, only ns is supported)",
5215 help="restricts the list to the subscriptions matching the filter",
5218 def subscription_list(ctx
, event_type
, filter):
5219 """list all subscriptions"""
5221 check_client_version(ctx
.obj
, ctx
.command
.name
)
5223 filter = "&".join(filter)
5224 resp
= ctx
.obj
.subscription
.list(event_type
, filter)
5225 table
= PrettyTable(["id", "filter", "CallbackUri"])
5230 wrap_text(text
=json
.dumps(sub
["filter"], indent
=2), width
=70),
5239 name
="subscription-show", short_help
="shows the details of a subscription"
5241 @click.argument("subscription_id")
5244 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5245 type=click
.Choice(["ns"], case_sensitive
=False),
5246 help="event type to be subscribed (for the moment, only ns is supported)",
5251 help="restricts the information to the fields in the filter",
5254 def subscription_show(ctx
, event_type
, subscription_id
, filter):
5255 """shows the details of a subscription
5257 SUBSCRIPTION_ID: ID of the subscription
5261 resp
= ctx
.obj
.subscription
.get(subscription_id
)
5262 table
= PrettyTable(["key", "attribute"])
5263 for k
, v
in list(resp
.items()):
5264 if not filter or k
in filter:
5265 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
5270 ####################
5272 ####################
5275 @cli_osm.command(name
="version", short_help
="shows client and server versions")
5277 def get_version(ctx
):
5278 """shows client and server versions"""
5280 check_client_version(ctx
.obj
, "version")
5281 print("Server version: {}".format(ctx
.obj
.get_version()))
5283 "Client version: {}".format(pkg_resources
.get_distribution("osmclient").version
)
5285 # except ClientException as e:
5291 name
="upload-package", short_help
="uploads a VNF package or NS package"
5293 @click.argument("filename")
5295 "--skip-charm-build",
5298 help="the charm will not be compiled, it is assumed to already exist",
5301 def upload_package(ctx
, filename
, skip_charm_build
):
5302 """uploads a vnf package or ns package
5304 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
5308 ctx
.obj
.package
.upload(filename
, skip_charm_build
=skip_charm_build
)
5309 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
5310 if fullclassname
!= "osmclient.sol005.client.Client":
5311 ctx
.obj
.package
.wait_for_upload(filename
)
5312 # except ClientException as e:
5317 # @cli_osm.command(name='ns-scaling-show')
5318 # @click.argument('ns_name')
5319 # @click.pass_context
5320 # def show_ns_scaling(ctx, ns_name):
5321 # """shows the status of a NS scaling operation
5323 # NS_NAME: name of the NS instance being scaled
5326 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5327 # resp = ctx.obj.ns.list()
5328 # except ClientException as e:
5332 # table = PrettyTable(
5335 # 'operational status',
5340 # if ns_name == ns['name']:
5341 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
5342 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
5343 # for record in scaling_records:
5344 # if 'instance' in record:
5345 # instances = record['instance']
5346 # for inst in instances:
5348 # [record['scaling-group-name-ref'],
5349 # inst['instance-id'],
5350 # inst['op-status'],
5351 # time.strftime('%Y-%m-%d %H:%M:%S',
5353 # inst['create-time'])),
5359 # @cli_osm.command(name='ns-scale')
5360 # @click.argument('ns_name')
5361 # @click.option('--ns_scale_group', prompt=True)
5362 # @click.option('--index', prompt=True)
5363 # @click.option('--wait',
5367 # help='do not return the control immediately, but keep it \
5368 # until the operation is completed, or timeout')
5369 # @click.pass_context
5370 # def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
5373 # NS_NAME: name of the NS instance to be scaled
5376 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5377 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
5378 # except ClientException as e:
5383 # @cli_osm.command(name='config-agent-list')
5384 # @click.pass_context
5385 # def config_agent_list(ctx):
5386 # """list config agents"""
5388 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5389 # except ClientException as e:
5392 # table = PrettyTable(['name', 'account-type', 'details'])
5393 # for account in ctx.obj.vca.list():
5396 # account['account-type'],
5402 # @cli_osm.command(name='config-agent-delete')
5403 # @click.argument('name')
5404 # @click.pass_context
5405 # def config_agent_delete(ctx, name):
5406 # """deletes a config agent
5408 # NAME: name of the config agent to be deleted
5411 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5412 # ctx.obj.vca.delete(name)
5413 # except ClientException as e:
5418 # @cli_osm.command(name='config-agent-add')
5419 # @click.option('--name',
5421 # @click.option('--account_type',
5423 # @click.option('--server',
5425 # @click.option('--user',
5427 # @click.option('--secret',
5430 # confirmation_prompt=True)
5431 # @click.pass_context
5432 # def config_agent_add(ctx, name, account_type, server, user, secret):
5433 # """adds a config agent"""
5435 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5436 # ctx.obj.vca.create(name, account_type, server, user, secret)
5437 # except ClientException as e:
5442 # @cli_osm.command(name='ro-dump')
5443 # @click.pass_context
5445 # """shows RO agent information"""
5446 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5447 # resp = ctx.obj.vim.get_resource_orchestrator()
5448 # table = PrettyTable(['key', 'attribute'])
5449 # for k, v in list(resp.items()):
5450 # table.add_row([k, json.dumps(v, indent=2)])
5455 # @cli_osm.command(name='vcs-list')
5456 # @click.pass_context
5457 # def vcs_list(ctx):
5458 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5459 # resp = ctx.obj.utils.get_vcs_info()
5460 # table = PrettyTable(['component name', 'state'])
5461 # for component in resp:
5462 # table.add_row([component['component_name'], component['state']])
5468 name
="ns-action", short_help
="executes an action/primitive over a NS instance"
5470 @click.argument("ns_name")
5474 help="member-vnf-index if the target is a vnf instead of a ns)",
5476 @click.option("--kdu_name", default
=None, help="kdu-name if the target is a kdu)")
5477 @click.option("--vdu_id", default
=None, help="vdu-id if the target is a vdu")
5479 "--vdu_count", default
=None, type=int, help="number of vdu instance of this vdu_id"
5481 @click.option("--action_name", prompt
=True, help="action name")
5482 @click.option("--params", default
=None, help="action params in YAML/JSON inline string")
5483 @click.option("--params_file", default
=None, help="YAML/JSON file with action params")
5485 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5492 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5508 """executes an action/primitive over a NS instance
5510 NS_NAME: name or ID of the NS instance
5514 check_client_version(ctx
.obj
, ctx
.command
.name
)
5517 op_data
["member_vnf_index"] = vnf_name
5519 op_data
["kdu_name"] = kdu_name
5521 op_data
["vdu_id"] = vdu_id
5522 if vdu_count
is not None:
5523 op_data
["vdu_count_index"] = vdu_count
5525 op_data
["timeout_ns_action"] = timeout
5526 op_data
["primitive"] = action_name
5528 with
open(params_file
, "r") as pf
:
5531 op_data
["primitive_params"] = yaml
.safe_load(params
)
5533 op_data
["primitive_params"] = {}
5534 print(ctx
.obj
.ns
.exec_op(ns_name
, op_name
="action", op_data
=op_data
, wait
=wait
))
5536 # except ClientException as e:
5542 name
="vnf-scale", short_help
="executes a VNF scale (adding/removing VDUs)"
5544 @click.argument("ns_name")
5545 @click.argument("vnf_name")
5547 "--scaling-group", prompt
=True, help="scaling-group-descriptor name to use"
5550 "--scale-in", default
=False, is_flag
=True, help="performs a scale in operation"
5556 help="performs a scale out operation (by default)",
5559 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5566 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5570 ctx
, ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
, timeout
, wait
5573 Executes a VNF scale (adding/removing VDUs)
5576 NS_NAME: name or ID of the NS instance.
5577 VNF_NAME: member-vnf-index in the NS to be scaled.
5581 check_client_version(ctx
.obj
, ctx
.command
.name
)
5582 if not scale_in
and not scale_out
:
5584 ctx
.obj
.ns
.scale_vnf(
5585 ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
, wait
, timeout
5587 # except ClientException as e:
5593 name
="ns-update", short_help
="executes an update of a Network Service."
5595 @click.argument("ns_name")
5597 "--updatetype", required
=True, type=str, help="available types: CHANGE_VNFPKG"
5603 help="extra information for update operation as YAML/JSON inline string as --config"
5604 " '{changeVnfPackageData:[{vnfInstanceId: xxx, vnfdId: yyy}]}'",
5607 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5614 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5617 def update(ctx
, ns_name
, updatetype
, config
, timeout
, wait
):
5618 """Executes an update of a Network Service.
5620 The update will check new revisions of the Network Functions that are part of the
5621 Network Service, and it will update them if needed.
5622 Sample update command: osm ns-update ns_instance_id --updatetype CHANGE_VNFPKG
5623 --config '{changeVnfPackageData: [{vnfInstanceId: id_x,vnfdId: id_y}]}' --timeout 300 --wait
5625 NS_NAME: Network service instance name or ID.
5630 "updateType": updatetype
,
5633 op_data
["config"] = yaml
.safe_load(config
)
5635 check_client_version(ctx
.obj
, ctx
.command
.name
)
5636 ctx
.obj
.ns
.update(ns_name
, op_data
, wait
=wait
)
5639 def iterator_split(iterator
, separators
):
5641 Splits a tuple or list into several lists whenever a separator is found
5642 For instance, the following tuple will be separated with the separator "--vnf" as follows.
5644 ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1", "--vnf", "B", "--cause", "cause_B", ...
5645 "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", "--vdu", "vdu_B1", "--count_index", "2")
5648 ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1"),
5649 ("--vnf", "B", "--cause", "cause_B", "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", ...
5650 "--vdu", "vdu_B1", "--count_index", "2")
5653 Returns as many lists as separators are found
5656 if iterator
[0] not in separators
:
5657 raise ClientException(f
"Expected one of {separators}. Received: {iterator[0]}.")
5660 for i
in range(len(iterator
)):
5661 if iterator
[i
] in separators
:
5665 raise ClientException(f
"Expected at least one argument after separator (possible separators: {separators}).")
5666 list_of_lists
.append(list(iterator
[first
:i
]))
5668 if ((len(iterator
) - first
) < 2):
5669 raise ClientException(f
"Expected at least one argument after separator (possible separators: {separators}).")
5671 list_of_lists
.append(list(iterator
[first
:len(iterator
)]))
5672 # logger.debug(f"List of lists: {list_of_lists}")
5673 return list_of_lists
5676 def process_common_heal_params(heal_vnf_dict
, args
):
5678 current_item
= "vnf"
5680 while i
< len(args
):
5681 if args
[i
] == "--cause":
5682 if (i
+1 >= len(args
)) or args
[i
+1].startswith("--"):
5683 raise ClientException("No cause was provided after --cause")
5684 heal_vnf_dict
["cause"] = args
[i
+1]
5687 if args
[i
] == "--run-day1":
5688 if current_item
== "vnf":
5689 if "additionalParams" not in heal_vnf_dict
:
5690 heal_vnf_dict
["additionalParams"] = {}
5691 heal_vnf_dict
["additionalParams"]["run-day1"] = True
5693 # if current_item == "vdu"
5694 heal_vnf_dict
["additionalParams"]["vdu"][-1]["run-day1"] = True
5697 if args
[i
] == "--vdu":
5698 if "additionalParams" not in heal_vnf_dict
:
5699 heal_vnf_dict
["additionalParams"] = {}
5700 heal_vnf_dict
["additionalParams"]["vdu"] = []
5701 if (i
+1 >= len(args
)) or args
[i
+1].startswith("--"):
5702 raise ClientException("No VDU ID was provided after --vdu")
5703 heal_vnf_dict
["additionalParams"]["vdu"].append({"vdu-id": args
[i
+1]})
5704 current_item
= "vdu"
5707 if args
[i
] == "--count-index":
5708 if current_item
== "vnf":
5709 raise ClientException("Option --count-index only applies to VDU, not to VNF")
5710 if (i
+1 >= len(args
)) or args
[i
+1].startswith("--"):
5711 raise ClientException("No count index was provided after --count-index")
5712 heal_vnf_dict
["additionalParams"]["vdu"][-1]["count-index"] = int(args
[i
+1])
5719 def process_ns_heal_params(ctx
, param
, value
):
5721 Processes the params in the command ns-heal
5722 Click does not allow advanced patterns for positional options like this:
5723 --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf"
5724 --vdu several_volumes-VM
5725 --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf"
5726 --vdu mgmtVM --count-index 1 --run-day1
5727 --vdu mgmtVM --count-index 2
5729 It returns the dictionary with all the params stored in ctx.params["heal_params"]
5732 # logger.debug(f"Args: {value}")
5733 if param
.name
!= "args":
5734 raise ClientException(f
"Unexpected param: {param.name}")
5735 # Split the tuple "value" by "--vnf"
5736 vnfs
= iterator_split(value
, ["--vnf"])
5737 logger
.debug(f
"VNFs: {vnfs}")
5739 heal_dict
["healVnfData"] = []
5741 # logger.debug(f"VNF: {vnf}")
5743 if vnf
[1].startswith("--"):
5744 raise ClientException("Expected a VNF_ID after --vnf")
5745 heal_vnf
["vnfInstanceId"] = vnf
[1]
5746 process_common_heal_params(heal_vnf
, vnf
[2:])
5747 heal_dict
["healVnfData"].append(heal_vnf
)
5748 ctx
.params
["heal_params"] = heal_dict
5754 short_help
="heals (recreates) VNFs or VDUs of a NS instance",
5755 context_settings
=dict(ignore_unknown_options
=True,)
5757 @click.argument("ns_name")
5761 type=click
.UNPROCESSED
,
5762 callback
=process_ns_heal_params
,
5768 help="timeout in seconds"
5774 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5785 """heals (recreates) VNFs or VDUs of a NS instance
5787 NS_NAME: name or ID of the NS instance
5791 --vnf TEXT VNF instance ID or VNF id in the NS [required]
5792 --cause TEXT human readable cause of the healing
5793 --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU
5795 --count-index INTEGER count-index
5799 osm ns-heal NS_NAME|NS_ID --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf"
5800 --vdu several_volumes-VM
5801 --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf"
5802 --vdu mgmtVM --count-index 1 --run-day1
5803 --vdu mgmtVM --count-index 2
5806 heal_dict
= ctx
.params
["heal_params"]
5807 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
5808 # replace VNF id in the NS by the VNF instance ID
5809 for vnf
in heal_dict
["healVnfData"]:
5810 vnf_id
= vnf
["vnfInstanceId"]
5811 if not validate_uuid4(vnf_id
):
5812 vnf_filter
= f
"member-vnf-index-ref={vnf_id}"
5813 vnf_list
= ctx
.obj
.vnf
.list(ns
=ns_name
, filter=vnf_filter
)
5814 if len(vnf_list
) == 0:
5815 raise ClientException(f
"No VNF found in NS {ns_name} with filter {vnf_filter}")
5816 elif len(vnf_list
) == 1:
5817 vnf
["vnfInstanceId"] = vnf_list
[0]["_id"]
5819 raise ClientException(f
"More than 1 VNF found in NS {ns_name} with filter {vnf_filter}")
5820 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
5821 check_client_version(ctx
.obj
, ctx
.command
.name
)
5822 ctx
.obj
.ns
.heal(ns_name
, heal_dict
, wait
, timeout
)
5826 def process_vnf_heal_params(ctx
, param
, value
):
5828 Processes the params in the command vnf-heal
5829 Click does not allow advanced patterns for positional options like this:
5830 --vdu mgmtVM --count-index 1 --run-day1 --vdu mgmtVM --count-index 2
5832 It returns the dictionary with all the params stored in ctx.params["heal_params"]
5835 # logger.debug(f"Args: {value}")
5836 if param
.name
!= "args":
5837 raise ClientException(f
"Unexpected param: {param.name}")
5838 # Split the tuple "value" by "--vnf"
5841 heal_dict
["healVnfData"] = []
5842 logger
.debug(f
"VNF: {vnf}")
5843 heal_vnf
= {"vnfInstanceId": "id_to_be_substituted"}
5844 process_common_heal_params(heal_vnf
, vnf
)
5845 heal_dict
["healVnfData"].append(heal_vnf
)
5846 ctx
.params
["heal_params"] = heal_dict
5852 short_help
="heals (recreates) a VNF instance or the VDUs of a VNF instance",
5853 context_settings
=dict(ignore_unknown_options
=True,)
5855 @click.argument("vnf_name")
5859 type=click
.UNPROCESSED
,
5860 callback
=process_vnf_heal_params
,
5866 help="timeout in seconds"
5872 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5883 """heals (recreates) a VNF instance or the VDUs of a VNF instance
5885 VNF_NAME: name or ID of the VNF instance
5889 --cause TEXT human readable cause of the healing of the VNF
5890 --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU
5892 --count-index INTEGER count-index
5896 osm vnf-heal VNF_INSTANCE_ID --vdu mgmtVM --count-index 1 --run-day1
5897 --vdu mgmtVM --count-index 2
5900 heal_dict
= ctx
.params
["heal_params"]
5901 heal_dict
["healVnfData"][-1]["vnfInstanceId"] = vnf_name
5902 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
5903 check_client_version(ctx
.obj
, ctx
.command
.name
)
5904 vnfr
= ctx
.obj
.vnf
.get(vnf_name
)
5905 ns_id
= vnfr
["nsr-id-ref"]
5906 ctx
.obj
.ns
.heal(ns_id
, heal_dict
, wait
, timeout
)
5910 @cli_osm.command(name
="alarm-show", short_help
="show alarm details")
5911 @click.argument("uuid")
5913 def alarm_show(ctx
, uuid
):
5914 """Show alarm's detail information"""
5916 check_client_version(ctx
.obj
, ctx
.command
.name
)
5917 resp
= ctx
.obj
.ns
.get_alarm(uuid
=uuid
)
5931 table
= PrettyTable(["key", "attribute"])
5933 # Arrange and return the response data
5934 alarm
= resp
.replace("ObjectId", "")
5935 for key
in alarm_filter
:
5937 value
= alarm
.get(key
)
5940 value
= alarm
.get(key
)
5942 elif key
== "ns-id":
5943 value
= alarm
["tags"].get("ns_id")
5944 elif key
== "vdu_name":
5945 value
= alarm
["tags"].get("vdu_name")
5946 elif key
== "status":
5947 value
= alarm
["alarm_status"]
5950 table
.add_row([key
, wrap_text(text
=json
.dumps(value
, indent
=2), width
=100)])
5958 @cli_osm.command(name
="alarm-list", short_help
="list all alarms")
5960 "--ns_id", default
=None, required
=False, help="List out alarm for given ns id"
5963 def alarm_list(ctx
, ns_id
):
5964 """list all alarm"""
5966 check_client_version(ctx
.obj
, ctx
.command
.name
)
5967 project_name
= os
.getenv("OSM_PROJECT", "admin")
5968 resp
= ctx
.obj
.ns
.get_alarm(project_name
=project_name
, ns_id
=ns_id
)
5970 table
= PrettyTable(
5971 ["alarm-id", "metric", "threshold", "operation", "action", "status"]
5974 # return the response data in a table
5975 resp
= resp
.replace("ObjectId", "")
5979 wrap_text(text
=str(alarm
["uuid"]), width
=38),
5983 wrap_text(text
=alarm
["action"], width
=25),
5984 alarm
["alarm_status"],
5992 @cli_osm.command(name
="alarm-update", short_help
="Update a alarm")
5993 @click.argument("uuid")
5994 @click.option("--threshold", default
=None, help="Alarm threshold")
5995 @click.option("--is_enable", default
=None, type=bool, help="enable or disable alarm")
5997 def alarm_update(ctx
, uuid
, threshold
, is_enable
):
6002 if not threshold
and is_enable
is None:
6003 raise ClientException(
6004 "Please provide option to update i.e threshold or is_enable"
6006 ctx
.obj
.ns
.update_alarm(uuid
, threshold
, is_enable
)
6009 ##############################
6010 # Role Management Operations #
6011 ##############################
6014 @cli_osm.command(name
="role-create", short_help
="creates a new role")
6015 @click.argument("name")
6016 @click.option("--permissions", default
=None, help="role permissions using a dictionary")
6018 def role_create(ctx
, name
, permissions
):
6023 NAME: Name or ID of the role.
6024 DEFINITION: Definition of grant/denial of access to resources.
6028 check_client_version(ctx
.obj
, ctx
.command
.name
)
6029 ctx
.obj
.role
.create(name
, permissions
)
6030 # except ClientException as e:
6035 @cli_osm.command(name
="role-update", short_help
="updates a role")
6036 @click.argument("name")
6037 @click.option("--set-name", default
=None, help="change name of rle")
6038 # @click.option('--permissions',
6040 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
6044 help="yaml format dictionary with permission: True/False to access grant/denial",
6046 @click.option("--remove", default
=None, help="yaml format list to remove a permission")
6048 def role_update(ctx
, name
, set_name
, add
, remove
):
6053 NAME: Name or ID of the role.
6054 DEFINITION: Definition overwrites the old definition.
6055 ADD: Grant/denial of access to resource to add.
6056 REMOVE: Grant/denial of access to resource to remove.
6060 check_client_version(ctx
.obj
, ctx
.command
.name
)
6061 ctx
.obj
.role
.update(name
, set_name
, None, add
, remove
)
6062 # except ClientException as e:
6067 @cli_osm.command(name
="role-delete", short_help
="deletes a role")
6068 @click.argument("name")
6069 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
6071 def role_delete(ctx
, name
):
6076 NAME: Name or ID of the role.
6080 check_client_version(ctx
.obj
, ctx
.command
.name
)
6081 ctx
.obj
.role
.delete(name
)
6082 # except ClientException as e:
6087 @cli_osm.command(name
="role-list", short_help
="list all roles")
6092 help="restricts the list to the projects matching the filter",
6095 def role_list(ctx
, filter):
6101 check_client_version(ctx
.obj
, ctx
.command
.name
)
6103 filter = "&".join(filter)
6104 resp
= ctx
.obj
.role
.list(filter)
6105 # except ClientException as e:
6108 table
= PrettyTable(["name", "id"])
6110 table
.add_row([role
["name"], role
["_id"]])
6115 @cli_osm.command(name
="role-show", short_help
="show specific role")
6116 @click.argument("name")
6118 def role_show(ctx
, name
):
6120 Shows the details of a role.
6123 NAME: Name or ID of the role.
6127 check_client_version(ctx
.obj
, ctx
.command
.name
)
6128 resp
= ctx
.obj
.role
.get(name
)
6129 # except ClientException as e:
6133 table
= PrettyTable(["key", "attribute"])
6134 for k
, v
in resp
.items():
6135 table
.add_row([k
, json
.dumps(v
, indent
=2)])
6140 @cli_osm.command(name
="package-create", short_help
="Create empty NS package structure")
6141 @click.argument("package-type")
6142 @click.argument("package-name")
6146 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'),
6150 default
="image-name",
6151 help='(VNF) Set the name of the vdu image. Default "image-name"',
6154 "--vdus", default
=1, help="(VNF) Set the number of vdus in a VNF. Default 1"
6157 "--vcpu", default
=1, help="(VNF) Set the number of virtual CPUs in a vdu. Default 1"
6162 help="(VNF) Set the memory size (MB) of the vdu. Default 1024",
6165 "--storage", default
=10, help="(VNF) Set the disk size (GB) of the vdu. Default 10"
6170 help="(VNF) Set the number of additional interfaces apart from the management interface. Default 0",
6173 "--vendor", default
="OSM", help='(NS/VNF) Set the descriptor vendor. Default "OSM"'
6179 help="(NS/VNF/NST) Flag for overriding the package if exists.",
6185 help="(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options",
6188 "--netslice-subnets", default
=1, help="(NST) Number of netslice subnets. Default 1"
6191 "--netslice-vlds", default
=1, help="(NST) Number of netslice vlds. Default 1"
6197 help="Flag to create a descriptor using the previous OSM format (pre SOL006, OSM<9)",
6219 Creates an OSM NS, VNF, NST package
6222 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
6223 PACKAGE_NAME: Name of the package to create the folder with the content.
6228 check_client_version(ctx
.obj
, ctx
.command
.name
)
6230 "Creating the {} structure: {}/{}".format(
6231 package_type
.upper(), base_directory
, package_name
6234 resp
= ctx
.obj
.package_tool
.create(
6244 interfaces
=interfaces
,
6247 netslice_subnets
=netslice_subnets
,
6248 netslice_vlds
=netslice_vlds
,
6252 # except ClientException as inst:
6253 # print("ERROR: {}".format(inst))
6258 name
="package-validate", short_help
="Validate descriptors given a base directory"
6260 @click.argument("base-directory", default
=".", required
=False)
6262 "--recursive/--no-recursive",
6264 help="The activated recursive option will validate the yaml files"
6265 " within the indicated directory and in its subdirectories",
6271 help="Validates also the descriptors using the previous OSM format (pre SOL006)",
6274 def package_validate(ctx
, base_directory
, recursive
, old
):
6276 Validate descriptors given a base directory.
6279 BASE_DIRECTORY: Base folder for NS, VNF or NST package.
6283 check_client_version(ctx
.obj
, ctx
.command
.name
)
6284 results
= ctx
.obj
.package_tool
.validate(base_directory
, recursive
, old
)
6285 table
= PrettyTable()
6286 table
.field_names
= ["TYPE", "PATH", "VALID", "ERROR"]
6287 # Print the dictionary generated by the validation function
6288 for result
in results
:
6290 [result
["type"], result
["path"], result
["valid"], result
["error"]]
6292 table
.sortby
= "VALID"
6293 table
.align
["PATH"] = "l"
6294 table
.align
["TYPE"] = "l"
6295 table
.align
["ERROR"] = "l"
6297 # except ClientException as inst:
6298 # print("ERROR: {}".format(inst))
6303 name
="package-translate", short_help
="Translate descriptors given a base directory"
6305 @click.argument("base-directory", default
=".", required
=False)
6307 "--recursive/--no-recursive",
6309 help="The activated recursive option will translate the yaml files"
6310 " within the indicated directory and in its subdirectories",
6316 help="Do not translate yet, only make a dry-run to test translation",
6319 def package_translate(ctx
, base_directory
, recursive
, dryrun
):
6321 Translate descriptors given a base directory.
6324 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
6327 check_client_version(ctx
.obj
, ctx
.command
.name
)
6328 results
= ctx
.obj
.package_tool
.translate(base_directory
, recursive
, dryrun
)
6329 table
= PrettyTable()
6330 table
.field_names
= [
6338 # Print the dictionary generated by the validation function
6339 for result
in results
:
6342 result
["current type"],
6346 result
["translated"],
6350 table
.sortby
= "TRANSLATED"
6351 table
.align
["PATH"] = "l"
6352 table
.align
["TYPE"] = "l"
6353 table
.align
["ERROR"] = "l"
6355 # except ClientException as inst:
6356 # print("ERROR: {}".format(inst))
6360 @cli_osm.command(name
="package-build", short_help
="Build the tar.gz of the package")
6361 @click.argument("package-folder")
6363 "--skip-validation", default
=False, is_flag
=True, help="skip package validation"
6366 "--skip-charm-build",
6369 help="the charm will not be compiled, it is assumed to already exist",
6372 def package_build(ctx
, package_folder
, skip_validation
, skip_charm_build
):
6374 Build the package NS, VNF given the package_folder.
6377 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
6381 check_client_version(ctx
.obj
, ctx
.command
.name
)
6382 results
= ctx
.obj
.package_tool
.build(
6384 skip_validation
=skip_validation
,
6385 skip_charm_build
=skip_charm_build
,
6388 # except ClientException as inst:
6389 # print("ERROR: {}".format(inst))
6394 name
="descriptor-translate",
6395 short_help
="Translate input descriptor file from Rel EIGHT OSM descriptors to SOL006 and prints in standard output",
6397 @click.argument("descriptor-file", required
=True)
6399 def descriptor_translate(ctx
, descriptor_file
):
6401 Translate input descriptor.
6404 DESCRIPTOR_FILE: Descriptor file for NS, VNF or Network Slice.
6407 check_client_version(ctx
.obj
, ctx
.command
.name
)
6408 result
= ctx
.obj
.package_tool
.descriptor_translate(descriptor_file
)
6416 except pycurl
.error
as exc
:
6419 'Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified'
6421 except ClientException
as exc
:
6422 print("ERROR: {}".format(exc
))
6423 except (FileNotFoundError
, PermissionError
) as exc
:
6424 print("Cannot open file: {}".format(exc
))
6425 except yaml
.YAMLError
as exc
:
6426 print("Invalid YAML format: {}".format(exc
))
6428 # TODO capture other controlled exceptions here
6429 # TODO remove the ClientException captures from all places, unless they do something different
6432 if __name__
== "__main__":