fac267dd1e8f639c826d9e73090bec3777ca51ac
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",
131 help="user (defaults to admin). " + "Also can set OSM_USER in environment",
136 envvar
="OSM_PASSWORD",
137 help="password (defaults to admin). " + "Also can set OSM_PASSWORD in environment",
142 envvar
="OSM_PROJECT",
143 help="project (defaults to admin). " + "Also can set OSM_PROJECT in environment",
149 help="increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)",
151 @click.option("--all-projects", default
=None, is_flag
=True, help="include all projects")
153 "--public/--no-public",
155 help="flag for public items (packages, instances, VIM accounts, etc.)",
158 "--project-domain-name",
159 "project_domain_name",
161 envvar
="OSM_PROJECT_DOMAIN_NAME",
162 help="project domain name for keystone authentication (default to None). "
163 + "Also can set OSM_PROJECT_DOMAIN_NAME in environment",
166 "--user-domain-name",
169 envvar
="OSM_USER_DOMAIN_NAME",
170 help="user domain name for keystone authentication (default to None). "
171 + "Also can set OSM_USER_DOMAIN_NAME in environment",
174 def cli_osm(ctx
, **kwargs
):
176 hostname
= kwargs
.pop("hostname", None)
180 "either hostname option or OSM_HOSTNAME "
181 + "environment variable needs to be specified"
186 kwargs
= {k
: v
for k
, v
in kwargs
.items() if v
is not None}
187 sol005
= os
.getenv("OSM_SOL005", True)
188 ctx
.obj
= client
.Client(host
=hostname
, sol005
=sol005
, **kwargs
)
189 logger
= logging
.getLogger("osmclient")
197 @cli_osm.command(name
="ns-list", short_help
="list all NS instances")
202 help="restricts the list to the NS instances matching the filter.",
207 help="get more details of the NS (project, vim, deployment status, configuration status.",
210 def ns_list(ctx
, filter, long):
211 """list all NS instances
215 --filter filterExpr Restricts the list to the NS instances matching the filter
218 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
219 concatenated using the "&" character:
222 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
223 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
224 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
226 value := scalar value
230 * zero or more occurrences
231 ? zero or one occurrence
232 [] grouping of expressions to be used with ? and *
233 "" quotation marks for marking string constants
237 "AttrName" is the name of one attribute in the data type that defines the representation
238 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
239 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
240 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
241 entries, it means that the operator "op" is applied to the attribute addressed by the last
242 <attrName> entry included in the concatenation. All simple filter expressions are combined
243 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
244 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
245 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
246 prefix". If an attribute referenced in an expression is an array, an object that contains a
247 corresponding array shall be considered to match the expression if any of the elements in the
248 array matches all expressions that have the same attribute prefix.
252 --filter admin-status=ENABLED
253 --filter nsd-ref=<NSD_NAME>
254 --filter nsd.vendor=<VENDOR>
255 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
256 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
259 def summarize_deployment_status(status_dict
):
266 net_list
= status_dict
.get("nets", [])
269 if net
["status"] not in status_nets
:
270 status_nets
[net
["status"]] = 1
272 status_nets
[net
["status"]] += 1
274 for k
, v
in status_nets
.items():
275 message
+= "{}:{},".format(k
, v
)
276 message
+= "TOTAL:{}".format(n_nets
)
277 summary
+= "{}".format(message
)
282 vnf_list
= status_dict
["vnfs"]
284 member_vnf_index
= vnf
["member_vnf_index"]
285 if member_vnf_index
not in status_vnfs
:
286 status_vnfs
[member_vnf_index
] = {}
287 for vm
in vnf
["vms"]:
289 if vm
["status"] not in status_vms
:
290 status_vms
[vm
["status"]] = 1
292 status_vms
[vm
["status"]] += 1
293 if vm
["status"] not in status_vnfs
[member_vnf_index
]:
294 status_vnfs
[member_vnf_index
][vm
["status"]] = 1
296 status_vnfs
[member_vnf_index
][vm
["status"]] += 1
298 for k
, v
in status_vms
.items():
299 message
+= "{}:{},".format(k
, v
)
300 message
+= "TOTAL:{}".format(n_vms
)
301 summary
+= "\n{}".format(message
)
303 for k
, v
in status_vnfs
.items():
305 message
= "\n {} VMs: ".format(k
)
306 for k2
, v2
in v
.items():
307 message
+= "{}:{},".format(k2
, v2
)
309 message
+= "TOTAL:{}".format(total
)
313 def summarize_config_status(ee_list
):
321 if ee
["elementType"] not in status_ee
:
322 status_ee
[ee
["elementType"]] = {}
323 status_ee
[ee
["elementType"]][ee
["status"]] = 1
325 if ee
["status"] in status_ee
[ee
["elementType"]]:
326 status_ee
[ee
["elementType"]][ee
["status"]] += 1
328 status_ee
[ee
["elementType"]][ee
["status"]] = 1
329 for elementType
in ["KDU", "VDU", "PDU", "VNF", "NS"]:
330 if elementType
in status_ee
:
333 for k
, v
in status_ee
[elementType
].items():
334 message
+= "{}:{},".format(k
, v
)
336 message
+= "TOTAL:{}\n".format(total
)
337 summary
+= "{}: {}".format(elementType
, message
)
338 summary
+= "TOTAL Exec. Env.: {}".format(n_ee
)
343 check_client_version(ctx
.obj
, "--filter")
344 filter = "&".join(filter)
345 resp
= ctx
.obj
.ns
.list(filter)
347 resp
= ctx
.obj
.ns
.list()
360 "configuration status",
363 project_list
= ctx
.obj
.project
.list()
365 vim_list
= ctx
.obj
.vim
.list()
380 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
381 if fullclassname
== "osmclient.sol005.client.Client":
383 logger
.debug("NS info: {}".format(nsr
))
384 nsr_name
= nsr
["name"]
386 date
= datetime
.fromtimestamp(nsr
["create-time"]).strftime(
389 ns_state
= nsr
.get("nsState", nsr
["_admin"]["nsState"])
391 deployment_status
= summarize_deployment_status(
392 nsr
.get("deploymentStatus")
394 config_status
= summarize_config_status(nsr
.get("configurationStatus"))
395 project_id
, project_name
= get_project(project_list
, nsr
)
396 # project = '{} ({})'.format(project_name, project_id)
397 project
= project_name
398 vim_id
= nsr
.get("datacenter")
399 vim_name
= get_vim_name(vim_list
, vim_id
)
401 # vim = '{} ({})'.format(vim_name, vim_id)
403 if "currentOperation" in nsr
:
404 current_operation
= "{} ({})".format(
405 nsr
["currentOperation"], nsr
["currentOperationID"]
408 current_operation
= "{} ({})".format(
409 nsr
["_admin"].get("current-operation", "-"),
410 nsr
["_admin"]["nslcmop"],
412 error_details
= "N/A"
415 or ns_state
== "DEGRADED"
416 or ("currentOperation" not in nsr
and nsr
.get("errorDescription"))
418 error_details
= "{}\nDetail: {}".format(
419 nsr
["errorDescription"], nsr
["errorDetail"]
422 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
423 nsr
= nsopdata
["nsr:nsr"]
424 nsr_name
= nsr
["name-ref"]
425 nsr_id
= nsr
["ns-instance-config-ref"]
428 deployment_status
= (
429 nsr
["operational-status"]
430 if "operational-status" in nsr
433 ns_state
= deployment_status
434 config_status
= nsr
.get("config-status", "Not found")
435 current_operation
= "Unknown"
436 error_details
= nsr
.get("detailed-status", "Not found")
437 if config_status
== "config_not_needed":
438 config_status
= "configured (no charms)"
448 wrap_text(text
=error_details
, width
=40),
463 wrap_text(text
=error_details
, width
=40),
468 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
470 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
474 def nsd_list(ctx
, filter, long):
477 check_client_version(ctx
.obj
, "--filter")
478 filter = "&".join(filter)
479 resp
= ctx
.obj
.nsd
.list(filter)
481 resp
= ctx
.obj
.nsd
.list()
482 # print(yaml.safe_dump(resp))
483 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
484 if fullclassname
== "osmclient.sol005.client.Client":
498 table
= PrettyTable(["nsd name", "id"])
500 name
= nsd
.get("id", "-")
502 onb_state
= nsd
["_admin"].get("onboardingState", "-")
503 op_state
= nsd
["_admin"].get("operationalState", "-")
504 usage_state
= nsd
["_admin"].get("usageState", "-")
505 date
= datetime
.fromtimestamp(nsd
["_admin"]["created"]).strftime(
508 last_update
= datetime
.fromtimestamp(
509 nsd
["_admin"]["modified"]
510 ).strftime("%Y-%m-%dT%H:%M:%S")
523 table
.add_row([name
, nsd
["_id"]])
525 table
= PrettyTable(["nsd name", "id"])
527 table
.add_row([nsd
["name"], nsd
["id"]])
532 @cli_osm.command(name
="nsd-list", short_help
="list all NS packages")
537 help="restricts the list to the NSD/NSpkg matching the filter",
539 @click.option("--long", is_flag
=True, help="get more details")
541 def nsd_list1(ctx
, filter, long):
542 """list all NSD/NS pkg in the system"""
544 nsd_list(ctx
, filter, long)
547 @cli_osm.command(name
="nspkg-list", short_help
="list all NS packages")
552 help="restricts the list to the NSD/NSpkg matching the filter",
554 @click.option("--long", is_flag
=True, help="get more details")
556 def nsd_list2(ctx
, filter, long):
557 """list all NS packages"""
559 nsd_list(ctx
, filter, long)
562 def pkg_repo_list(ctx
, pkgtype
, filter, repo
, long):
563 resp
= ctx
.obj
.osmrepo
.pkg_list(pkgtype
, filter, repo
)
566 ["nfpkg name", "vendor", "version", "latest", "description", "repository"]
569 table
= PrettyTable(["nfpkg name", "repository"])
571 name
= vnfd
.get("id", vnfd
.get("name", "-"))
572 repository
= vnfd
.get("repository")
574 vendor
= vnfd
.get("provider", vnfd
.get("vendor"))
575 version
= vnfd
.get("version")
576 description
= vnfd
.get("description")
577 latest
= vnfd
.get("latest")
578 table
.add_row([name
, vendor
, version
, latest
, description
, repository
])
580 table
.add_row([name
, repository
])
585 def vnfd_list(ctx
, nf_type
, filter, long):
588 check_client_version(ctx
.obj
, "--nf_type")
590 check_client_version(ctx
.obj
, "--filter")
592 filter = "&".join(filter)
595 nf_filter
= "_admin.type=vnfd"
596 elif nf_type
== "pnf":
597 nf_filter
= "_admin.type=pnfd"
598 elif nf_type
== "hnf":
599 nf_filter
= "_admin.type=hnfd"
601 raise ClientException(
602 'wrong value for "--nf_type" option, allowed values: vnf, pnf, hnf'
605 filter = "{}&{}".format(nf_filter
, filter)
609 resp
= ctx
.obj
.vnfd
.list(filter)
611 resp
= ctx
.obj
.vnfd
.list()
612 # print(yaml.safe_dump(resp))
613 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
614 if fullclassname
== "osmclient.sol005.client.Client":
631 table
= PrettyTable(["nfpkg name", "id", "desc type"])
633 name
= vnfd
.get("id", vnfd
.get("name", "-"))
634 descriptor_type
= "sol006" if "product-name" in vnfd
else "rel8"
636 onb_state
= vnfd
["_admin"].get("onboardingState", "-")
637 op_state
= vnfd
["_admin"].get("operationalState", "-")
638 vendor
= vnfd
.get("provider", vnfd
.get("vendor"))
639 version
= vnfd
.get("version")
640 usage_state
= vnfd
["_admin"].get("usageState", "-")
641 date
= datetime
.fromtimestamp(vnfd
["_admin"]["created"]).strftime(
644 last_update
= datetime
.fromtimestamp(
645 vnfd
["_admin"]["modified"]
646 ).strftime("%Y-%m-%dT%H:%M:%S")
662 table
.add_row([name
, vnfd
["_id"], descriptor_type
])
664 table
= PrettyTable(["nfpkg name", "id"])
666 table
.add_row([vnfd
["name"], vnfd
["id"]])
671 @cli_osm.command(name
="vnfd-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
672 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
677 help="restricts the list to the NF pkg matching the filter",
679 @click.option("--long", is_flag
=True, help="get more details")
681 def vnfd_list1(ctx
, nf_type
, filter, long):
682 """list all xNF packages (VNF, HNF, PNF)"""
684 vnfd_list(ctx
, nf_type
, filter, long)
687 @cli_osm.command(name
="vnfpkg-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
688 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
693 help="restricts the list to the NFpkg matching the filter",
695 @click.option("--long", is_flag
=True, help="get more details")
697 def vnfd_list2(ctx
, nf_type
, filter, long):
698 """list all xNF packages (VNF, HNF, PNF)"""
700 vnfd_list(ctx
, nf_type
, filter, long)
703 @cli_osm.command(name
="nfpkg-list", short_help
="list all xNF packages (VNF, HNF, PNF)")
704 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
709 help="restricts the list to the NFpkg matching the filter",
711 @click.option("--long", is_flag
=True, help="get more details")
713 def nfpkg_list(ctx
, nf_type
, filter, long):
714 """list all xNF packages (VNF, HNF, PNF)"""
717 check_client_version(ctx
.obj
, ctx
.command
.name
)
718 vnfd_list(ctx
, nf_type
, filter, long)
719 # except ClientException as e:
725 name
="vnfpkg-repo-list", short_help
="list all xNF from OSM repositories"
731 help="restricts the list to the NFpkg matching the filter",
734 "--repo", default
=None, help="restricts the list to a particular OSM repository"
736 @click.option("--long", is_flag
=True, help="get more details")
738 def nfpkg_repo_list1(ctx
, filter, repo
, long):
739 """list xNF packages from OSM repositories"""
741 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
745 name
="nfpkg-repo-list", short_help
="list all xNF from OSM repositories"
751 help="restricts the list to the NFpkg matching the filter",
754 "--repo", default
=None, help="restricts the list to a particular OSM repository"
756 @click.option("--long", is_flag
=True, help="get more details")
758 def nfpkg_repo_list2(ctx
, filter, repo
, long):
759 """list xNF packages from OSM repositories"""
761 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
764 def vnf_list(ctx
, ns
, filter, long):
768 check_client_version(ctx
.obj
, "--ns")
770 filter = "&".join(filter)
771 check_client_version(ctx
.obj
, "--filter")
772 resp
= ctx
.obj
.vnf
.list(ns
, filter)
774 resp
= ctx
.obj
.vnf
.list()
775 # except ClientException as e:
778 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
779 if fullclassname
== "osmclient.sol005.client.Client":
801 table
= PrettyTable(field_names
)
803 name
= vnfr
["name"] if "name" in vnfr
else "-"
808 vnfr
["member-vnf-index-ref"],
810 vnfr
["vim-account-id"],
814 date
= datetime
.fromtimestamp(vnfr
["_admin"]["created"]).strftime(
817 last_update
= datetime
.fromtimestamp(
818 vnfr
["_admin"]["modified"]
819 ).strftime("%Y-%m-%dT%H:%M:%S")
820 new_row
.extend([date
, last_update
])
821 table
.add_row(new_row
)
823 table
= PrettyTable(["vnf name", "id", "operational status", "config status"])
825 if "mgmt-interface" not in vnfr
:
826 vnfr
["mgmt-interface"] = {}
827 vnfr
["mgmt-interface"]["ip-address"] = None
832 vnfr
["operational-status"],
833 vnfr
["config-status"],
840 @cli_osm.command(name
="vnf-list", short_help
="list all NF instances")
842 "--ns", default
=None, help="NS instance id or name to restrict the NF list"
848 help="restricts the list to the NF instances matching the filter.",
850 @click.option("--long", is_flag
=True, help="get more details")
852 def vnf_list1(ctx
, ns
, filter, long):
853 """list all NF instances"""
855 vnf_list(ctx
, ns
, filter, long)
858 @cli_osm.command(name
="nsd-repo-list", short_help
="list all NS from OSM repositories")
863 help="restricts the list to the NS matching the filter",
866 "--repo", default
=None, help="restricts the list to a particular OSM repository"
868 @click.option("--long", is_flag
=True, help="get more details")
870 def nspkg_repo_list(ctx
, filter, repo
, long):
871 """list xNF packages from OSM repositories"""
873 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
876 @cli_osm.command(name
="nspkg-repo-list", short_help
="list all NS from OSM repositories")
881 help="restricts the list to the NS matching the filter",
884 "--repo", default
=None, help="restricts the list to a particular OSM repository"
886 @click.option("--long", is_flag
=True, help="get more details")
888 def nspkg_repo_list2(ctx
, filter, repo
, long):
889 """list xNF packages from OSM repositories"""
891 pkg_repo_list(ctx
, pkgtype
, filter, repo
, long)
894 @cli_osm.command(name
="nf-list", short_help
="list all NF instances")
896 "--ns", default
=None, help="NS instance id or name to restrict the NF list"
902 help="restricts the list to the NF instances matching the filter.",
904 @click.option("--long", is_flag
=True, help="get more details")
906 def nf_list(ctx
, ns
, filter, long):
907 """list all NF instances
911 --ns TEXT NS instance id or name to restrict the VNF list
912 --filter filterExpr Restricts the list to the VNF instances matching the filter
915 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
916 concatenated using the "&" character:
919 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
920 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
921 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
923 value := scalar value
927 * zero or more occurrences
928 ? zero or one occurrence
929 [] grouping of expressions to be used with ? and *
930 "" quotation marks for marking string constants
934 "AttrName" is the name of one attribute in the data type that defines the representation
935 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
936 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
937 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
938 entries, it means that the operator "op" is applied to the attribute addressed by the last
939 <attrName> entry included in the concatenation. All simple filter expressions are combined
940 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
941 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
942 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
943 prefix". If an attribute referenced in an expression is an array, an object that contains a
944 corresponding array shall be considered to match the expression if any of the elements in the
945 array matches all expressions that have the same attribute prefix.
949 --filter vim-account-id=<VIM_ACCOUNT_ID>
950 --filter vnfd-ref=<VNFD_NAME>
951 --filter vdur.ip-address=<IP_ADDRESS>
952 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
955 vnf_list(ctx
, ns
, filter, long)
959 name
="ns-op-list", short_help
="shows the history of operations over a NS instance"
961 @click.argument("name")
963 "--long", is_flag
=True, help="get more details of the NS operation (date, )."
966 def ns_op_list(ctx
, name
, long):
967 """shows the history of operations over a NS instance
969 NAME: name or ID of the NS instance
972 def formatParams(params
):
973 if params
["lcmOperationType"] == "instantiate":
974 params
.pop("nsDescription")
978 elif params
["lcmOperationType"] == "action":
979 params
.pop("primitive")
980 params
.pop("lcmOperationType")
981 params
.pop("nsInstanceId")
986 check_client_version(ctx
.obj
, ctx
.command
.name
)
987 resp
= ctx
.obj
.ns
.list_op(name
)
988 # except ClientException as e:
1006 table
= PrettyTable(
1007 ["id", "operation", "action_name", "status", "date", "detail"]
1010 # print(yaml.safe_dump(resp))
1013 if op
["lcmOperationType"] == "action":
1014 action_name
= op
["operationParams"]["primitive"]
1016 if op
["operationState"] == "PROCESSING":
1017 if op
.get("queuePosition") is not None and op
.get("queuePosition") > 0:
1018 detail
= "In queue. Current position: {}".format(op
["queuePosition"])
1019 elif op
["lcmOperationType"] in ("instantiate", "terminate"):
1021 detail
= op
["stage"]
1022 elif op
["operationState"] in ("FAILED", "FAILED_TEMP"):
1023 detail
= op
.get("errorMessage", "-")
1024 date
= datetime
.fromtimestamp(op
["startTime"]).strftime("%Y-%m-%dT%H:%M:%S")
1025 last_update
= datetime
.fromtimestamp(op
["statusEnteredTime"]).strftime(
1032 op
["lcmOperationType"],
1035 text
=json
.dumps(formatParams(op
["operationParams"]), indent
=2),
1038 op
["operationState"],
1041 wrap_text(text
=detail
, width
=50),
1048 op
["lcmOperationType"],
1050 op
["operationState"],
1052 wrap_text(text
=detail
or "", width
=50),
1059 def nsi_list(ctx
, filter):
1060 """list all Network Slice Instances"""
1063 check_client_version(ctx
.obj
, ctx
.command
.name
)
1065 filter = "&".join(filter)
1066 resp
= ctx
.obj
.nsi
.list(filter)
1067 # except ClientException as e:
1070 table
= PrettyTable(
1072 "netslice instance name",
1074 "operational status",
1080 nsi_name
= nsi
["name"]
1083 nsi
["operational-status"] if "operational-status" in nsi
else "Not found"
1085 configstatus
= nsi
["config-status"] if "config-status" in nsi
else "Not found"
1087 nsi
["detailed-status"] if "detailed-status" in nsi
else "Not found"
1089 if configstatus
== "config_not_needed":
1090 configstatus
= "configured (no charms)"
1091 table
.add_row([nsi_name
, nsi_id
, opstatus
, configstatus
, detailed_status
])
1096 @cli_osm.command(name
="nsi-list", short_help
="list all Network Slice Instances (NSI)")
1101 help="restricts the list to the Network Slice Instances matching the filter",
1104 def nsi_list1(ctx
, filter):
1105 """list all Network Slice Instances (NSI)"""
1107 nsi_list(ctx
, filter)
1111 name
="netslice-instance-list", short_help
="list all Network Slice Instances (NSI)"
1117 help="restricts the list to the Network Slice Instances matching the filter",
1120 def nsi_list2(ctx
, filter):
1121 """list all Network Slice Instances (NSI)"""
1123 nsi_list(ctx
, filter)
1126 def nst_list(ctx
, filter):
1129 check_client_version(ctx
.obj
, ctx
.command
.name
)
1131 filter = "&".join(filter)
1132 resp
= ctx
.obj
.nst
.list(filter)
1133 # except ClientException as e:
1136 # print(yaml.safe_dump(resp))
1137 table
= PrettyTable(["nst name", "id"])
1139 name
= nst
["name"] if "name" in nst
else "-"
1140 table
.add_row([name
, nst
["_id"]])
1145 @cli_osm.command(name
="nst-list", short_help
="list all Network Slice Templates (NST)")
1150 help="restricts the list to the NST matching the filter",
1153 def nst_list1(ctx
, filter):
1154 """list all Network Slice Templates (NST) in the system"""
1156 nst_list(ctx
, filter)
1160 name
="netslice-template-list", short_help
="list all Network Slice Templates (NST)"
1166 help="restricts the list to the NST matching the filter",
1169 def nst_list2(ctx
, filter):
1170 """list all Network Slice Templates (NST) in the system"""
1172 nst_list(ctx
, filter)
1175 def nsi_op_list(ctx
, name
):
1178 check_client_version(ctx
.obj
, ctx
.command
.name
)
1179 resp
= ctx
.obj
.nsi
.list_op(name
)
1180 # except ClientException as e:
1183 table
= PrettyTable(["id", "operation", "status"])
1185 table
.add_row([op
["id"], op
["lcmOperationType"], op
["operationState"]])
1192 short_help
="shows the history of operations over a Network Slice Instance (NSI)",
1194 @click.argument("name")
1196 def nsi_op_list1(ctx
, name
):
1197 """shows the history of operations over a Network Slice Instance (NSI)
1199 NAME: name or ID of the Network Slice Instance
1202 nsi_op_list(ctx
, name
)
1206 name
="netslice-instance-op-list",
1207 short_help
="shows the history of operations over a Network Slice Instance (NSI)",
1209 @click.argument("name")
1211 def nsi_op_list2(ctx
, name
):
1212 """shows the history of operations over a Network Slice Instance (NSI)
1214 NAME: name or ID of the Network Slice Instance
1217 nsi_op_list(ctx
, name
)
1220 @cli_osm.command(name
="pdu-list", short_help
="list all Physical Deployment Units (PDU)")
1225 help="restricts the list to the Physical Deployment Units matching the filter",
1228 def pdu_list(ctx
, filter):
1229 """list all Physical Deployment Units (PDU)"""
1232 check_client_version(ctx
.obj
, ctx
.command
.name
)
1234 filter = "&".join(filter)
1235 resp
= ctx
.obj
.pdu
.list(filter)
1236 # except ClientException as e:
1239 table
= PrettyTable(["pdu name", "id", "type", "mgmt ip address"])
1241 pdu_name
= pdu
["name"]
1243 pdu_type
= pdu
["type"]
1244 pdu_ipaddress
= "None"
1245 for iface
in pdu
["interfaces"]:
1247 pdu_ipaddress
= iface
["ip-address"]
1249 table
.add_row([pdu_name
, pdu_id
, pdu_type
, pdu_ipaddress
])
1254 ####################
1256 ####################
1259 def nsd_show(ctx
, name
, literal
):
1262 resp
= ctx
.obj
.nsd
.get(name
)
1263 # resp = ctx.obj.nsd.get_individual(name)
1264 # except ClientException as e:
1269 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1272 table
= PrettyTable(["field", "value"])
1273 for k
, v
in list(resp
.items()):
1274 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1279 @cli_osm.command(name
="nsd-show", short_help
="shows the details of a NS package")
1280 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1281 @click.argument("name")
1283 def nsd_show1(ctx
, name
, literal
):
1284 """shows the content of a NSD
1286 NAME: name or ID of the NSD/NSpkg
1289 nsd_show(ctx
, name
, literal
)
1292 @cli_osm.command(name
="nspkg-show", short_help
="shows the details of a NS package")
1293 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1294 @click.argument("name")
1296 def nsd_show2(ctx
, name
, literal
):
1297 """shows the content of a NSD
1299 NAME: name or ID of the NSD/NSpkg
1302 nsd_show(ctx
, name
, literal
)
1305 def vnfd_show(ctx
, name
, literal
):
1308 resp
= ctx
.obj
.vnfd
.get(name
)
1309 # resp = ctx.obj.vnfd.get_individual(name)
1310 # except ClientException as e:
1315 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1318 table
= PrettyTable(["field", "value"])
1319 for k
, v
in list(resp
.items()):
1320 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1325 def pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
):
1328 filter = "&".join(filter)
1330 resp
= ctx
.obj
.osmrepo
.pkg_get(pkgtype
, name
, repo
, version
, filter)
1333 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1336 catalog
= pkgtype
+ "-catalog"
1337 full_catalog
= pkgtype
+ ":" + catalog
1338 if resp
.get(catalog
):
1339 resp
= resp
.pop(catalog
)[pkgtype
][0]
1340 elif resp
.get(full_catalog
):
1341 resp
= resp
.pop(full_catalog
)[pkgtype
][0]
1343 table
= PrettyTable(["field", "value"])
1344 for k
, v
in list(resp
.items()):
1345 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1350 @cli_osm.command(name
="vnfd-show", short_help
="shows the details of a NF package")
1351 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1352 @click.argument("name")
1354 def vnfd_show1(ctx
, name
, literal
):
1355 """shows the content of a VNFD
1357 NAME: name or ID of the VNFD/VNFpkg
1360 vnfd_show(ctx
, name
, literal
)
1363 @cli_osm.command(name
="vnfpkg-show", short_help
="shows the details of a NF package")
1364 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1365 @click.argument("name")
1367 def vnfd_show2(ctx
, name
, literal
):
1368 """shows the content of a VNFD
1370 NAME: name or ID of the VNFD/VNFpkg
1373 vnfd_show(ctx
, name
, literal
)
1377 name
="vnfpkg-repo-show",
1378 short_help
="shows the details of a NF package in an OSM repository",
1380 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1381 @click.option("--repo", required
=True, help="Repository name")
1382 @click.argument("name")
1383 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1384 @click.option("--version", default
="latest", help="package version")
1386 def vnfd_show3(ctx
, name
, repo
, version
, literal
=None, filter=None):
1387 """shows the content of a VNFD in a repository
1389 NAME: name or ID of the VNFD/VNFpkg
1392 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1396 name
="nsd-repo-show",
1397 short_help
="shows the details of a NS package in an OSM repository",
1399 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1400 @click.option("--repo", required
=True, help="Repository name")
1401 @click.argument("name")
1402 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1403 @click.option("--version", default
="latest", help="package version")
1405 def nsd_repo_show(ctx
, name
, repo
, version
, literal
=None, filter=None):
1406 """shows the content of a VNFD in a repository
1408 NAME: name or ID of the VNFD/VNFpkg
1411 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1415 name
="nspkg-repo-show",
1416 short_help
="shows the details of a NS package in an OSM repository",
1418 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1419 @click.option("--repo", required
=True, help="Repository name")
1420 @click.argument("name")
1421 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1422 @click.option("--version", default
="latest", help="package version")
1424 def nsd_repo_show2(ctx
, name
, repo
, version
, literal
=None, filter=None):
1425 """shows the content of a VNFD in a repository
1427 NAME: name or ID of the VNFD/VNFpkg
1430 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1433 @cli_osm.command(name
="nfpkg-show", short_help
="shows the details of a NF package")
1434 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1435 @click.argument("name")
1437 def nfpkg_show(ctx
, name
, literal
):
1438 """shows the content of a NF Descriptor
1440 NAME: name or ID of the NFpkg
1443 vnfd_show(ctx
, name
, literal
)
1447 name
="nfpkg-repo-show",
1448 short_help
="shows the details of a NF package in an OSM repository",
1450 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1451 @click.option("--repo", required
=True, help="Repository name")
1452 @click.argument("name")
1453 @click.option("--filter", default
=None, multiple
=True, help="filter by fields")
1454 @click.option("--version", default
="latest", help="package version")
1456 def vnfd_show4(ctx
, name
, repo
, version
, literal
=None, filter=None):
1457 """shows the content of a VNFD in a repository
1459 NAME: name or ID of the VNFD/VNFpkg
1462 pkg_repo_show(ctx
, pkgtype
, name
, repo
, version
, filter, literal
)
1465 @cli_osm.command(name
="ns-show", short_help
="shows the info of a NS instance")
1466 @click.argument("name")
1467 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1471 help="restricts the information to the fields in the filter",
1474 def ns_show(ctx
, name
, literal
, filter):
1475 """shows the info of a NS instance
1477 NAME: name or ID of the NS instance
1481 ns
= ctx
.obj
.ns
.get(name
)
1482 # except ClientException as e:
1487 print(yaml
.safe_dump(ns
, indent
=4, default_flow_style
=False))
1490 table
= PrettyTable(["field", "value"])
1492 for k
, v
in list(ns
.items()):
1493 if not filter or k
in filter:
1494 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1496 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
1497 if fullclassname
!= "osmclient.sol005.client.Client":
1498 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
1499 nsr_optdata
= nsopdata
["nsr:nsr"]
1500 for k
, v
in list(nsr_optdata
.items()):
1501 if not filter or k
in filter:
1502 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), width
=100)])
1507 @cli_osm.command(name
="vnf-show", short_help
="shows the info of a VNF instance")
1508 @click.argument("name")
1509 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1513 help="restricts the information to the fields in the filter",
1515 @click.option("--kdu", default
=None, help="KDU name (whose status will be shown)")
1517 def vnf_show(ctx
, name
, literal
, filter, kdu
):
1518 """shows the info of a VNF instance
1520 NAME: name or ID of the VNF instance
1523 def print_kdu_status(op_info_status
):
1524 """print KDU status properly formatted"""
1526 op_status
= yaml
.safe_load(op_info_status
)
1528 "namespace" in op_status
1529 and "info" in op_status
1530 and "last_deployed" in op_status
["info"]
1531 and "status" in op_status
["info"]
1532 and "code" in op_status
["info"]["status"]
1533 and "resources" in op_status
["info"]["status"]
1534 and "seconds" in op_status
["info"]["last_deployed"]
1536 last_deployed_time
= datetime
.fromtimestamp(
1537 op_status
["info"]["last_deployed"]["seconds"]
1538 ).strftime("%a %b %d %I:%M:%S %Y")
1539 print("LAST DEPLOYED: {}".format(last_deployed_time
))
1540 print("NAMESPACE: {}".format(op_status
["namespace"]))
1541 status_code
= "UNKNOWN"
1542 if op_status
["info"]["status"]["code"] == 1:
1543 status_code
= "DEPLOYED"
1544 print("STATUS: {}".format(status_code
))
1547 print(op_status
["info"]["status"]["resources"])
1548 if "notes" in op_status
["info"]["status"]:
1550 print(op_status
["info"]["status"]["notes"])
1552 print(op_info_status
)
1554 print(op_info_status
)
1559 raise ClientException(
1560 '"--literal" option is incompatible with "--kdu" option'
1563 raise ClientException(
1564 '"--filter" option is incompatible with "--kdu" option'
1568 check_client_version(ctx
.obj
, ctx
.command
.name
)
1569 resp
= ctx
.obj
.vnf
.get(name
)
1572 ns_id
= resp
["nsr-id-ref"]
1574 op_data
["member_vnf_index"] = resp
["member-vnf-index-ref"]
1575 op_data
["kdu_name"] = kdu
1576 op_data
["primitive"] = "status"
1577 op_data
["primitive_params"] = {}
1578 op_id
= ctx
.obj
.ns
.exec_op(ns_id
, op_name
="action", op_data
=op_data
, wait
=False)
1581 op_info
= ctx
.obj
.ns
.get_op(op_id
)
1582 if op_info
["operationState"] == "COMPLETED":
1583 print_kdu_status(op_info
["detailed-status"])
1587 print("Could not determine KDU status")
1591 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1594 table
= PrettyTable(["field", "value"])
1595 for k
, v
in list(resp
.items()):
1596 if not filter or k
in filter:
1597 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
1600 # except ClientException as e:
1605 # @cli_osm.command(name='vnf-monitoring-show')
1606 # @click.argument('vnf_name')
1607 # @click.pass_context
1608 # def vnf_monitoring_show(ctx, vnf_name):
1610 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1611 # resp = ctx.obj.vnf.get_monitoring(vnf_name)
1612 # except ClientException as e:
1616 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1617 # if resp is not None:
1618 # for monitor in resp:
1622 # monitor['value-integer'],
1623 # monitor['units']])
1628 # @cli_osm.command(name='ns-monitoring-show')
1629 # @click.argument('ns_name')
1630 # @click.pass_context
1631 # def ns_monitoring_show(ctx, ns_name):
1633 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1634 # resp = ctx.obj.ns.get_monitoring(ns_name)
1635 # except ClientException as e:
1639 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1640 # for key, val in list(resp.items()):
1641 # for monitor in val:
1645 # monitor['value-integer'],
1646 # monitor['units']])
1651 @cli_osm.command(name
="ns-op-show", short_help
="shows the info of a NS operation")
1652 @click.argument("id")
1656 help="restricts the information to the fields in the filter",
1658 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1660 def ns_op_show(ctx
, id, filter, literal
):
1661 """shows the detailed info of a NS operation
1663 ID: operation identifier
1667 check_client_version(ctx
.obj
, ctx
.command
.name
)
1668 op_info
= ctx
.obj
.ns
.get_op(id)
1669 # except ClientException as e:
1674 print(yaml
.safe_dump(op_info
, indent
=4, default_flow_style
=False))
1677 table
= PrettyTable(["field", "value"])
1678 for k
, v
in list(op_info
.items()):
1679 if not filter or k
in filter:
1680 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1685 def nst_show(ctx
, name
, literal
):
1688 check_client_version(ctx
.obj
, ctx
.command
.name
)
1689 resp
= ctx
.obj
.nst
.get(name
)
1690 # resp = ctx.obj.nst.get_individual(name)
1691 # except ClientException as e:
1696 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
1699 table
= PrettyTable(["field", "value"])
1700 for k
, v
in list(resp
.items()):
1701 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1707 name
="nst-show", short_help
="shows the content of a Network Slice Template (NST)"
1709 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1710 @click.argument("name")
1712 def nst_show1(ctx
, name
, literal
):
1713 """shows the content of a Network Slice Template (NST)
1715 NAME: name or ID of the NST
1718 nst_show(ctx
, name
, literal
)
1722 name
="netslice-template-show",
1723 short_help
="shows the content of a Network Slice Template (NST)",
1725 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1726 @click.argument("name")
1728 def nst_show2(ctx
, name
, literal
):
1729 """shows the content of a Network Slice Template (NST)
1731 NAME: name or ID of the NST
1734 nst_show(ctx
, name
, literal
)
1737 def nsi_show(ctx
, name
, literal
, filter):
1740 check_client_version(ctx
.obj
, ctx
.command
.name
)
1741 nsi
= ctx
.obj
.nsi
.get(name
)
1742 # except ClientException as e:
1747 print(yaml
.safe_dump(nsi
, indent
=4, default_flow_style
=False))
1750 table
= PrettyTable(["field", "value"])
1752 for k
, v
in list(nsi
.items()):
1753 if not filter or k
in filter:
1754 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1761 name
="nsi-show", short_help
="shows the content of a Network Slice Instance (NSI)"
1763 @click.argument("name")
1764 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1768 help="restricts the information to the fields in the filter",
1771 def nsi_show1(ctx
, name
, literal
, filter):
1772 """shows the content of a Network Slice Instance (NSI)
1774 NAME: name or ID of the Network Slice Instance
1777 nsi_show(ctx
, name
, literal
, filter)
1781 name
="netslice-instance-show",
1782 short_help
="shows the content of a Network Slice Instance (NSI)",
1784 @click.argument("name")
1785 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1789 help="restricts the information to the fields in the filter",
1792 def nsi_show2(ctx
, name
, literal
, filter):
1793 """shows the content of a Network Slice Instance (NSI)
1795 NAME: name or ID of the Network Slice Instance
1798 nsi_show(ctx
, name
, literal
, filter)
1801 def nsi_op_show(ctx
, id, filter):
1804 check_client_version(ctx
.obj
, ctx
.command
.name
)
1805 op_info
= ctx
.obj
.nsi
.get_op(id)
1806 # except ClientException as e:
1810 table
= PrettyTable(["field", "value"])
1811 for k
, v
in list(op_info
.items()):
1812 if not filter or k
in filter:
1813 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1820 short_help
="shows the info of an operation over a Network Slice Instance(NSI)",
1822 @click.argument("id")
1826 help="restricts the information to the fields in the filter",
1829 def nsi_op_show1(ctx
, id, filter):
1830 """shows the info of an operation over a Network Slice Instance(NSI)
1832 ID: operation identifier
1835 nsi_op_show(ctx
, id, filter)
1839 name
="netslice-instance-op-show",
1840 short_help
="shows the info of an operation over a Network Slice Instance(NSI)",
1842 @click.argument("id")
1846 help="restricts the information to the fields in the filter",
1849 def nsi_op_show2(ctx
, id, filter):
1850 """shows the info of an operation over a Network Slice Instance(NSI)
1852 ID: operation identifier
1855 nsi_op_show(ctx
, id, filter)
1859 name
="pdu-show", short_help
="shows the content of a Physical Deployment Unit (PDU)"
1861 @click.argument("name")
1862 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
1866 help="restricts the information to the fields in the filter",
1869 def pdu_show(ctx
, name
, literal
, filter):
1870 """shows the content of a Physical Deployment Unit (PDU)
1872 NAME: name or ID of the PDU
1876 check_client_version(ctx
.obj
, ctx
.command
.name
)
1877 pdu
= ctx
.obj
.pdu
.get(name
)
1878 # except ClientException as e:
1883 print(yaml
.safe_dump(pdu
, indent
=4, default_flow_style
=False))
1886 table
= PrettyTable(["field", "value"])
1888 for k
, v
in list(pdu
.items()):
1889 if not filter or k
in filter:
1890 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1896 ####################
1898 ####################
1901 def nsd_create(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
1904 check_client_version(ctx
.obj
, ctx
.command
.name
)
1906 filename
= ctx
.obj
.osmrepo
.get_pkg("ns", filename
, repo
, vendor
, version
)
1907 ctx
.obj
.nsd
.create(filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1908 # except ClientException as e:
1913 @cli_osm.command(name
="nsd-create", short_help
="creates a new NSD/NSpkg")
1914 @click.argument("filename")
1918 default
=None, # hidden=True,
1919 help="Deprecated. Use override",
1925 help="overrides fields in descriptor, format: "
1926 '"key1.key2...=value[;key3...=value;...]"',
1929 "--skip-charm-build",
1932 help="The charm will not be compiled, it is assumed to already exist",
1934 @click.option("--repo", default
=None, help="[repository]: Repository name")
1935 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
1939 help="[repository]: filter by version. Default: latest",
1942 def nsd_create1(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
1943 """onboards a new NSpkg (alias of nspkg-create) (TO BE DEPRECATED)
1946 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
1947 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
1948 If FILENAME is an NF Package folder, it is built and then onboarded.
1954 overwrite
=overwrite
,
1955 skip_charm_build
=skip_charm_build
,
1962 @cli_osm.command(name
="nspkg-create", short_help
="creates a new NSD/NSpkg")
1963 @click.argument("filename")
1967 default
=None, # hidden=True,
1968 help="Deprecated. Use override",
1974 help="overrides fields in descriptor, format: "
1975 '"key1.key2...=value[;key3...=value;...]"',
1978 "--skip-charm-build",
1981 help="The charm will not be compiled, it is assumed to already exist",
1983 @click.option("--repo", default
=None, help="[repository]: Repository name")
1984 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
1988 help="[repository]: filter by version. Default: latest",
1991 def nsd_pkg_create(ctx
, filename
, overwrite
, skip_charm_build
, repo
, vendor
, version
):
1992 """onboards a new NSpkg
1994 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
1995 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
1996 If FILENAME is an NF Package folder, it is built and then onboarded.
2002 overwrite
=overwrite
,
2003 skip_charm_build
=skip_charm_build
,
2024 check_client_version(ctx
.obj
, ctx
.command
.name
)
2026 filename
= ctx
.obj
.osmrepo
.get_pkg("vnf", filename
, repo
, vendor
, version
)
2027 ctx
.obj
.vnfd
.create(
2029 overwrite
=overwrite
,
2030 skip_charm_build
=skip_charm_build
,
2031 override_epa
=override_epa
,
2032 override_nonepa
=override_nonepa
,
2033 override_paravirt
=override_paravirt
,
2035 # except ClientException as e:
2040 @cli_osm.command(name
="vnfd-create", short_help
="creates a new VNFD/VNFpkg")
2041 @click.argument("filename")
2043 "--overwrite", "overwrite", default
=None, help="overwrite deprecated, use override"
2049 help="overrides fields in descriptor, format: "
2050 '"key1.key2...=value[;key3...=value;...]"',
2053 "--skip-charm-build",
2056 help="The charm will not be compiled, it is assumed to already exist",
2063 help="adds guest-epa parameters to all VDU",
2066 "--override-nonepa",
2070 help="removes all guest-epa parameters from all VDU",
2073 "--override-paravirt",
2077 help="overrides all VDU interfaces to PARAVIRT",
2079 @click.option("--repo", default
=None, help="[repository]: Repository name")
2080 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2084 help="[repository]: filter by version. Default: latest",
2099 """creates a new VNFD/VNFpkg
2101 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2102 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2103 If FILENAME is an NF Package folder, it is built and then onboarded.
2109 overwrite
=overwrite
,
2110 skip_charm_build
=skip_charm_build
,
2111 override_epa
=override_epa
,
2112 override_nonepa
=override_nonepa
,
2113 override_paravirt
=override_paravirt
,
2120 @cli_osm.command(name
="vnfpkg-create", short_help
="creates a new VNFD/VNFpkg")
2121 @click.argument("filename")
2125 default
=None, # hidden=True,
2126 help="Deprecated. Use override",
2132 help="overrides fields in descriptor, format: "
2133 '"key1.key2...=value[;key3...=value;...]"',
2136 "--skip-charm-build",
2139 help="The charm will not be compiled, it is assumed to already exist",
2146 help="adds guest-epa parameters to all VDU",
2149 "--override-nonepa",
2153 help="removes all guest-epa parameters from all VDU",
2156 "--override-paravirt",
2160 help="overrides all VDU interfaces to PARAVIRT",
2162 @click.option("--repo", default
=None, help="[repository]: Repository name")
2163 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2167 help="[repository]: filter by version. Default: latest",
2182 """creates a new VNFD/VNFpkg
2184 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2185 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2186 If FILENAME is an NF Package folder, it is built and then onboarded.
2192 overwrite
=overwrite
,
2193 skip_charm_build
=skip_charm_build
,
2194 override_epa
=override_epa
,
2195 override_nonepa
=override_nonepa
,
2196 override_paravirt
=override_paravirt
,
2203 @cli_osm.command(name
="nfpkg-create", short_help
="creates a new NFpkg")
2204 @click.argument("filename")
2208 default
=None, # hidden=True,
2209 help="Deprecated. Use override",
2215 help="overrides fields in descriptor, format: "
2216 '"key1.key2...=value[;key3...=value;...]"',
2219 "--skip-charm-build",
2222 help="The charm will not be compiled, it is assumed to already exist",
2229 help="adds guest-epa parameters to all VDU",
2232 "--override-nonepa",
2236 help="removes all guest-epa parameters from all VDU",
2239 "--override-paravirt",
2243 help="overrides all VDU interfaces to PARAVIRT",
2245 @click.option("--repo", default
=None, help="[repository]: Repository name")
2246 @click.option("--vendor", default
=None, help="[repository]: filter by vendor]")
2250 help="[repository]: filter by version. Default: latest",
2265 """creates a new NFpkg
2268 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2269 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2270 If FILENAME is an NF Package folder, it is built and then onboarded.
2276 overwrite
=overwrite
,
2277 skip_charm_build
=skip_charm_build
,
2278 override_epa
=override_epa
,
2279 override_nonepa
=override_nonepa
,
2280 override_paravirt
=override_paravirt
,
2287 @cli_osm.command(name
="ns-create", short_help
="creates a new Network Service instance")
2288 @click.option("--ns_name", prompt
=True, help="name of the NS instance")
2289 @click.option("--nsd_name", prompt
=True, help="name of the NS descriptor")
2293 help="default VIM account id or name for the deployment",
2298 help="default PaaS account id or name for the deployment",
2300 @click.option("--admin_status", default
="ENABLED", help="administration status")
2304 help="comma separated list of public key files to inject to vnfs",
2306 @click.option("--config", default
=None, help="ns specific yaml configuration")
2307 @click.option("--config_file", default
=None, help="ns specific yaml configuration file")
2313 help="do not return the control immediately, but keep it "
2314 "until the operation is completed, or timeout",
2316 @click.option("--timeout", default
=None, help="ns deployment timeout")
2331 """creates a new NS instance"""
2335 check_client_version(ctx
.obj
, "--config_file")
2337 raise ClientException(
2338 '"--config" option is incompatible with "--config_file" option'
2340 with
open(config_file
, "r") as cf
:
2342 if not (vim_account
or paas_account
):
2343 raise ClientException(
2344 'specify "vim_account" or "paas_account", both options can not be empty'
2346 if vim_account
and paas_account
:
2347 raise ClientException(
2348 '"vim_account" and "paas_account" can not be used together, use only one of them'
2355 vim_account
=vim_account
,
2356 paas_account
=paas_account
,
2357 admin_status
=admin_status
,
2363 def nst_create(ctx
, filename
, overwrite
):
2366 check_client_version(ctx
.obj
, ctx
.command
.name
)
2367 ctx
.obj
.nst
.create(filename
, overwrite
)
2368 # except ClientException as e:
2374 name
="nst-create", short_help
="creates a new Network Slice Template (NST)"
2376 @click.argument("filename")
2380 default
=None, # hidden=True,
2381 help="Deprecated. Use override",
2387 help="overrides fields in descriptor, format: "
2388 '"key1.key2...=value[;key3...=value;...]"',
2391 def nst_create1(ctx
, filename
, overwrite
):
2392 """creates a new Network Slice Template (NST)
2394 FILENAME: NST package folder, NST yaml file or NSTpkg tar.gz file
2397 nst_create(ctx
, filename
, overwrite
)
2401 name
="netslice-template-create",
2402 short_help
="creates a new Network Slice Template (NST)",
2404 @click.argument("filename")
2408 default
=None, # hidden=True,
2409 help="Deprecated. Use override",
2415 help="overrides fields in descriptor, format: "
2416 '"key1.key2...=value[;key3...=value;...]"',
2419 def nst_create2(ctx
, filename
, overwrite
):
2420 """creates a new Network Slice Template (NST)
2422 FILENAME: NST yaml file or NSTpkg tar.gz file
2425 nst_create(ctx
, filename
, overwrite
)
2429 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2431 """creates a new Network Slice Instance (NSI)"""
2434 check_client_version(ctx
.obj
, ctx
.command
.name
)
2437 raise ClientException(
2438 '"--config" option is incompatible with "--config_file" option'
2440 with
open(config_file
, "r") as cf
:
2447 account
=vim_account
,
2450 # except ClientException as e:
2455 @cli_osm.command(name
="nsi-create", short_help
="creates a new Network Slice Instance")
2456 @click.option("--nsi_name", prompt
=True, help="name of the Network Slice Instance")
2457 @click.option("--nst_name", prompt
=True, help="name of the Network Slice Template")
2461 help="default VIM account id or name for the deployment",
2464 "--ssh_keys", default
=None, help="comma separated list of keys to inject to vnfs"
2469 help="Netslice specific yaml configuration:\n"
2470 "netslice_subnet: [\n"
2471 "id: TEXT, vim_account: TEXT,\n"
2472 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2473 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n"
2474 "additionalParamsForNsi: {param: value, ...}\n"
2475 "additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n"
2477 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2480 "--config_file", default
=None, help="nsi specific yaml configuration file"
2487 help="do not return the control immediately, but keep it "
2488 "until the operation is completed, or timeout",
2492 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2494 """creates a new Network Slice Instance (NSI)"""
2497 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
2502 name
="netslice-instance-create", short_help
="creates a new Network Slice Instance"
2504 @click.option("--nsi_name", prompt
=True, help="name of the Network Slice Instance")
2505 @click.option("--nst_name", prompt
=True, help="name of the Network Slice Template")
2509 help="default VIM account id or name for the deployment",
2512 "--ssh_keys", default
=None, help="comma separated list of keys to inject to vnfs"
2517 help="Netslice specific yaml configuration:\n"
2518 "netslice_subnet: [\n"
2519 "id: TEXT, vim_account: TEXT,\n"
2520 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2521 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]"
2523 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2526 "--config_file", default
=None, help="nsi specific yaml configuration file"
2533 help="do not return the control immediately, but keep it "
2534 "until the operation is completed, or timeout",
2538 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
2540 """creates a new Network Slice Instance (NSI)"""
2543 ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
2548 name
="pdu-create", short_help
="adds a new Physical Deployment Unit to the catalog"
2550 @click.option("--name", help="name of the Physical Deployment Unit")
2551 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2554 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2555 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2558 @click.option("--description", help="human readable description")
2561 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2562 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2563 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2567 "--descriptor_file",
2569 help="PDU descriptor file (as an alternative to using the other arguments)",
2573 ctx
, name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2575 """creates a new Physical Deployment Unit (PDU)"""
2578 check_client_version(ctx
.obj
, ctx
.command
.name
)
2580 pdu
= create_pdu_dictionary(
2581 name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2583 ctx
.obj
.pdu
.create(pdu
)
2586 ########################
2587 # UPDATE PDU operation #
2588 ########################
2592 name
="pdu-update", short_help
="updates a Physical Deployment Unit to the catalog"
2594 @click.argument("name")
2595 @click.option("--newname", help="New name for the Physical Deployment Unit")
2596 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2599 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2600 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2603 @click.option("--description", help="human readable description")
2606 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2607 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2608 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2612 "--descriptor_file",
2614 help="PDU descriptor file (as an alternative to using the other arguments)",
2618 ctx
, name
, newname
, pdu_type
, interface
, description
, vim_account
, descriptor_file
2620 """Updates a new Physical Deployment Unit (PDU)"""
2623 check_client_version(ctx
.obj
, ctx
.command
.name
)
2630 pdu
= create_pdu_dictionary(
2631 newname
, pdu_type
, interface
, description
, vim_account
, descriptor_file
, update
2633 ctx
.obj
.pdu
.update(name
, pdu
)
2636 def create_pdu_dictionary(
2637 name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
, update
=False
2643 if not descriptor_file
:
2646 raise ClientException(
2647 'in absence of descriptor file, option "--name" is mandatory'
2650 raise ClientException(
2651 'in absence of descriptor file, option "--pdu_type" is mandatory'
2654 raise ClientException(
2655 'in absence of descriptor file, option "--interface" is mandatory (at least once)'
2658 raise ClientException(
2659 'in absence of descriptor file, option "--vim_account" is mandatory (at least once)'
2662 with
open(descriptor_file
, "r") as df
:
2663 pdu
= yaml
.safe_load(df
.read())
2667 pdu
["type"] = pdu_type
2669 pdu
["description"] = description
2671 pdu
["vim_accounts"] = vim_account
2674 for iface
in interface
:
2675 new_iface
= {k
: v
for k
, v
in [i
.split("=") for i
in iface
.split(",")]}
2676 new_iface
["mgmt"] = new_iface
.get("mgmt", "false").lower() == "true"
2677 ifaces_list
.append(new_iface
)
2678 pdu
["interfaces"] = ifaces_list
2682 ####################
2684 ####################
2687 def nsd_update(ctx
, name
, content
):
2690 check_client_version(ctx
.obj
, ctx
.command
.name
)
2691 ctx
.obj
.nsd
.update(name
, content
)
2692 # except ClientException as e:
2697 @cli_osm.command(name
="nsd-update", short_help
="updates a NSD/NSpkg")
2698 @click.argument("name")
2702 help="filename with the NSD/NSpkg replacing the current one",
2705 def nsd_update1(ctx
, name
, content
):
2706 """updates a NSD/NSpkg
2708 NAME: name or ID of the NSD/NSpkg
2711 nsd_update(ctx
, name
, content
)
2714 @cli_osm.command(name
="nspkg-update", short_help
="updates a NSD/NSpkg")
2715 @click.argument("name")
2719 help="filename with the NSD/NSpkg replacing the current one",
2722 def nsd_update2(ctx
, name
, content
):
2723 """updates a NSD/NSpkg
2725 NAME: name or ID of the NSD/NSpkg
2728 nsd_update(ctx
, name
, content
)
2731 def vnfd_update(ctx
, name
, content
):
2734 check_client_version(ctx
.obj
, ctx
.command
.name
)
2735 ctx
.obj
.vnfd
.update(name
, content
)
2736 # except ClientException as e:
2741 @cli_osm.command(name
="vnfd-update", short_help
="updates a new VNFD/VNFpkg")
2742 @click.argument("name")
2746 help="filename with the VNFD/VNFpkg replacing the current one",
2749 def vnfd_update1(ctx
, name
, content
):
2750 """updates a VNFD/VNFpkg
2752 NAME: name or ID of the VNFD/VNFpkg
2755 vnfd_update(ctx
, name
, content
)
2758 @cli_osm.command(name
="vnfpkg-update", short_help
="updates a VNFD/VNFpkg")
2759 @click.argument("name")
2763 help="filename with the VNFD/VNFpkg replacing the current one",
2766 def vnfd_update2(ctx
, name
, content
):
2767 """updates a VNFD/VNFpkg
2769 NAME: VNFD yaml file or VNFpkg tar.gz file
2772 vnfd_update(ctx
, name
, content
)
2775 @cli_osm.command(name
="nfpkg-update", short_help
="updates a NFpkg")
2776 @click.argument("name")
2778 "--content", default
=None, help="filename with the NFpkg replacing the current one"
2781 def nfpkg_update(ctx
, name
, content
):
2784 NAME: NF Descriptor yaml file or NFpkg tar.gz file
2787 vnfd_update(ctx
, name
, content
)
2790 def nst_update(ctx
, name
, content
):
2793 check_client_version(ctx
.obj
, ctx
.command
.name
)
2794 ctx
.obj
.nst
.update(name
, content
)
2795 # except ClientException as e:
2800 @cli_osm.command(name
="nst-update", short_help
="updates a Network Slice Template (NST)")
2801 @click.argument("name")
2805 help="filename with the NST/NSTpkg replacing the current one",
2808 def nst_update1(ctx
, name
, content
):
2809 """updates a Network Slice Template (NST)
2811 NAME: name or ID of the NSD/NSpkg
2814 nst_update(ctx
, name
, content
)
2818 name
="netslice-template-update", short_help
="updates a Network Slice Template (NST)"
2820 @click.argument("name")
2824 help="filename with the NST/NSTpkg replacing the current one",
2827 def nst_update2(ctx
, name
, content
):
2828 """updates a Network Slice Template (NST)
2830 NAME: name or ID of the NSD/NSpkg
2833 nst_update(ctx
, name
, content
)
2836 ####################
2838 ####################
2841 def nsd_delete(ctx
, name
, force
):
2845 ctx
.obj
.nsd
.delete(name
)
2847 check_client_version(ctx
.obj
, "--force")
2848 ctx
.obj
.nsd
.delete(name
, force
)
2849 # except ClientException as e:
2854 @cli_osm.command(name
="nsd-delete", short_help
="deletes a NSD/NSpkg")
2855 @click.argument("name")
2857 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2860 def nsd_delete1(ctx
, name
, force
):
2861 """deletes a NSD/NSpkg
2863 NAME: name or ID of the NSD/NSpkg to be deleted
2866 nsd_delete(ctx
, name
, force
)
2869 @cli_osm.command(name
="nspkg-delete", short_help
="deletes a NSD/NSpkg")
2870 @click.argument("name")
2872 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2875 def nsd_delete2(ctx
, name
, force
):
2876 """deletes a NSD/NSpkg
2878 NAME: name or ID of the NSD/NSpkg to be deleted
2881 nsd_delete(ctx
, name
, force
)
2884 def vnfd_delete(ctx
, name
, force
):
2888 ctx
.obj
.vnfd
.delete(name
)
2890 check_client_version(ctx
.obj
, "--force")
2891 ctx
.obj
.vnfd
.delete(name
, force
)
2892 # except ClientException as e:
2897 @cli_osm.command(name
="vnfd-delete", short_help
="deletes a VNFD/VNFpkg")
2898 @click.argument("name")
2900 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2903 def vnfd_delete1(ctx
, name
, force
):
2904 """deletes a VNFD/VNFpkg
2906 NAME: name or ID of the VNFD/VNFpkg to be deleted
2909 vnfd_delete(ctx
, name
, force
)
2912 @cli_osm.command(name
="vnfpkg-delete", short_help
="deletes a VNFD/VNFpkg")
2913 @click.argument("name")
2915 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2918 def vnfd_delete2(ctx
, name
, force
):
2919 """deletes a VNFD/VNFpkg
2921 NAME: name or ID of the VNFD/VNFpkg to be deleted
2924 vnfd_delete(ctx
, name
, force
)
2927 @cli_osm.command(name
="nfpkg-delete", short_help
="deletes a NFpkg")
2928 @click.argument("name")
2930 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2933 def nfpkg_delete(ctx
, name
, force
):
2936 NAME: name or ID of the NFpkg to be deleted
2939 vnfd_delete(ctx
, name
, force
)
2942 @cli_osm.command(name
="ns-delete", short_help
="deletes a NS instance")
2943 @click.argument("name")
2945 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2950 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
2951 "600, skip_terminate_primitives: True}'",
2958 help="do not return the control immediately, but keep it "
2959 "until the operation is completed, or timeout",
2962 def ns_delete(ctx
, name
, force
, config
, wait
):
2963 """deletes a NS instance
2965 NAME: name or ID of the NS instance to be deleted
2970 ctx
.obj
.ns
.delete(name
, config
=config
, wait
=wait
)
2972 check_client_version(ctx
.obj
, "--force")
2973 ctx
.obj
.ns
.delete(name
, force
, config
=config
, wait
=wait
)
2974 # except ClientException as e:
2979 def nst_delete(ctx
, name
, force
):
2982 check_client_version(ctx
.obj
, ctx
.command
.name
)
2983 ctx
.obj
.nst
.delete(name
, force
)
2984 # except ClientException as e:
2989 @cli_osm.command(name
="nst-delete", short_help
="deletes a Network Slice Template (NST)")
2990 @click.argument("name")
2992 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
2995 def nst_delete1(ctx
, name
, force
):
2996 """deletes a Network Slice Template (NST)
2998 NAME: name or ID of the NST/NSTpkg to be deleted
3001 nst_delete(ctx
, name
, force
)
3005 name
="netslice-template-delete", short_help
="deletes a Network Slice Template (NST)"
3007 @click.argument("name")
3009 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3012 def nst_delete2(ctx
, name
, force
):
3013 """deletes a Network Slice Template (NST)
3015 NAME: name or ID of the NST/NSTpkg to be deleted
3018 nst_delete(ctx
, name
, force
)
3021 def nsi_delete(ctx
, name
, force
, wait
):
3024 check_client_version(ctx
.obj
, ctx
.command
.name
)
3025 ctx
.obj
.nsi
.delete(name
, force
, wait
=wait
)
3026 # except ClientException as e:
3031 @cli_osm.command(name
="nsi-delete", short_help
="deletes a Network Slice Instance (NSI)")
3032 @click.argument("name")
3034 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3041 help="do not return the control immediately, but keep it "
3042 "until the operation is completed, or timeout",
3045 def nsi_delete1(ctx
, name
, force
, wait
):
3046 """deletes a Network Slice Instance (NSI)
3048 NAME: name or ID of the Network Slice instance to be deleted
3051 nsi_delete(ctx
, name
, force
, wait
=wait
)
3055 name
="netslice-instance-delete", short_help
="deletes a Network Slice Instance (NSI)"
3057 @click.argument("name")
3059 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3062 def nsi_delete2(ctx
, name
, force
, wait
):
3063 """deletes a Network Slice Instance (NSI)
3065 NAME: name or ID of the Network Slice instance to be deleted
3068 nsi_delete(ctx
, name
, force
, wait
=wait
)
3072 name
="pdu-delete", short_help
="deletes a Physical Deployment Unit (PDU)"
3074 @click.argument("name")
3076 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3079 def pdu_delete(ctx
, name
, force
):
3080 """deletes a Physical Deployment Unit (PDU)
3082 NAME: name or ID of the PDU to be deleted
3086 check_client_version(ctx
.obj
, ctx
.command
.name
)
3087 ctx
.obj
.pdu
.delete(name
, force
)
3088 # except ClientException as e:
3098 def _check_ca_cert(vim_config
: dict) -> None:
3100 Checks if the VIM has a CA certificate.
3101 In that case, reads the content and add it to the config
3102 : param vim_config: configuration provided with the VIM creation
3106 if vim_config
.get("ca_cert"):
3107 with
open(vim_config
["ca_cert"], "r") as cert_f
:
3108 vim_config
["ca_cert_content"] = str(cert_f
.read())
3109 del vim_config
["ca_cert"]
3112 @cli_osm.command(name
="vim-create", short_help
="creates a new VIM account")
3113 @click.option("--name", required
=True, help="Name to create datacenter")
3114 @click.option("--user", default
=None, help="VIM username")
3115 @click.option("--password", default
=None, help="VIM password")
3116 @click.option("--auth_url", default
=None, help="VIM url")
3118 "--tenant", "--project", "tenant", default
=None, help="VIM tenant/project name"
3120 @click.option("--config", default
=None, help="VIM specific config parameters")
3124 help="VIM specific config parameters in YAML or JSON file",
3126 @click.option("--account_type", default
="openstack", help="VIM type")
3127 @click.option("--description", default
=None, help="human readable description")
3131 help="Name or id of the SDN controller associated to this VIM account",
3134 "--sdn_port_mapping",
3136 help="File describing the port mapping between compute nodes' ports and switch ports",
3143 help="do not return the control immediately, but keep it "
3144 "until the operation is completed, or timeout",
3146 @click.option("--vca", default
=None, help="VCA to be used in this VIM account")
3148 "--creds", default
=None, help="credentials file (only applycable for GCP VIM type)"
3151 "--prometheus_config_file",
3153 help="Prometheus configuration to get VIM data",
3172 prometheus_config_file
,
3174 """creates a new VIM account"""
3178 check_client_version(ctx
.obj
, "--sdn_controller")
3179 if sdn_port_mapping
:
3180 check_client_version(ctx
.obj
, "--sdn_port_mapping")
3182 if prometheus_config_file
:
3183 with
open(prometheus_config_file
) as prometheus_file
:
3184 prometheus_config_dict
= json
.load(prometheus_file
)
3185 vim
["prometheus-config"] = prometheus_config_dict
3187 vim
["vim-username"] = user
3188 vim
["vim-password"] = password
3189 vim
["vim-url"] = auth_url
3190 vim
["vim-tenant-name"] = tenant
3191 vim
["vim-type"] = account_type
3192 vim
["description"] = description
3195 vim_config
= create_config(config_file
, config
)
3196 _check_ca_cert(vim_config
)
3198 with
open(creds
, "r") as cf
:
3199 vim_config
["credentials"] = yaml
.safe_load(cf
.read())
3201 name
, vim
, vim_config
, sdn_controller
, sdn_port_mapping
, wait
=wait
3203 # except ClientException as e:
3208 @cli_osm.command(name
="vim-update", short_help
="updates a VIM account")
3209 @click.argument("name")
3210 @click.option("--newname", help="New name for the VIM account")
3211 @click.option("--user", help="VIM username")
3212 @click.option("--password", help="VIM password")
3213 @click.option("--auth_url", help="VIM url")
3214 @click.option("--tenant", help="VIM tenant name")
3215 @click.option("--config", help="VIM specific config parameters")
3219 help="VIM specific config parameters in YAML or JSON file",
3221 @click.option("--account_type", help="VIM type")
3222 @click.option("--description", help="human readable description")
3226 help="Name or id of the SDN controller to be associated with this VIM"
3227 "account. Use empty string to disassociate",
3230 "--sdn_port_mapping",
3232 help="File describing the port mapping between compute nodes' ports and switch ports",
3239 help="do not return the control immediately, but keep it "
3240 "until the operation is completed, or timeout",
3243 "--creds", default
=None, help="credentials file (only applycable for GCP VIM type)"
3246 "--prometheus_config_file",
3248 help="Prometheus configuration to get VIM data",
3267 prometheus_config_file
,
3269 """updates a VIM account
3271 NAME: name or ID of the VIM account
3275 check_client_version(ctx
.obj
, ctx
.command
.name
)
3278 vim
["name"] = newname
3280 vim
["vim_user"] = user
3282 vim
["vim_password"] = password
3284 vim
["vim_url"] = auth_url
3286 vim
["vim-tenant-name"] = tenant
3288 vim
["vim_type"] = account_type
3290 vim
["description"] = description
3292 if config
or config_file
:
3293 vim_config
= create_config(config_file
, config
)
3294 _check_ca_cert(vim_config
)
3296 with
open(creds
, "r") as cf
:
3297 vim_config
["credentials"] = yaml
.safe_load(cf
.read())
3298 if prometheus_config_file
:
3299 with
open(prometheus_config_file
) as prometheus_file
:
3300 prometheus_config_dict
= json
.load(prometheus_file
)
3301 vim
["prometheus-config"] = prometheus_config_dict
3302 logger
.info(f
"VIM: {vim}, VIM config: {vim_config}")
3304 name
, vim
, vim_config
, sdn_controller
, sdn_port_mapping
, wait
=wait
3306 # except ClientException as e:
3311 @cli_osm.command(name
="vim-delete", short_help
="deletes a VIM account")
3312 @click.argument("name")
3314 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3321 help="do not return the control immediately, but keep it "
3322 "until the operation is completed, or timeout",
3325 def vim_delete(ctx
, name
, force
, wait
):
3326 """deletes a VIM account
3328 NAME: name or ID of the VIM account to be deleted
3333 ctx
.obj
.vim
.delete(name
, wait
=wait
)
3335 check_client_version(ctx
.obj
, "--force")
3336 ctx
.obj
.vim
.delete(name
, force
, wait
=wait
)
3337 # except ClientException as e:
3342 @cli_osm.command(name
="vim-list", short_help
="list all VIM accounts")
3343 # @click.option('--ro_update/--no_ro_update',
3345 # help='update list from RO')
3350 help="restricts the list to the VIM accounts matching the filter",
3355 help="get more details of the NS (project, vim, deployment status, configuration status.",
3358 def vim_list(ctx
, filter, long):
3359 """list all VIM accounts"""
3362 filter = "&".join(filter)
3363 check_client_version(ctx
.obj
, "--filter")
3365 # check_client_version(ctx.obj, '--ro_update', 'v1')
3366 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
3367 if fullclassname
== "osmclient.sol005.client.Client":
3368 resp
= ctx
.obj
.vim
.list(filter)
3370 # resp = ctx.obj.vim.list(ro_update)
3372 table
= PrettyTable(
3373 ["vim name", "uuid", "project", "operational state", "error details"]
3375 project_list
= ctx
.obj
.project
.list()
3377 table
= PrettyTable(["vim name", "uuid", "operational state"])
3380 if "vim_password" in vim
:
3381 vim
["vim_password"] = "********"
3382 if "config" in vim
and "credentials" in vim
["config"]:
3383 vim
["config"]["credentials"] = "********"
3384 logger
.debug("VIM details: {}".format(yaml
.safe_dump(vim
)))
3385 vim_state
= vim
["_admin"].get("operationalState", "-")
3386 error_details
= "N/A"
3387 if vim_state
== "ERROR":
3388 error_details
= vim
["_admin"].get("detailed-status", "Not found")
3389 project_id
, project_name
= get_project(project_list
, vim
)
3390 # project_info = '{} ({})'.format(project_name, project_id)
3391 project_info
= project_name
3398 wrap_text(text
=error_details
, width
=80),
3403 [vim
["name"], vim
["uuid"], vim
["_admin"].get("operationalState", "-")]
3409 @cli_osm.command(name
="vim-show", short_help
="shows the details of a VIM account")
3410 @click.argument("name")
3414 help="restricts the information to the fields in the filter",
3416 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
3418 def vim_show(ctx
, name
, filter, literal
):
3419 """shows the details of a VIM account
3421 NAME: name or ID of the VIM account
3425 resp
= ctx
.obj
.vim
.get(name
)
3426 if "vim_password" in resp
:
3427 resp
["vim_password"] = "********"
3428 if "config" in resp
and "credentials" in resp
["config"]:
3429 resp
["config"]["credentials"] = "********"
3430 # except ClientException as e:
3435 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
3437 table
= PrettyTable(["key", "attribute"])
3438 for k
, v
in list(resp
.items()):
3439 if not filter or k
in filter:
3440 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
3445 ####################
3447 ####################
3450 @cli_osm.command(name
="wim-create", short_help
="creates a new WIM account")
3451 @click.option("--name", prompt
=True, help="Name for the WIM account")
3452 @click.option("--user", help="WIM username")
3453 @click.option("--password", help="WIM password")
3454 @click.option("--url", prompt
=True, help="WIM url")
3455 # @click.option('--tenant',
3456 # help='wIM tenant name')
3457 @click.option("--config", default
=None, help="WIM specific config parameters")
3458 @click.option("--wim_type", help="WIM type")
3459 @click.option("--description", default
=None, help="human readable description")
3461 "--wim_port_mapping",
3463 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3464 "(WAN service endpoint id and info)",
3471 help="do not return the control immediately, but keep it "
3472 "until the operation is completed, or timeout",
3488 """creates a new WIM account"""
3491 check_client_version(ctx
.obj
, ctx
.command
.name
)
3492 # if sdn_controller:
3493 # check_client_version(ctx.obj, '--sdn_controller')
3494 # if sdn_port_mapping:
3495 # check_client_version(ctx.obj, '--sdn_port_mapping')
3500 wim
["password"] = password
3502 wim
["wim_url"] = url
3503 # if tenant: wim['tenant'] = tenant
3504 wim
["wim_type"] = wim_type
3506 wim
["description"] = description
3508 wim
["config"] = config
3509 ctx
.obj
.wim
.create(name
, wim
, wim_port_mapping
, wait
=wait
)
3510 # except ClientException as e:
3515 @cli_osm.command(name
="wim-update", short_help
="updates a WIM account")
3516 @click.argument("name")
3517 @click.option("--newname", help="New name for the WIM account")
3518 @click.option("--user", help="WIM username")
3519 @click.option("--password", help="WIM password")
3520 @click.option("--url", help="WIM url")
3521 @click.option("--config", help="WIM specific config parameters")
3522 @click.option("--wim_type", help="WIM type")
3523 @click.option("--description", help="human readable description")
3525 "--wim_port_mapping",
3527 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3528 "(WAN service endpoint id and info)",
3535 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3551 """updates a WIM account
3553 NAME: name or ID of the WIM account
3557 check_client_version(ctx
.obj
, ctx
.command
.name
)
3560 wim
["name"] = newname
3564 wim
["password"] = password
3567 # if tenant: wim['tenant'] = tenant
3569 wim
["wim_type"] = wim_type
3571 wim
["description"] = description
3573 wim
["config"] = config
3574 ctx
.obj
.wim
.update(name
, wim
, wim_port_mapping
, wait
=wait
)
3575 # except ClientException as e:
3580 @cli_osm.command(name
="wim-delete", short_help
="deletes a WIM account")
3581 @click.argument("name")
3583 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3590 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3593 def wim_delete(ctx
, name
, force
, wait
):
3594 """deletes a WIM account
3596 NAME: name or ID of the WIM account to be deleted
3600 check_client_version(ctx
.obj
, ctx
.command
.name
)
3601 ctx
.obj
.wim
.delete(name
, force
, wait
=wait
)
3602 # except ClientException as e:
3607 @cli_osm.command(name
="wim-list", short_help
="list all WIM accounts")
3612 help="restricts the list to the WIM accounts matching the filter",
3615 def wim_list(ctx
, filter):
3616 """list all WIM accounts"""
3619 check_client_version(ctx
.obj
, ctx
.command
.name
)
3621 filter = "&".join(filter)
3622 resp
= ctx
.obj
.wim
.list(filter)
3623 table
= PrettyTable(["wim name", "uuid"])
3625 table
.add_row([wim
["name"], wim
["uuid"]])
3628 # except ClientException as e:
3633 @cli_osm.command(name
="wim-show", short_help
="shows the details of a WIM account")
3634 @click.argument("name")
3636 def wim_show(ctx
, name
):
3637 """shows the details of a WIM account
3639 NAME: name or ID of the WIM account
3643 check_client_version(ctx
.obj
, ctx
.command
.name
)
3644 resp
= ctx
.obj
.wim
.get(name
)
3645 if "password" in resp
:
3646 resp
["password"] = "********"
3647 # except ClientException as e:
3651 table
= PrettyTable(["key", "attribute"])
3652 for k
, v
in list(resp
.items()):
3653 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3658 ####################
3659 # SDN controller operations
3660 ####################
3663 @cli_osm.command(name
="sdnc-create", short_help
="creates a new SDN controller")
3664 @click.option("--name", prompt
=True, help="Name to create sdn controller")
3665 @click.option("--type", prompt
=True, help="SDN controller type")
3667 "--sdn_controller_version", # hidden=True,
3668 help="Deprecated. Use --config {version: sdn_controller_version}",
3670 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3671 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True,
3672 @click.option("--port", help="Deprecated. Use --url") # hidden=True,
3674 "--switch_dpid", help="Deprecated. Use --config {switch_id: DPID}" # hidden=True,
3678 help="Extra information for SDN in yaml format, as {switch_id: identity used for the plugin (e.g. DPID: "
3679 "Openflow Datapath ID), version: version}",
3681 @click.option("--user", help="SDN controller username")
3685 confirmation_prompt
=True,
3686 help="SDN controller password",
3688 @click.option("--description", default
=None, help="human readable description")
3694 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3697 def sdnc_create(ctx
, **kwargs
):
3698 """creates a new SDN controller"""
3703 if kwargs
[x
] and x
not in ("wait", "ip_address", "port", "switch_dpid")
3705 if kwargs
.get("port"):
3706 print("option '--port' is deprecated, use '--url' instead")
3707 sdncontroller
["port"] = int(kwargs
["port"])
3708 if kwargs
.get("ip_address"):
3709 print("option '--ip_address' is deprecated, use '--url' instead")
3710 sdncontroller
["ip"] = kwargs
["ip_address"]
3711 if kwargs
.get("switch_dpid"):
3713 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3715 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
3716 if kwargs
.get("sdn_controller_version"):
3718 "option '--sdn_controller_version' is deprecated, use '--config={version: SDN_CONTROLLER_VERSION}'"
3722 check_client_version(ctx
.obj
, ctx
.command
.name
)
3723 ctx
.obj
.sdnc
.create(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
3724 # except ClientException as e:
3729 @cli_osm.command(name
="sdnc-update", short_help
="updates an SDN controller")
3730 @click.argument("name")
3731 @click.option("--newname", help="New name for the SDN controller")
3732 @click.option("--description", default
=None, help="human readable description")
3733 @click.option("--type", help="SDN controller type")
3734 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3737 help="Extra information for SDN in yaml format, as "
3738 "{switch_id: identity used for the plugin (e.g. DPID: "
3739 "Openflow Datapath ID), version: version}",
3741 @click.option("--user", help="SDN controller username")
3742 @click.option("--password", help="SDN controller password")
3743 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True
3744 @click.option("--port", help="Deprecated. Use --url") # hidden=True
3746 "--switch_dpid", help="Deprecated. Use --config {switch_dpid: DPID}"
3749 "--sdn_controller_version", help="Deprecated. Use --config {version: VERSION}"
3756 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3759 def sdnc_update(ctx
, **kwargs
):
3760 """updates an SDN controller
3762 NAME: name or ID of the SDN controller
3769 and x
not in ("wait", "ip_address", "port", "switch_dpid", "new_name")
3771 if kwargs
.get("newname"):
3772 sdncontroller
["name"] = kwargs
["newname"]
3773 if kwargs
.get("port"):
3774 print("option '--port' is deprecated, use '--url' instead")
3775 sdncontroller
["port"] = int(kwargs
["port"])
3776 if kwargs
.get("ip_address"):
3777 print("option '--ip_address' is deprecated, use '--url' instead")
3778 sdncontroller
["ip"] = kwargs
["ip_address"]
3779 if kwargs
.get("switch_dpid"):
3781 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3783 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
3784 if kwargs
.get("sdn_controller_version"):
3786 "option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
3791 check_client_version(ctx
.obj
, ctx
.command
.name
)
3792 ctx
.obj
.sdnc
.update(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
3793 # except ClientException as e:
3798 @cli_osm.command(name
="sdnc-delete", short_help
="deletes an SDN controller")
3799 @click.argument("name")
3801 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
3808 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3811 def sdnc_delete(ctx
, name
, force
, wait
):
3812 """deletes an SDN controller
3814 NAME: name or ID of the SDN controller to be deleted
3818 check_client_version(ctx
.obj
, ctx
.command
.name
)
3819 ctx
.obj
.sdnc
.delete(name
, force
, wait
=wait
)
3820 # except ClientException as e:
3825 @cli_osm.command(name
="sdnc-list", short_help
="list all SDN controllers")
3830 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'",
3833 def sdnc_list(ctx
, filter):
3834 """list all SDN controllers"""
3837 check_client_version(ctx
.obj
, ctx
.command
.name
)
3839 filter = "&".join(filter)
3840 resp
= ctx
.obj
.sdnc
.list(filter)
3841 # except ClientException as e:
3844 table
= PrettyTable(["sdnc name", "id"])
3846 table
.add_row([sdnc
["name"], sdnc
["_id"]])
3851 @cli_osm.command(name
="sdnc-show", short_help
="shows the details of an SDN controller")
3852 @click.argument("name")
3854 def sdnc_show(ctx
, name
):
3855 """shows the details of an SDN controller
3857 NAME: name or ID of the SDN controller
3861 check_client_version(ctx
.obj
, ctx
.command
.name
)
3862 resp
= ctx
.obj
.sdnc
.get(name
)
3863 # except ClientException as e:
3867 table
= PrettyTable(["key", "attribute"])
3868 for k
, v
in list(resp
.items()):
3869 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3874 ###########################
3875 # K8s cluster operations
3876 ###########################
3879 @cli_osm.command(name
="k8scluster-add", short_help
="adds a K8s cluster to OSM")
3880 @click.argument("name")
3882 "--creds", prompt
=True, help="credentials file, i.e. a valid `.kube/config` file"
3884 @click.option("--version", prompt
=True, help="Kubernetes version")
3886 "--vim", prompt
=True, help="VIM target, the VIM where the cluster resides"
3891 help='''list of VIM networks, in JSON inline format, where the cluster is
3892 accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3895 "--init-helm2/--skip-helm2", required
=False, default
=True, help="Initialize helm v2"
3898 "--init-helm3/--skip-helm3", required
=False, default
=True, help="Initialize helm v3"
3901 "--init-jujubundle/--skip-jujubundle",
3904 help="Initialize juju-bundle",
3906 @click.option("--description", default
=None, help="human readable description")
3909 default
="kube-system",
3910 help="namespace to be used for its operation, defaults to `kube-system`",
3917 help="do not return the control immediately, but keep it "
3918 "until the operation is completed, or timeout",
3923 help="list of CNI plugins, in JSON inline format, used in the cluster",
3925 # @click.option('--skip-init',
3927 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
3928 # @click.option('--wait',
3930 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3947 """adds a K8s cluster to OSM
3949 NAME: name of the K8s cluster
3952 check_client_version(ctx
.obj
, ctx
.command
.name
)
3954 cluster
["name"] = name
3955 with
open(creds
, "r") as cf
:
3956 cluster
["credentials"] = yaml
.safe_load(cf
.read())
3957 cluster
["k8s_version"] = version
3958 cluster
["vim_account"] = vim
3959 cluster
["nets"] = yaml
.safe_load(k8s_nets
)
3960 if not (init_helm2
and init_jujubundle
and init_helm3
):
3961 cluster
["deployment_methods"] = {
3962 "helm-chart": init_helm2
,
3963 "juju-bundle": init_jujubundle
,
3964 "helm-chart-v3": init_helm3
,
3967 cluster
["description"] = description
3969 cluster
["namespace"] = namespace
3971 cluster
["cni"] = yaml
.safe_load(cni
)
3972 ctx
.obj
.k8scluster
.create(name
, cluster
, wait
)
3973 # except ClientException as e:
3978 @cli_osm.command(name
="k8scluster-update", short_help
="updates a K8s cluster")
3979 @click.argument("name")
3980 @click.option("--newname", help="New name for the K8s cluster")
3981 @click.option("--creds", help="credentials file, i.e. a valid `.kube/config` file")
3982 @click.option("--version", help="Kubernetes version")
3983 @click.option("--vim", help="VIM target, the VIM where the cluster resides")
3986 help='''list of VIM networks, in JSON inline format, where the cluster is accessible
3987 via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3989 @click.option("--description", help="human readable description")
3992 help="namespace to be used for its operation, defaults to `kube-system`",
3999 help="do not return the control immediately, but keep it "
4000 "until the operation is completed, or timeout",
4003 "--cni", help="list of CNI plugins, in JSON inline format, used in the cluster"
4006 def k8scluster_update(
4007 ctx
, name
, newname
, creds
, version
, vim
, k8s_nets
, description
, namespace
, wait
, cni
4009 """updates a K8s cluster
4011 NAME: name or ID of the K8s cluster
4014 check_client_version(ctx
.obj
, ctx
.command
.name
)
4017 cluster
["name"] = newname
4019 with
open(creds
, "r") as cf
:
4020 cluster
["credentials"] = yaml
.safe_load(cf
.read())
4022 cluster
["k8s_version"] = version
4024 cluster
["vim_account"] = vim
4026 cluster
["nets"] = yaml
.safe_load(k8s_nets
)
4028 cluster
["description"] = description
4030 cluster
["namespace"] = namespace
4032 cluster
["cni"] = yaml
.safe_load(cni
)
4033 ctx
.obj
.k8scluster
.update(name
, cluster
, wait
)
4034 # except ClientException as e:
4039 @cli_osm.command(name
="k8scluster-delete", short_help
="deletes a K8s cluster")
4040 @click.argument("name")
4042 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4049 help="do not return the control immediately, but keep it "
4050 "until the operation is completed, or timeout",
4053 def k8scluster_delete(ctx
, name
, force
, wait
):
4054 """deletes a K8s cluster
4056 NAME: name or ID of the K8s cluster to be deleted
4059 check_client_version(ctx
.obj
, ctx
.command
.name
)
4060 ctx
.obj
.k8scluster
.delete(name
, force
, wait
)
4061 # except ClientException as e:
4066 @cli_osm.command(name
="k8scluster-list")
4071 help="restricts the list to the K8s clusters matching the filter",
4073 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4074 @click.option("--long", is_flag
=True, help="get more details")
4076 def k8scluster_list(ctx
, filter, literal
, long):
4077 """list all K8s clusters"""
4079 check_client_version(ctx
.obj
, ctx
.command
.name
)
4081 filter = "&".join(filter)
4082 resp
= ctx
.obj
.k8scluster
.list(filter)
4084 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4087 table
= PrettyTable(
4095 "Deployment methods",
4096 "Operational State",
4097 "Op. state (details)",
4102 project_list
= ctx
.obj
.project
.list()
4104 table
= PrettyTable(
4105 ["Name", "Id", "VIM", "Operational State", "Op. state details"]
4108 vim_list
= ctx
.obj
.vim
.list()
4111 for cluster
in resp
:
4112 logger
.debug("Cluster details: {}".format(yaml
.safe_dump(cluster
)))
4113 vim_name
= get_vim_name(vim_list
, cluster
["vim_account"])
4114 # vim_info = '{} ({})'.format(vim_name,cluster['vim_account'])
4116 op_state_details
= "Helm: {}\nJuju: {}".format(
4117 cluster
["_admin"].get("helm-chart", {}).get("operationalState", "-"),
4118 cluster
["_admin"].get("juju-bundle", {}).get("operationalState", "-"),
4121 project_id
, project_name
= get_project(project_list
, cluster
)
4122 # project_info = '{} ({})'.format(project_name, project_id)
4123 project_info
= project_name
4124 detailed_status
= cluster
["_admin"].get("detailed-status", "-")
4130 cluster
["k8s_version"],
4132 json
.dumps(cluster
["nets"]),
4133 json
.dumps(cluster
["deployment_methods"]),
4134 cluster
["_admin"]["operationalState"],
4136 trunc_text(cluster
.get("description") or "", 40),
4137 wrap_text(text
=detailed_status
, width
=40),
4146 cluster
["_admin"]["operationalState"],
4152 # except ClientException as e:
4158 name
="k8scluster-show", short_help
="shows the details of a K8s cluster"
4160 @click.argument("name")
4161 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4163 def k8scluster_show(ctx
, name
, literal
):
4164 """shows the details of a K8s cluster
4166 NAME: name or ID of the K8s cluster
4169 resp
= ctx
.obj
.k8scluster
.get(name
)
4171 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4173 table
= PrettyTable(["key", "attribute"])
4174 for k
, v
in list(resp
.items()):
4175 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
4178 # except ClientException as e:
4183 ###########################
4185 ###########################
4188 @cli_osm.command(name
="vca-add", short_help
="adds a VCA (Juju controller) to OSM")
4189 @click.argument("name")
4193 help="Comma-separated list of IP or hostnames of the Juju controller",
4195 @click.option("--user", prompt
=True, help="Username with admin priviledges")
4196 @click.option("--secret", prompt
=True, help="Password of the specified username")
4197 @click.option("--cacert", prompt
=True, help="CA certificate")
4201 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4204 "--lxd-credentials",
4206 help="Name of the cloud credentialsto be used for the LXD cloud",
4211 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4214 "--k8s-credentials",
4216 help="Name of the cloud credentialsto be used for the K8s cloud",
4218 @click.option("--model-config", default
={}, help="Configuration options for the models")
4219 @click.option("--description", default
=None, help="human readable description")
4235 """adds a VCA to OSM
4237 NAME: name of the VCA
4239 check_client_version(ctx
.obj
, ctx
.command
.name
)
4242 vca
["endpoints"] = endpoints
.split(",")
4244 vca
["secret"] = secret
4245 vca
["cacert"] = cacert
4246 vca
["lxd-cloud"] = lxd_cloud
4247 vca
["lxd-credentials"] = lxd_credentials
4248 vca
["k8s-cloud"] = k8s_cloud
4249 vca
["k8s-credentials"] = k8s_credentials
4251 vca
["description"] = description
4253 model_config
= load(model_config
)
4254 vca
["model-config"] = model_config
4255 ctx
.obj
.vca
.create(name
, vca
)
4258 def load(data
: Any
):
4259 if os
.path
.isfile(data
):
4260 return load_file(data
)
4263 return json
.loads(data
)
4264 except ValueError as e
:
4265 raise ClientException(e
)
4268 def load_file(file_path
: str) -> Dict
:
4270 with
open(file_path
, "r") as f
:
4273 return yaml
.safe_load(content
)
4274 except yaml
.scanner
.ScannerError
:
4277 return json
.loads(content
)
4280 raise ClientException(f
"{file_path} must be a valid yaml or json file")
4283 @cli_osm.command(name
="vca-update", short_help
="updates a K8s cluster")
4284 @click.argument("name")
4286 "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
4288 @click.option("--user", help="Username with admin priviledges")
4289 @click.option("--secret", help="Password of the specified username")
4290 @click.option("--cacert", help="CA certificate")
4293 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4296 "--lxd-credentials",
4297 help="Name of the cloud credentialsto be used for the LXD cloud",
4301 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4304 "--k8s-credentials",
4305 help="Name of the cloud credentialsto be used for the K8s cloud",
4307 @click.option("--model-config", help="Configuration options for the models")
4308 @click.option("--description", default
=None, help="human readable description")
4324 """updates a K8s cluster
4326 NAME: name or ID of the K8s cluster
4328 check_client_version(ctx
.obj
, ctx
.command
.name
)
4332 vca
["endpoints"] = endpoints
.split(",")
4336 vca
["secret"] = secret
4338 vca
["cacert"] = cacert
4340 vca
["lxd-cloud"] = lxd_cloud
4342 vca
["lxd-credentials"] = lxd_credentials
4344 vca
["k8s-cloud"] = k8s_cloud
4346 vca
["k8s-credentials"] = k8s_credentials
4348 vca
["description"] = description
4350 model_config
= load(model_config
)
4351 vca
["model-config"] = model_config
4352 ctx
.obj
.vca
.update(name
, vca
)
4355 @cli_osm.command(name
="vca-delete", short_help
="deletes a K8s cluster")
4356 @click.argument("name")
4358 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4361 def vca_delete(ctx
, name
, force
):
4362 """deletes a K8s cluster
4364 NAME: name or ID of the K8s cluster to be deleted
4366 check_client_version(ctx
.obj
, ctx
.command
.name
)
4367 ctx
.obj
.vca
.delete(name
, force
=force
)
4370 @cli_osm.command(name
="vca-list")
4375 help="restricts the list to the VCAs matching the filter",
4377 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4378 @click.option("--long", is_flag
=True, help="get more details")
4380 def vca_list(ctx
, filter, literal
, long):
4382 check_client_version(ctx
.obj
, ctx
.command
.name
)
4384 filter = "&".join(filter)
4385 resp
= ctx
.obj
.vca
.list(filter)
4387 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4390 table
= PrettyTable(
4391 ["Name", "Id", "Project", "Operational State", "Detailed Status"]
4393 project_list
= ctx
.obj
.project
.list()
4395 table
= PrettyTable(["Name", "Id", "Operational State"])
4397 logger
.debug("VCA details: {}".format(yaml
.safe_dump(vca
)))
4399 project_id
, project_name
= get_project(project_list
, vca
)
4400 detailed_status
= vca
.get("_admin", {}).get("detailed-status", "-")
4406 vca
.get("_admin", {}).get("operationalState", "-"),
4407 wrap_text(text
=detailed_status
, width
=40),
4415 vca
.get("_admin", {}).get("operationalState", "-"),
4422 @cli_osm.command(name
="vca-show", short_help
="shows the details of a K8s cluster")
4423 @click.argument("name")
4424 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4426 def vca_show(ctx
, name
, literal
):
4427 """shows the details of a K8s cluster
4429 NAME: name or ID of the K8s cluster
4432 resp
= ctx
.obj
.vca
.get(name
)
4434 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4436 table
= PrettyTable(["key", "attribute"])
4437 for k
, v
in list(resp
.items()):
4438 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
4443 ###########################
4445 ###########################
4448 @cli_osm.command(name
="paas-add", short_help
="adds a PaaS to OSM.")
4449 @click.argument("name")
4452 type=click
.Choice(["juju"]),
4455 help="Type of PaaS that can be used. (For the moment, only juju is supported).",
4460 help="Comma-separated list of IP or hostnames of the PaaS.",
4462 @click.option("--user", prompt
=True, help="Username with admin priviledges.")
4463 @click.option("--secret", prompt
=True, help="Password of the specified username.")
4465 "--config", default
={}, help="Extra configuration needed by PaaS service."
4467 @click.option("--description", default
=None, help="Human readable description.")
4469 def paas_add(ctx
, name
, paas_type
, endpoints
, user
, secret
, config
, description
):
4470 """adds a PaaS to OSM.
4472 name (str): Name of the new PaaS.
4474 check_client_version(ctx
.obj
, ctx
.command
.name
)
4477 "paas_type": paas_type
,
4478 "endpoints": endpoints
.split(","),
4483 paas
["description"] = description
4485 config
= load(config
)
4486 paas
["config"] = config
4487 ctx
.obj
.paas
.create(paas
)
4490 @cli_osm.command(name
="paas-update", short_help
="updates a PaaS")
4491 @click.argument("name")
4492 @click.option("--newname", help="New name for the PaaS")
4495 type=click
.Choice(["juju"]),
4496 help="Type of PaaS that can be used. (For the moment, only juju is supported)",
4499 "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
4501 @click.option("--user", help="Username with admin priviledges")
4502 @click.option("--secret", help="Password of the specified username")
4503 @click.option("--config", help="Extra configuration needed by PaaS service")
4504 @click.option("--description", default
=None, help="Human readable description")
4507 ctx
, name
, newname
, paas_type
, endpoints
, user
, secret
, config
, description
4511 name (str): Name or ID of the PaaS to update.
4513 check_client_version(ctx
.obj
, ctx
.command
.name
)
4516 paas
["name"] = newname
4518 paas
["paas_type"] = paas_type
4520 paas
["endpoints"] = endpoints
.split(",")
4524 paas
["secret"] = secret
4526 paas
["description"] = description
4528 config
= load(config
)
4529 paas
["config"] = config
4530 ctx
.obj
.paas
.update(name
, paas
)
4533 @cli_osm.command(name
="paas-delete", short_help
="deletes a PaaS")
4534 @click.argument("name")
4536 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4539 def paas_delete(ctx
, name
, force
):
4543 name (str): Name or ID of the PaaS to delete.
4545 check_client_version(ctx
.obj
, ctx
.command
.name
)
4546 ctx
.obj
.paas
.delete(name
, force
=force
)
4549 @cli_osm.command(name
="paas-list")
4554 help="Restricts the list to the PaaS matching the filter",
4556 @click.option("--literal", is_flag
=True, help="Print literally, no pretty table")
4557 @click.option("--long", is_flag
=True, help="get more details")
4559 def paas_list(ctx
, filter, literal
, long):
4561 check_client_version(ctx
.obj
, ctx
.command
.name
)
4563 filter = "&".join(filter)
4564 resp
= ctx
.obj
.paas
.list(filter)
4566 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4569 table
= _get_paas_table_header(long)
4570 project_list
= ctx
.obj
.project
.list()
4572 logger
.debug("PaaS details: {}".format(yaml
.safe_dump(paas
)))
4574 _add_paas_long_row(table
, paas
, project_list
)
4576 _add_paas_row(table
, paas
)
4581 def _get_paas_table_header(long):
4584 ["Name", "Id", "Project", "Operational State", "Detailed Status"]
4586 return PrettyTable(["Name", "Id", "Operational State"])
4589 def _add_paas_long_row(table
, paas
, project_list
):
4590 _
, project_name
= get_project(project_list
, paas
)
4591 detailed_status
= paas
.get("_admin", {}).get("detailed-status", "-")
4597 paas
.get("_admin", {}).get("operationalState", "-"),
4598 wrap_text(text
=detailed_status
, width
=40),
4603 def _add_paas_row(table
, paas
):
4605 [paas
["name"], paas
["_id"], paas
.get("_admin", {}).get("operationalState", "-")]
4609 @cli_osm.command(name
="paas-show", short_help
="Shows the details of a PaaS")
4610 @click.argument("name")
4611 @click.option("--literal", is_flag
=True, help="Print literally, no pretty table")
4613 def paas_show(ctx
, name
, literal
):
4614 """Shows the details of a PaaS.
4617 name (str): Name or ID of the PaaS to show.
4619 resp
= ctx
.obj
.paas
.get(name
)
4621 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4623 table
= PrettyTable(["key", "attribute"])
4624 for k
, v
in list(resp
.items()):
4625 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
4630 ###########################
4632 ###########################
4635 @cli_osm.command(name
="repo-add", short_help
="adds a repo to OSM")
4636 @click.argument("name")
4637 @click.argument("uri")
4640 type=click
.Choice(["helm-chart", "juju-bundle", "osm"]),
4642 help="type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles, osm for OSM Repositories)",
4644 @click.option("--description", default
=None, help="human readable description")
4646 "--user", default
=None, help="OSM repository: The username of the OSM repository"
4651 help="OSM repository: The password of the OSM repository",
4653 # @click.option('--wait',
4655 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4657 def repo_add(ctx
, **kwargs
):
4658 """adds a repo to OSM
4660 NAME: name of the repo
4661 URI: URI of the repo
4664 kwargs
= {k
: v
for k
, v
in kwargs
.items() if v
is not None}
4666 repo
["url"] = repo
.pop("uri")
4667 if repo
["type"] in ["helm-chart", "juju-bundle"]:
4668 ctx
.obj
.repo
.create(repo
["name"], repo
)
4670 ctx
.obj
.osmrepo
.create(repo
["name"], repo
)
4671 # except ClientException as e:
4676 @cli_osm.command(name
="repo-update", short_help
="updates a repo in OSM")
4677 @click.argument("name")
4678 @click.option("--newname", help="New name for the repo")
4679 @click.option("--uri", help="URI of the repo")
4680 @click.option("--description", help="human readable description")
4681 # @click.option('--wait',
4683 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4685 def repo_update(ctx
, name
, newname
, uri
, description
):
4686 """updates a repo in OSM
4688 NAME: name of the repo
4691 check_client_version(ctx
.obj
, ctx
.command
.name
)
4694 repo
["name"] = newname
4698 repo
["description"] = description
4700 ctx
.obj
.repo
.update(name
, repo
)
4702 ctx
.obj
.osmrepo
.update(name
, repo
)
4704 # except ClientException as e:
4710 name
="repo-index", short_help
="Index a repository from a folder with artifacts"
4713 "--origin", default
=".", help="origin path where the artifacts are located"
4716 "--destination", default
=".", help="destination path where the index is deployed"
4719 def repo_index(ctx
, origin
, destination
):
4720 """Index a repository
4722 NAME: name or ID of the repo to be deleted
4724 check_client_version(ctx
.obj
, ctx
.command
.name
)
4725 ctx
.obj
.osmrepo
.repo_index(origin
, destination
)
4728 @cli_osm.command(name
="repo-delete", short_help
="deletes a repo")
4729 @click.argument("name")
4731 "--force", is_flag
=True, help="forces the deletion from the DB (not recommended)"
4733 # @click.option('--wait',
4735 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4737 def repo_delete(ctx
, name
, force
):
4740 NAME: name or ID of the repo to be deleted
4744 ctx
.obj
.repo
.delete(name
, force
=force
)
4746 ctx
.obj
.osmrepo
.delete(name
, force
=force
)
4747 # except ClientException as e:
4752 @cli_osm.command(name
="repo-list")
4757 help="restricts the list to the repos matching the filter",
4759 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4761 def repo_list(ctx
, filter, literal
):
4762 """list all repos"""
4765 check_client_version(ctx
.obj
, ctx
.command
.name
)
4767 filter = "&".join(filter)
4768 resp
= ctx
.obj
.repo
.list(filter)
4769 resp
+= ctx
.obj
.osmrepo
.list(filter)
4771 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4773 table
= PrettyTable(["Name", "Id", "Type", "URI", "Description"])
4775 # cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
4782 trunc_text(repo
.get("description") or "", 40),
4788 # except ClientException as e:
4793 @cli_osm.command(name
="repo-show", short_help
="shows the details of a repo")
4794 @click.argument("name")
4795 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
4797 def repo_show(ctx
, name
, literal
):
4798 """shows the details of a repo
4800 NAME: name or ID of the repo
4803 resp
= ctx
.obj
.repo
.get(name
)
4805 resp
= ctx
.obj
.osmrepo
.get(name
)
4809 print(yaml
.safe_dump(resp
, indent
=4, default_flow_style
=False))
4811 table
= PrettyTable(["key", "attribute"])
4813 for k
, v
in list(resp
.items()):
4814 table
.add_row([k
, json
.dumps(v
, indent
=2)])
4818 # except ClientException as e:
4823 ####################
4824 # Project mgmt operations
4825 ####################
4828 @cli_osm.command(name
="project-create", short_help
="creates a new project")
4829 @click.argument("name")
4830 # @click.option('--description',
4831 # default='no description',
4832 # help='human readable description')
4833 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
4839 help="provide quotas. Can be used several times: 'quota1=number[,quota2=number,...]'. Quotas can be one "
4840 "of vnfds, nsds, nsts, pdus, nsrs, nsis, vim_accounts, wim_accounts, sdns, k8sclusters, k8srepos",
4843 def project_create(ctx
, name
, domain_name
, quotas
):
4844 """Creates a new project
4846 NAME: name of the project
4847 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
4848 QUOTAS: set quotas for the project
4851 project
= {"name": name
}
4853 project
["domain_name"] = domain_name
4854 quotas_dict
= _process_project_quotas(quotas
)
4856 project
["quotas"] = quotas_dict
4859 check_client_version(ctx
.obj
, ctx
.command
.name
)
4860 ctx
.obj
.project
.create(name
, project
)
4861 # except ClientException as e:
4866 def _process_project_quotas(quota_list
):
4871 for quota
in quota_list
:
4872 for single_quota
in quota
.split(","):
4873 k
, v
= single_quota
.split("=")
4874 quotas_dict
[k
] = None if v
in ("None", "null", "") else int(v
)
4875 except (ValueError, TypeError):
4876 raise ClientException(
4877 "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
4882 @cli_osm.command(name
="project-delete", short_help
="deletes a project")
4883 @click.argument("name")
4884 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4886 def project_delete(ctx
, name
):
4887 """deletes a project
4889 NAME: name or ID of the project to be deleted
4893 check_client_version(ctx
.obj
, ctx
.command
.name
)
4894 ctx
.obj
.project
.delete(name
)
4895 # except ClientException as e:
4900 @cli_osm.command(name
="project-list", short_help
="list all projects")
4905 help="restricts the list to the projects matching the filter",
4908 def project_list(ctx
, filter):
4909 """list all projects"""
4912 check_client_version(ctx
.obj
, ctx
.command
.name
)
4914 filter = "&".join(filter)
4915 resp
= ctx
.obj
.project
.list(filter)
4916 # except ClientException as e:
4919 table
= PrettyTable(["name", "id"])
4921 table
.add_row([proj
["name"], proj
["_id"]])
4926 @cli_osm.command(name
="project-show", short_help
="shows the details of a project")
4927 @click.argument("name")
4929 def project_show(ctx
, name
):
4930 """shows the details of a project
4932 NAME: name or ID of the project
4936 check_client_version(ctx
.obj
, ctx
.command
.name
)
4937 resp
= ctx
.obj
.project
.get(name
)
4938 # except ClientException as e:
4942 table
= PrettyTable(["key", "attribute"])
4943 for k
, v
in resp
.items():
4944 table
.add_row([k
, json
.dumps(v
, indent
=2)])
4950 name
="project-update", short_help
="updates a project (only the name can be updated)"
4952 @click.argument("project")
4953 @click.option("--name", default
=None, help="new name for the project")
4959 help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
4960 "(use empty to reset quota to default",
4963 def project_update(ctx
, project
, name
, quotas
):
4965 Update a project name
4968 :param project: id or name of the project to modify
4969 :param name: new name for the project
4970 :param quotas: change quotas of the project
4974 project_changes
= {}
4976 project_changes
["name"] = name
4977 quotas_dict
= _process_project_quotas(quotas
)
4979 project_changes
["quotas"] = quotas_dict
4982 check_client_version(ctx
.obj
, ctx
.command
.name
)
4983 ctx
.obj
.project
.update(project
, project_changes
)
4984 # except ClientException as e:
4988 ####################
4989 # User mgmt operations
4990 ####################
4993 @cli_osm.command(name
="user-create", short_help
="creates a new user")
4994 @click.argument("username")
4999 confirmation_prompt
=True,
5000 help="user password",
5004 # prompt="Comma separate list of projects",
5006 callback
=lambda ctx
, param
, value
: "".join(value
).split(",")
5007 if all(len(x
) == 1 for x
in value
)
5009 help="list of project ids that the user belongs to",
5012 "--project-role-mappings",
5013 "project_role_mappings",
5016 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
5018 @click.option("--domain-name", "domain_name", default
=None, help="assign to a domain")
5020 def user_create(ctx
, username
, password
, projects
, project_role_mappings
, domain_name
):
5021 """Creates a new user
5024 USERNAME: name of the user
5025 PASSWORD: password of the user
5026 PROJECTS: projects assigned to user (internal only)
5027 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
5028 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
5032 user
["username"] = username
5033 user
["password"] = password
5034 user
["projects"] = projects
5035 user
["project_role_mappings"] = project_role_mappings
5037 user
["domain_name"] = domain_name
5040 check_client_version(ctx
.obj
, ctx
.command
.name
)
5041 ctx
.obj
.user
.create(username
, user
)
5042 # except ClientException as e:
5047 @cli_osm.command(name
="user-update", short_help
="updates user information")
5048 @click.argument("username")
5053 # confirmation_prompt=True,
5054 help="user password",
5056 @click.option("--set-username", "set_username", default
=None, help="change username")
5062 help="create/replace the roles for this project: 'project,role1[,role2,...]'",
5069 help="removes project from user: 'project'",
5072 "--add-project-role",
5076 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
5079 "--remove-project-role",
5080 "remove_project_role",
5083 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
5085 @click.option("--change_password", "change_password", help="user's current password")
5089 help="user's new password to update in expiry condition",
5100 remove_project_role
,
5104 """Update a user information
5107 USERNAME: name of the user
5108 PASSWORD: new password
5109 SET_USERNAME: new username
5110 SET_PROJECT: creating mappings for project/role(s)
5111 REMOVE_PROJECT: deleting mappings for project/role(s)
5112 ADD_PROJECT_ROLE: adding mappings for project/role(s)
5113 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
5114 CHANGE_PASSWORD: user's current password to change
5115 NEW_PASSWORD: user's new password to update in expiry condition
5119 user
["password"] = password
5120 user
["username"] = set_username
5121 user
["set-project"] = set_project
5122 user
["remove-project"] = remove_project
5123 user
["add-project-role"] = add_project_role
5124 user
["remove-project-role"] = remove_project_role
5125 user
["change_password"] = change_password
5126 user
["new_password"] = new_password
5129 check_client_version(ctx
.obj
, ctx
.command
.name
)
5130 if not user
.get("change_password"):
5131 ctx
.obj
.user
.update(username
, user
)
5133 ctx
.obj
.user
.update(username
, user
, pwd_change
=True)
5134 # except ClientException as e:
5139 @cli_osm.command(name
="user-delete", short_help
="deletes a user")
5140 @click.argument("name")
5141 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
5143 def user_delete(ctx
, name
):
5147 NAME: name or ID of the user to be deleted
5151 check_client_version(ctx
.obj
, ctx
.command
.name
)
5152 ctx
.obj
.user
.delete(name
)
5153 # except ClientException as e:
5158 @cli_osm.command(name
="user-list", short_help
="list all users")
5163 help="restricts the list to the users matching the filter",
5166 def user_list(ctx
, filter):
5167 """list all users"""
5169 check_client_version(ctx
.obj
, ctx
.command
.name
)
5171 filter = "&".join(filter)
5172 resp
= ctx
.obj
.user
.list(filter)
5173 # except ClientException as e:
5176 table
= PrettyTable(["name", "id"])
5178 table
.add_row([user
["username"], user
["_id"]])
5183 @cli_osm.command(name
="user-show", short_help
="shows the details of a user")
5184 @click.argument("name")
5186 def user_show(ctx
, name
):
5187 """shows the details of a user
5189 NAME: name or ID of the user
5193 check_client_version(ctx
.obj
, ctx
.command
.name
)
5194 resp
= ctx
.obj
.user
.get(name
)
5195 if "password" in resp
:
5196 resp
["password"] = "********"
5197 # except ClientException as e:
5201 table
= PrettyTable(["key", "attribute"])
5202 for k
, v
in resp
.items():
5203 table
.add_row([k
, json
.dumps(v
, indent
=2)])
5208 ####################
5209 # Fault Management operations
5210 ####################
5213 @cli_osm.command(name
="ns-alarm-create")
5214 @click.argument("name")
5215 @click.option("--ns", prompt
=True, help="NS instance id or name")
5217 "--vnf", prompt
=True, help="VNF name (VNF member index as declared in the NSD)"
5219 @click.option("--vdu", prompt
=True, help="VDU name (VDU name as declared in the VNFD)")
5220 @click.option("--metric", prompt
=True, help="Name of the metric (e.g. cpu_utilization)")
5224 help="severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)",
5227 "--threshold_value",
5229 help="threshold value that, when crossed, an alarm is triggered",
5232 "--threshold_operator",
5234 help="threshold operator describing the comparison (GE, LE, GT, LT, EQ)",
5239 help="statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)",
5242 def ns_alarm_create(
5254 """creates a new alarm for a NS instance"""
5255 # TODO: Check how to validate threshold_value.
5256 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
5259 ns_instance
= ctx
.obj
.ns
.get(ns
)
5261 alarm
["alarm_name"] = name
5262 alarm
["ns_id"] = ns_instance
["_id"]
5263 alarm
["correlation_id"] = ns_instance
["_id"]
5264 alarm
["vnf_member_index"] = vnf
5265 alarm
["vdu_name"] = vdu
5266 alarm
["metric_name"] = metric
5267 alarm
["severity"] = severity
5268 alarm
["threshold_value"] = int(threshold_value
)
5269 alarm
["operation"] = threshold_operator
5270 alarm
["statistic"] = statistic
5271 check_client_version(ctx
.obj
, ctx
.command
.name
)
5272 ctx
.obj
.ns
.create_alarm(alarm
)
5273 # except ClientException as e:
5278 # @cli_osm.command(name='ns-alarm-delete')
5279 # @click.argument('name')
5280 # @click.pass_context
5281 # def ns_alarm_delete(ctx, name):
5282 # """deletes an alarm
5284 # NAME: name of the alarm to be deleted
5287 # check_client_version(ctx.obj, ctx.command.name)
5288 # ctx.obj.ns.delete_alarm(name)
5289 # except ClientException as e:
5294 ####################
5295 # Performance Management operations
5296 ####################
5300 name
="ns-metric-export",
5301 short_help
="exports a metric to the internal OSM bus, which can be read by other apps",
5303 @click.option("--ns", prompt
=True, help="NS instance id or name")
5305 "--vnf", prompt
=True, help="VNF name (VNF member index as declared in the NSD)"
5307 @click.option("--vdu", prompt
=True, help="VDU name (VDU name as declared in the VNFD)")
5308 @click.option("--metric", prompt
=True, help="name of the metric (e.g. cpu_utilization)")
5309 # @click.option('--period', default='1w',
5310 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
5312 "--interval", help="periodic interval (seconds) to export metrics continuously"
5315 def ns_metric_export(ctx
, ns
, vnf
, vdu
, metric
, interval
):
5316 """exports a metric to the internal OSM bus, which can be read by other apps"""
5317 # TODO: Check how to validate interval.
5318 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
5321 ns_instance
= ctx
.obj
.ns
.get(ns
)
5323 metric_data
["ns_id"] = ns_instance
["_id"]
5324 metric_data
["correlation_id"] = ns_instance
["_id"]
5325 metric_data
["vnf_member_index"] = vnf
5326 metric_data
["vdu_name"] = vdu
5327 metric_data
["metric_name"] = metric
5328 metric_data
["collection_unit"] = "WEEK"
5329 metric_data
["collection_period"] = 1
5330 check_client_version(ctx
.obj
, ctx
.command
.name
)
5332 print("{}".format(ctx
.obj
.ns
.export_metric(metric_data
)))
5336 print("{} {}".format(ctx
.obj
.ns
.export_metric(metric_data
), i
))
5337 time
.sleep(int(interval
))
5339 # except ClientException as e:
5345 # Subscription operations
5350 name
="subscription-create",
5351 short_help
="creates a new subscription to a specific event",
5355 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5356 type=click
.Choice(["ns"], case_sensitive
=False),
5357 help="event type to be subscribed (for the moment, only ns is supported)",
5359 @click.option("--event", default
=None, help="specific yaml configuration for the event")
5361 "--event_file", default
=None, help="specific yaml configuration file for the event"
5364 def subscription_create(ctx
, event_type
, event
, event_file
):
5365 """creates a new subscription to a specific event"""
5367 check_client_version(ctx
.obj
, ctx
.command
.name
)
5370 raise ClientException(
5371 '"--event" option is incompatible with "--event_file" option'
5373 with
open(event_file
, "r") as cf
:
5375 ctx
.obj
.subscription
.create(event_type
, event
)
5378 @cli_osm.command(name
="subscription-delete", short_help
="deletes a subscription")
5381 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5382 type=click
.Choice(["ns"], case_sensitive
=False),
5383 help="event type to be subscribed (for the moment, only ns is supported)",
5385 @click.argument("subscription_id")
5387 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
5390 def subscription_delete(ctx
, event_type
, subscription_id
, force
):
5391 """deletes a subscription
5393 SUBSCRIPTION_ID: ID of the subscription to be deleted
5396 check_client_version(ctx
.obj
, ctx
.command
.name
)
5397 ctx
.obj
.subscription
.delete(event_type
, subscription_id
, force
)
5400 @cli_osm.command(name
="subscription-list", short_help
="list all subscriptions")
5403 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5404 type=click
.Choice(["ns"], case_sensitive
=False),
5405 help="event type to be subscribed (for the moment, only ns is supported)",
5411 help="restricts the list to the subscriptions matching the filter",
5414 def subscription_list(ctx
, event_type
, filter):
5415 """list all subscriptions"""
5417 check_client_version(ctx
.obj
, ctx
.command
.name
)
5419 filter = "&".join(filter)
5420 resp
= ctx
.obj
.subscription
.list(event_type
, filter)
5421 table
= PrettyTable(["id", "filter", "CallbackUri"])
5426 wrap_text(text
=json
.dumps(sub
["filter"], indent
=2), width
=70),
5435 name
="subscription-show", short_help
="shows the details of a subscription"
5437 @click.argument("subscription_id")
5440 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5441 type=click
.Choice(["ns"], case_sensitive
=False),
5442 help="event type to be subscribed (for the moment, only ns is supported)",
5447 help="restricts the information to the fields in the filter",
5450 def subscription_show(ctx
, event_type
, subscription_id
, filter):
5451 """shows the details of a subscription
5453 SUBSCRIPTION_ID: ID of the subscription
5457 resp
= ctx
.obj
.subscription
.get(subscription_id
)
5458 table
= PrettyTable(["key", "attribute"])
5459 for k
, v
in list(resp
.items()):
5460 if not filter or k
in filter:
5461 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
5466 ####################
5468 ####################
5471 @cli_osm.command(name
="version", short_help
="shows client and server versions")
5473 def get_version(ctx
):
5474 """shows client and server versions"""
5476 check_client_version(ctx
.obj
, "version")
5477 print("Server version: {}".format(ctx
.obj
.get_version()))
5479 "Client version: {}".format(pkg_resources
.get_distribution("osmclient").version
)
5481 # except ClientException as e:
5487 name
="upload-package", short_help
="uploads a VNF package or NS package"
5489 @click.argument("filename")
5491 "--skip-charm-build",
5494 help="the charm will not be compiled, it is assumed to already exist",
5497 def upload_package(ctx
, filename
, skip_charm_build
):
5498 """uploads a vnf package or ns package
5500 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
5504 ctx
.obj
.package
.upload(filename
, skip_charm_build
=skip_charm_build
)
5505 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
5506 if fullclassname
!= "osmclient.sol005.client.Client":
5507 ctx
.obj
.package
.wait_for_upload(filename
)
5508 # except ClientException as e:
5513 # @cli_osm.command(name='ns-scaling-show')
5514 # @click.argument('ns_name')
5515 # @click.pass_context
5516 # def show_ns_scaling(ctx, ns_name):
5517 # """shows the status of a NS scaling operation
5519 # NS_NAME: name of the NS instance being scaled
5522 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5523 # resp = ctx.obj.ns.list()
5524 # except ClientException as e:
5528 # table = PrettyTable(
5531 # 'operational status',
5536 # if ns_name == ns['name']:
5537 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
5538 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
5539 # for record in scaling_records:
5540 # if 'instance' in record:
5541 # instances = record['instance']
5542 # for inst in instances:
5544 # [record['scaling-group-name-ref'],
5545 # inst['instance-id'],
5546 # inst['op-status'],
5547 # time.strftime('%Y-%m-%d %H:%M:%S',
5549 # inst['create-time'])),
5555 # @cli_osm.command(name='ns-scale')
5556 # @click.argument('ns_name')
5557 # @click.option('--ns_scale_group', prompt=True)
5558 # @click.option('--index', prompt=True)
5559 # @click.option('--wait',
5563 # help='do not return the control immediately, but keep it \
5564 # until the operation is completed, or timeout')
5565 # @click.pass_context
5566 # def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
5569 # NS_NAME: name of the NS instance to be scaled
5572 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5573 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
5574 # except ClientException as e:
5579 # @cli_osm.command(name='config-agent-list')
5580 # @click.pass_context
5581 # def config_agent_list(ctx):
5582 # """list config agents"""
5584 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5585 # except ClientException as e:
5588 # table = PrettyTable(['name', 'account-type', 'details'])
5589 # for account in ctx.obj.vca.list():
5592 # account['account-type'],
5598 # @cli_osm.command(name='config-agent-delete')
5599 # @click.argument('name')
5600 # @click.pass_context
5601 # def config_agent_delete(ctx, name):
5602 # """deletes a config agent
5604 # NAME: name of the config agent to be deleted
5607 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5608 # ctx.obj.vca.delete(name)
5609 # except ClientException as e:
5614 # @cli_osm.command(name='config-agent-add')
5615 # @click.option('--name',
5617 # @click.option('--account_type',
5619 # @click.option('--server',
5621 # @click.option('--user',
5623 # @click.option('--secret',
5626 # confirmation_prompt=True)
5627 # @click.pass_context
5628 # def config_agent_add(ctx, name, account_type, server, user, secret):
5629 # """adds a config agent"""
5631 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5632 # ctx.obj.vca.create(name, account_type, server, user, secret)
5633 # except ClientException as e:
5638 # @cli_osm.command(name='ro-dump')
5639 # @click.pass_context
5641 # """shows RO agent information"""
5642 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5643 # resp = ctx.obj.vim.get_resource_orchestrator()
5644 # table = PrettyTable(['key', 'attribute'])
5645 # for k, v in list(resp.items()):
5646 # table.add_row([k, json.dumps(v, indent=2)])
5651 # @cli_osm.command(name='vcs-list')
5652 # @click.pass_context
5653 # def vcs_list(ctx):
5654 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5655 # resp = ctx.obj.utils.get_vcs_info()
5656 # table = PrettyTable(['component name', 'state'])
5657 # for component in resp:
5658 # table.add_row([component['component_name'], component['state']])
5664 name
="ns-action", short_help
="executes an action/primitive over a NS instance"
5666 @click.argument("ns_name")
5670 help="member-vnf-index if the target is a vnf instead of a ns)",
5672 @click.option("--kdu_name", default
=None, help="kdu-name if the target is a kdu)")
5673 @click.option("--vdu_id", default
=None, help="vdu-id if the target is a vdu")
5675 "--vdu_count", default
=None, type=int, help="number of vdu instance of this vdu_id"
5677 @click.option("--action_name", prompt
=True, help="action name")
5678 @click.option("--params", default
=None, help="action params in YAML/JSON inline string")
5679 @click.option("--params_file", default
=None, help="YAML/JSON file with action params")
5681 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5688 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5704 """executes an action/primitive over a NS instance
5706 NS_NAME: name or ID of the NS instance
5710 check_client_version(ctx
.obj
, ctx
.command
.name
)
5713 op_data
["member_vnf_index"] = vnf_name
5715 op_data
["kdu_name"] = kdu_name
5717 op_data
["vdu_id"] = vdu_id
5718 if vdu_count
is not None:
5719 op_data
["vdu_count_index"] = vdu_count
5721 op_data
["timeout_ns_action"] = timeout
5722 op_data
["primitive"] = action_name
5724 with
open(params_file
, "r") as pf
:
5727 op_data
["primitive_params"] = yaml
.safe_load(params
)
5729 op_data
["primitive_params"] = {}
5730 print(ctx
.obj
.ns
.exec_op(ns_name
, op_name
="action", op_data
=op_data
, wait
=wait
))
5732 # except ClientException as e:
5738 name
="vnf-scale", short_help
="executes a VNF scale (adding/removing VDUs)"
5740 @click.argument("ns_name")
5741 @click.argument("vnf_name")
5743 "--scaling-group", prompt
=True, help="scaling-group-descriptor name to use"
5746 "--scale-in", default
=False, is_flag
=True, help="performs a scale in operation"
5752 help="performs a scale out operation (by default)",
5755 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5762 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5766 ctx
, ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
, timeout
, wait
5769 Executes a VNF scale (adding/removing VDUs)
5772 NS_NAME: name or ID of the NS instance.
5773 VNF_NAME: member-vnf-index in the NS to be scaled.
5777 check_client_version(ctx
.obj
, ctx
.command
.name
)
5778 if not scale_in
and not scale_out
:
5780 ctx
.obj
.ns
.scale_vnf(
5781 ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
, wait
, timeout
5783 # except ClientException as e:
5789 name
="ns-update", short_help
="executes an update of a Network Service."
5791 @click.argument("ns_name")
5793 "--updatetype", required
=True, type=str, help="available types: CHANGE_VNFPKG"
5799 help="extra information for update operation as YAML/JSON inline string as --config"
5800 " '{changeVnfPackageData:[{vnfInstanceId: xxx, vnfdId: yyy}]}'",
5803 "--timeout", required
=False, default
=None, type=int, help="timeout in seconds"
5810 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5813 def update(ctx
, ns_name
, updatetype
, config
, timeout
, wait
):
5814 """Executes an update of a Network Service.
5816 The update will check new revisions of the Network Functions that are part of the
5817 Network Service, and it will update them if needed.
5818 Sample update command: osm ns-update ns_instance_id --updatetype CHANGE_VNFPKG
5819 --config '{changeVnfPackageData: [{vnfInstanceId: id_x,vnfdId: id_y}]}' --timeout 300 --wait
5821 NS_NAME: Network service instance name or ID.
5824 op_data
= {"timeout": timeout
, "updateType": updatetype
}
5826 op_data
["config"] = yaml
.safe_load(config
)
5828 check_client_version(ctx
.obj
, ctx
.command
.name
)
5829 ctx
.obj
.ns
.update(ns_name
, op_data
, wait
=wait
)
5832 def iterator_split(iterator
, separators
):
5834 Splits a tuple or list into several lists whenever a separator is found
5835 For instance, the following tuple will be separated with the separator "--vnf" as follows.
5837 ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1", "--vnf", "B", "--cause", "cause_B", ...
5838 "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", "--vdu", "vdu_B1", "--count_index", "2")
5841 ("--vnf", "A", "--cause", "cause_A", "--vdu", "vdu_A1"),
5842 ("--vnf", "B", "--cause", "cause_B", "--vdu", "vdu_B1", "--count_index", "1", "--run-day1", ...
5843 "--vdu", "vdu_B1", "--count_index", "2")
5846 Returns as many lists as separators are found
5849 if iterator
[0] not in separators
:
5850 raise ClientException(f
"Expected one of {separators}. Received: {iterator[0]}.")
5853 for i
in range(len(iterator
)):
5854 if iterator
[i
] in separators
:
5858 raise ClientException(
5859 f
"Expected at least one argument after separator (possible separators: {separators})."
5861 list_of_lists
.append(list(iterator
[first
:i
]))
5863 if (len(iterator
) - first
) < 2:
5864 raise ClientException(
5865 f
"Expected at least one argument after separator (possible separators: {separators})."
5868 list_of_lists
.append(list(iterator
[first
: len(iterator
)]))
5869 # logger.debug(f"List of lists: {list_of_lists}")
5870 return list_of_lists
5873 def process_common_heal_params(heal_vnf_dict
, args
):
5875 current_item
= "vnf"
5877 while i
< len(args
):
5878 if args
[i
] == "--cause":
5879 if (i
+ 1 >= len(args
)) or args
[i
+ 1].startswith("--"):
5880 raise ClientException("No cause was provided after --cause")
5881 heal_vnf_dict
["cause"] = args
[i
+ 1]
5884 if args
[i
] == "--run-day1":
5885 if current_item
== "vnf":
5886 if "additionalParams" not in heal_vnf_dict
:
5887 heal_vnf_dict
["additionalParams"] = {}
5888 heal_vnf_dict
["additionalParams"]["run-day1"] = True
5890 # if current_item == "vdu"
5891 heal_vnf_dict
["additionalParams"]["vdu"][-1]["run-day1"] = True
5894 if args
[i
] == "--vdu":
5895 if "additionalParams" not in heal_vnf_dict
:
5896 heal_vnf_dict
["additionalParams"] = {}
5897 heal_vnf_dict
["additionalParams"]["vdu"] = []
5898 if (i
+ 1 >= len(args
)) or args
[i
+ 1].startswith("--"):
5899 raise ClientException("No VDU ID was provided after --vdu")
5900 heal_vnf_dict
["additionalParams"]["vdu"].append({"vdu-id": args
[i
+ 1]})
5901 current_item
= "vdu"
5904 if args
[i
] == "--count-index":
5905 if current_item
== "vnf":
5906 raise ClientException(
5907 "Option --count-index only applies to VDU, not to VNF"
5909 if (i
+ 1 >= len(args
)) or args
[i
+ 1].startswith("--"):
5910 raise ClientException("No count index was provided after --count-index")
5911 heal_vnf_dict
["additionalParams"]["vdu"][-1]["count-index"] = int(
5920 def process_ns_heal_params(ctx
, param
, value
):
5922 Processes the params in the command ns-heal
5923 Click does not allow advanced patterns for positional options like this:
5924 --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf"
5925 --vdu several_volumes-VM
5926 --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf"
5927 --vdu mgmtVM --count-index 1 --run-day1
5928 --vdu mgmtVM --count-index 2
5930 It returns the dictionary with all the params stored in ctx.params["heal_params"]
5933 # logger.debug(f"Args: {value}")
5934 if param
.name
!= "args":
5935 raise ClientException(f
"Unexpected param: {param.name}")
5936 # Split the tuple "value" by "--vnf"
5937 vnfs
= iterator_split(value
, ["--vnf"])
5938 logger
.debug(f
"VNFs: {vnfs}")
5940 heal_dict
["healVnfData"] = []
5942 # logger.debug(f"VNF: {vnf}")
5944 if vnf
[1].startswith("--"):
5945 raise ClientException("Expected a VNF_ID after --vnf")
5946 heal_vnf
["vnfInstanceId"] = vnf
[1]
5947 process_common_heal_params(heal_vnf
, vnf
[2:])
5948 heal_dict
["healVnfData"].append(heal_vnf
)
5949 ctx
.params
["heal_params"] = heal_dict
5955 short_help
="heals (recreates) VNFs or VDUs of a NS instance",
5956 context_settings
=dict(ignore_unknown_options
=True),
5958 @click.argument("ns_name")
5960 "args", nargs
=-1, type=click
.UNPROCESSED
, callback
=process_ns_heal_params
5962 @click.option("--timeout", type=int, default
=None, help="timeout in seconds")
5967 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5970 def ns_heal(ctx
, ns_name
, args
, heal_params
, timeout
, wait
):
5971 """heals (recreates) VNFs or VDUs of a NS instance
5973 NS_NAME: name or ID of the NS instance
5977 --vnf TEXT VNF instance ID or VNF id in the NS [required]
5978 --cause TEXT human readable cause of the healing
5979 --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU
5981 --count-index INTEGER count-index
5985 osm ns-heal NS_NAME|NS_ID --vnf volumes_vnf --cause "Heal several_volumes-VM of several_volumes_vnf"
5986 --vdu several_volumes-VM
5987 --vnf charm_vnf --cause "Heal two VMs of native_manual_scale_charm_vnf"
5988 --vdu mgmtVM --count-index 1 --run-day1
5989 --vdu mgmtVM --count-index 2
5992 heal_dict
= ctx
.params
["heal_params"]
5993 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
5994 # replace VNF id in the NS by the VNF instance ID
5995 for vnf
in heal_dict
["healVnfData"]:
5996 vnf_id
= vnf
["vnfInstanceId"]
5997 if not validate_uuid4(vnf_id
):
5998 vnf_filter
= f
"member-vnf-index-ref={vnf_id}"
5999 vnf_list
= ctx
.obj
.vnf
.list(ns
=ns_name
, filter=vnf_filter
)
6000 if len(vnf_list
) == 0:
6001 raise ClientException(
6002 f
"No VNF found in NS {ns_name} with filter {vnf_filter}"
6004 elif len(vnf_list
) == 1:
6005 vnf
["vnfInstanceId"] = vnf_list
[0]["_id"]
6007 raise ClientException(
6008 f
"More than 1 VNF found in NS {ns_name} with filter {vnf_filter}"
6010 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
6011 check_client_version(ctx
.obj
, ctx
.command
.name
)
6012 ctx
.obj
.ns
.heal(ns_name
, heal_dict
, wait
, timeout
)
6016 def process_vnf_heal_params(ctx
, param
, value
):
6018 Processes the params in the command vnf-heal
6019 Click does not allow advanced patterns for positional options like this:
6020 --vdu mgmtVM --count-index 1 --run-day1 --vdu mgmtVM --count-index 2
6022 It returns the dictionary with all the params stored in ctx.params["heal_params"]
6025 # logger.debug(f"Args: {value}")
6026 if param
.name
!= "args":
6027 raise ClientException(f
"Unexpected param: {param.name}")
6028 # Split the tuple "value" by "--vnf"
6031 heal_dict
["healVnfData"] = []
6032 logger
.debug(f
"VNF: {vnf}")
6033 heal_vnf
= {"vnfInstanceId": "id_to_be_substituted"}
6034 process_common_heal_params(heal_vnf
, vnf
)
6035 heal_dict
["healVnfData"].append(heal_vnf
)
6036 ctx
.params
["heal_params"] = heal_dict
6042 short_help
="heals (recreates) a VNF instance or the VDUs of a VNF instance",
6043 context_settings
=dict(ignore_unknown_options
=True),
6045 @click.argument("vnf_name")
6047 "args", nargs
=-1, type=click
.UNPROCESSED
, callback
=process_vnf_heal_params
6049 @click.option("--timeout", type=int, default
=None, help="timeout in seconds")
6054 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
6057 def vnf_heal2(ctx
, vnf_name
, args
, heal_params
, timeout
, wait
):
6058 """heals (recreates) a VNF instance or the VDUs of a VNF instance
6060 VNF_NAME: name or ID of the VNF instance
6064 --cause TEXT human readable cause of the healing of the VNF
6065 --run-day1 indicates whether or not to run day1 primitives for the VNF/VDU
6067 --count-index INTEGER count-index
6071 osm vnf-heal VNF_INSTANCE_ID --vdu mgmtVM --count-index 1 --run-day1
6072 --vdu mgmtVM --count-index 2
6075 heal_dict
= ctx
.params
["heal_params"]
6076 heal_dict
["healVnfData"][-1]["vnfInstanceId"] = vnf_name
6077 logger
.debug(f
"Heal dict:\n{yaml.safe_dump(heal_dict)}")
6078 check_client_version(ctx
.obj
, ctx
.command
.name
)
6079 vnfr
= ctx
.obj
.vnf
.get(vnf_name
)
6080 ns_id
= vnfr
["nsr-id-ref"]
6081 ctx
.obj
.ns
.heal(ns_id
, heal_dict
, wait
, timeout
)
6085 @cli_osm.command(name
="alarm-show", short_help
="show alarm details")
6086 @click.argument("uuid")
6088 def alarm_show(ctx
, uuid
):
6089 """Show alarm's detail information"""
6091 check_client_version(ctx
.obj
, ctx
.command
.name
)
6092 resp
= ctx
.obj
.ns
.get_alarm(uuid
=uuid
)
6106 table
= PrettyTable(["key", "attribute"])
6108 # Arrange and return the response data
6109 alarm
= resp
.replace("ObjectId", "")
6110 for key
in alarm_filter
:
6112 value
= alarm
.get(key
)
6115 value
= alarm
.get(key
)
6117 elif key
== "ns-id":
6118 value
= alarm
["tags"].get("ns_id")
6119 elif key
== "vdu_name":
6120 value
= alarm
["tags"].get("vdu_name")
6121 elif key
== "status":
6122 value
= alarm
["alarm_status"]
6125 table
.add_row([key
, wrap_text(text
=json
.dumps(value
, indent
=2), width
=100)])
6133 @cli_osm.command(name
="alarm-list", short_help
="list all alarms")
6135 "--ns_id", default
=None, required
=False, help="List out alarm for given ns id"
6138 def alarm_list(ctx
, ns_id
):
6139 """list all alarm"""
6141 check_client_version(ctx
.obj
, ctx
.command
.name
)
6142 project_name
= os
.getenv("OSM_PROJECT", "admin")
6143 resp
= ctx
.obj
.ns
.get_alarm(project_name
=project_name
, ns_id
=ns_id
)
6145 table
= PrettyTable(
6146 ["alarm-id", "metric", "threshold", "operation", "action", "status"]
6149 # return the response data in a table
6150 resp
= resp
.replace("ObjectId", "")
6154 wrap_text(text
=str(alarm
["uuid"]), width
=38),
6158 wrap_text(text
=alarm
["action"], width
=25),
6159 alarm
["alarm_status"],
6167 @cli_osm.command(name
="alarm-update", short_help
="Update a alarm")
6168 @click.argument("uuid")
6169 @click.option("--threshold", default
=None, help="Alarm threshold")
6170 @click.option("--is_enable", default
=None, type=bool, help="enable or disable alarm")
6172 def alarm_update(ctx
, uuid
, threshold
, is_enable
):
6177 if not threshold
and is_enable
is None:
6178 raise ClientException(
6179 "Please provide option to update i.e threshold or is_enable"
6181 ctx
.obj
.ns
.update_alarm(uuid
, threshold
, is_enable
)
6184 ##############################
6185 # Role Management Operations #
6186 ##############################
6189 @cli_osm.command(name
="role-create", short_help
="creates a new role")
6190 @click.argument("name")
6191 @click.option("--permissions", default
=None, help="role permissions using a dictionary")
6193 def role_create(ctx
, name
, permissions
):
6198 NAME: Name or ID of the role.
6199 DEFINITION: Definition of grant/denial of access to resources.
6203 check_client_version(ctx
.obj
, ctx
.command
.name
)
6204 ctx
.obj
.role
.create(name
, permissions
)
6205 # except ClientException as e:
6210 @cli_osm.command(name
="role-update", short_help
="updates a role")
6211 @click.argument("name")
6212 @click.option("--set-name", default
=None, help="change name of rle")
6213 # @click.option('--permissions',
6215 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
6219 help="yaml format dictionary with permission: True/False to access grant/denial",
6221 @click.option("--remove", default
=None, help="yaml format list to remove a permission")
6223 def role_update(ctx
, name
, set_name
, add
, remove
):
6228 NAME: Name or ID of the role.
6229 DEFINITION: Definition overwrites the old definition.
6230 ADD: Grant/denial of access to resource to add.
6231 REMOVE: Grant/denial of access to resource to remove.
6235 check_client_version(ctx
.obj
, ctx
.command
.name
)
6236 ctx
.obj
.role
.update(name
, set_name
, None, add
, remove
)
6237 # except ClientException as e:
6242 @cli_osm.command(name
="role-delete", short_help
="deletes a role")
6243 @click.argument("name")
6244 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
6246 def role_delete(ctx
, name
):
6251 NAME: Name or ID of the role.
6255 check_client_version(ctx
.obj
, ctx
.command
.name
)
6256 ctx
.obj
.role
.delete(name
)
6257 # except ClientException as e:
6262 @cli_osm.command(name
="role-list", short_help
="list all roles")
6267 help="restricts the list to the projects matching the filter",
6270 def role_list(ctx
, filter):
6276 check_client_version(ctx
.obj
, ctx
.command
.name
)
6278 filter = "&".join(filter)
6279 resp
= ctx
.obj
.role
.list(filter)
6280 # except ClientException as e:
6283 table
= PrettyTable(["name", "id"])
6285 table
.add_row([role
["name"], role
["_id"]])
6290 @cli_osm.command(name
="role-show", short_help
="show specific role")
6291 @click.argument("name")
6293 def role_show(ctx
, name
):
6295 Shows the details of a role.
6298 NAME: Name or ID of the role.
6302 check_client_version(ctx
.obj
, ctx
.command
.name
)
6303 resp
= ctx
.obj
.role
.get(name
)
6304 # except ClientException as e:
6308 table
= PrettyTable(["key", "attribute"])
6309 for k
, v
in resp
.items():
6310 table
.add_row([k
, json
.dumps(v
, indent
=2)])
6315 @cli_osm.command(name
="package-create", short_help
="Create empty NS package structure")
6316 @click.argument("package-type")
6317 @click.argument("package-name")
6321 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'),
6325 default
="image-name",
6326 help='(VNF) Set the name of the vdu image. Default "image-name"',
6329 "--vdus", default
=1, help="(VNF) Set the number of vdus in a VNF. Default 1"
6332 "--vcpu", default
=1, help="(VNF) Set the number of virtual CPUs in a vdu. Default 1"
6337 help="(VNF) Set the memory size (MB) of the vdu. Default 1024",
6340 "--storage", default
=10, help="(VNF) Set the disk size (GB) of the vdu. Default 10"
6345 help="(VNF) Set the number of additional interfaces apart from the management interface. Default 0",
6348 "--vendor", default
="OSM", help='(NS/VNF) Set the descriptor vendor. Default "OSM"'
6354 help="(NS/VNF/NST) Flag for overriding the package if exists.",
6360 help="(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options",
6363 "--netslice-subnets", default
=1, help="(NST) Number of netslice subnets. Default 1"
6366 "--netslice-vlds", default
=1, help="(NST) Number of netslice vlds. Default 1"
6372 help="Flag to create a descriptor using the previous OSM format (pre SOL006, OSM<9)",
6394 Creates an OSM NS, VNF, NST package
6397 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
6398 PACKAGE_NAME: Name of the package to create the folder with the content.
6403 check_client_version(ctx
.obj
, ctx
.command
.name
)
6405 "Creating the {} structure: {}/{}".format(
6406 package_type
.upper(), base_directory
, package_name
6409 resp
= ctx
.obj
.package_tool
.create(
6419 interfaces
=interfaces
,
6422 netslice_subnets
=netslice_subnets
,
6423 netslice_vlds
=netslice_vlds
,
6427 # except ClientException as inst:
6428 # print("ERROR: {}".format(inst))
6433 name
="package-validate", short_help
="Validate descriptors given a base directory"
6435 @click.argument("base-directory", default
=".", required
=False)
6437 "--recursive/--no-recursive",
6439 help="The activated recursive option will validate the yaml files"
6440 " within the indicated directory and in its subdirectories",
6446 help="Validates also the descriptors using the previous OSM format (pre SOL006)",
6449 def package_validate(ctx
, base_directory
, recursive
, old
):
6451 Validate descriptors given a base directory.
6454 BASE_DIRECTORY: Base folder for NS, VNF or NST package.
6458 check_client_version(ctx
.obj
, ctx
.command
.name
)
6459 results
= ctx
.obj
.package_tool
.validate(base_directory
, recursive
, old
)
6460 table
= PrettyTable()
6461 table
.field_names
= ["TYPE", "PATH", "VALID", "ERROR"]
6462 # Print the dictionary generated by the validation function
6463 for result
in results
:
6465 [result
["type"], result
["path"], result
["valid"], result
["error"]]
6467 table
.sortby
= "VALID"
6468 table
.align
["PATH"] = "l"
6469 table
.align
["TYPE"] = "l"
6470 table
.align
["ERROR"] = "l"
6472 # except ClientException as inst:
6473 # print("ERROR: {}".format(inst))
6478 name
="package-translate", short_help
="Translate descriptors given a base directory"
6480 @click.argument("base-directory", default
=".", required
=False)
6482 "--recursive/--no-recursive",
6484 help="The activated recursive option will translate the yaml files"
6485 " within the indicated directory and in its subdirectories",
6491 help="Do not translate yet, only make a dry-run to test translation",
6494 def package_translate(ctx
, base_directory
, recursive
, dryrun
):
6496 Translate descriptors given a base directory.
6499 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
6502 check_client_version(ctx
.obj
, ctx
.command
.name
)
6503 results
= ctx
.obj
.package_tool
.translate(base_directory
, recursive
, dryrun
)
6504 table
= PrettyTable()
6505 table
.field_names
= [
6513 # Print the dictionary generated by the validation function
6514 for result
in results
:
6517 result
["current type"],
6521 result
["translated"],
6525 table
.sortby
= "TRANSLATED"
6526 table
.align
["PATH"] = "l"
6527 table
.align
["TYPE"] = "l"
6528 table
.align
["ERROR"] = "l"
6530 # except ClientException as inst:
6531 # print("ERROR: {}".format(inst))
6535 @cli_osm.command(name
="package-build", short_help
="Build the tar.gz of the package")
6536 @click.argument("package-folder")
6538 "--skip-validation", default
=False, is_flag
=True, help="skip package validation"
6541 "--skip-charm-build",
6544 help="the charm will not be compiled, it is assumed to already exist",
6547 def package_build(ctx
, package_folder
, skip_validation
, skip_charm_build
):
6549 Build the package NS, VNF given the package_folder.
6552 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
6556 check_client_version(ctx
.obj
, ctx
.command
.name
)
6557 results
= ctx
.obj
.package_tool
.build(
6559 skip_validation
=skip_validation
,
6560 skip_charm_build
=skip_charm_build
,
6563 # except ClientException as inst:
6564 # print("ERROR: {}".format(inst))
6569 name
="descriptor-translate",
6570 short_help
="Translate input descriptor file from Rel EIGHT OSM descriptors to SOL006 and prints in standard output",
6572 @click.argument("descriptor-file", required
=True)
6574 def descriptor_translate(ctx
, descriptor_file
):
6576 Translate input descriptor.
6579 DESCRIPTOR_FILE: Descriptor file for NS, VNF or Network Slice.
6582 check_client_version(ctx
.obj
, ctx
.command
.name
)
6583 result
= ctx
.obj
.package_tool
.descriptor_translate(descriptor_file
)
6589 cli_osm() # pylint: disable=no-value-for-parameter
6591 except pycurl
.error
as exc
:
6594 'Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified'
6596 except (ClientException
, NotFound
) as exc
:
6597 print("ERROR: {}".format(exc
))
6598 except (FileNotFoundError
, PermissionError
) as exc
:
6599 print("Cannot open file: {}".format(exc
))
6600 except yaml
.YAMLError
as exc
:
6601 print("Invalid YAML format: {}".format(exc
))
6603 # TODO capture other controlled exceptions here
6604 # TODO remove the ClientException captures from all places, unless they do something different
6607 if __name__
== "__main__":