Feature 10920: Monitoring of NFVI-leve VNF metrics form Prometheus TSDB
[osm/osmclient.git] / osmclient / scripts / osm.py
1 # Copyright 2017-2018 Sandvine
2 # Copyright 2018 Telefonica
3 #
4 # All Rights Reserved.
5 #
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
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
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
16 # under the License.
17 """
18 OSM shell/cli
19 """
20
21 import click
22 from osmclient import client
23 from osmclient.common.exceptions import ClientException, NotFound
24 from prettytable import PrettyTable
25 import yaml
26 import json
27 import time
28 import pycurl
29 import os
30 import textwrap
31 import pkg_resources
32 import logging
33 from datetime import datetime
34 from typing import Any, Dict
35
36
37 def wrap_text(text, width):
38 wrapper = textwrap.TextWrapper(width=width)
39 lines = text.splitlines()
40 return "\n".join(map(wrapper.fill, lines))
41
42
43 def trunc_text(text, length):
44 if len(text) > length:
45 return text[: (length - 3)] + "..."
46 else:
47 return text
48
49
50 def check_client_version(obj, what, version="sol005"):
51 """
52 Checks the version of the client object and raises error if it not the expected.
53
54 :param obj: the client object
55 :what: the function or command under evaluation (used when an error is raised)
56 :return: -
57 :raises ClientError: if the specified version does not match the client version
58 """
59 logger.debug("")
60 fullclassname = obj.__module__ + "." + obj.__class__.__name__
61 message = 'The following commands or options are only supported with the option "--sol005": {}'.format(
62 what
63 )
64 if version == "v1":
65 message = 'The following commands or options are not supported when using option "--sol005": {}'.format(
66 what
67 )
68 if fullclassname != "osmclient.{}.client.Client".format(version):
69 raise ClientException(message)
70 return
71
72
73 def get_project(project_list, item):
74 # project_list = ctx.obj.project.list()
75 item_project_list = item.get("_admin", {}).get("projects_read")
76 project_id = "None"
77 project_name = "None"
78 if item_project_list:
79 for p1 in item_project_list:
80 project_id = p1
81 for p2 in project_list:
82 if p2["_id"] == project_id:
83 project_name = p2["name"]
84 return project_id, project_name
85 return project_id, project_name
86
87
88 def get_vim_name(vim_list, vim_id):
89 vim_name = "-"
90 for v in vim_list:
91 if v["uuid"] == vim_id:
92 vim_name = v["name"]
93 break
94 return vim_name
95
96
97 def create_config(config_file, json_string):
98 '''
99 Combines a YAML or JSON file with a JSON string into a Python3 structure
100 It loads the YAML or JSON file 'cfile' into a first dictionary.
101 It loads the JSON string into a second dictionary.
102 Then it updates the first dictionary with the info in the second dictionary.
103 If the field is present in both cfile and cdict, the field in cdict prevails.
104 If both cfile and cdict are None, it returns an empty dict (i.e. {})
105 '''
106 config = {}
107 if config_file:
108 with open(config_file, "r") as cf:
109 config = yaml.safe_load(cf.read())
110 if json_string:
111 cdict = yaml.safe_load(json_string)
112 for k, v in cdict.items():
113 config[k] = v
114 return config
115
116
117 @click.group(
118 context_settings=dict(help_option_names=["-h", "--help"], max_content_width=160)
119 )
120 @click.option(
121 "--hostname",
122 default="127.0.0.1",
123 envvar="OSM_HOSTNAME",
124 help="hostname of server. " + "Also can set OSM_HOSTNAME in environment",
125 )
126 # @click.option('--sol005/--no-sol005',
127 # default=True,
128 # envvar='OSM_SOL005',
129 # help='Use ETSI NFV SOL005 API (default) or the previous SO API. ' +
130 # 'Also can set OSM_SOL005 in environment')
131 @click.option(
132 "--user",
133 default=None,
134 envvar="OSM_USER",
135 help="user (defaults to admin). " + "Also can set OSM_USER in environment",
136 )
137 @click.option(
138 "--password",
139 default=None,
140 envvar="OSM_PASSWORD",
141 help="password (defaults to admin). " + "Also can set OSM_PASSWORD in environment",
142 )
143 @click.option(
144 "--project",
145 default=None,
146 envvar="OSM_PROJECT",
147 help="project (defaults to admin). " + "Also can set OSM_PROJECT in environment",
148 )
149 @click.option(
150 "-v",
151 "--verbose",
152 count=True,
153 help="increase verbosity (-v INFO, -vv VERBOSE, -vvv DEBUG)",
154 )
155 @click.option("--all-projects", default=None, is_flag=True, help="include all projects")
156 @click.option(
157 "--public/--no-public",
158 default=None,
159 help="flag for public items (packages, instances, VIM accounts, etc.)",
160 )
161 @click.option(
162 "--project-domain-name",
163 "project_domain_name",
164 default=None,
165 envvar="OSM_PROJECT_DOMAIN_NAME",
166 help="project domain name for keystone authentication (default to None). "
167 + "Also can set OSM_PROJECT_DOMAIN_NAME in environment",
168 )
169 @click.option(
170 "--user-domain-name",
171 "user_domain_name",
172 default=None,
173 envvar="OSM_USER_DOMAIN_NAME",
174 help="user domain name for keystone authentication (default to None). "
175 + "Also can set OSM_USER_DOMAIN_NAME in environment",
176 )
177 # @click.option('--so-port',
178 # default=None,
179 # envvar='OSM_SO_PORT',
180 # help='hostname of server. ' +
181 # 'Also can set OSM_SO_PORT in environment')
182 # @click.option('--so-project',
183 # default=None,
184 # envvar='OSM_SO_PROJECT',
185 # help='Project Name in SO. ' +
186 # 'Also can set OSM_SO_PROJECT in environment')
187 # @click.option('--ro-hostname',
188 # default=None,
189 # envvar='OSM_RO_HOSTNAME',
190 # help='hostname of RO server. ' +
191 # 'Also can set OSM_RO_HOSTNAME in environment')
192 # @click.option('--ro-port',
193 # default=None,
194 # envvar='OSM_RO_PORT',
195 # help='hostname of RO server. ' +
196 # 'Also can set OSM_RO_PORT in environment')
197 @click.pass_context
198 def cli_osm(ctx, **kwargs):
199 global logger
200 hostname = kwargs.pop("hostname", None)
201 if hostname is None:
202 print(
203 (
204 "either hostname option or OSM_HOSTNAME "
205 + "environment variable needs to be specified"
206 )
207 )
208 exit(1)
209 # Remove None values
210 kwargs = {k: v for k, v in kwargs.items() if v is not None}
211 # if so_port is not None:
212 # kwargs['so_port']=so_port
213 # if so_project is not None:
214 # kwargs['so_project']=so_project
215 # if ro_hostname is not None:
216 # kwargs['ro_host']=ro_hostname
217 # if ro_port is not None:
218 # kwargs['ro_port']=ro_port
219 sol005 = os.getenv("OSM_SOL005", True)
220 # if user is not None:
221 # kwargs['user']=user
222 # if password is not None:
223 # kwargs['password']=password
224 # if project is not None:
225 # kwargs['project']=project
226 # if all_projects:
227 # kwargs['all_projects']=all_projects
228 # if public is not None:
229 # kwargs['public']=public
230 ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs)
231 logger = logging.getLogger("osmclient")
232
233
234 ####################
235 # LIST operations
236 ####################
237
238
239 @cli_osm.command(name="ns-list", short_help="list all NS instances")
240 @click.option(
241 "--filter",
242 default=None,
243 multiple=True,
244 help="restricts the list to the NS instances matching the filter.",
245 )
246 @click.option(
247 "--long",
248 is_flag=True,
249 help="get more details of the NS (project, vim, deployment status, configuration status.",
250 )
251 @click.pass_context
252 def ns_list(ctx, filter, long):
253 """list all NS instances
254
255 \b
256 Options:
257 --filter filterExpr Restricts the list to the NS instances matching the filter
258
259 \b
260 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
261 concatenated using the "&" character:
262
263 \b
264 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
265 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
266 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
267 attrName := string
268 value := scalar value
269
270 \b
271 where:
272 * zero or more occurrences
273 ? zero or one occurrence
274 [] grouping of expressions to be used with ? and *
275 "" quotation marks for marking string constants
276 <> name separator
277
278 \b
279 "AttrName" is the name of one attribute in the data type that defines the representation
280 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
281 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
282 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
283 entries, it means that the operator "op" is applied to the attribute addressed by the last
284 <attrName> entry included in the concatenation. All simple filter expressions are combined
285 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
286 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
287 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
288 prefix". If an attribute referenced in an expression is an array, an object that contains a
289 corresponding array shall be considered to match the expression if any of the elements in the
290 array matches all expressions that have the same attribute prefix.
291
292 \b
293 Filter examples:
294 --filter admin-status=ENABLED
295 --filter nsd-ref=<NSD_NAME>
296 --filter nsd.vendor=<VENDOR>
297 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
298 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
299 """
300
301 def summarize_deployment_status(status_dict):
302 # Nets
303 summary = ""
304 if not status_dict:
305 return summary
306 n_nets = 0
307 status_nets = {}
308 net_list = status_dict.get("nets", [])
309 for net in net_list:
310 n_nets += 1
311 if net["status"] not in status_nets:
312 status_nets[net["status"]] = 1
313 else:
314 status_nets[net["status"]] += 1
315 message = "Nets: "
316 for k, v in status_nets.items():
317 message += "{}:{},".format(k, v)
318 message += "TOTAL:{}".format(n_nets)
319 summary += "{}".format(message)
320 # VMs and VNFs
321 n_vms = 0
322 status_vms = {}
323 status_vnfs = {}
324 vnf_list = status_dict["vnfs"]
325 for vnf in vnf_list:
326 member_vnf_index = vnf["member_vnf_index"]
327 if member_vnf_index not in status_vnfs:
328 status_vnfs[member_vnf_index] = {}
329 for vm in vnf["vms"]:
330 n_vms += 1
331 if vm["status"] not in status_vms:
332 status_vms[vm["status"]] = 1
333 else:
334 status_vms[vm["status"]] += 1
335 if vm["status"] not in status_vnfs[member_vnf_index]:
336 status_vnfs[member_vnf_index][vm["status"]] = 1
337 else:
338 status_vnfs[member_vnf_index][vm["status"]] += 1
339 message = "VMs: "
340 for k, v in status_vms.items():
341 message += "{}:{},".format(k, v)
342 message += "TOTAL:{}".format(n_vms)
343 summary += "\n{}".format(message)
344 summary += "\nNFs:"
345 for k, v in status_vnfs.items():
346 total = 0
347 message = "\n {} VMs: ".format(k)
348 for k2, v2 in v.items():
349 message += "{}:{},".format(k2, v2)
350 total += v2
351 message += "TOTAL:{}".format(total)
352 summary += message
353 return summary
354
355 def summarize_config_status(ee_list):
356 summary = ""
357 if not ee_list:
358 return summary
359 n_ee = 0
360 status_ee = {}
361 for ee in ee_list:
362 n_ee += 1
363 if ee["elementType"] not in status_ee:
364 status_ee[ee["elementType"]] = {}
365 status_ee[ee["elementType"]][ee["status"]] = 1
366 continue
367 if ee["status"] in status_ee[ee["elementType"]]:
368 status_ee[ee["elementType"]][ee["status"]] += 1
369 else:
370 status_ee[ee["elementType"]][ee["status"]] = 1
371 for elementType in ["KDU", "VDU", "PDU", "VNF", "NS"]:
372 if elementType in status_ee:
373 message = ""
374 total = 0
375 for k, v in status_ee[elementType].items():
376 message += "{}:{},".format(k, v)
377 total += v
378 message += "TOTAL:{}\n".format(total)
379 summary += "{}: {}".format(elementType, message)
380 summary += "TOTAL Exec. Env.: {}".format(n_ee)
381 return summary
382
383 logger.debug("")
384 if filter:
385 check_client_version(ctx.obj, "--filter")
386 filter = "&".join(filter)
387 resp = ctx.obj.ns.list(filter)
388 else:
389 resp = ctx.obj.ns.list()
390 if long:
391 table = PrettyTable(
392 [
393 "ns instance name",
394 "id",
395 "date",
396 "ns state",
397 "current operation",
398 "error details",
399 "project",
400 "vim (inst param)",
401 "deployment status",
402 "configuration status",
403 ]
404 )
405 project_list = ctx.obj.project.list()
406 try:
407 vim_list = ctx.obj.vim.list()
408 except Exception:
409 vim_list = []
410 else:
411 table = PrettyTable(
412 [
413 "ns instance name",
414 "id",
415 "date",
416 "ns state",
417 "current operation",
418 "error details",
419 ]
420 )
421 for ns in resp:
422 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
423 if fullclassname == "osmclient.sol005.client.Client":
424 nsr = ns
425 logger.debug("NS info: {}".format(nsr))
426 nsr_name = nsr["name"]
427 nsr_id = nsr["_id"]
428 date = datetime.fromtimestamp(nsr["create-time"]).strftime(
429 "%Y-%m-%dT%H:%M:%S"
430 )
431 ns_state = nsr.get("nsState", nsr["_admin"]["nsState"])
432 if long:
433 deployment_status = summarize_deployment_status(
434 nsr.get("deploymentStatus")
435 )
436 config_status = summarize_config_status(nsr.get("configurationStatus"))
437 project_id, project_name = get_project(project_list, nsr)
438 # project = '{} ({})'.format(project_name, project_id)
439 project = project_name
440 vim_id = nsr.get("datacenter")
441 vim_name = get_vim_name(vim_list, vim_id)
442
443 # vim = '{} ({})'.format(vim_name, vim_id)
444 vim = vim_name
445 if "currentOperation" in nsr:
446 current_operation = "{} ({})".format(
447 nsr["currentOperation"], nsr["currentOperationID"]
448 )
449 else:
450 current_operation = "{} ({})".format(
451 nsr["_admin"].get("current-operation", "-"),
452 nsr["_admin"]["nslcmop"],
453 )
454 error_details = "N/A"
455 if (
456 ns_state == "BROKEN"
457 or ns_state == "DEGRADED"
458 or ("currentOperation" not in nsr and nsr.get("errorDescription"))
459 ):
460 error_details = "{}\nDetail: {}".format(
461 nsr["errorDescription"], nsr["errorDetail"]
462 )
463 else:
464 nsopdata = ctx.obj.ns.get_opdata(ns["id"])
465 nsr = nsopdata["nsr:nsr"]
466 nsr_name = nsr["name-ref"]
467 nsr_id = nsr["ns-instance-config-ref"]
468 date = "-"
469 project = "-"
470 deployment_status = (
471 nsr["operational-status"]
472 if "operational-status" in nsr
473 else "Not found"
474 )
475 ns_state = deployment_status
476 config_status = nsr.get("config-status", "Not found")
477 current_operation = "Unknown"
478 error_details = nsr.get("detailed-status", "Not found")
479 if config_status == "config_not_needed":
480 config_status = "configured (no charms)"
481
482 if long:
483 table.add_row(
484 [
485 nsr_name,
486 nsr_id,
487 date,
488 ns_state,
489 current_operation,
490 wrap_text(text=error_details, width=40),
491 project,
492 vim,
493 deployment_status,
494 config_status,
495 ]
496 )
497 else:
498 table.add_row(
499 [
500 nsr_name,
501 nsr_id,
502 date,
503 ns_state,
504 current_operation,
505 wrap_text(text=error_details, width=40),
506 ]
507 )
508 table.align = "l"
509 print(table)
510 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
511 print(
512 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
513 )
514
515
516 def nsd_list(ctx, filter, long):
517 logger.debug("")
518 if filter:
519 check_client_version(ctx.obj, "--filter")
520 filter = "&".join(filter)
521 resp = ctx.obj.nsd.list(filter)
522 else:
523 resp = ctx.obj.nsd.list()
524 # print(yaml.safe_dump(resp))
525 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
526 if fullclassname == "osmclient.sol005.client.Client":
527 if long:
528 table = PrettyTable(
529 [
530 "nsd name",
531 "id",
532 "onboarding state",
533 "operational state",
534 "usage state",
535 "date",
536 "last update",
537 ]
538 )
539 else:
540 table = PrettyTable(["nsd name", "id"])
541 for nsd in resp:
542 name = nsd.get("id", "-")
543 if long:
544 onb_state = nsd["_admin"].get("onboardingState", "-")
545 op_state = nsd["_admin"].get("operationalState", "-")
546 usage_state = nsd["_admin"].get("usageState", "-")
547 date = datetime.fromtimestamp(nsd["_admin"]["created"]).strftime(
548 "%Y-%m-%dT%H:%M:%S"
549 )
550 last_update = datetime.fromtimestamp(
551 nsd["_admin"]["modified"]
552 ).strftime("%Y-%m-%dT%H:%M:%S")
553 table.add_row(
554 [
555 name,
556 nsd["_id"],
557 onb_state,
558 op_state,
559 usage_state,
560 date,
561 last_update,
562 ]
563 )
564 else:
565 table.add_row([name, nsd["_id"]])
566 else:
567 table = PrettyTable(["nsd name", "id"])
568 for nsd in resp:
569 table.add_row([nsd["name"], nsd["id"]])
570 table.align = "l"
571 print(table)
572
573
574 @cli_osm.command(name="nsd-list", short_help="list all NS packages")
575 @click.option(
576 "--filter",
577 default=None,
578 multiple=True,
579 help="restricts the list to the NSD/NSpkg matching the filter",
580 )
581 @click.option("--long", is_flag=True, help="get more details")
582 @click.pass_context
583 def nsd_list1(ctx, filter, long):
584 """list all NSD/NS pkg in the system"""
585 logger.debug("")
586 nsd_list(ctx, filter, long)
587
588
589 @cli_osm.command(name="nspkg-list", short_help="list all NS packages")
590 @click.option(
591 "--filter",
592 default=None,
593 multiple=True,
594 help="restricts the list to the NSD/NSpkg matching the filter",
595 )
596 @click.option("--long", is_flag=True, help="get more details")
597 @click.pass_context
598 def nsd_list2(ctx, filter, long):
599 """list all NS packages"""
600 logger.debug("")
601 nsd_list(ctx, filter, long)
602
603
604 def pkg_repo_list(ctx, pkgtype, filter, repo, long):
605 resp = ctx.obj.osmrepo.pkg_list(pkgtype, filter, repo)
606 if long:
607 table = PrettyTable(
608 ["nfpkg name", "vendor", "version", "latest", "description", "repository"]
609 )
610 else:
611 table = PrettyTable(["nfpkg name", "repository"])
612 for vnfd in resp:
613 name = vnfd.get("id", vnfd.get("name", "-"))
614 repository = vnfd.get("repository")
615 if long:
616 vendor = vnfd.get("provider", vnfd.get("vendor"))
617 version = vnfd.get("version")
618 description = vnfd.get("description")
619 latest = vnfd.get("latest")
620 table.add_row([name, vendor, version, latest, description, repository])
621 else:
622 table.add_row([name, repository])
623 table.align = "l"
624 print(table)
625
626
627 def vnfd_list(ctx, nf_type, filter, long):
628 logger.debug("")
629 if nf_type:
630 check_client_version(ctx.obj, "--nf_type")
631 elif filter:
632 check_client_version(ctx.obj, "--filter")
633 if filter:
634 filter = "&".join(filter)
635 if nf_type:
636 if nf_type == "vnf":
637 nf_filter = "_admin.type=vnfd"
638 elif nf_type == "pnf":
639 nf_filter = "_admin.type=pnfd"
640 elif nf_type == "hnf":
641 nf_filter = "_admin.type=hnfd"
642 else:
643 raise ClientException(
644 'wrong value for "--nf_type" option, allowed values: vnf, pnf, hnf'
645 )
646 if filter:
647 filter = "{}&{}".format(nf_filter, filter)
648 else:
649 filter = nf_filter
650 if filter:
651 resp = ctx.obj.vnfd.list(filter)
652 else:
653 resp = ctx.obj.vnfd.list()
654 # print(yaml.safe_dump(resp))
655 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
656 if fullclassname == "osmclient.sol005.client.Client":
657 if long:
658 table = PrettyTable(
659 [
660 "nfpkg name",
661 "id",
662 "desc type",
663 "vendor",
664 "version",
665 "onboarding state",
666 "operational state",
667 "usage state",
668 "date",
669 "last update",
670 ]
671 )
672 else:
673 table = PrettyTable(["nfpkg name", "id", "desc type"])
674 for vnfd in resp:
675 name = vnfd.get("id", vnfd.get("name", "-"))
676 descriptor_type = "sol006" if "product-name" in vnfd else "rel8"
677 if long:
678 onb_state = vnfd["_admin"].get("onboardingState", "-")
679 op_state = vnfd["_admin"].get("operationalState", "-")
680 vendor = vnfd.get("provider", vnfd.get("vendor"))
681 version = vnfd.get("version")
682 usage_state = vnfd["_admin"].get("usageState", "-")
683 date = datetime.fromtimestamp(vnfd["_admin"]["created"]).strftime(
684 "%Y-%m-%dT%H:%M:%S"
685 )
686 last_update = datetime.fromtimestamp(
687 vnfd["_admin"]["modified"]
688 ).strftime("%Y-%m-%dT%H:%M:%S")
689 table.add_row(
690 [
691 name,
692 vnfd["_id"],
693 descriptor_type,
694 vendor,
695 version,
696 onb_state,
697 op_state,
698 usage_state,
699 date,
700 last_update,
701 ]
702 )
703 else:
704 table.add_row([name, vnfd["_id"], descriptor_type])
705 else:
706 table = PrettyTable(["nfpkg name", "id"])
707 for vnfd in resp:
708 table.add_row([vnfd["name"], vnfd["id"]])
709 table.align = "l"
710 print(table)
711
712
713 @cli_osm.command(name="vnfd-list", short_help="list all xNF packages (VNF, HNF, PNF)")
714 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
715 @click.option(
716 "--filter",
717 default=None,
718 multiple=True,
719 help="restricts the list to the NF pkg matching the filter",
720 )
721 @click.option("--long", is_flag=True, help="get more details")
722 @click.pass_context
723 def vnfd_list1(ctx, nf_type, filter, long):
724 """list all xNF packages (VNF, HNF, PNF)"""
725 logger.debug("")
726 vnfd_list(ctx, nf_type, filter, long)
727
728
729 @cli_osm.command(name="vnfpkg-list", short_help="list all xNF packages (VNF, HNF, PNF)")
730 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
731 @click.option(
732 "--filter",
733 default=None,
734 multiple=True,
735 help="restricts the list to the NFpkg matching the filter",
736 )
737 @click.option("--long", is_flag=True, help="get more details")
738 @click.pass_context
739 def vnfd_list2(ctx, nf_type, filter, long):
740 """list all xNF packages (VNF, HNF, PNF)"""
741 logger.debug("")
742 vnfd_list(ctx, nf_type, filter, long)
743
744
745 @cli_osm.command(name="nfpkg-list", short_help="list all xNF packages (VNF, HNF, PNF)")
746 @click.option("--nf_type", help="type of NF (vnf, pnf, hnf)")
747 @click.option(
748 "--filter",
749 default=None,
750 multiple=True,
751 help="restricts the list to the NFpkg matching the filter",
752 )
753 @click.option("--long", is_flag=True, help="get more details")
754 @click.pass_context
755 def nfpkg_list(ctx, nf_type, filter, long):
756 """list all xNF packages (VNF, HNF, PNF)"""
757 logger.debug("")
758 # try:
759 check_client_version(ctx.obj, ctx.command.name)
760 vnfd_list(ctx, nf_type, filter, long)
761 # except ClientException as e:
762 # print(str(e))
763 # exit(1)
764
765
766 @cli_osm.command(
767 name="vnfpkg-repo-list", short_help="list all xNF from OSM repositories"
768 )
769 @click.option(
770 "--filter",
771 default=None,
772 multiple=True,
773 help="restricts the list to the NFpkg matching the filter",
774 )
775 @click.option(
776 "--repo", default=None, help="restricts the list to a particular OSM repository"
777 )
778 @click.option("--long", is_flag=True, help="get more details")
779 @click.pass_context
780 def nfpkg_repo_list1(ctx, filter, repo, long):
781 """list xNF packages from OSM repositories"""
782 pkgtype = "vnf"
783 pkg_repo_list(ctx, pkgtype, filter, repo, long)
784
785
786 @cli_osm.command(
787 name="nfpkg-repo-list", short_help="list all xNF from OSM repositories"
788 )
789 @click.option(
790 "--filter",
791 default=None,
792 multiple=True,
793 help="restricts the list to the NFpkg matching the filter",
794 )
795 @click.option(
796 "--repo", default=None, help="restricts the list to a particular OSM repository"
797 )
798 @click.option("--long", is_flag=True, help="get more details")
799 @click.pass_context
800 def nfpkg_repo_list2(ctx, filter, repo, long):
801 """list xNF packages from OSM repositories"""
802 pkgtype = "vnf"
803 pkg_repo_list(ctx, pkgtype, filter, repo, long)
804
805
806 def vnf_list(ctx, ns, filter, long):
807 # try:
808 if ns or filter:
809 if ns:
810 check_client_version(ctx.obj, "--ns")
811 if filter:
812 filter = "&".join(filter)
813 check_client_version(ctx.obj, "--filter")
814 resp = ctx.obj.vnf.list(ns, filter)
815 else:
816 resp = ctx.obj.vnf.list()
817 # except ClientException as e:
818 # print(str(e))
819 # exit(1)
820 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
821 if fullclassname == "osmclient.sol005.client.Client":
822 field_names = [
823 "vnf id",
824 "name",
825 "ns id",
826 "vnf member index",
827 "vnfd name",
828 "vim account id",
829 "ip address",
830 ]
831 if long:
832 field_names = [
833 "vnf id",
834 "name",
835 "ns id",
836 "vnf member index",
837 "vnfd name",
838 "vim account id",
839 "ip address",
840 "date",
841 "last update",
842 ]
843 table = PrettyTable(field_names)
844 for vnfr in resp:
845 name = vnfr["name"] if "name" in vnfr else "-"
846 new_row = [
847 vnfr["_id"],
848 name,
849 vnfr["nsr-id-ref"],
850 vnfr["member-vnf-index-ref"],
851 vnfr["vnfd-ref"],
852 vnfr["vim-account-id"],
853 vnfr["ip-address"],
854 ]
855 if long:
856 date = datetime.fromtimestamp(vnfr["_admin"]["created"]).strftime(
857 "%Y-%m-%dT%H:%M:%S"
858 )
859 last_update = datetime.fromtimestamp(
860 vnfr["_admin"]["modified"]
861 ).strftime("%Y-%m-%dT%H:%M:%S")
862 new_row.extend([date, last_update])
863 table.add_row(new_row)
864 else:
865 table = PrettyTable(["vnf name", "id", "operational status", "config status"])
866 for vnfr in resp:
867 if "mgmt-interface" not in vnfr:
868 vnfr["mgmt-interface"] = {}
869 vnfr["mgmt-interface"]["ip-address"] = None
870 table.add_row(
871 [
872 vnfr["name"],
873 vnfr["id"],
874 vnfr["operational-status"],
875 vnfr["config-status"],
876 ]
877 )
878 table.align = "l"
879 print(table)
880
881
882 @cli_osm.command(name="vnf-list", short_help="list all NF instances")
883 @click.option(
884 "--ns", default=None, help="NS instance id or name to restrict the NF list"
885 )
886 @click.option(
887 "--filter",
888 default=None,
889 multiple=True,
890 help="restricts the list to the NF instances matching the filter.",
891 )
892 @click.option("--long", is_flag=True, help="get more details")
893 @click.pass_context
894 def vnf_list1(ctx, ns, filter, long):
895 """list all NF instances"""
896 logger.debug("")
897 vnf_list(ctx, ns, filter, long)
898
899
900 @cli_osm.command(name="nsd-repo-list", short_help="list all NS from OSM repositories")
901 @click.option(
902 "--filter",
903 default=None,
904 multiple=True,
905 help="restricts the list to the NS matching the filter",
906 )
907 @click.option(
908 "--repo", default=None, help="restricts the list to a particular OSM repository"
909 )
910 @click.option("--long", is_flag=True, help="get more details")
911 @click.pass_context
912 def nspkg_repo_list(ctx, filter, repo, long):
913 """list xNF packages from OSM repositories"""
914 pkgtype = "ns"
915 pkg_repo_list(ctx, pkgtype, filter, repo, long)
916
917
918 @cli_osm.command(name="nspkg-repo-list", short_help="list all NS from OSM repositories")
919 @click.option(
920 "--filter",
921 default=None,
922 multiple=True,
923 help="restricts the list to the NS matching the filter",
924 )
925 @click.option(
926 "--repo", default=None, help="restricts the list to a particular OSM repository"
927 )
928 @click.option("--long", is_flag=True, help="get more details")
929 @click.pass_context
930 def nspkg_repo_list2(ctx, filter, repo, long):
931 """list xNF packages from OSM repositories"""
932 pkgtype = "ns"
933 pkg_repo_list(ctx, pkgtype, filter, repo, long)
934
935
936 @cli_osm.command(name="nf-list", short_help="list all NF instances")
937 @click.option(
938 "--ns", default=None, help="NS instance id or name to restrict the NF list"
939 )
940 @click.option(
941 "--filter",
942 default=None,
943 multiple=True,
944 help="restricts the list to the NF instances matching the filter.",
945 )
946 @click.option("--long", is_flag=True, help="get more details")
947 @click.pass_context
948 def nf_list(ctx, ns, filter, long):
949 """list all NF instances
950
951 \b
952 Options:
953 --ns TEXT NS instance id or name to restrict the VNF list
954 --filter filterExpr Restricts the list to the VNF instances matching the filter
955
956 \b
957 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
958 concatenated using the "&" character:
959
960 \b
961 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
962 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
963 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
964 attrName := string
965 value := scalar value
966
967 \b
968 where:
969 * zero or more occurrences
970 ? zero or one occurrence
971 [] grouping of expressions to be used with ? and *
972 "" quotation marks for marking string constants
973 <> name separator
974
975 \b
976 "AttrName" is the name of one attribute in the data type that defines the representation
977 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
978 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
979 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
980 entries, it means that the operator "op" is applied to the attribute addressed by the last
981 <attrName> entry included in the concatenation. All simple filter expressions are combined
982 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
983 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
984 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
985 prefix". If an attribute referenced in an expression is an array, an object that contains a
986 corresponding array shall be considered to match the expression if any of the elements in the
987 array matches all expressions that have the same attribute prefix.
988
989 \b
990 Filter examples:
991 --filter vim-account-id=<VIM_ACCOUNT_ID>
992 --filter vnfd-ref=<VNFD_NAME>
993 --filter vdur.ip-address=<IP_ADDRESS>
994 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
995 """
996 logger.debug("")
997 vnf_list(ctx, ns, filter, long)
998
999
1000 @cli_osm.command(
1001 name="ns-op-list", short_help="shows the history of operations over a NS instance"
1002 )
1003 @click.argument("name")
1004 @click.option(
1005 "--long", is_flag=True, help="get more details of the NS operation (date, )."
1006 )
1007 @click.pass_context
1008 def ns_op_list(ctx, name, long):
1009 """shows the history of operations over a NS instance
1010
1011 NAME: name or ID of the NS instance
1012 """
1013
1014 def formatParams(params):
1015 if params["lcmOperationType"] == "instantiate":
1016 params.pop("nsDescription")
1017 params.pop("nsName")
1018 params.pop("nsdId")
1019 params.pop("nsr_id")
1020 elif params["lcmOperationType"] == "action":
1021 params.pop("primitive")
1022 params.pop("lcmOperationType")
1023 params.pop("nsInstanceId")
1024 return params
1025
1026 logger.debug("")
1027 # try:
1028 check_client_version(ctx.obj, ctx.command.name)
1029 resp = ctx.obj.ns.list_op(name)
1030 # except ClientException as e:
1031 # print(str(e))
1032 # exit(1)
1033
1034 if long:
1035 table = PrettyTable(
1036 [
1037 "id",
1038 "operation",
1039 "action_name",
1040 "operation_params",
1041 "status",
1042 "date",
1043 "last update",
1044 "detail",
1045 ]
1046 )
1047 else:
1048 table = PrettyTable(
1049 ["id", "operation", "action_name", "status", "date", "detail"]
1050 )
1051
1052 # print(yaml.safe_dump(resp))
1053 for op in resp:
1054 action_name = "N/A"
1055 if op["lcmOperationType"] == "action":
1056 action_name = op["operationParams"]["primitive"]
1057 detail = "-"
1058 if op["operationState"] == "PROCESSING":
1059 if op["queuePosition"] is not None and op["queuePosition"] > 0:
1060 detail = "In queue. Current position: {}".format(op["queuePosition"])
1061 elif op["lcmOperationType"] in ("instantiate", "terminate"):
1062 if op["stage"]:
1063 detail = op["stage"]
1064 elif op["operationState"] in ("FAILED", "FAILED_TEMP"):
1065 detail = op.get("errorMessage", "-")
1066 date = datetime.fromtimestamp(op["startTime"]).strftime("%Y-%m-%dT%H:%M:%S")
1067 last_update = datetime.fromtimestamp(op["statusEnteredTime"]).strftime(
1068 "%Y-%m-%dT%H:%M:%S"
1069 )
1070 if long:
1071 table.add_row(
1072 [
1073 op["id"],
1074 op["lcmOperationType"],
1075 action_name,
1076 wrap_text(
1077 text=json.dumps(formatParams(op["operationParams"]), indent=2),
1078 width=50,
1079 ),
1080 op["operationState"],
1081 date,
1082 last_update,
1083 wrap_text(text=detail, width=50),
1084 ]
1085 )
1086 else:
1087 table.add_row(
1088 [
1089 op["id"],
1090 op["lcmOperationType"],
1091 action_name,
1092 op["operationState"],
1093 date,
1094 wrap_text(text=detail or "", width=50),
1095 ]
1096 )
1097 table.align = "l"
1098 print(table)
1099
1100
1101 def nsi_list(ctx, filter):
1102 """list all Network Slice Instances"""
1103 logger.debug("")
1104 # try:
1105 check_client_version(ctx.obj, ctx.command.name)
1106 if filter:
1107 filter = "&".join(filter)
1108 resp = ctx.obj.nsi.list(filter)
1109 # except ClientException as e:
1110 # print(str(e))
1111 # exit(1)
1112 table = PrettyTable(
1113 [
1114 "netslice instance name",
1115 "id",
1116 "operational status",
1117 "config status",
1118 "detailed status",
1119 ]
1120 )
1121 for nsi in resp:
1122 nsi_name = nsi["name"]
1123 nsi_id = nsi["_id"]
1124 opstatus = (
1125 nsi["operational-status"] if "operational-status" in nsi else "Not found"
1126 )
1127 configstatus = nsi["config-status"] if "config-status" in nsi else "Not found"
1128 detailed_status = (
1129 nsi["detailed-status"] if "detailed-status" in nsi else "Not found"
1130 )
1131 if configstatus == "config_not_needed":
1132 configstatus = "configured (no charms)"
1133 table.add_row([nsi_name, nsi_id, opstatus, configstatus, detailed_status])
1134 table.align = "l"
1135 print(table)
1136
1137
1138 @cli_osm.command(name="nsi-list", short_help="list all Network Slice Instances (NSI)")
1139 @click.option(
1140 "--filter",
1141 default=None,
1142 multiple=True,
1143 help="restricts the list to the Network Slice Instances matching the filter",
1144 )
1145 @click.pass_context
1146 def nsi_list1(ctx, filter):
1147 """list all Network Slice Instances (NSI)"""
1148 logger.debug("")
1149 nsi_list(ctx, filter)
1150
1151
1152 @cli_osm.command(
1153 name="netslice-instance-list", short_help="list all Network Slice Instances (NSI)"
1154 )
1155 @click.option(
1156 "--filter",
1157 default=None,
1158 multiple=True,
1159 help="restricts the list to the Network Slice Instances matching the filter",
1160 )
1161 @click.pass_context
1162 def nsi_list2(ctx, filter):
1163 """list all Network Slice Instances (NSI)"""
1164 logger.debug("")
1165 nsi_list(ctx, filter)
1166
1167
1168 def nst_list(ctx, filter):
1169 logger.debug("")
1170 # try:
1171 check_client_version(ctx.obj, ctx.command.name)
1172 if filter:
1173 filter = "&".join(filter)
1174 resp = ctx.obj.nst.list(filter)
1175 # except ClientException as e:
1176 # print(str(e))
1177 # exit(1)
1178 # print(yaml.safe_dump(resp))
1179 table = PrettyTable(["nst name", "id"])
1180 for nst in resp:
1181 name = nst["name"] if "name" in nst else "-"
1182 table.add_row([name, nst["_id"]])
1183 table.align = "l"
1184 print(table)
1185
1186
1187 @cli_osm.command(name="nst-list", short_help="list all Network Slice Templates (NST)")
1188 @click.option(
1189 "--filter",
1190 default=None,
1191 multiple=True,
1192 help="restricts the list to the NST matching the filter",
1193 )
1194 @click.pass_context
1195 def nst_list1(ctx, filter):
1196 """list all Network Slice Templates (NST) in the system"""
1197 logger.debug("")
1198 nst_list(ctx, filter)
1199
1200
1201 @cli_osm.command(
1202 name="netslice-template-list", short_help="list all Network Slice Templates (NST)"
1203 )
1204 @click.option(
1205 "--filter",
1206 default=None,
1207 multiple=True,
1208 help="restricts the list to the NST matching the filter",
1209 )
1210 @click.pass_context
1211 def nst_list2(ctx, filter):
1212 """list all Network Slice Templates (NST) in the system"""
1213 logger.debug("")
1214 nst_list(ctx, filter)
1215
1216
1217 def nsi_op_list(ctx, name):
1218 logger.debug("")
1219 # try:
1220 check_client_version(ctx.obj, ctx.command.name)
1221 resp = ctx.obj.nsi.list_op(name)
1222 # except ClientException as e:
1223 # print(str(e))
1224 # exit(1)
1225 table = PrettyTable(["id", "operation", "status"])
1226 for op in resp:
1227 table.add_row([op["id"], op["lcmOperationType"], op["operationState"]])
1228 table.align = "l"
1229 print(table)
1230
1231
1232 @cli_osm.command(
1233 name="nsi-op-list",
1234 short_help="shows the history of operations over a Network Slice Instance (NSI)",
1235 )
1236 @click.argument("name")
1237 @click.pass_context
1238 def nsi_op_list1(ctx, name):
1239 """shows the history of operations over a Network Slice Instance (NSI)
1240
1241 NAME: name or ID of the Network Slice Instance
1242 """
1243 logger.debug("")
1244 nsi_op_list(ctx, name)
1245
1246
1247 @cli_osm.command(
1248 name="netslice-instance-op-list",
1249 short_help="shows the history of operations over a Network Slice Instance (NSI)",
1250 )
1251 @click.argument("name")
1252 @click.pass_context
1253 def nsi_op_list2(ctx, name):
1254 """shows the history of operations over a Network Slice Instance (NSI)
1255
1256 NAME: name or ID of the Network Slice Instance
1257 """
1258 logger.debug("")
1259 nsi_op_list(ctx, name)
1260
1261
1262 @cli_osm.command(name="pdu-list", short_help="list all Physical Deployment Units (PDU)")
1263 @click.option(
1264 "--filter",
1265 default=None,
1266 multiple=True,
1267 help="restricts the list to the Physical Deployment Units matching the filter",
1268 )
1269 @click.pass_context
1270 def pdu_list(ctx, filter):
1271 """list all Physical Deployment Units (PDU)"""
1272 logger.debug("")
1273 # try:
1274 check_client_version(ctx.obj, ctx.command.name)
1275 if filter:
1276 filter = "&".join(filter)
1277 resp = ctx.obj.pdu.list(filter)
1278 # except ClientException as e:
1279 # print(str(e))
1280 # exit(1)
1281 table = PrettyTable(["pdu name", "id", "type", "mgmt ip address"])
1282 for pdu in resp:
1283 pdu_name = pdu["name"]
1284 pdu_id = pdu["_id"]
1285 pdu_type = pdu["type"]
1286 pdu_ipaddress = "None"
1287 for iface in pdu["interfaces"]:
1288 if iface["mgmt"]:
1289 pdu_ipaddress = iface["ip-address"]
1290 break
1291 table.add_row([pdu_name, pdu_id, pdu_type, pdu_ipaddress])
1292 table.align = "l"
1293 print(table)
1294
1295
1296 ####################
1297 # SHOW operations
1298 ####################
1299
1300
1301 def nsd_show(ctx, name, literal):
1302 logger.debug("")
1303 # try:
1304 resp = ctx.obj.nsd.get(name)
1305 # resp = ctx.obj.nsd.get_individual(name)
1306 # except ClientException as e:
1307 # print(str(e))
1308 # exit(1)
1309
1310 if literal:
1311 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
1312 return
1313
1314 table = PrettyTable(["field", "value"])
1315 for k, v in list(resp.items()):
1316 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
1317 table.align = "l"
1318 print(table)
1319
1320
1321 @cli_osm.command(name="nsd-show", short_help="shows the details of a NS package")
1322 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1323 @click.argument("name")
1324 @click.pass_context
1325 def nsd_show1(ctx, name, literal):
1326 """shows the content of a NSD
1327
1328 NAME: name or ID of the NSD/NSpkg
1329 """
1330 logger.debug("")
1331 nsd_show(ctx, name, literal)
1332
1333
1334 @cli_osm.command(name="nspkg-show", short_help="shows the details of a NS package")
1335 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1336 @click.argument("name")
1337 @click.pass_context
1338 def nsd_show2(ctx, name, literal):
1339 """shows the content of a NSD
1340
1341 NAME: name or ID of the NSD/NSpkg
1342 """
1343 logger.debug("")
1344 nsd_show(ctx, name, literal)
1345
1346
1347 def vnfd_show(ctx, name, literal):
1348 logger.debug("")
1349 # try:
1350 resp = ctx.obj.vnfd.get(name)
1351 # resp = ctx.obj.vnfd.get_individual(name)
1352 # except ClientException as e:
1353 # print(str(e))
1354 # exit(1)
1355
1356 if literal:
1357 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
1358 return
1359
1360 table = PrettyTable(["field", "value"])
1361 for k, v in list(resp.items()):
1362 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
1363 table.align = "l"
1364 print(table)
1365
1366
1367 def pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal):
1368 logger.debug("")
1369 if filter:
1370 filter = "&".join(filter)
1371 # try:
1372 resp = ctx.obj.osmrepo.pkg_get(pkgtype, name, repo, version, filter)
1373
1374 if literal:
1375 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
1376 return
1377 pkgtype += "d"
1378 catalog = pkgtype + "-catalog"
1379 full_catalog = pkgtype + ":" + catalog
1380 if resp.get(catalog):
1381 resp = resp.pop(catalog)[pkgtype][0]
1382 elif resp.get(full_catalog):
1383 resp = resp.pop(full_catalog)[pkgtype][0]
1384
1385 table = PrettyTable(["field", "value"])
1386 for k, v in list(resp.items()):
1387 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
1388 table.align = "l"
1389 print(table)
1390
1391
1392 @cli_osm.command(name="vnfd-show", short_help="shows the details of a NF package")
1393 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1394 @click.argument("name")
1395 @click.pass_context
1396 def vnfd_show1(ctx, name, literal):
1397 """shows the content of a VNFD
1398
1399 NAME: name or ID of the VNFD/VNFpkg
1400 """
1401 logger.debug("")
1402 vnfd_show(ctx, name, literal)
1403
1404
1405 @cli_osm.command(name="vnfpkg-show", short_help="shows the details of a NF package")
1406 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1407 @click.argument("name")
1408 @click.pass_context
1409 def vnfd_show2(ctx, name, literal):
1410 """shows the content of a VNFD
1411
1412 NAME: name or ID of the VNFD/VNFpkg
1413 """
1414 logger.debug("")
1415 vnfd_show(ctx, name, literal)
1416
1417
1418 @cli_osm.command(
1419 name="vnfpkg-repo-show",
1420 short_help="shows the details of a NF package in an OSM repository",
1421 )
1422 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1423 @click.option("--repo", required=True, help="Repository name")
1424 @click.argument("name")
1425 @click.option("--filter", default=None, multiple=True, help="filter by fields")
1426 @click.option("--version", default="latest", help="package version")
1427 @click.pass_context
1428 def vnfd_show3(ctx, name, repo, version, literal=None, filter=None):
1429 """shows the content of a VNFD in a repository
1430
1431 NAME: name or ID of the VNFD/VNFpkg
1432 """
1433 pkgtype = "vnf"
1434 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal)
1435
1436
1437 @cli_osm.command(
1438 name="nsd-repo-show",
1439 short_help="shows the details of a NS package in an OSM repository",
1440 )
1441 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1442 @click.option("--repo", required=True, help="Repository name")
1443 @click.argument("name")
1444 @click.option("--filter", default=None, multiple=True, help="filter by fields")
1445 @click.option("--version", default="latest", help="package version")
1446 @click.pass_context
1447 def nsd_repo_show(ctx, name, repo, version, literal=None, filter=None):
1448 """shows the content of a VNFD in a repository
1449
1450 NAME: name or ID of the VNFD/VNFpkg
1451 """
1452 pkgtype = "ns"
1453 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal)
1454
1455
1456 @cli_osm.command(
1457 name="nspkg-repo-show",
1458 short_help="shows the details of a NS package in an OSM repository",
1459 )
1460 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1461 @click.option("--repo", required=True, help="Repository name")
1462 @click.argument("name")
1463 @click.option("--filter", default=None, multiple=True, help="filter by fields")
1464 @click.option("--version", default="latest", help="package version")
1465 @click.pass_context
1466 def nsd_repo_show2(ctx, name, repo, version, literal=None, filter=None):
1467 """shows the content of a VNFD in a repository
1468
1469 NAME: name or ID of the VNFD/VNFpkg
1470 """
1471 pkgtype = "ns"
1472 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal)
1473
1474
1475 @cli_osm.command(name="nfpkg-show", short_help="shows the details of a NF package")
1476 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1477 @click.argument("name")
1478 @click.pass_context
1479 def nfpkg_show(ctx, name, literal):
1480 """shows the content of a NF Descriptor
1481
1482 NAME: name or ID of the NFpkg
1483 """
1484 logger.debug("")
1485 vnfd_show(ctx, name, literal)
1486
1487
1488 @cli_osm.command(
1489 name="nfpkg-repo-show",
1490 short_help="shows the details of a NF package in an OSM repository",
1491 )
1492 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1493 @click.option("--repo", required=True, help="Repository name")
1494 @click.argument("name")
1495 @click.option("--filter", default=None, multiple=True, help="filter by fields")
1496 @click.option("--version", default="latest", help="package version")
1497 @click.pass_context
1498 def vnfd_show4(ctx, name, repo, version, literal=None, filter=None):
1499 """shows the content of a VNFD in a repository
1500
1501 NAME: name or ID of the VNFD/VNFpkg
1502 """
1503 pkgtype = "vnf"
1504 pkg_repo_show(ctx, pkgtype, name, repo, version, filter, literal)
1505
1506
1507 @cli_osm.command(name="ns-show", short_help="shows the info of a NS instance")
1508 @click.argument("name")
1509 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1510 @click.option(
1511 "--filter",
1512 multiple=True,
1513 help="restricts the information to the fields in the filter",
1514 )
1515 @click.pass_context
1516 def ns_show(ctx, name, literal, filter):
1517 """shows the info of a NS instance
1518
1519 NAME: name or ID of the NS instance
1520 """
1521 logger.debug("")
1522 # try:
1523 ns = ctx.obj.ns.get(name)
1524 # except ClientException as e:
1525 # print(str(e))
1526 # exit(1)
1527
1528 if literal:
1529 print(yaml.safe_dump(ns, indent=4, default_flow_style=False))
1530 return
1531
1532 table = PrettyTable(["field", "value"])
1533
1534 for k, v in list(ns.items()):
1535 if not filter or k in filter:
1536 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
1537
1538 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
1539 if fullclassname != "osmclient.sol005.client.Client":
1540 nsopdata = ctx.obj.ns.get_opdata(ns["id"])
1541 nsr_optdata = nsopdata["nsr:nsr"]
1542 for k, v in list(nsr_optdata.items()):
1543 if not filter or k in filter:
1544 table.add_row([k, wrap_text(json.dumps(v, indent=2), width=100)])
1545 table.align = "l"
1546 print(table)
1547
1548
1549 @cli_osm.command(name="vnf-show", short_help="shows the info of a VNF instance")
1550 @click.argument("name")
1551 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1552 @click.option(
1553 "--filter",
1554 multiple=True,
1555 help="restricts the information to the fields in the filter",
1556 )
1557 @click.option("--kdu", default=None, help="KDU name (whose status will be shown)")
1558 @click.pass_context
1559 def vnf_show(ctx, name, literal, filter, kdu):
1560 """shows the info of a VNF instance
1561
1562 NAME: name or ID of the VNF instance
1563 """
1564
1565 def print_kdu_status(op_info_status):
1566 """print KDU status properly formatted"""
1567 try:
1568 op_status = yaml.safe_load(op_info_status)
1569 if (
1570 "namespace" in op_status
1571 and "info" in op_status
1572 and "last_deployed" in op_status["info"]
1573 and "status" in op_status["info"]
1574 and "code" in op_status["info"]["status"]
1575 and "resources" in op_status["info"]["status"]
1576 and "seconds" in op_status["info"]["last_deployed"]
1577 ):
1578 last_deployed_time = datetime.fromtimestamp(
1579 op_status["info"]["last_deployed"]["seconds"]
1580 ).strftime("%a %b %d %I:%M:%S %Y")
1581 print("LAST DEPLOYED: {}".format(last_deployed_time))
1582 print("NAMESPACE: {}".format(op_status["namespace"]))
1583 status_code = "UNKNOWN"
1584 if op_status["info"]["status"]["code"] == 1:
1585 status_code = "DEPLOYED"
1586 print("STATUS: {}".format(status_code))
1587 print()
1588 print("RESOURCES:")
1589 print(op_status["info"]["status"]["resources"])
1590 if "notes" in op_status["info"]["status"]:
1591 print("NOTES:")
1592 print(op_status["info"]["status"]["notes"])
1593 else:
1594 print(op_info_status)
1595 except Exception:
1596 print(op_info_status)
1597
1598 logger.debug("")
1599 if kdu:
1600 if literal:
1601 raise ClientException(
1602 '"--literal" option is incompatible with "--kdu" option'
1603 )
1604 if filter:
1605 raise ClientException(
1606 '"--filter" option is incompatible with "--kdu" option'
1607 )
1608
1609 # try:
1610 check_client_version(ctx.obj, ctx.command.name)
1611 resp = ctx.obj.vnf.get(name)
1612
1613 if kdu:
1614 ns_id = resp["nsr-id-ref"]
1615 op_data = {}
1616 op_data["member_vnf_index"] = resp["member-vnf-index-ref"]
1617 op_data["kdu_name"] = kdu
1618 op_data["primitive"] = "status"
1619 op_data["primitive_params"] = {}
1620 op_id = ctx.obj.ns.exec_op(ns_id, op_name="action", op_data=op_data, wait=False)
1621 t = 0
1622 while t < 30:
1623 op_info = ctx.obj.ns.get_op(op_id)
1624 if op_info["operationState"] == "COMPLETED":
1625 print_kdu_status(op_info["detailed-status"])
1626 return
1627 time.sleep(5)
1628 t += 5
1629 print("Could not determine KDU status")
1630 return
1631
1632 if literal:
1633 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
1634 return
1635
1636 table = PrettyTable(["field", "value"])
1637 for k, v in list(resp.items()):
1638 if not filter or k in filter:
1639 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
1640 table.align = "l"
1641 print(table)
1642 # except ClientException as e:
1643 # print(str(e))
1644 # exit(1)
1645
1646
1647 # @cli_osm.command(name='vnf-monitoring-show')
1648 # @click.argument('vnf_name')
1649 # @click.pass_context
1650 # def vnf_monitoring_show(ctx, vnf_name):
1651 # try:
1652 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1653 # resp = ctx.obj.vnf.get_monitoring(vnf_name)
1654 # except ClientException as e:
1655 # print(str(e))
1656 # exit(1)
1657 #
1658 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1659 # if resp is not None:
1660 # for monitor in resp:
1661 # table.add_row(
1662 # [vnf_name,
1663 # monitor['name'],
1664 # monitor['value-integer'],
1665 # monitor['units']])
1666 # table.align = 'l'
1667 # print(table)
1668
1669
1670 # @cli_osm.command(name='ns-monitoring-show')
1671 # @click.argument('ns_name')
1672 # @click.pass_context
1673 # def ns_monitoring_show(ctx, ns_name):
1674 # try:
1675 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1676 # resp = ctx.obj.ns.get_monitoring(ns_name)
1677 # except ClientException as e:
1678 # print(str(e))
1679 # exit(1)
1680 #
1681 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1682 # for key, val in list(resp.items()):
1683 # for monitor in val:
1684 # table.add_row(
1685 # [key,
1686 # monitor['name'],
1687 # monitor['value-integer'],
1688 # monitor['units']])
1689 # table.align = 'l'
1690 # print(table)
1691
1692
1693 @cli_osm.command(name="ns-op-show", short_help="shows the info of a NS operation")
1694 @click.argument("id")
1695 @click.option(
1696 "--filter",
1697 multiple=True,
1698 help="restricts the information to the fields in the filter",
1699 )
1700 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1701 @click.pass_context
1702 def ns_op_show(ctx, id, filter, literal):
1703 """shows the detailed info of a NS operation
1704
1705 ID: operation identifier
1706 """
1707 logger.debug("")
1708 # try:
1709 check_client_version(ctx.obj, ctx.command.name)
1710 op_info = ctx.obj.ns.get_op(id)
1711 # except ClientException as e:
1712 # print(str(e))
1713 # exit(1)
1714
1715 if literal:
1716 print(yaml.safe_dump(op_info, indent=4, default_flow_style=False))
1717 return
1718
1719 table = PrettyTable(["field", "value"])
1720 for k, v in list(op_info.items()):
1721 if not filter or k in filter:
1722 table.add_row([k, wrap_text(json.dumps(v, indent=2), 100)])
1723 table.align = "l"
1724 print(table)
1725
1726
1727 def nst_show(ctx, name, literal):
1728 logger.debug("")
1729 # try:
1730 check_client_version(ctx.obj, ctx.command.name)
1731 resp = ctx.obj.nst.get(name)
1732 # resp = ctx.obj.nst.get_individual(name)
1733 # except ClientException as e:
1734 # print(str(e))
1735 # exit(1)
1736
1737 if literal:
1738 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
1739 return
1740
1741 table = PrettyTable(["field", "value"])
1742 for k, v in list(resp.items()):
1743 table.add_row([k, wrap_text(json.dumps(v, indent=2), 100)])
1744 table.align = "l"
1745 print(table)
1746
1747
1748 @cli_osm.command(
1749 name="nst-show", short_help="shows the content of a Network Slice Template (NST)"
1750 )
1751 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1752 @click.argument("name")
1753 @click.pass_context
1754 def nst_show1(ctx, name, literal):
1755 """shows the content of a Network Slice Template (NST)
1756
1757 NAME: name or ID of the NST
1758 """
1759 logger.debug("")
1760 nst_show(ctx, name, literal)
1761
1762
1763 @cli_osm.command(
1764 name="netslice-template-show",
1765 short_help="shows the content of a Network Slice Template (NST)",
1766 )
1767 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1768 @click.argument("name")
1769 @click.pass_context
1770 def nst_show2(ctx, name, literal):
1771 """shows the content of a Network Slice Template (NST)
1772
1773 NAME: name or ID of the NST
1774 """
1775 logger.debug("")
1776 nst_show(ctx, name, literal)
1777
1778
1779 def nsi_show(ctx, name, literal, filter):
1780 logger.debug("")
1781 # try:
1782 check_client_version(ctx.obj, ctx.command.name)
1783 nsi = ctx.obj.nsi.get(name)
1784 # except ClientException as e:
1785 # print(str(e))
1786 # exit(1)
1787
1788 if literal:
1789 print(yaml.safe_dump(nsi, indent=4, default_flow_style=False))
1790 return
1791
1792 table = PrettyTable(["field", "value"])
1793
1794 for k, v in list(nsi.items()):
1795 if not filter or k in filter:
1796 table.add_row([k, json.dumps(v, indent=2)])
1797
1798 table.align = "l"
1799 print(table)
1800
1801
1802 @cli_osm.command(
1803 name="nsi-show", short_help="shows the content of a Network Slice Instance (NSI)"
1804 )
1805 @click.argument("name")
1806 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1807 @click.option(
1808 "--filter",
1809 multiple=True,
1810 help="restricts the information to the fields in the filter",
1811 )
1812 @click.pass_context
1813 def nsi_show1(ctx, name, literal, filter):
1814 """shows the content of a Network Slice Instance (NSI)
1815
1816 NAME: name or ID of the Network Slice Instance
1817 """
1818 logger.debug("")
1819 nsi_show(ctx, name, literal, filter)
1820
1821
1822 @cli_osm.command(
1823 name="netslice-instance-show",
1824 short_help="shows the content of a Network Slice Instance (NSI)",
1825 )
1826 @click.argument("name")
1827 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1828 @click.option(
1829 "--filter",
1830 multiple=True,
1831 help="restricts the information to the fields in the filter",
1832 )
1833 @click.pass_context
1834 def nsi_show2(ctx, name, literal, filter):
1835 """shows the content of a Network Slice Instance (NSI)
1836
1837 NAME: name or ID of the Network Slice Instance
1838 """
1839 logger.debug("")
1840 nsi_show(ctx, name, literal, filter)
1841
1842
1843 def nsi_op_show(ctx, id, filter):
1844 logger.debug("")
1845 # try:
1846 check_client_version(ctx.obj, ctx.command.name)
1847 op_info = ctx.obj.nsi.get_op(id)
1848 # except ClientException as e:
1849 # print(str(e))
1850 # exit(1)
1851
1852 table = PrettyTable(["field", "value"])
1853 for k, v in list(op_info.items()):
1854 if not filter or k in filter:
1855 table.add_row([k, json.dumps(v, indent=2)])
1856 table.align = "l"
1857 print(table)
1858
1859
1860 @cli_osm.command(
1861 name="nsi-op-show",
1862 short_help="shows the info of an operation over a Network Slice Instance(NSI)",
1863 )
1864 @click.argument("id")
1865 @click.option(
1866 "--filter",
1867 multiple=True,
1868 help="restricts the information to the fields in the filter",
1869 )
1870 @click.pass_context
1871 def nsi_op_show1(ctx, id, filter):
1872 """shows the info of an operation over a Network Slice Instance(NSI)
1873
1874 ID: operation identifier
1875 """
1876 logger.debug("")
1877 nsi_op_show(ctx, id, filter)
1878
1879
1880 @cli_osm.command(
1881 name="netslice-instance-op-show",
1882 short_help="shows the info of an operation over a Network Slice Instance(NSI)",
1883 )
1884 @click.argument("id")
1885 @click.option(
1886 "--filter",
1887 multiple=True,
1888 help="restricts the information to the fields in the filter",
1889 )
1890 @click.pass_context
1891 def nsi_op_show2(ctx, id, filter):
1892 """shows the info of an operation over a Network Slice Instance(NSI)
1893
1894 ID: operation identifier
1895 """
1896 logger.debug("")
1897 nsi_op_show(ctx, id, filter)
1898
1899
1900 @cli_osm.command(
1901 name="pdu-show", short_help="shows the content of a Physical Deployment Unit (PDU)"
1902 )
1903 @click.argument("name")
1904 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
1905 @click.option(
1906 "--filter",
1907 multiple=True,
1908 help="restricts the information to the fields in the filter",
1909 )
1910 @click.pass_context
1911 def pdu_show(ctx, name, literal, filter):
1912 """shows the content of a Physical Deployment Unit (PDU)
1913
1914 NAME: name or ID of the PDU
1915 """
1916 logger.debug("")
1917 # try:
1918 check_client_version(ctx.obj, ctx.command.name)
1919 pdu = ctx.obj.pdu.get(name)
1920 # except ClientException as e:
1921 # print(str(e))
1922 # exit(1)
1923
1924 if literal:
1925 print(yaml.safe_dump(pdu, indent=4, default_flow_style=False))
1926 return
1927
1928 table = PrettyTable(["field", "value"])
1929
1930 for k, v in list(pdu.items()):
1931 if not filter or k in filter:
1932 table.add_row([k, json.dumps(v, indent=2)])
1933
1934 table.align = "l"
1935 print(table)
1936
1937
1938 ####################
1939 # CREATE operations
1940 ####################
1941
1942
1943 def nsd_create(ctx, filename, overwrite, skip_charm_build, repo, vendor, version):
1944 logger.debug("")
1945 # try:
1946 check_client_version(ctx.obj, ctx.command.name)
1947 if repo:
1948 filename = ctx.obj.osmrepo.get_pkg("ns", filename, repo, vendor, version)
1949 ctx.obj.nsd.create(filename, overwrite=overwrite, skip_charm_build=skip_charm_build)
1950 # except ClientException as e:
1951 # print(str(e))
1952 # exit(1)
1953
1954
1955 @cli_osm.command(name="nsd-create", short_help="creates a new NSD/NSpkg")
1956 @click.argument("filename")
1957 @click.option(
1958 "--overwrite",
1959 "overwrite",
1960 default=None, # hidden=True,
1961 help="Deprecated. Use override",
1962 )
1963 @click.option(
1964 "--override",
1965 "overwrite",
1966 default=None,
1967 help="overrides fields in descriptor, format: "
1968 '"key1.key2...=value[;key3...=value;...]"',
1969 )
1970 @click.option(
1971 "--skip-charm-build",
1972 default=False,
1973 is_flag=True,
1974 help="The charm will not be compiled, it is assumed to already exist",
1975 )
1976 @click.option("--repo", default=None, help="[repository]: Repository name")
1977 @click.option("--vendor", default=None, help="[repository]: filter by vendor]")
1978 @click.option(
1979 "--version",
1980 default="latest",
1981 help="[repository]: filter by version. Default: latest",
1982 )
1983 @click.pass_context
1984 def nsd_create1(ctx, filename, overwrite, skip_charm_build, repo, vendor, version):
1985 """onboards a new NSpkg (alias of nspkg-create) (TO BE DEPRECATED)
1986
1987 \b
1988 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
1989 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
1990 If FILENAME is an NF Package folder, it is built and then onboarded.
1991 """
1992 logger.debug("")
1993 nsd_create(
1994 ctx,
1995 filename,
1996 overwrite=overwrite,
1997 skip_charm_build=skip_charm_build,
1998 repo=repo,
1999 vendor=vendor,
2000 version=version,
2001 )
2002
2003
2004 @cli_osm.command(name="nspkg-create", short_help="creates a new NSD/NSpkg")
2005 @click.argument("filename")
2006 @click.option(
2007 "--overwrite",
2008 "overwrite",
2009 default=None, # hidden=True,
2010 help="Deprecated. Use override",
2011 )
2012 @click.option(
2013 "--override",
2014 "overwrite",
2015 default=None,
2016 help="overrides fields in descriptor, format: "
2017 '"key1.key2...=value[;key3...=value;...]"',
2018 )
2019 @click.option(
2020 "--skip-charm-build",
2021 default=False,
2022 is_flag=True,
2023 help="The charm will not be compiled, it is assumed to already exist",
2024 )
2025 @click.option("--repo", default=None, help="[repository]: Repository name")
2026 @click.option("--vendor", default=None, help="[repository]: filter by vendor]")
2027 @click.option(
2028 "--version",
2029 default="latest",
2030 help="[repository]: filter by version. Default: latest",
2031 )
2032 @click.pass_context
2033 def nsd_pkg_create(ctx, filename, overwrite, skip_charm_build, repo, vendor, version):
2034 """onboards a new NSpkg
2035 \b
2036 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2037 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2038 If FILENAME is an NF Package folder, it is built and then onboarded.
2039 """
2040 logger.debug("")
2041 nsd_create(
2042 ctx,
2043 filename,
2044 overwrite=overwrite,
2045 skip_charm_build=skip_charm_build,
2046 repo=repo,
2047 vendor=vendor,
2048 version=version,
2049 )
2050
2051
2052 def vnfd_create(
2053 ctx,
2054 filename,
2055 overwrite,
2056 skip_charm_build,
2057 override_epa,
2058 override_nonepa,
2059 override_paravirt,
2060 repo,
2061 vendor,
2062 version,
2063 ):
2064 logger.debug("")
2065 # try:
2066 check_client_version(ctx.obj, ctx.command.name)
2067 if repo:
2068 filename = ctx.obj.osmrepo.get_pkg("vnf", filename, repo, vendor, version)
2069 ctx.obj.vnfd.create(
2070 filename,
2071 overwrite=overwrite,
2072 skip_charm_build=skip_charm_build,
2073 override_epa=override_epa,
2074 override_nonepa=override_nonepa,
2075 override_paravirt=override_paravirt,
2076 )
2077 # except ClientException as e:
2078 # print(str(e))
2079 # exit(1)
2080
2081
2082 @cli_osm.command(name="vnfd-create", short_help="creates a new VNFD/VNFpkg")
2083 @click.argument("filename")
2084 @click.option(
2085 "--overwrite", "overwrite", default=None, help="overwrite deprecated, use override"
2086 )
2087 @click.option(
2088 "--override",
2089 "overwrite",
2090 default=None,
2091 help="overrides fields in descriptor, format: "
2092 '"key1.key2...=value[;key3...=value;...]"',
2093 )
2094 @click.option(
2095 "--skip-charm-build",
2096 default=False,
2097 is_flag=True,
2098 help="The charm will not be compiled, it is assumed to already exist",
2099 )
2100 @click.option(
2101 "--override-epa",
2102 required=False,
2103 default=False,
2104 is_flag=True,
2105 help="adds guest-epa parameters to all VDU",
2106 )
2107 @click.option(
2108 "--override-nonepa",
2109 required=False,
2110 default=False,
2111 is_flag=True,
2112 help="removes all guest-epa parameters from all VDU",
2113 )
2114 @click.option(
2115 "--override-paravirt",
2116 required=False,
2117 default=False,
2118 is_flag=True,
2119 help="overrides all VDU interfaces to PARAVIRT",
2120 )
2121 @click.option("--repo", default=None, help="[repository]: Repository name")
2122 @click.option("--vendor", default=None, help="[repository]: filter by vendor]")
2123 @click.option(
2124 "--version",
2125 default="latest",
2126 help="[repository]: filter by version. Default: latest",
2127 )
2128 @click.pass_context
2129 def vnfd_create1(
2130 ctx,
2131 filename,
2132 overwrite,
2133 skip_charm_build,
2134 override_epa,
2135 override_nonepa,
2136 override_paravirt,
2137 repo,
2138 vendor,
2139 version,
2140 ):
2141 """creates a new VNFD/VNFpkg
2142 \b
2143 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2144 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2145 If FILENAME is an NF Package folder, it is built and then onboarded.
2146 """
2147 logger.debug("")
2148 vnfd_create(
2149 ctx,
2150 filename,
2151 overwrite=overwrite,
2152 skip_charm_build=skip_charm_build,
2153 override_epa=override_epa,
2154 override_nonepa=override_nonepa,
2155 override_paravirt=override_paravirt,
2156 repo=repo,
2157 vendor=vendor,
2158 version=version,
2159 )
2160
2161
2162 @cli_osm.command(name="vnfpkg-create", short_help="creates a new VNFD/VNFpkg")
2163 @click.argument("filename")
2164 @click.option(
2165 "--overwrite",
2166 "overwrite",
2167 default=None, # hidden=True,
2168 help="Deprecated. Use override",
2169 )
2170 @click.option(
2171 "--override",
2172 "overwrite",
2173 default=None,
2174 help="overrides fields in descriptor, format: "
2175 '"key1.key2...=value[;key3...=value;...]"',
2176 )
2177 @click.option(
2178 "--skip-charm-build",
2179 default=False,
2180 is_flag=True,
2181 help="The charm will not be compiled, it is assumed to already exist",
2182 )
2183 @click.option(
2184 "--override-epa",
2185 required=False,
2186 default=False,
2187 is_flag=True,
2188 help="adds guest-epa parameters to all VDU",
2189 )
2190 @click.option(
2191 "--override-nonepa",
2192 required=False,
2193 default=False,
2194 is_flag=True,
2195 help="removes all guest-epa parameters from all VDU",
2196 )
2197 @click.option(
2198 "--override-paravirt",
2199 required=False,
2200 default=False,
2201 is_flag=True,
2202 help="overrides all VDU interfaces to PARAVIRT",
2203 )
2204 @click.option("--repo", default=None, help="[repository]: Repository name")
2205 @click.option("--vendor", default=None, help="[repository]: filter by vendor]")
2206 @click.option(
2207 "--version",
2208 default="latest",
2209 help="[repository]: filter by version. Default: latest",
2210 )
2211 @click.pass_context
2212 def vnfd_create2(
2213 ctx,
2214 filename,
2215 overwrite,
2216 skip_charm_build,
2217 override_epa,
2218 override_nonepa,
2219 override_paravirt,
2220 repo,
2221 vendor,
2222 version,
2223 ):
2224 """creates a new VNFD/VNFpkg
2225 \b
2226 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2227 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2228 If FILENAME is an NF Package folder, it is built and then onboarded.
2229 """
2230 logger.debug("")
2231 vnfd_create(
2232 ctx,
2233 filename,
2234 overwrite=overwrite,
2235 skip_charm_build=skip_charm_build,
2236 override_epa=override_epa,
2237 override_nonepa=override_nonepa,
2238 override_paravirt=override_paravirt,
2239 repo=repo,
2240 vendor=vendor,
2241 version=version,
2242 )
2243
2244
2245 @cli_osm.command(name="nfpkg-create", short_help="creates a new NFpkg")
2246 @click.argument("filename")
2247 @click.option(
2248 "--overwrite",
2249 "overwrite",
2250 default=None, # hidden=True,
2251 help="Deprecated. Use override",
2252 )
2253 @click.option(
2254 "--override",
2255 "overwrite",
2256 default=None,
2257 help="overrides fields in descriptor, format: "
2258 '"key1.key2...=value[;key3...=value;...]"',
2259 )
2260 @click.option(
2261 "--skip-charm-build",
2262 default=False,
2263 is_flag=True,
2264 help="The charm will not be compiled, it is assumed to already exist",
2265 )
2266 @click.option(
2267 "--override-epa",
2268 required=False,
2269 default=False,
2270 is_flag=True,
2271 help="adds guest-epa parameters to all VDU",
2272 )
2273 @click.option(
2274 "--override-nonepa",
2275 required=False,
2276 default=False,
2277 is_flag=True,
2278 help="removes all guest-epa parameters from all VDU",
2279 )
2280 @click.option(
2281 "--override-paravirt",
2282 required=False,
2283 default=False,
2284 is_flag=True,
2285 help="overrides all VDU interfaces to PARAVIRT",
2286 )
2287 @click.option("--repo", default=None, help="[repository]: Repository name")
2288 @click.option("--vendor", default=None, help="[repository]: filter by vendor]")
2289 @click.option(
2290 "--version",
2291 default="latest",
2292 help="[repository]: filter by version. Default: latest",
2293 )
2294 @click.pass_context
2295 def nfpkg_create(
2296 ctx,
2297 filename,
2298 overwrite,
2299 skip_charm_build,
2300 override_epa,
2301 override_nonepa,
2302 override_paravirt,
2303 repo,
2304 vendor,
2305 version,
2306 ):
2307 """creates a new NFpkg
2308
2309 \b
2310 FILENAME: NF Package tar.gz file, NF Descriptor YAML file or NF Package folder
2311 If FILENAME is a file (NF Package tar.gz or NF Descriptor YAML), it is onboarded.
2312 If FILENAME is an NF Package folder, it is built and then onboarded.
2313 """
2314 logger.debug("")
2315 vnfd_create(
2316 ctx,
2317 filename,
2318 overwrite=overwrite,
2319 skip_charm_build=skip_charm_build,
2320 override_epa=override_epa,
2321 override_nonepa=override_nonepa,
2322 override_paravirt=override_paravirt,
2323 repo=repo,
2324 vendor=vendor,
2325 version=version,
2326 )
2327
2328
2329 @cli_osm.command(name="ns-create", short_help="creates a new Network Service instance")
2330 @click.option("--ns_name", prompt=True, help="name of the NS instance")
2331 @click.option("--nsd_name", prompt=True, help="name of the NS descriptor")
2332 @click.option(
2333 "--vim_account",
2334 prompt=True,
2335 help="default VIM account id or name for the deployment",
2336 )
2337 @click.option("--admin_status", default="ENABLED", help="administration status")
2338 @click.option(
2339 "--ssh_keys",
2340 default=None,
2341 help="comma separated list of public key files to inject to vnfs",
2342 )
2343 @click.option("--config", default=None, help="ns specific yaml configuration")
2344 @click.option("--config_file", default=None, help="ns specific yaml configuration file")
2345 @click.option(
2346 "--wait",
2347 required=False,
2348 default=False,
2349 is_flag=True,
2350 help="do not return the control immediately, but keep it "
2351 "until the operation is completed, or timeout",
2352 )
2353 @click.option("--timeout", default=None, help="ns deployment timeout")
2354 @click.pass_context
2355 def ns_create(
2356 ctx,
2357 nsd_name,
2358 ns_name,
2359 vim_account,
2360 admin_status,
2361 ssh_keys,
2362 config,
2363 config_file,
2364 wait,
2365 timeout
2366 ):
2367 """creates a new NS instance"""
2368 logger.debug("")
2369 # try:
2370 if config_file:
2371 check_client_version(ctx.obj, "--config_file")
2372 if config:
2373 raise ClientException(
2374 '"--config" option is incompatible with "--config_file" option'
2375 )
2376 with open(config_file, "r") as cf:
2377 config = cf.read()
2378 ctx.obj.ns.create(
2379 nsd_name,
2380 ns_name,
2381 config=config,
2382 ssh_keys=ssh_keys,
2383 account=vim_account,
2384 wait=wait,
2385 timeout=timeout,
2386 )
2387 # except ClientException as e:
2388 # print(str(e))
2389 # exit(1)
2390
2391
2392 def nst_create(ctx, filename, overwrite):
2393 logger.debug("")
2394 # try:
2395 check_client_version(ctx.obj, ctx.command.name)
2396 ctx.obj.nst.create(filename, overwrite)
2397 # except ClientException as e:
2398 # print(str(e))
2399 # exit(1)
2400
2401
2402 @cli_osm.command(
2403 name="nst-create", short_help="creates a new Network Slice Template (NST)"
2404 )
2405 @click.argument("filename")
2406 @click.option(
2407 "--overwrite",
2408 "overwrite",
2409 default=None, # hidden=True,
2410 help="Deprecated. Use override",
2411 )
2412 @click.option(
2413 "--override",
2414 "overwrite",
2415 default=None,
2416 help="overrides fields in descriptor, format: "
2417 '"key1.key2...=value[;key3...=value;...]"',
2418 )
2419 @click.pass_context
2420 def nst_create1(ctx, filename, overwrite):
2421 """creates a new Network Slice Template (NST)
2422
2423 FILENAME: NST package folder, NST yaml file or NSTpkg tar.gz file
2424 """
2425 logger.debug("")
2426 nst_create(ctx, filename, overwrite)
2427
2428
2429 @cli_osm.command(
2430 name="netslice-template-create",
2431 short_help="creates a new Network Slice Template (NST)",
2432 )
2433 @click.argument("filename")
2434 @click.option(
2435 "--overwrite",
2436 "overwrite",
2437 default=None, # hidden=True,
2438 help="Deprecated. Use override",
2439 )
2440 @click.option(
2441 "--override",
2442 "overwrite",
2443 default=None,
2444 help="overrides fields in descriptor, format: "
2445 '"key1.key2...=value[;key3...=value;...]"',
2446 )
2447 @click.pass_context
2448 def nst_create2(ctx, filename, overwrite):
2449 """creates a new Network Slice Template (NST)
2450
2451 FILENAME: NST yaml file or NSTpkg tar.gz file
2452 """
2453 logger.debug("")
2454 nst_create(ctx, filename, overwrite)
2455
2456
2457 def nsi_create(
2458 ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait
2459 ):
2460 """creates a new Network Slice Instance (NSI)"""
2461 logger.debug("")
2462 # try:
2463 check_client_version(ctx.obj, ctx.command.name)
2464 if config_file:
2465 if config:
2466 raise ClientException(
2467 '"--config" option is incompatible with "--config_file" option'
2468 )
2469 with open(config_file, "r") as cf:
2470 config = cf.read()
2471 ctx.obj.nsi.create(
2472 nst_name,
2473 nsi_name,
2474 config=config,
2475 ssh_keys=ssh_keys,
2476 account=vim_account,
2477 wait=wait,
2478 )
2479 # except ClientException as e:
2480 # print(str(e))
2481 # exit(1)
2482
2483
2484 @cli_osm.command(name="nsi-create", short_help="creates a new Network Slice Instance")
2485 @click.option("--nsi_name", prompt=True, help="name of the Network Slice Instance")
2486 @click.option("--nst_name", prompt=True, help="name of the Network Slice Template")
2487 @click.option(
2488 "--vim_account",
2489 prompt=True,
2490 help="default VIM account id or name for the deployment",
2491 )
2492 @click.option(
2493 "--ssh_keys", default=None, help="comma separated list of keys to inject to vnfs"
2494 )
2495 @click.option(
2496 "--config",
2497 default=None,
2498 help="Netslice specific yaml configuration:\n"
2499 "netslice_subnet: [\n"
2500 "id: TEXT, vim_account: TEXT,\n"
2501 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2502 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n"
2503 "additionalParamsForNsi: {param: value, ...}\n"
2504 "additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n"
2505 "],\n"
2506 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2507 )
2508 @click.option(
2509 "--config_file", default=None, help="nsi specific yaml configuration file"
2510 )
2511 @click.option(
2512 "--wait",
2513 required=False,
2514 default=False,
2515 is_flag=True,
2516 help="do not return the control immediately, but keep it "
2517 "until the operation is completed, or timeout",
2518 )
2519 @click.pass_context
2520 def nsi_create1(
2521 ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait
2522 ):
2523 """creates a new Network Slice Instance (NSI)"""
2524 logger.debug("")
2525 nsi_create(
2526 ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait
2527 )
2528
2529
2530 @cli_osm.command(
2531 name="netslice-instance-create", short_help="creates a new Network Slice Instance"
2532 )
2533 @click.option("--nsi_name", prompt=True, help="name of the Network Slice Instance")
2534 @click.option("--nst_name", prompt=True, help="name of the Network Slice Template")
2535 @click.option(
2536 "--vim_account",
2537 prompt=True,
2538 help="default VIM account id or name for the deployment",
2539 )
2540 @click.option(
2541 "--ssh_keys", default=None, help="comma separated list of keys to inject to vnfs"
2542 )
2543 @click.option(
2544 "--config",
2545 default=None,
2546 help="Netslice specific yaml configuration:\n"
2547 "netslice_subnet: [\n"
2548 "id: TEXT, vim_account: TEXT,\n"
2549 "vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n"
2550 "vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]"
2551 "],\n"
2552 "netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]",
2553 )
2554 @click.option(
2555 "--config_file", default=None, help="nsi specific yaml configuration file"
2556 )
2557 @click.option(
2558 "--wait",
2559 required=False,
2560 default=False,
2561 is_flag=True,
2562 help="do not return the control immediately, but keep it "
2563 "until the operation is completed, or timeout",
2564 )
2565 @click.pass_context
2566 def nsi_create2(
2567 ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait
2568 ):
2569 """creates a new Network Slice Instance (NSI)"""
2570 logger.debug("")
2571 nsi_create(
2572 ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait
2573 )
2574
2575
2576 @cli_osm.command(
2577 name="pdu-create", short_help="adds a new Physical Deployment Unit to the catalog"
2578 )
2579 @click.option("--name", help="name of the Physical Deployment Unit")
2580 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2581 @click.option(
2582 "--interface",
2583 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2584 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2585 multiple=True,
2586 )
2587 @click.option("--description", help="human readable description")
2588 @click.option(
2589 "--vim_account",
2590 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2591 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2592 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2593 multiple=True,
2594 )
2595 @click.option(
2596 "--descriptor_file",
2597 default=None,
2598 help="PDU descriptor file (as an alternative to using the other arguments)",
2599 )
2600 @click.pass_context
2601 def pdu_create(
2602 ctx, name, pdu_type, interface, description, vim_account, descriptor_file
2603 ):
2604 """creates a new Physical Deployment Unit (PDU)"""
2605 logger.debug("")
2606
2607 check_client_version(ctx.obj, ctx.command.name)
2608
2609 pdu = create_pdu_dictionary(
2610 name, pdu_type, interface, description, vim_account, descriptor_file
2611 )
2612 ctx.obj.pdu.create(pdu)
2613
2614
2615 ########################
2616 # UPDATE PDU operation #
2617 ########################
2618
2619
2620 @cli_osm.command(
2621 name="pdu-update", short_help="updates a Physical Deployment Unit to the catalog"
2622 )
2623 @click.argument("name")
2624 @click.option("--newname", help="New name for the Physical Deployment Unit")
2625 @click.option("--pdu_type", help="type of PDU (e.g. router, firewall, FW001)")
2626 @click.option(
2627 "--interface",
2628 help="interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>"
2629 + "[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]",
2630 multiple=True,
2631 )
2632 @click.option("--description", help="human readable description")
2633 @click.option(
2634 "--vim_account",
2635 help="list of VIM accounts (in the same VIM) that can reach this PDU\n"
2636 + "The format for multiple VIMs is --vim_account <vim_account_id_1> "
2637 + "--vim_account <vim_account_id_2> ... --vim_account <vim_account_id_N>",
2638 multiple=True,
2639 )
2640 @click.option(
2641 "--descriptor_file",
2642 default=None,
2643 help="PDU descriptor file (as an alternative to using the other arguments)",
2644 )
2645 @click.pass_context
2646 def pdu_update(
2647 ctx, name, newname, pdu_type, interface, description, vim_account, descriptor_file
2648 ):
2649 """Updates a new Physical Deployment Unit (PDU)"""
2650 logger.debug("")
2651
2652 check_client_version(ctx.obj, ctx.command.name)
2653
2654 update = True
2655
2656 if not newname:
2657 newname = name
2658
2659 pdu = create_pdu_dictionary(
2660 newname, pdu_type, interface, description, vim_account, descriptor_file, update
2661 )
2662 ctx.obj.pdu.update(name, pdu)
2663
2664
2665 def create_pdu_dictionary(
2666 name, pdu_type, interface, description, vim_account, descriptor_file, update=False
2667 ):
2668
2669 logger.debug("")
2670 pdu = {}
2671
2672 if not descriptor_file:
2673 if not update:
2674 if not name:
2675 raise ClientException(
2676 'in absence of descriptor file, option "--name" is mandatory'
2677 )
2678 if not pdu_type:
2679 raise ClientException(
2680 'in absence of descriptor file, option "--pdu_type" is mandatory'
2681 )
2682 if not interface:
2683 raise ClientException(
2684 'in absence of descriptor file, option "--interface" is mandatory (at least once)'
2685 )
2686 if not vim_account:
2687 raise ClientException(
2688 'in absence of descriptor file, option "--vim_account" is mandatory (at least once)'
2689 )
2690 else:
2691 with open(descriptor_file, "r") as df:
2692 pdu = yaml.safe_load(df.read())
2693 if name:
2694 pdu["name"] = name
2695 if pdu_type:
2696 pdu["type"] = pdu_type
2697 if description:
2698 pdu["description"] = description
2699 if vim_account:
2700 pdu["vim_accounts"] = vim_account
2701 if interface:
2702 ifaces_list = []
2703 for iface in interface:
2704 new_iface = {k: v for k, v in [i.split("=") for i in iface.split(",")]}
2705 new_iface["mgmt"] = new_iface.get("mgmt", "false").lower() == "true"
2706 ifaces_list.append(new_iface)
2707 pdu["interfaces"] = ifaces_list
2708 return pdu
2709
2710
2711 ####################
2712 # UPDATE operations
2713 ####################
2714
2715
2716 def nsd_update(ctx, name, content):
2717 logger.debug("")
2718 # try:
2719 check_client_version(ctx.obj, ctx.command.name)
2720 ctx.obj.nsd.update(name, content)
2721 # except ClientException as e:
2722 # print(str(e))
2723 # exit(1)
2724
2725
2726 @cli_osm.command(name="nsd-update", short_help="updates a NSD/NSpkg")
2727 @click.argument("name")
2728 @click.option(
2729 "--content",
2730 default=None,
2731 help="filename with the NSD/NSpkg replacing the current one",
2732 )
2733 @click.pass_context
2734 def nsd_update1(ctx, name, content):
2735 """updates a NSD/NSpkg
2736
2737 NAME: name or ID of the NSD/NSpkg
2738 """
2739 logger.debug("")
2740 nsd_update(ctx, name, content)
2741
2742
2743 @cli_osm.command(name="nspkg-update", short_help="updates a NSD/NSpkg")
2744 @click.argument("name")
2745 @click.option(
2746 "--content",
2747 default=None,
2748 help="filename with the NSD/NSpkg replacing the current one",
2749 )
2750 @click.pass_context
2751 def nsd_update2(ctx, name, content):
2752 """updates a NSD/NSpkg
2753
2754 NAME: name or ID of the NSD/NSpkg
2755 """
2756 logger.debug("")
2757 nsd_update(ctx, name, content)
2758
2759
2760 def vnfd_update(ctx, name, content):
2761 logger.debug("")
2762 # try:
2763 check_client_version(ctx.obj, ctx.command.name)
2764 ctx.obj.vnfd.update(name, content)
2765 # except ClientException as e:
2766 # print(str(e))
2767 # exit(1)
2768
2769
2770 @cli_osm.command(name="vnfd-update", short_help="updates a new VNFD/VNFpkg")
2771 @click.argument("name")
2772 @click.option(
2773 "--content",
2774 default=None,
2775 help="filename with the VNFD/VNFpkg replacing the current one",
2776 )
2777 @click.pass_context
2778 def vnfd_update1(ctx, name, content):
2779 """updates a VNFD/VNFpkg
2780
2781 NAME: name or ID of the VNFD/VNFpkg
2782 """
2783 logger.debug("")
2784 vnfd_update(ctx, name, content)
2785
2786
2787 @cli_osm.command(name="vnfpkg-update", short_help="updates a VNFD/VNFpkg")
2788 @click.argument("name")
2789 @click.option(
2790 "--content",
2791 default=None,
2792 help="filename with the VNFD/VNFpkg replacing the current one",
2793 )
2794 @click.pass_context
2795 def vnfd_update2(ctx, name, content):
2796 """updates a VNFD/VNFpkg
2797
2798 NAME: VNFD yaml file or VNFpkg tar.gz file
2799 """
2800 logger.debug("")
2801 vnfd_update(ctx, name, content)
2802
2803
2804 @cli_osm.command(name="nfpkg-update", short_help="updates a NFpkg")
2805 @click.argument("name")
2806 @click.option(
2807 "--content", default=None, help="filename with the NFpkg replacing the current one"
2808 )
2809 @click.pass_context
2810 def nfpkg_update(ctx, name, content):
2811 """updates a NFpkg
2812
2813 NAME: NF Descriptor yaml file or NFpkg tar.gz file
2814 """
2815 logger.debug("")
2816 vnfd_update(ctx, name, content)
2817
2818
2819 def nst_update(ctx, name, content):
2820 logger.debug("")
2821 # try:
2822 check_client_version(ctx.obj, ctx.command.name)
2823 ctx.obj.nst.update(name, content)
2824 # except ClientException as e:
2825 # print(str(e))
2826 # exit(1)
2827
2828
2829 @cli_osm.command(name="nst-update", short_help="updates a Network Slice Template (NST)")
2830 @click.argument("name")
2831 @click.option(
2832 "--content",
2833 default=None,
2834 help="filename with the NST/NSTpkg replacing the current one",
2835 )
2836 @click.pass_context
2837 def nst_update1(ctx, name, content):
2838 """updates a Network Slice Template (NST)
2839
2840 NAME: name or ID of the NSD/NSpkg
2841 """
2842 logger.debug("")
2843 nst_update(ctx, name, content)
2844
2845
2846 @cli_osm.command(
2847 name="netslice-template-update", short_help="updates a Network Slice Template (NST)"
2848 )
2849 @click.argument("name")
2850 @click.option(
2851 "--content",
2852 default=None,
2853 help="filename with the NST/NSTpkg replacing the current one",
2854 )
2855 @click.pass_context
2856 def nst_update2(ctx, name, content):
2857 """updates a Network Slice Template (NST)
2858
2859 NAME: name or ID of the NSD/NSpkg
2860 """
2861 logger.debug("")
2862 nst_update(ctx, name, content)
2863
2864
2865 ####################
2866 # DELETE operations
2867 ####################
2868
2869
2870 def nsd_delete(ctx, name, force):
2871 logger.debug("")
2872 # try:
2873 if not force:
2874 ctx.obj.nsd.delete(name)
2875 else:
2876 check_client_version(ctx.obj, "--force")
2877 ctx.obj.nsd.delete(name, force)
2878 # except ClientException as e:
2879 # print(str(e))
2880 # exit(1)
2881
2882
2883 @cli_osm.command(name="nsd-delete", short_help="deletes a NSD/NSpkg")
2884 @click.argument("name")
2885 @click.option(
2886 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2887 )
2888 @click.pass_context
2889 def nsd_delete1(ctx, name, force):
2890 """deletes a NSD/NSpkg
2891
2892 NAME: name or ID of the NSD/NSpkg to be deleted
2893 """
2894 logger.debug("")
2895 nsd_delete(ctx, name, force)
2896
2897
2898 @cli_osm.command(name="nspkg-delete", short_help="deletes a NSD/NSpkg")
2899 @click.argument("name")
2900 @click.option(
2901 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2902 )
2903 @click.pass_context
2904 def nsd_delete2(ctx, name, force):
2905 """deletes a NSD/NSpkg
2906
2907 NAME: name or ID of the NSD/NSpkg to be deleted
2908 """
2909 logger.debug("")
2910 nsd_delete(ctx, name, force)
2911
2912
2913 def vnfd_delete(ctx, name, force):
2914 logger.debug("")
2915 # try:
2916 if not force:
2917 ctx.obj.vnfd.delete(name)
2918 else:
2919 check_client_version(ctx.obj, "--force")
2920 ctx.obj.vnfd.delete(name, force)
2921 # except ClientException as e:
2922 # print(str(e))
2923 # exit(1)
2924
2925
2926 @cli_osm.command(name="vnfd-delete", short_help="deletes a VNFD/VNFpkg")
2927 @click.argument("name")
2928 @click.option(
2929 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2930 )
2931 @click.pass_context
2932 def vnfd_delete1(ctx, name, force):
2933 """deletes a VNFD/VNFpkg
2934
2935 NAME: name or ID of the VNFD/VNFpkg to be deleted
2936 """
2937 logger.debug("")
2938 vnfd_delete(ctx, name, force)
2939
2940
2941 @cli_osm.command(name="vnfpkg-delete", short_help="deletes a VNFD/VNFpkg")
2942 @click.argument("name")
2943 @click.option(
2944 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2945 )
2946 @click.pass_context
2947 def vnfd_delete2(ctx, name, force):
2948 """deletes a VNFD/VNFpkg
2949
2950 NAME: name or ID of the VNFD/VNFpkg to be deleted
2951 """
2952 logger.debug("")
2953 vnfd_delete(ctx, name, force)
2954
2955
2956 @cli_osm.command(name="nfpkg-delete", short_help="deletes a NFpkg")
2957 @click.argument("name")
2958 @click.option(
2959 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2960 )
2961 @click.pass_context
2962 def nfpkg_delete(ctx, name, force):
2963 """deletes a NFpkg
2964
2965 NAME: name or ID of the NFpkg to be deleted
2966 """
2967 logger.debug("")
2968 vnfd_delete(ctx, name, force)
2969
2970
2971 @cli_osm.command(name="ns-delete", short_help="deletes a NS instance")
2972 @click.argument("name")
2973 @click.option(
2974 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2975 )
2976 @click.option(
2977 "--config",
2978 default=None,
2979 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
2980 "600, skip_terminate_primitives: True}'",
2981 )
2982 @click.option(
2983 "--wait",
2984 required=False,
2985 default=False,
2986 is_flag=True,
2987 help="do not return the control immediately, but keep it "
2988 "until the operation is completed, or timeout",
2989 )
2990 @click.pass_context
2991 def ns_delete(ctx, name, force, config, wait):
2992 """deletes a NS instance
2993
2994 NAME: name or ID of the NS instance to be deleted
2995 """
2996 logger.debug("")
2997 # try:
2998 if not force:
2999 ctx.obj.ns.delete(name, config=config, wait=wait)
3000 else:
3001 check_client_version(ctx.obj, "--force")
3002 ctx.obj.ns.delete(name, force, config=config, wait=wait)
3003 # except ClientException as e:
3004 # print(str(e))
3005 # exit(1)
3006
3007
3008 def nst_delete(ctx, name, force):
3009 logger.debug("")
3010 # try:
3011 check_client_version(ctx.obj, ctx.command.name)
3012 ctx.obj.nst.delete(name, force)
3013 # except ClientException as e:
3014 # print(str(e))
3015 # exit(1)
3016
3017
3018 @cli_osm.command(name="nst-delete", short_help="deletes a Network Slice Template (NST)")
3019 @click.argument("name")
3020 @click.option(
3021 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3022 )
3023 @click.pass_context
3024 def nst_delete1(ctx, name, force):
3025 """deletes a Network Slice Template (NST)
3026
3027 NAME: name or ID of the NST/NSTpkg to be deleted
3028 """
3029 logger.debug("")
3030 nst_delete(ctx, name, force)
3031
3032
3033 @cli_osm.command(
3034 name="netslice-template-delete", short_help="deletes a Network Slice Template (NST)"
3035 )
3036 @click.argument("name")
3037 @click.option(
3038 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3039 )
3040 @click.pass_context
3041 def nst_delete2(ctx, name, force):
3042 """deletes a Network Slice Template (NST)
3043
3044 NAME: name or ID of the NST/NSTpkg to be deleted
3045 """
3046 logger.debug("")
3047 nst_delete(ctx, name, force)
3048
3049
3050 def nsi_delete(ctx, name, force, wait):
3051 logger.debug("")
3052 # try:
3053 check_client_version(ctx.obj, ctx.command.name)
3054 ctx.obj.nsi.delete(name, force, wait=wait)
3055 # except ClientException as e:
3056 # print(str(e))
3057 # exit(1)
3058
3059
3060 @cli_osm.command(name="nsi-delete", short_help="deletes a Network Slice Instance (NSI)")
3061 @click.argument("name")
3062 @click.option(
3063 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3064 )
3065 @click.option(
3066 "--wait",
3067 required=False,
3068 default=False,
3069 is_flag=True,
3070 help="do not return the control immediately, but keep it "
3071 "until the operation is completed, or timeout",
3072 )
3073 @click.pass_context
3074 def nsi_delete1(ctx, name, force, wait):
3075 """deletes a Network Slice Instance (NSI)
3076
3077 NAME: name or ID of the Network Slice instance to be deleted
3078 """
3079 logger.debug("")
3080 nsi_delete(ctx, name, force, wait=wait)
3081
3082
3083 @cli_osm.command(
3084 name="netslice-instance-delete", short_help="deletes a Network Slice Instance (NSI)"
3085 )
3086 @click.argument("name")
3087 @click.option(
3088 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3089 )
3090 @click.pass_context
3091 def nsi_delete2(ctx, name, force, wait):
3092 """deletes a Network Slice Instance (NSI)
3093
3094 NAME: name or ID of the Network Slice instance to be deleted
3095 """
3096 logger.debug("")
3097 nsi_delete(ctx, name, force, wait=wait)
3098
3099
3100 @cli_osm.command(
3101 name="pdu-delete", short_help="deletes a Physical Deployment Unit (PDU)"
3102 )
3103 @click.argument("name")
3104 @click.option(
3105 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3106 )
3107 @click.pass_context
3108 def pdu_delete(ctx, name, force):
3109 """deletes a Physical Deployment Unit (PDU)
3110
3111 NAME: name or ID of the PDU to be deleted
3112 """
3113 logger.debug("")
3114 # try:
3115 check_client_version(ctx.obj, ctx.command.name)
3116 ctx.obj.pdu.delete(name, force)
3117 # except ClientException as e:
3118 # print(str(e))
3119 # exit(1)
3120
3121
3122 #################
3123 # VIM operations
3124 #################
3125
3126
3127 @cli_osm.command(name="vim-create", short_help="creates a new VIM account")
3128 @click.option("--name", required=True, help="Name to create datacenter")
3129 @click.option("--user", default=None, help="VIM username")
3130 @click.option("--password", default=None, help="VIM password")
3131 @click.option("--auth_url", default=None, help="VIM url")
3132 @click.option("--tenant", "--project", "tenant", default=None, help="VIM tenant/project name")
3133 @click.option("--config", default=None, help="VIM specific config parameters")
3134 @click.option("--config_file", default=None, help="VIM specific config parameters in YAML or JSON file")
3135 @click.option("--account_type", default="openstack", help="VIM type")
3136 @click.option("--description", default=None, help="human readable description")
3137 @click.option(
3138 "--sdn_controller",
3139 default=None,
3140 help="Name or id of the SDN controller associated to this VIM account",
3141 )
3142 @click.option(
3143 "--sdn_port_mapping",
3144 default=None,
3145 help="File describing the port mapping between compute nodes' ports and switch ports",
3146 )
3147 @click.option(
3148 "--wait",
3149 required=False,
3150 default=False,
3151 is_flag=True,
3152 help="do not return the control immediately, but keep it "
3153 "until the operation is completed, or timeout",
3154 )
3155 @click.option("--vca", default=None, help="VCA to be used in this VIM account")
3156 @click.option("--creds", default=None, help="credentials file (only applycable for GCP VIM type)")
3157 @click.option("--prometheus_config_file", default=None, help="Prometheus configuration to get VIM data")
3158 @click.pass_context
3159 def vim_create(
3160 ctx,
3161 name,
3162 user,
3163 password,
3164 auth_url,
3165 tenant,
3166 config,
3167 config_file,
3168 account_type,
3169 description,
3170 sdn_controller,
3171 sdn_port_mapping,
3172 wait,
3173 vca,
3174 creds,
3175 prometheus_config_file
3176 ):
3177 """creates a new VIM account"""
3178 logger.debug("")
3179 # try:
3180 if sdn_controller:
3181 check_client_version(ctx.obj, "--sdn_controller")
3182 if sdn_port_mapping:
3183 check_client_version(ctx.obj, "--sdn_port_mapping")
3184 vim = {}
3185 if prometheus_config_file:
3186 with open(prometheus_config_file) as prometheus_file:
3187 prometheus_config_dict = json.load(prometheus_file)
3188 vim["prometheus-config"] = prometheus_config_dict
3189
3190 vim["vim-username"] = user
3191 vim["vim-password"] = password
3192 vim["vim-url"] = auth_url
3193 vim["vim-tenant-name"] = tenant
3194 vim["vim-type"] = account_type
3195 vim["description"] = description
3196 if vca:
3197 vim["vca"] = vca
3198 vim_config = create_config(config_file, config)
3199 if creds:
3200 with open(creds, "r") as cf:
3201 vim_config["credentials"] = yaml.safe_load(cf.read())
3202 ctx.obj.vim.create(name, vim, vim_config, sdn_controller, sdn_port_mapping, wait=wait)
3203 # except ClientException as e:
3204 # print(str(e))
3205 # exit(1)
3206
3207
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")
3216 @click.option("--config_file", default=None, help="VIM specific config parameters in YAML or JSON file")
3217 @click.option("--account_type", help="VIM type")
3218 @click.option("--description", help="human readable description")
3219 @click.option(
3220 "--sdn_controller",
3221 default=None,
3222 help="Name or id of the SDN controller to be associated with this VIM"
3223 "account. Use empty string to disassociate",
3224 )
3225 @click.option(
3226 "--sdn_port_mapping",
3227 default=None,
3228 help="File describing the port mapping between compute nodes' ports and switch ports",
3229 )
3230 @click.option(
3231 "--wait",
3232 required=False,
3233 default=False,
3234 is_flag=True,
3235 help="do not return the control immediately, but keep it "
3236 "until the operation is completed, or timeout",
3237 )
3238 @click.option("--creds", default=None, help="credentials file (only applycable for GCP VIM type)")
3239 @click.option("--prometheus_config_file", default=None, help="Prometheus configuration to get VIM data")
3240 @click.pass_context
3241 def vim_update(
3242 ctx,
3243 name,
3244 newname,
3245 user,
3246 password,
3247 auth_url,
3248 tenant,
3249 config,
3250 config_file,
3251 account_type,
3252 description,
3253 sdn_controller,
3254 sdn_port_mapping,
3255 wait,
3256 creds,
3257 prometheus_config_file
3258 ):
3259 """updates a VIM account
3260
3261 NAME: name or ID of the VIM account
3262 """
3263 logger.debug("")
3264 # try:
3265 check_client_version(ctx.obj, ctx.command.name)
3266 vim = {}
3267 if newname:
3268 vim["name"] = newname
3269 if user:
3270 vim["vim_user"] = user
3271 if password:
3272 vim["vim_password"] = password
3273 if auth_url:
3274 vim["vim_url"] = auth_url
3275 if tenant:
3276 vim["vim-tenant-name"] = tenant
3277 if account_type:
3278 vim["vim_type"] = account_type
3279 if description:
3280 vim["description"] = description
3281 vim_config = None
3282 if config or config_file:
3283 vim_config = create_config(config_file, config)
3284 if creds:
3285 with open(creds, "r") as cf:
3286 vim_config["credentials"] = yaml.safe_load(cf.read())
3287 if prometheus_config_file:
3288 with open(prometheus_config_file) as prometheus_file:
3289 prometheus_config_dict = json.load(prometheus_file)
3290 vim["prometheus-config"] = prometheus_config_dict
3291 logger.info(f"VIM: {vim}, VIM config: {vim_config}")
3292 ctx.obj.vim.update(name, vim, vim_config, sdn_controller, sdn_port_mapping, wait=wait)
3293 # except ClientException as e:
3294 # print(str(e))
3295 # exit(1)
3296
3297
3298 @cli_osm.command(name="vim-delete", short_help="deletes a VIM account")
3299 @click.argument("name")
3300 @click.option(
3301 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3302 )
3303 @click.option(
3304 "--wait",
3305 required=False,
3306 default=False,
3307 is_flag=True,
3308 help="do not return the control immediately, but keep it "
3309 "until the operation is completed, or timeout",
3310 )
3311 @click.pass_context
3312 def vim_delete(ctx, name, force, wait):
3313 """deletes a VIM account
3314
3315 NAME: name or ID of the VIM account to be deleted
3316 """
3317 logger.debug("")
3318 # try:
3319 if not force:
3320 ctx.obj.vim.delete(name, wait=wait)
3321 else:
3322 check_client_version(ctx.obj, "--force")
3323 ctx.obj.vim.delete(name, force, wait=wait)
3324 # except ClientException as e:
3325 # print(str(e))
3326 # exit(1)
3327
3328
3329 @cli_osm.command(name="vim-list", short_help="list all VIM accounts")
3330 # @click.option('--ro_update/--no_ro_update',
3331 # default=False,
3332 # help='update list from RO')
3333 @click.option(
3334 "--filter",
3335 default=None,
3336 multiple=True,
3337 help="restricts the list to the VIM accounts matching the filter",
3338 )
3339 @click.option(
3340 "--long",
3341 is_flag=True,
3342 help="get more details of the NS (project, vim, deployment status, configuration status.",
3343 )
3344 @click.pass_context
3345 def vim_list(ctx, filter, long):
3346 """list all VIM accounts"""
3347 logger.debug("")
3348 if filter:
3349 filter = "&".join(filter)
3350 check_client_version(ctx.obj, "--filter")
3351 # if ro_update:
3352 # check_client_version(ctx.obj, '--ro_update', 'v1')
3353 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
3354 if fullclassname == "osmclient.sol005.client.Client":
3355 resp = ctx.obj.vim.list(filter)
3356 # else:
3357 # resp = ctx.obj.vim.list(ro_update)
3358 if long:
3359 table = PrettyTable(
3360 ["vim name", "uuid", "project", "operational state", "error details"]
3361 )
3362 project_list = ctx.obj.project.list()
3363 else:
3364 table = PrettyTable(["vim name", "uuid", "operational state"])
3365 for vim in resp:
3366 if long:
3367 if "vim_password" in vim:
3368 vim["vim_password"] = "********"
3369 if "config" in vim and "credentials" in vim["config"]:
3370 vim["config"]["credentials"] = "********"
3371 logger.debug("VIM details: {}".format(yaml.safe_dump(vim)))
3372 vim_state = vim["_admin"].get("operationalState", "-")
3373 error_details = "N/A"
3374 if vim_state == "ERROR":
3375 error_details = vim["_admin"].get("detailed-status", "Not found")
3376 project_id, project_name = get_project(project_list, vim)
3377 # project_info = '{} ({})'.format(project_name, project_id)
3378 project_info = project_name
3379 table.add_row(
3380 [
3381 vim["name"],
3382 vim["uuid"],
3383 project_info,
3384 vim_state,
3385 wrap_text(text=error_details, width=80),
3386 ]
3387 )
3388 else:
3389 table.add_row(
3390 [vim["name"], vim["uuid"], vim["_admin"].get("operationalState", "-")]
3391 )
3392 table.align = "l"
3393 print(table)
3394
3395
3396 @cli_osm.command(name="vim-show", short_help="shows the details of a VIM account")
3397 @click.argument("name")
3398 @click.option(
3399 "--filter",
3400 multiple=True,
3401 help="restricts the information to the fields in the filter",
3402 )
3403 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
3404 @click.pass_context
3405 def vim_show(ctx, name, filter, literal):
3406 """shows the details of a VIM account
3407
3408 NAME: name or ID of the VIM account
3409 """
3410 logger.debug("")
3411 # try:
3412 resp = ctx.obj.vim.get(name)
3413 if "vim_password" in resp:
3414 resp["vim_password"] = "********"
3415 if "config" in resp and "credentials" in resp["config"]:
3416 resp["config"]["credentials"] = "********"
3417 # except ClientException as e:
3418 # print(str(e))
3419 # exit(1)
3420
3421 if literal:
3422 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
3423 return
3424 table = PrettyTable(["key", "attribute"])
3425 for k, v in list(resp.items()):
3426 if not filter or k in filter:
3427 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
3428 table.align = "l"
3429 print(table)
3430
3431
3432 ####################
3433 # WIM operations
3434 ####################
3435
3436
3437 @cli_osm.command(name="wim-create", short_help="creates a new WIM account")
3438 @click.option("--name", prompt=True, help="Name for the WIM account")
3439 @click.option("--user", help="WIM username")
3440 @click.option("--password", help="WIM password")
3441 @click.option("--url", prompt=True, help="WIM url")
3442 # @click.option('--tenant',
3443 # help='wIM tenant name')
3444 @click.option("--config", default=None, help="WIM specific config parameters")
3445 @click.option("--wim_type", help="WIM type")
3446 @click.option("--description", default=None, help="human readable description")
3447 @click.option(
3448 "--wim_port_mapping",
3449 default=None,
3450 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3451 "(WAN service endpoint id and info)",
3452 )
3453 @click.option(
3454 "--wait",
3455 required=False,
3456 default=False,
3457 is_flag=True,
3458 help="do not return the control immediately, but keep it "
3459 "until the operation is completed, or timeout",
3460 )
3461 @click.pass_context
3462 def wim_create(
3463 ctx,
3464 name,
3465 user,
3466 password,
3467 url,
3468 # tenant,
3469 config,
3470 wim_type,
3471 description,
3472 wim_port_mapping,
3473 wait,
3474 ):
3475 """creates a new WIM account"""
3476 logger.debug("")
3477 # try:
3478 check_client_version(ctx.obj, ctx.command.name)
3479 # if sdn_controller:
3480 # check_client_version(ctx.obj, '--sdn_controller')
3481 # if sdn_port_mapping:
3482 # check_client_version(ctx.obj, '--sdn_port_mapping')
3483 wim = {}
3484 if user:
3485 wim["user"] = user
3486 if password:
3487 wim["password"] = password
3488 if url:
3489 wim["wim_url"] = url
3490 # if tenant: wim['tenant'] = tenant
3491 wim["wim_type"] = wim_type
3492 if description:
3493 wim["description"] = description
3494 if config:
3495 wim["config"] = config
3496 ctx.obj.wim.create(name, wim, wim_port_mapping, wait=wait)
3497 # except ClientException as e:
3498 # print(str(e))
3499 # exit(1)
3500
3501
3502 @cli_osm.command(name="wim-update", short_help="updates a WIM account")
3503 @click.argument("name")
3504 @click.option("--newname", help="New name for the WIM account")
3505 @click.option("--user", help="WIM username")
3506 @click.option("--password", help="WIM password")
3507 @click.option("--url", help="WIM url")
3508 @click.option("--config", help="WIM specific config parameters")
3509 @click.option("--wim_type", help="WIM type")
3510 @click.option("--description", help="human readable description")
3511 @click.option(
3512 "--wim_port_mapping",
3513 default=None,
3514 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3515 "(WAN service endpoint id and info)",
3516 )
3517 @click.option(
3518 "--wait",
3519 required=False,
3520 default=False,
3521 is_flag=True,
3522 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3523 )
3524 @click.pass_context
3525 def wim_update(
3526 ctx,
3527 name,
3528 newname,
3529 user,
3530 password,
3531 url,
3532 config,
3533 wim_type,
3534 description,
3535 wim_port_mapping,
3536 wait,
3537 ):
3538 """updates a WIM account
3539
3540 NAME: name or ID of the WIM account
3541 """
3542 logger.debug("")
3543 # try:
3544 check_client_version(ctx.obj, ctx.command.name)
3545 wim = {}
3546 if newname:
3547 wim["name"] = newname
3548 if user:
3549 wim["user"] = user
3550 if password:
3551 wim["password"] = password
3552 if url:
3553 wim["url"] = url
3554 # if tenant: wim['tenant'] = tenant
3555 if wim_type:
3556 wim["wim_type"] = wim_type
3557 if description:
3558 wim["description"] = description
3559 if config:
3560 wim["config"] = config
3561 ctx.obj.wim.update(name, wim, wim_port_mapping, wait=wait)
3562 # except ClientException as e:
3563 # print(str(e))
3564 # exit(1)
3565
3566
3567 @cli_osm.command(name="wim-delete", short_help="deletes a WIM account")
3568 @click.argument("name")
3569 @click.option(
3570 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3571 )
3572 @click.option(
3573 "--wait",
3574 required=False,
3575 default=False,
3576 is_flag=True,
3577 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3578 )
3579 @click.pass_context
3580 def wim_delete(ctx, name, force, wait):
3581 """deletes a WIM account
3582
3583 NAME: name or ID of the WIM account to be deleted
3584 """
3585 logger.debug("")
3586 # try:
3587 check_client_version(ctx.obj, ctx.command.name)
3588 ctx.obj.wim.delete(name, force, wait=wait)
3589 # except ClientException as e:
3590 # print(str(e))
3591 # exit(1)
3592
3593
3594 @cli_osm.command(name="wim-list", short_help="list all WIM accounts")
3595 @click.option(
3596 "--filter",
3597 default=None,
3598 multiple=True,
3599 help="restricts the list to the WIM accounts matching the filter",
3600 )
3601 @click.pass_context
3602 def wim_list(ctx, filter):
3603 """list all WIM accounts"""
3604 logger.debug("")
3605 # try:
3606 check_client_version(ctx.obj, ctx.command.name)
3607 if filter:
3608 filter = "&".join(filter)
3609 resp = ctx.obj.wim.list(filter)
3610 table = PrettyTable(["wim name", "uuid"])
3611 for wim in resp:
3612 table.add_row([wim["name"], wim["uuid"]])
3613 table.align = "l"
3614 print(table)
3615 # except ClientException as e:
3616 # print(str(e))
3617 # exit(1)
3618
3619
3620 @cli_osm.command(name="wim-show", short_help="shows the details of a WIM account")
3621 @click.argument("name")
3622 @click.pass_context
3623 def wim_show(ctx, name):
3624 """shows the details of a WIM account
3625
3626 NAME: name or ID of the WIM account
3627 """
3628 logger.debug("")
3629 # try:
3630 check_client_version(ctx.obj, ctx.command.name)
3631 resp = ctx.obj.wim.get(name)
3632 if "password" in resp:
3633 resp["wim_password"] = "********"
3634 # except ClientException as e:
3635 # print(str(e))
3636 # exit(1)
3637
3638 table = PrettyTable(["key", "attribute"])
3639 for k, v in list(resp.items()):
3640 table.add_row([k, json.dumps(v, indent=2)])
3641 table.align = "l"
3642 print(table)
3643
3644
3645 ####################
3646 # SDN controller operations
3647 ####################
3648
3649
3650 @cli_osm.command(name="sdnc-create", short_help="creates a new SDN controller")
3651 @click.option("--name", prompt=True, help="Name to create sdn controller")
3652 @click.option("--type", prompt=True, help="SDN controller type")
3653 @click.option(
3654 "--sdn_controller_version", # hidden=True,
3655 help="Deprecated. Use --config {version: sdn_controller_version}",
3656 )
3657 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3658 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True,
3659 @click.option("--port", help="Deprecated. Use --url") # hidden=True,
3660 @click.option(
3661 "--switch_dpid", help="Deprecated. Use --config {switch_id: DPID}" # hidden=True,
3662 )
3663 @click.option(
3664 "--config",
3665 help="Extra information for SDN in yaml format, as {switch_id: identity used for the plugin (e.g. DPID: "
3666 "Openflow Datapath ID), version: version}",
3667 )
3668 @click.option("--user", help="SDN controller username")
3669 @click.option(
3670 "--password",
3671 hide_input=True,
3672 confirmation_prompt=True,
3673 help="SDN controller password",
3674 )
3675 @click.option("--description", default=None, help="human readable description")
3676 @click.option(
3677 "--wait",
3678 required=False,
3679 default=False,
3680 is_flag=True,
3681 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3682 )
3683 @click.pass_context
3684 def sdnc_create(ctx, **kwargs):
3685 """creates a new SDN controller"""
3686 logger.debug("")
3687 sdncontroller = {
3688 x: kwargs[x]
3689 for x in kwargs
3690 if kwargs[x] and x not in ("wait", "ip_address", "port", "switch_dpid")
3691 }
3692 if kwargs.get("port"):
3693 print("option '--port' is deprecated, use '--url' instead")
3694 sdncontroller["port"] = int(kwargs["port"])
3695 if kwargs.get("ip_address"):
3696 print("option '--ip_address' is deprecated, use '--url' instead")
3697 sdncontroller["ip"] = kwargs["ip_address"]
3698 if kwargs.get("switch_dpid"):
3699 print(
3700 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3701 )
3702 sdncontroller["dpid"] = kwargs["switch_dpid"]
3703 if kwargs.get("sdn_controller_version"):
3704 print(
3705 "option '--sdn_controller_version' is deprecated, use '--config={version: SDN_CONTROLLER_VERSION}'"
3706 " instead"
3707 )
3708 # try:
3709 check_client_version(ctx.obj, ctx.command.name)
3710 ctx.obj.sdnc.create(kwargs["name"], sdncontroller, wait=kwargs["wait"])
3711 # except ClientException as e:
3712 # print(str(e))
3713 # exit(1)
3714
3715
3716 @cli_osm.command(name="sdnc-update", short_help="updates an SDN controller")
3717 @click.argument("name")
3718 @click.option("--newname", help="New name for the SDN controller")
3719 @click.option("--description", default=None, help="human readable description")
3720 @click.option("--type", help="SDN controller type")
3721 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3722 @click.option(
3723 "--config",
3724 help="Extra information for SDN in yaml format, as "
3725 "{switch_id: identity used for the plugin (e.g. DPID: "
3726 "Openflow Datapath ID), version: version}",
3727 )
3728 @click.option("--user", help="SDN controller username")
3729 @click.option("--password", help="SDN controller password")
3730 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True
3731 @click.option("--port", help="Deprecated. Use --url") # hidden=True
3732 @click.option(
3733 "--switch_dpid", help="Deprecated. Use --config {switch_dpid: DPID}"
3734 ) # hidden=True
3735 @click.option(
3736 "--sdn_controller_version", help="Deprecated. Use --config {version: VERSION}"
3737 ) # hidden=True
3738 @click.option(
3739 "--wait",
3740 required=False,
3741 default=False,
3742 is_flag=True,
3743 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3744 )
3745 @click.pass_context
3746 def sdnc_update(ctx, **kwargs):
3747 """updates an SDN controller
3748
3749 NAME: name or ID of the SDN controller
3750 """
3751 logger.debug("")
3752 sdncontroller = {
3753 x: kwargs[x]
3754 for x in kwargs
3755 if kwargs[x]
3756 and x not in ("wait", "ip_address", "port", "switch_dpid", "new_name")
3757 }
3758 if kwargs.get("newname"):
3759 sdncontroller["name"] = kwargs["newname"]
3760 if kwargs.get("port"):
3761 print("option '--port' is deprecated, use '--url' instead")
3762 sdncontroller["port"] = int(kwargs["port"])
3763 if kwargs.get("ip_address"):
3764 print("option '--ip_address' is deprecated, use '--url' instead")
3765 sdncontroller["ip"] = kwargs["ip_address"]
3766 if kwargs.get("switch_dpid"):
3767 print(
3768 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3769 )
3770 sdncontroller["dpid"] = kwargs["switch_dpid"]
3771 if kwargs.get("sdn_controller_version"):
3772 print(
3773 "option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
3774 " instead"
3775 )
3776
3777 # try:
3778 check_client_version(ctx.obj, ctx.command.name)
3779 ctx.obj.sdnc.update(kwargs["name"], sdncontroller, wait=kwargs["wait"])
3780 # except ClientException as e:
3781 # print(str(e))
3782 # exit(1)
3783
3784
3785 @cli_osm.command(name="sdnc-delete", short_help="deletes an SDN controller")
3786 @click.argument("name")
3787 @click.option(
3788 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3789 )
3790 @click.option(
3791 "--wait",
3792 required=False,
3793 default=False,
3794 is_flag=True,
3795 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3796 )
3797 @click.pass_context
3798 def sdnc_delete(ctx, name, force, wait):
3799 """deletes an SDN controller
3800
3801 NAME: name or ID of the SDN controller to be deleted
3802 """
3803 logger.debug("")
3804 # try:
3805 check_client_version(ctx.obj, ctx.command.name)
3806 ctx.obj.sdnc.delete(name, force, wait=wait)
3807 # except ClientException as e:
3808 # print(str(e))
3809 # exit(1)
3810
3811
3812 @cli_osm.command(name="sdnc-list", short_help="list all SDN controllers")
3813 @click.option(
3814 "--filter",
3815 default=None,
3816 multiple=True,
3817 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'",
3818 )
3819 @click.pass_context
3820 def sdnc_list(ctx, filter):
3821 """list all SDN controllers"""
3822 logger.debug("")
3823 # try:
3824 check_client_version(ctx.obj, ctx.command.name)
3825 if filter:
3826 filter = "&".join(filter)
3827 resp = ctx.obj.sdnc.list(filter)
3828 # except ClientException as e:
3829 # print(str(e))
3830 # exit(1)
3831 table = PrettyTable(["sdnc name", "id"])
3832 for sdnc in resp:
3833 table.add_row([sdnc["name"], sdnc["_id"]])
3834 table.align = "l"
3835 print(table)
3836
3837
3838 @cli_osm.command(name="sdnc-show", short_help="shows the details of an SDN controller")
3839 @click.argument("name")
3840 @click.pass_context
3841 def sdnc_show(ctx, name):
3842 """shows the details of an SDN controller
3843
3844 NAME: name or ID of the SDN controller
3845 """
3846 logger.debug("")
3847 # try:
3848 check_client_version(ctx.obj, ctx.command.name)
3849 resp = ctx.obj.sdnc.get(name)
3850 # except ClientException as e:
3851 # print(str(e))
3852 # exit(1)
3853
3854 table = PrettyTable(["key", "attribute"])
3855 for k, v in list(resp.items()):
3856 table.add_row([k, json.dumps(v, indent=2)])
3857 table.align = "l"
3858 print(table)
3859
3860
3861 ###########################
3862 # K8s cluster operations
3863 ###########################
3864
3865
3866 @cli_osm.command(name="k8scluster-add", short_help="adds a K8s cluster to OSM")
3867 @click.argument("name")
3868 @click.option(
3869 "--creds", prompt=True, help="credentials file, i.e. a valid `.kube/config` file"
3870 )
3871 @click.option("--version", prompt=True, help="Kubernetes version")
3872 @click.option(
3873 "--vim", prompt=True, help="VIM target, the VIM where the cluster resides"
3874 )
3875 @click.option(
3876 "--k8s-nets",
3877 prompt=True,
3878 help='''list of VIM networks, in JSON inline format, where the cluster is
3879 accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3880 )
3881 @click.option("--description", default=None, help="human readable description")
3882 @click.option(
3883 "--namespace",
3884 default="kube-system",
3885 help="namespace to be used for its operation, defaults to `kube-system`",
3886 )
3887 @click.option(
3888 "--wait",
3889 required=False,
3890 default=False,
3891 is_flag=True,
3892 help="do not return the control immediately, but keep it "
3893 "until the operation is completed, or timeout",
3894 )
3895 @click.option(
3896 "--cni",
3897 default=None,
3898 help="list of CNI plugins, in JSON inline format, used in the cluster",
3899 )
3900 # @click.option('--skip-init',
3901 # is_flag=True,
3902 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
3903 # @click.option('--wait',
3904 # is_flag=True,
3905 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3906 @click.pass_context
3907 def k8scluster_add(
3908 ctx, name, creds, version, vim, k8s_nets, description, namespace, wait, cni
3909 ):
3910 """adds a K8s cluster to OSM
3911
3912 NAME: name of the K8s cluster
3913 """
3914 # try:
3915 check_client_version(ctx.obj, ctx.command.name)
3916 cluster = {}
3917 cluster["name"] = name
3918 with open(creds, "r") as cf:
3919 cluster["credentials"] = yaml.safe_load(cf.read())
3920 cluster["k8s_version"] = version
3921 cluster["vim_account"] = vim
3922 cluster["nets"] = yaml.safe_load(k8s_nets)
3923 if description:
3924 cluster["description"] = description
3925 if namespace:
3926 cluster["namespace"] = namespace
3927 if cni:
3928 cluster["cni"] = yaml.safe_load(cni)
3929 ctx.obj.k8scluster.create(name, cluster, wait)
3930 # except ClientException as e:
3931 # print(str(e))
3932 # exit(1)
3933
3934
3935 @cli_osm.command(name="k8scluster-update", short_help="updates a K8s cluster")
3936 @click.argument("name")
3937 @click.option("--newname", help="New name for the K8s cluster")
3938 @click.option("--creds", help="credentials file, i.e. a valid `.kube/config` file")
3939 @click.option("--version", help="Kubernetes version")
3940 @click.option("--vim", help="VIM target, the VIM where the cluster resides")
3941 @click.option(
3942 "--k8s-nets",
3943 help='''list of VIM networks, in JSON inline format, where the cluster is accessible
3944 via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3945 )
3946 @click.option("--description", help="human readable description")
3947 @click.option(
3948 "--namespace",
3949 help="namespace to be used for its operation, defaults to `kube-system`",
3950 )
3951 @click.option(
3952 "--wait",
3953 required=False,
3954 default=False,
3955 is_flag=True,
3956 help="do not return the control immediately, but keep it "
3957 "until the operation is completed, or timeout",
3958 )
3959 @click.option(
3960 "--cni", help="list of CNI plugins, in JSON inline format, used in the cluster"
3961 )
3962 @click.pass_context
3963 def k8scluster_update(
3964 ctx, name, newname, creds, version, vim, k8s_nets, description, namespace, wait, cni
3965 ):
3966 """updates a K8s cluster
3967
3968 NAME: name or ID of the K8s cluster
3969 """
3970 # try:
3971 check_client_version(ctx.obj, ctx.command.name)
3972 cluster = {}
3973 if newname:
3974 cluster["name"] = newname
3975 if creds:
3976 with open(creds, "r") as cf:
3977 cluster["credentials"] = yaml.safe_load(cf.read())
3978 if version:
3979 cluster["k8s_version"] = version
3980 if vim:
3981 cluster["vim_account"] = vim
3982 if k8s_nets:
3983 cluster["nets"] = yaml.safe_load(k8s_nets)
3984 if description:
3985 cluster["description"] = description
3986 if namespace:
3987 cluster["namespace"] = namespace
3988 if cni:
3989 cluster["cni"] = yaml.safe_load(cni)
3990 ctx.obj.k8scluster.update(name, cluster, wait)
3991 # except ClientException as e:
3992 # print(str(e))
3993 # exit(1)
3994
3995
3996 @cli_osm.command(name="k8scluster-delete", short_help="deletes a K8s cluster")
3997 @click.argument("name")
3998 @click.option(
3999 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
4000 )
4001 @click.option(
4002 "--wait",
4003 required=False,
4004 default=False,
4005 is_flag=True,
4006 help="do not return the control immediately, but keep it "
4007 "until the operation is completed, or timeout",
4008 )
4009 @click.pass_context
4010 def k8scluster_delete(ctx, name, force, wait):
4011 """deletes a K8s cluster
4012
4013 NAME: name or ID of the K8s cluster to be deleted
4014 """
4015 # try:
4016 check_client_version(ctx.obj, ctx.command.name)
4017 ctx.obj.k8scluster.delete(name, force, wait)
4018 # except ClientException as e:
4019 # print(str(e))
4020 # exit(1)
4021
4022
4023 @cli_osm.command(name="k8scluster-list")
4024 @click.option(
4025 "--filter",
4026 default=None,
4027 multiple=True,
4028 help="restricts the list to the K8s clusters matching the filter",
4029 )
4030 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4031 @click.option("--long", is_flag=True, help="get more details")
4032 @click.pass_context
4033 def k8scluster_list(ctx, filter, literal, long):
4034 """list all K8s clusters"""
4035 # try:
4036 check_client_version(ctx.obj, ctx.command.name)
4037 if filter:
4038 filter = "&".join(filter)
4039 resp = ctx.obj.k8scluster.list(filter)
4040 if literal:
4041 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4042 return
4043 if long:
4044 table = PrettyTable(
4045 [
4046 "Name",
4047 "Id",
4048 "Project",
4049 "Version",
4050 "VIM",
4051 "K8s-nets",
4052 "Operational State",
4053 "Op. state (details)",
4054 "Description",
4055 "Detailed status",
4056 ]
4057 )
4058 project_list = ctx.obj.project.list()
4059 else:
4060 table = PrettyTable(
4061 ["Name", "Id", "VIM", "Operational State", "Op. state details"]
4062 )
4063 try:
4064 vim_list = ctx.obj.vim.list()
4065 except Exception:
4066 vim_list = []
4067 for cluster in resp:
4068 logger.debug("Cluster details: {}".format(yaml.safe_dump(cluster)))
4069 vim_name = get_vim_name(vim_list, cluster["vim_account"])
4070 # vim_info = '{} ({})'.format(vim_name,cluster['vim_account'])
4071 vim_info = vim_name
4072 op_state_details = "Helm: {}\nJuju: {}".format(
4073 cluster["_admin"].get("helm-chart", {}).get("operationalState", "-"),
4074 cluster["_admin"].get("juju-bundle", {}).get("operationalState", "-"),
4075 )
4076 if long:
4077 project_id, project_name = get_project(project_list, cluster)
4078 # project_info = '{} ({})'.format(project_name, project_id)
4079 project_info = project_name
4080 detailed_status = cluster["_admin"].get("detailed-status", "-")
4081 table.add_row(
4082 [
4083 cluster["name"],
4084 cluster["_id"],
4085 project_info,
4086 cluster["k8s_version"],
4087 vim_info,
4088 json.dumps(cluster["nets"]),
4089 cluster["_admin"]["operationalState"],
4090 op_state_details,
4091 trunc_text(cluster.get("description") or "", 40),
4092 wrap_text(text=detailed_status, width=40),
4093 ]
4094 )
4095 else:
4096 table.add_row(
4097 [
4098 cluster["name"],
4099 cluster["_id"],
4100 vim_info,
4101 cluster["_admin"]["operationalState"],
4102 op_state_details,
4103 ]
4104 )
4105 table.align = "l"
4106 print(table)
4107 # except ClientException as e:
4108 # print(str(e))
4109 # exit(1)
4110
4111
4112 @cli_osm.command(
4113 name="k8scluster-show", short_help="shows the details of a K8s cluster"
4114 )
4115 @click.argument("name")
4116 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4117 @click.pass_context
4118 def k8scluster_show(ctx, name, literal):
4119 """shows the details of a K8s cluster
4120
4121 NAME: name or ID of the K8s cluster
4122 """
4123 # try:
4124 resp = ctx.obj.k8scluster.get(name)
4125 if literal:
4126 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4127 return
4128 table = PrettyTable(["key", "attribute"])
4129 for k, v in list(resp.items()):
4130 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
4131 table.align = "l"
4132 print(table)
4133 # except ClientException as e:
4134 # print(str(e))
4135 # exit(1)
4136
4137
4138 ###########################
4139 # VCA operations
4140 ###########################
4141
4142
4143 @cli_osm.command(name="vca-add", short_help="adds a VCA (Juju controller) to OSM")
4144 @click.argument("name")
4145 @click.option(
4146 "--endpoints",
4147 prompt=True,
4148 help="Comma-separated list of IP or hostnames of the Juju controller",
4149 )
4150 @click.option("--user", prompt=True, help="Username with admin priviledges")
4151 @click.option("--secret", prompt=True, help="Password of the specified username")
4152 @click.option("--cacert", prompt=True, help="CA certificate")
4153 @click.option(
4154 "--lxd-cloud",
4155 prompt=True,
4156 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4157 )
4158 @click.option(
4159 "--lxd-credentials",
4160 prompt=True,
4161 help="Name of the cloud credentialsto be used for the LXD cloud",
4162 )
4163 @click.option(
4164 "--k8s-cloud",
4165 prompt=True,
4166 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4167 )
4168 @click.option(
4169 "--k8s-credentials",
4170 prompt=True,
4171 help="Name of the cloud credentialsto be used for the K8s cloud",
4172 )
4173 @click.option(
4174 "--model-config",
4175 default={},
4176 help="Configuration options for the models",
4177 )
4178 @click.option("--description", default=None, help="human readable description")
4179 @click.pass_context
4180 def vca_add(
4181 ctx,
4182 name,
4183 endpoints,
4184 user,
4185 secret,
4186 cacert,
4187 lxd_cloud,
4188 lxd_credentials,
4189 k8s_cloud,
4190 k8s_credentials,
4191 model_config,
4192 description,
4193 ):
4194 """adds a VCA to OSM
4195
4196 NAME: name of the VCA
4197 """
4198 check_client_version(ctx.obj, ctx.command.name)
4199 vca = {}
4200 vca["name"] = name
4201 vca["endpoints"] = endpoints.split(",")
4202 vca["user"] = user
4203 vca["secret"] = secret
4204 vca["cacert"] = cacert
4205 vca["lxd-cloud"] = lxd_cloud
4206 vca["lxd-credentials"] = lxd_credentials
4207 vca["k8s-cloud"] = k8s_cloud
4208 vca["k8s-credentials"] = k8s_credentials
4209 if description:
4210 vca["description"] = description
4211 if model_config:
4212 model_config = load(model_config)
4213 vca["model-config"] = model_config
4214 ctx.obj.vca.create(name, vca)
4215
4216
4217 def load(data: Any):
4218 if os.path.isfile(data):
4219 return load_file(data)
4220 else:
4221 try:
4222 return json.loads(data)
4223 except ValueError as e:
4224 raise ClientException(e)
4225
4226
4227 def load_file(file_path: str) -> Dict:
4228 content = None
4229 with open(file_path, "r") as f:
4230 content = f.read()
4231 try:
4232 return yaml.safe_load(content)
4233 except yaml.scanner.ScannerError:
4234 pass
4235 try:
4236 return json.loads(content)
4237 except ValueError:
4238 pass
4239 raise ClientException(f"{file_path} must be a valid yaml or json file")
4240
4241
4242 @cli_osm.command(name="vca-update", short_help="updates a K8s cluster")
4243 @click.argument("name")
4244 @click.option(
4245 "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
4246 )
4247 @click.option("--user", help="Username with admin priviledges")
4248 @click.option("--secret", help="Password of the specified username")
4249 @click.option("--cacert", help="CA certificate")
4250 @click.option(
4251 "--lxd-cloud",
4252 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4253 )
4254 @click.option(
4255 "--lxd-credentials",
4256 help="Name of the cloud credentialsto be used for the LXD cloud",
4257 )
4258 @click.option(
4259 "--k8s-cloud",
4260 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4261 )
4262 @click.option(
4263 "--k8s-credentials",
4264 help="Name of the cloud credentialsto be used for the K8s cloud",
4265 )
4266 @click.option(
4267 "--model-config",
4268 help="Configuration options for the models",
4269 )
4270 @click.option("--description", default=None, help="human readable description")
4271 @click.pass_context
4272 def vca_update(
4273 ctx,
4274 name,
4275 endpoints,
4276 user,
4277 secret,
4278 cacert,
4279 lxd_cloud,
4280 lxd_credentials,
4281 k8s_cloud,
4282 k8s_credentials,
4283 model_config,
4284 description,
4285 ):
4286 """updates a K8s cluster
4287
4288 NAME: name or ID of the K8s cluster
4289 """
4290 check_client_version(ctx.obj, ctx.command.name)
4291 vca = {}
4292 vca["name"] = name
4293 if endpoints:
4294 vca["endpoints"] = endpoints.split(",")
4295 if user:
4296 vca["user"] = user
4297 if secret:
4298 vca["secret"] = secret
4299 if cacert:
4300 vca["cacert"] = cacert
4301 if lxd_cloud:
4302 vca["lxd-cloud"] = lxd_cloud
4303 if lxd_credentials:
4304 vca["lxd-credentials"] = lxd_credentials
4305 if k8s_cloud:
4306 vca["k8s-cloud"] = k8s_cloud
4307 if k8s_credentials:
4308 vca["k8s-credentials"] = k8s_credentials
4309 if description:
4310 vca["description"] = description
4311 if model_config:
4312 model_config = load(model_config)
4313 vca["model-config"] = model_config
4314 ctx.obj.vca.update(name, vca)
4315
4316
4317 @cli_osm.command(name="vca-delete", short_help="deletes a K8s cluster")
4318 @click.argument("name")
4319 @click.option(
4320 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
4321 )
4322 @click.pass_context
4323 def vca_delete(ctx, name, force):
4324 """deletes a K8s cluster
4325
4326 NAME: name or ID of the K8s cluster to be deleted
4327 """
4328 check_client_version(ctx.obj, ctx.command.name)
4329 ctx.obj.vca.delete(name, force=force)
4330
4331
4332 @cli_osm.command(name="vca-list")
4333 @click.option(
4334 "--filter",
4335 default=None,
4336 multiple=True,
4337 help="restricts the list to the VCAs matching the filter",
4338 )
4339 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4340 @click.option("--long", is_flag=True, help="get more details")
4341 @click.pass_context
4342 def vca_list(ctx, filter, literal, long):
4343 """list VCAs"""
4344 check_client_version(ctx.obj, ctx.command.name)
4345 if filter:
4346 filter = "&".join(filter)
4347 resp = ctx.obj.vca.list(filter)
4348 if literal:
4349 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4350 return
4351 if long:
4352 table = PrettyTable(
4353 ["Name", "Id", "Project", "Operational State", "Detailed Status"]
4354 )
4355 project_list = ctx.obj.project.list()
4356 else:
4357 table = PrettyTable(["Name", "Id", "Operational State"])
4358 for vca in resp:
4359 logger.debug("VCA details: {}".format(yaml.safe_dump(vca)))
4360 if long:
4361 project_id, project_name = get_project(project_list, vca)
4362 detailed_status = vca.get("_admin", {}).get("detailed-status", "-")
4363 table.add_row(
4364 [
4365 vca["name"],
4366 vca["_id"],
4367 project_name,
4368 vca.get("_admin", {}).get("operationalState", "-"),
4369 wrap_text(text=detailed_status, width=40),
4370 ]
4371 )
4372 else:
4373 table.add_row(
4374 [
4375 vca["name"],
4376 vca["_id"],
4377 vca.get("_admin", {}).get("operationalState", "-"),
4378 ]
4379 )
4380 table.align = "l"
4381 print(table)
4382
4383
4384 @cli_osm.command(name="vca-show", short_help="shows the details of a K8s cluster")
4385 @click.argument("name")
4386 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4387 @click.pass_context
4388 def vca_show(ctx, name, literal):
4389 """shows the details of a K8s cluster
4390
4391 NAME: name or ID of the K8s cluster
4392 """
4393 # try:
4394 resp = ctx.obj.vca.get(name)
4395 if literal:
4396 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4397 return
4398 table = PrettyTable(["key", "attribute"])
4399 for k, v in list(resp.items()):
4400 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
4401 table.align = "l"
4402 print(table)
4403
4404
4405 ###########################
4406 # Repo operations
4407 ###########################
4408
4409
4410 @cli_osm.command(name="repo-add", short_help="adds a repo to OSM")
4411 @click.argument("name")
4412 @click.argument("uri")
4413 @click.option(
4414 "--type",
4415 type=click.Choice(["helm-chart", "juju-bundle", "osm"]),
4416 default="osm",
4417 help="type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles, osm for OSM Repositories)",
4418 )
4419 @click.option("--description", default=None, help="human readable description")
4420 @click.option(
4421 "--user", default=None, help="OSM repository: The username of the OSM repository"
4422 )
4423 @click.option(
4424 "--password",
4425 default=None,
4426 help="OSM repository: The password of the OSM repository",
4427 )
4428 # @click.option('--wait',
4429 # is_flag=True,
4430 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4431 @click.pass_context
4432 def repo_add(ctx, **kwargs):
4433 """adds a repo to OSM
4434
4435 NAME: name of the repo
4436 URI: URI of the repo
4437 """
4438 # try:
4439 kwargs = {k: v for k, v in kwargs.items() if v is not None}
4440 repo = kwargs
4441 repo["url"] = repo.pop("uri")
4442 if repo["type"] in ["helm-chart", "juju-bundle"]:
4443 ctx.obj.repo.create(repo["name"], repo)
4444 else:
4445 ctx.obj.osmrepo.create(repo["name"], repo)
4446 # except ClientException as e:
4447 # print(str(e))
4448 # exit(1)
4449
4450
4451 @cli_osm.command(name="repo-update", short_help="updates a repo in OSM")
4452 @click.argument("name")
4453 @click.option("--newname", help="New name for the repo")
4454 @click.option("--uri", help="URI of the repo")
4455 @click.option("--description", help="human readable description")
4456 # @click.option('--wait',
4457 # is_flag=True,
4458 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4459 @click.pass_context
4460 def repo_update(ctx, name, newname, uri, description):
4461 """updates a repo in OSM
4462
4463 NAME: name of the repo
4464 """
4465 # try:
4466 check_client_version(ctx.obj, ctx.command.name)
4467 repo = {}
4468 if newname:
4469 repo["name"] = newname
4470 if uri:
4471 repo["uri"] = uri
4472 if description:
4473 repo["description"] = description
4474 try:
4475 ctx.obj.repo.update(name, repo)
4476 except NotFound:
4477 ctx.obj.osmrepo.update(name, repo)
4478
4479 # except ClientException as e:
4480 # print(str(e))
4481 # exit(1)
4482
4483
4484 @cli_osm.command(
4485 name="repo-index", short_help="Index a repository from a folder with artifacts"
4486 )
4487 @click.option(
4488 "--origin", default=".", help="origin path where the artifacts are located"
4489 )
4490 @click.option(
4491 "--destination", default=".", help="destination path where the index is deployed"
4492 )
4493 @click.pass_context
4494 def repo_index(ctx, origin, destination):
4495 """Index a repository
4496
4497 NAME: name or ID of the repo to be deleted
4498 """
4499 check_client_version(ctx.obj, ctx.command.name)
4500 ctx.obj.osmrepo.repo_index(origin, destination)
4501
4502
4503 @cli_osm.command(name="repo-delete", short_help="deletes a repo")
4504 @click.argument("name")
4505 @click.option(
4506 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
4507 )
4508 # @click.option('--wait',
4509 # is_flag=True,
4510 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4511 @click.pass_context
4512 def repo_delete(ctx, name, force):
4513 """deletes a repo
4514
4515 NAME: name or ID of the repo to be deleted
4516 """
4517 logger.debug("")
4518 try:
4519 ctx.obj.repo.delete(name, force=force)
4520 except NotFound:
4521 ctx.obj.osmrepo.delete(name, force=force)
4522 # except ClientException as e:
4523 # print(str(e))
4524 # exit(1)
4525
4526
4527 @cli_osm.command(name="repo-list")
4528 @click.option(
4529 "--filter",
4530 default=None,
4531 multiple=True,
4532 help="restricts the list to the repos matching the filter",
4533 )
4534 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4535 @click.pass_context
4536 def repo_list(ctx, filter, literal):
4537 """list all repos"""
4538 # try:
4539 # K8s Repositories
4540 check_client_version(ctx.obj, ctx.command.name)
4541 if filter:
4542 filter = "&".join(filter)
4543 resp = ctx.obj.repo.list(filter)
4544 resp += ctx.obj.osmrepo.list(filter)
4545 if literal:
4546 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4547 return
4548 table = PrettyTable(["Name", "Id", "Type", "URI", "Description"])
4549 for repo in resp:
4550 # cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
4551 table.add_row(
4552 [
4553 repo["name"],
4554 repo["_id"],
4555 repo["type"],
4556 repo["url"],
4557 trunc_text(repo.get("description") or "", 40),
4558 ]
4559 )
4560 table.align = "l"
4561 print(table)
4562
4563 # except ClientException as e:
4564 # print(str(e))
4565 # exit(1)
4566
4567
4568 @cli_osm.command(name="repo-show", short_help="shows the details of a repo")
4569 @click.argument("name")
4570 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4571 @click.pass_context
4572 def repo_show(ctx, name, literal):
4573 """shows the details of a repo
4574
4575 NAME: name or ID of the repo
4576 """
4577 try:
4578 resp = ctx.obj.repo.get(name)
4579 except NotFound:
4580 resp = ctx.obj.osmrepo.get(name)
4581
4582 if literal:
4583 if resp:
4584 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4585 return
4586 table = PrettyTable(["key", "attribute"])
4587 if resp:
4588 for k, v in list(resp.items()):
4589 table.add_row([k, json.dumps(v, indent=2)])
4590
4591 table.align = "l"
4592 print(table)
4593 # except ClientException as e:
4594 # print(str(e))
4595 # exit(1)
4596
4597
4598 ####################
4599 # Project mgmt operations
4600 ####################
4601
4602
4603 @cli_osm.command(name="project-create", short_help="creates a new project")
4604 @click.argument("name")
4605 # @click.option('--description',
4606 # default='no description',
4607 # help='human readable description')
4608 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
4609 @click.option(
4610 "--quotas",
4611 "quotas",
4612 multiple=True,
4613 default=None,
4614 help="provide quotas. Can be used several times: 'quota1=number[,quota2=number,...]'. Quotas can be one "
4615 "of vnfds, nsds, nsts, pdus, nsrs, nsis, vim_accounts, wim_accounts, sdns, k8sclusters, k8srepos",
4616 )
4617 @click.pass_context
4618 def project_create(ctx, name, domain_name, quotas):
4619 """Creates a new project
4620
4621 NAME: name of the project
4622 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
4623 QUOTAS: set quotas for the project
4624 """
4625 logger.debug("")
4626 project = {"name": name}
4627 if domain_name:
4628 project["domain_name"] = domain_name
4629 quotas_dict = _process_project_quotas(quotas)
4630 if quotas_dict:
4631 project["quotas"] = quotas_dict
4632
4633 # try:
4634 check_client_version(ctx.obj, ctx.command.name)
4635 ctx.obj.project.create(name, project)
4636 # except ClientException as e:
4637 # print(str(e))
4638 # exit(1)
4639
4640
4641 def _process_project_quotas(quota_list):
4642 quotas_dict = {}
4643 if not quota_list:
4644 return quotas_dict
4645 try:
4646 for quota in quota_list:
4647 for single_quota in quota.split(","):
4648 k, v = single_quota.split("=")
4649 quotas_dict[k] = None if v in ("None", "null", "") else int(v)
4650 except (ValueError, TypeError):
4651 raise ClientException(
4652 "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
4653 )
4654 return quotas_dict
4655
4656
4657 @cli_osm.command(name="project-delete", short_help="deletes a project")
4658 @click.argument("name")
4659 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4660 @click.pass_context
4661 def project_delete(ctx, name):
4662 """deletes a project
4663
4664 NAME: name or ID of the project to be deleted
4665 """
4666 logger.debug("")
4667 # try:
4668 check_client_version(ctx.obj, ctx.command.name)
4669 ctx.obj.project.delete(name)
4670 # except ClientException as e:
4671 # print(str(e))
4672 # exit(1)
4673
4674
4675 @cli_osm.command(name="project-list", short_help="list all projects")
4676 @click.option(
4677 "--filter",
4678 default=None,
4679 multiple=True,
4680 help="restricts the list to the projects matching the filter",
4681 )
4682 @click.pass_context
4683 def project_list(ctx, filter):
4684 """list all projects"""
4685 logger.debug("")
4686 # try:
4687 check_client_version(ctx.obj, ctx.command.name)
4688 if filter:
4689 filter = "&".join(filter)
4690 resp = ctx.obj.project.list(filter)
4691 # except ClientException as e:
4692 # print(str(e))
4693 # exit(1)
4694 table = PrettyTable(["name", "id"])
4695 for proj in resp:
4696 table.add_row([proj["name"], proj["_id"]])
4697 table.align = "l"
4698 print(table)
4699
4700
4701 @cli_osm.command(name="project-show", short_help="shows the details of a project")
4702 @click.argument("name")
4703 @click.pass_context
4704 def project_show(ctx, name):
4705 """shows the details of a project
4706
4707 NAME: name or ID of the project
4708 """
4709 logger.debug("")
4710 # try:
4711 check_client_version(ctx.obj, ctx.command.name)
4712 resp = ctx.obj.project.get(name)
4713 # except ClientException as e:
4714 # print(str(e))
4715 # exit(1)
4716
4717 table = PrettyTable(["key", "attribute"])
4718 for k, v in resp.items():
4719 table.add_row([k, json.dumps(v, indent=2)])
4720 table.align = "l"
4721 print(table)
4722
4723
4724 @cli_osm.command(
4725 name="project-update", short_help="updates a project (only the name can be updated)"
4726 )
4727 @click.argument("project")
4728 @click.option("--name", default=None, help="new name for the project")
4729 @click.option(
4730 "--quotas",
4731 "quotas",
4732 multiple=True,
4733 default=None,
4734 help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
4735 "(use empty to reset quota to default",
4736 )
4737 @click.pass_context
4738 def project_update(ctx, project, name, quotas):
4739 """
4740 Update a project name
4741
4742 :param ctx:
4743 :param project: id or name of the project to modify
4744 :param name: new name for the project
4745 :param quotas: change quotas of the project
4746 :return:
4747 """
4748 logger.debug("")
4749 project_changes = {}
4750 if name:
4751 project_changes["name"] = name
4752 quotas_dict = _process_project_quotas(quotas)
4753 if quotas_dict:
4754 project_changes["quotas"] = quotas_dict
4755
4756 # try:
4757 check_client_version(ctx.obj, ctx.command.name)
4758 ctx.obj.project.update(project, project_changes)
4759 # except ClientException as e:
4760 # print(str(e))
4761
4762
4763 ####################
4764 # User mgmt operations
4765 ####################
4766
4767
4768 @cli_osm.command(name="user-create", short_help="creates a new user")
4769 @click.argument("username")
4770 @click.option(
4771 "--password",
4772 prompt=True,
4773 hide_input=True,
4774 confirmation_prompt=True,
4775 help="user password",
4776 )
4777 @click.option(
4778 "--projects",
4779 # prompt="Comma separate list of projects",
4780 multiple=True,
4781 callback=lambda ctx, param, value: "".join(value).split(",")
4782 if all(len(x) == 1 for x in value)
4783 else value,
4784 help="list of project ids that the user belongs to",
4785 )
4786 @click.option(
4787 "--project-role-mappings",
4788 "project_role_mappings",
4789 default=None,
4790 multiple=True,
4791 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4792 )
4793 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
4794 @click.pass_context
4795 def user_create(ctx, username, password, projects, project_role_mappings, domain_name):
4796 """Creates a new user
4797
4798 \b
4799 USERNAME: name of the user
4800 PASSWORD: password of the user
4801 PROJECTS: projects assigned to user (internal only)
4802 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
4803 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
4804 """
4805 logger.debug("")
4806 user = {}
4807 user["username"] = username
4808 user["password"] = password
4809 user["projects"] = projects
4810 user["project_role_mappings"] = project_role_mappings
4811 if domain_name:
4812 user["domain_name"] = domain_name
4813
4814 # try:
4815 check_client_version(ctx.obj, ctx.command.name)
4816 ctx.obj.user.create(username, user)
4817 # except ClientException as e:
4818 # print(str(e))
4819 # exit(1)
4820
4821
4822 @cli_osm.command(name="user-update", short_help="updates user information")
4823 @click.argument("username")
4824 @click.option(
4825 "--password",
4826 # prompt=True,
4827 # hide_input=True,
4828 # confirmation_prompt=True,
4829 help="user password",
4830 )
4831 @click.option("--set-username", "set_username", default=None, help="change username")
4832 @click.option(
4833 "--set-project",
4834 "set_project",
4835 default=None,
4836 multiple=True,
4837 help="create/replace the roles for this project: 'project,role1[,role2,...]'",
4838 )
4839 @click.option(
4840 "--remove-project",
4841 "remove_project",
4842 default=None,
4843 multiple=True,
4844 help="removes project from user: 'project'",
4845 )
4846 @click.option(
4847 "--add-project-role",
4848 "add_project_role",
4849 default=None,
4850 multiple=True,
4851 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4852 )
4853 @click.option(
4854 "--remove-project-role",
4855 "remove_project_role",
4856 default=None,
4857 multiple=True,
4858 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4859 )
4860 @click.option(
4861 "--change_password",
4862 "change_password",
4863 help="user's current password"
4864 )
4865 @click.option(
4866 "--new_password",
4867 "new_password",
4868 help="user's new password to update in expiry condition"
4869 )
4870 @click.pass_context
4871 def user_update(
4872 ctx,
4873 username,
4874 password,
4875 set_username,
4876 set_project,
4877 remove_project,
4878 add_project_role,
4879 remove_project_role,
4880 change_password,
4881 new_password,
4882 ):
4883 """Update a user information
4884
4885 \b
4886 USERNAME: name of the user
4887 PASSWORD: new password
4888 SET_USERNAME: new username
4889 SET_PROJECT: creating mappings for project/role(s)
4890 REMOVE_PROJECT: deleting mappings for project/role(s)
4891 ADD_PROJECT_ROLE: adding mappings for project/role(s)
4892 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
4893 CHANGE_PASSWORD: user's current password to change
4894 NEW_PASSWORD: user's new password to update in expiry condition
4895 """
4896 logger.debug("")
4897 user = {}
4898 user["password"] = password
4899 user["username"] = set_username
4900 user["set-project"] = set_project
4901 user["remove-project"] = remove_project
4902 user["add-project-role"] = add_project_role
4903 user["remove-project-role"] = remove_project_role
4904 user["change_password"] = change_password
4905 user["new_password"] = new_password
4906
4907 # try:
4908 check_client_version(ctx.obj, ctx.command.name)
4909 if not user.get("change_password"):
4910 ctx.obj.user.update(username, user)
4911 else:
4912 ctx.obj.user.update(username, user, pwd_change=True)
4913 # except ClientException as e:
4914 # print(str(e))
4915 # exit(1)
4916
4917
4918 @cli_osm.command(name="user-delete", short_help="deletes a user")
4919 @click.argument("name")
4920 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4921 @click.pass_context
4922 def user_delete(ctx, name):
4923 """deletes a user
4924
4925 \b
4926 NAME: name or ID of the user to be deleted
4927 """
4928 logger.debug("")
4929 # try:
4930 check_client_version(ctx.obj, ctx.command.name)
4931 ctx.obj.user.delete(name)
4932 # except ClientException as e:
4933 # print(str(e))
4934 # exit(1)
4935
4936
4937 @cli_osm.command(name="user-list", short_help="list all users")
4938 @click.option(
4939 "--filter",
4940 default=None,
4941 multiple=True,
4942 help="restricts the list to the users matching the filter",
4943 )
4944 @click.pass_context
4945 def user_list(ctx, filter):
4946 """list all users"""
4947 # try:
4948 check_client_version(ctx.obj, ctx.command.name)
4949 if filter:
4950 filter = "&".join(filter)
4951 resp = ctx.obj.user.list(filter)
4952 # except ClientException as e:
4953 # print(str(e))
4954 # exit(1)
4955 table = PrettyTable(["name", "id"])
4956 for user in resp:
4957 table.add_row([user["username"], user["_id"]])
4958 table.align = "l"
4959 print(table)
4960
4961
4962 @cli_osm.command(name="user-show", short_help="shows the details of a user")
4963 @click.argument("name")
4964 @click.pass_context
4965 def user_show(ctx, name):
4966 """shows the details of a user
4967
4968 NAME: name or ID of the user
4969 """
4970 logger.debug("")
4971 # try:
4972 check_client_version(ctx.obj, ctx.command.name)
4973 resp = ctx.obj.user.get(name)
4974 if "password" in resp:
4975 resp["password"] = "********"
4976 # except ClientException as e:
4977 # print(str(e))
4978 # exit(1)
4979
4980 table = PrettyTable(["key", "attribute"])
4981 for k, v in resp.items():
4982 table.add_row([k, json.dumps(v, indent=2)])
4983 table.align = "l"
4984 print(table)
4985
4986
4987 ####################
4988 # Fault Management operations
4989 ####################
4990
4991
4992 @cli_osm.command(name="ns-alarm-create")
4993 @click.argument("name")
4994 @click.option("--ns", prompt=True, help="NS instance id or name")
4995 @click.option(
4996 "--vnf", prompt=True, help="VNF name (VNF member index as declared in the NSD)"
4997 )
4998 @click.option("--vdu", prompt=True, help="VDU name (VDU name as declared in the VNFD)")
4999 @click.option("--metric", prompt=True, help="Name of the metric (e.g. cpu_utilization)")
5000 @click.option(
5001 "--severity",
5002 default="WARNING",
5003 help="severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)",
5004 )
5005 @click.option(
5006 "--threshold_value",
5007 prompt=True,
5008 help="threshold value that, when crossed, an alarm is triggered",
5009 )
5010 @click.option(
5011 "--threshold_operator",
5012 prompt=True,
5013 help="threshold operator describing the comparison (GE, LE, GT, LT, EQ)",
5014 )
5015 @click.option(
5016 "--statistic",
5017 default="AVERAGE",
5018 help="statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)",
5019 )
5020 @click.pass_context
5021 def ns_alarm_create(
5022 ctx,
5023 name,
5024 ns,
5025 vnf,
5026 vdu,
5027 metric,
5028 severity,
5029 threshold_value,
5030 threshold_operator,
5031 statistic,
5032 ):
5033 """creates a new alarm for a NS instance"""
5034 # TODO: Check how to validate threshold_value.
5035 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
5036 logger.debug("")
5037 # try:
5038 ns_instance = ctx.obj.ns.get(ns)
5039 alarm = {}
5040 alarm["alarm_name"] = name
5041 alarm["ns_id"] = ns_instance["_id"]
5042 alarm["correlation_id"] = ns_instance["_id"]
5043 alarm["vnf_member_index"] = vnf
5044 alarm["vdu_name"] = vdu
5045 alarm["metric_name"] = metric
5046 alarm["severity"] = severity
5047 alarm["threshold_value"] = int(threshold_value)
5048 alarm["operation"] = threshold_operator
5049 alarm["statistic"] = statistic
5050 check_client_version(ctx.obj, ctx.command.name)
5051 ctx.obj.ns.create_alarm(alarm)
5052 # except ClientException as e:
5053 # print(str(e))
5054 # exit(1)
5055
5056
5057 # @cli_osm.command(name='ns-alarm-delete')
5058 # @click.argument('name')
5059 # @click.pass_context
5060 # def ns_alarm_delete(ctx, name):
5061 # """deletes an alarm
5062 #
5063 # NAME: name of the alarm to be deleted
5064 # """
5065 # try:
5066 # check_client_version(ctx.obj, ctx.command.name)
5067 # ctx.obj.ns.delete_alarm(name)
5068 # except ClientException as e:
5069 # print(str(e))
5070 # exit(1)
5071
5072
5073 ####################
5074 # Performance Management operations
5075 ####################
5076
5077
5078 @cli_osm.command(
5079 name="ns-metric-export",
5080 short_help="exports a metric to the internal OSM bus, which can be read by other apps",
5081 )
5082 @click.option("--ns", prompt=True, help="NS instance id or name")
5083 @click.option(
5084 "--vnf", prompt=True, help="VNF name (VNF member index as declared in the NSD)"
5085 )
5086 @click.option("--vdu", prompt=True, help="VDU name (VDU name as declared in the VNFD)")
5087 @click.option("--metric", prompt=True, help="name of the metric (e.g. cpu_utilization)")
5088 # @click.option('--period', default='1w',
5089 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
5090 @click.option(
5091 "--interval", help="periodic interval (seconds) to export metrics continuously"
5092 )
5093 @click.pass_context
5094 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
5095 """exports a metric to the internal OSM bus, which can be read by other apps"""
5096 # TODO: Check how to validate interval.
5097 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
5098 logger.debug("")
5099 # try:
5100 ns_instance = ctx.obj.ns.get(ns)
5101 metric_data = {}
5102 metric_data["ns_id"] = ns_instance["_id"]
5103 metric_data["correlation_id"] = ns_instance["_id"]
5104 metric_data["vnf_member_index"] = vnf
5105 metric_data["vdu_name"] = vdu
5106 metric_data["metric_name"] = metric
5107 metric_data["collection_unit"] = "WEEK"
5108 metric_data["collection_period"] = 1
5109 check_client_version(ctx.obj, ctx.command.name)
5110 if not interval:
5111 print("{}".format(ctx.obj.ns.export_metric(metric_data)))
5112 else:
5113 i = 1
5114 while True:
5115 print("{} {}".format(ctx.obj.ns.export_metric(metric_data), i))
5116 time.sleep(int(interval))
5117 i += 1
5118 # except ClientException as e:
5119 # print(str(e))
5120 # exit(1)
5121
5122
5123 #################
5124 # Subscription operations
5125 #################
5126
5127
5128 @cli_osm.command(
5129 name="subscription-create",
5130 short_help="creates a new subscription to a specific event",
5131 )
5132 @click.option(
5133 "--event_type",
5134 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5135 type=click.Choice(["ns"], case_sensitive=False),
5136 help="event type to be subscribed (for the moment, only ns is supported)",
5137 )
5138 @click.option("--event", default=None, help="specific yaml configuration for the event")
5139 @click.option(
5140 "--event_file", default=None, help="specific yaml configuration file for the event"
5141 )
5142 @click.pass_context
5143 def subscription_create(ctx, event_type, event, event_file):
5144 """creates a new subscription to a specific event"""
5145 logger.debug("")
5146 check_client_version(ctx.obj, ctx.command.name)
5147 if event_file:
5148 if event:
5149 raise ClientException(
5150 '"--event" option is incompatible with "--event_file" option'
5151 )
5152 with open(event_file, "r") as cf:
5153 event = cf.read()
5154 ctx.obj.subscription.create(event_type, event)
5155
5156
5157 @cli_osm.command(name="subscription-delete", short_help="deletes a subscription")
5158 @click.option(
5159 "--event_type",
5160 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5161 type=click.Choice(["ns"], case_sensitive=False),
5162 help="event type to be subscribed (for the moment, only ns is supported)",
5163 )
5164 @click.argument("subscription_id")
5165 @click.option(
5166 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
5167 )
5168 @click.pass_context
5169 def subscription_delete(ctx, event_type, subscription_id, force):
5170 """deletes a subscription
5171
5172 SUBSCRIPTION_ID: ID of the subscription to be deleted
5173 """
5174 logger.debug("")
5175 check_client_version(ctx.obj, ctx.command.name)
5176 ctx.obj.subscription.delete(event_type, subscription_id, force)
5177
5178
5179 @cli_osm.command(name="subscription-list", short_help="list all subscriptions")
5180 @click.option(
5181 "--event_type",
5182 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5183 type=click.Choice(["ns"], case_sensitive=False),
5184 help="event type to be subscribed (for the moment, only ns is supported)",
5185 )
5186 @click.option(
5187 "--filter",
5188 default=None,
5189 multiple=True,
5190 help="restricts the list to the subscriptions matching the filter",
5191 )
5192 @click.pass_context
5193 def subscription_list(ctx, event_type, filter):
5194 """list all subscriptions"""
5195 logger.debug("")
5196 check_client_version(ctx.obj, ctx.command.name)
5197 if filter:
5198 filter = "&".join(filter)
5199 resp = ctx.obj.subscription.list(event_type, filter)
5200 table = PrettyTable(["id", "filter", "CallbackUri"])
5201 for sub in resp:
5202 table.add_row(
5203 [
5204 sub["_id"],
5205 wrap_text(text=json.dumps(sub["filter"], indent=2), width=70),
5206 sub["CallbackUri"],
5207 ]
5208 )
5209 table.align = "l"
5210 print(table)
5211
5212
5213 @cli_osm.command(
5214 name="subscription-show", short_help="shows the details of a subscription"
5215 )
5216 @click.argument("subscription_id")
5217 @click.option(
5218 "--event_type",
5219 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5220 type=click.Choice(["ns"], case_sensitive=False),
5221 help="event type to be subscribed (for the moment, only ns is supported)",
5222 )
5223 @click.option(
5224 "--filter",
5225 multiple=True,
5226 help="restricts the information to the fields in the filter",
5227 )
5228 @click.pass_context
5229 def subscription_show(ctx, event_type, subscription_id, filter):
5230 """shows the details of a subscription
5231
5232 SUBSCRIPTION_ID: ID of the subscription
5233 """
5234 logger.debug("")
5235 # try:
5236 resp = ctx.obj.subscription.get(subscription_id)
5237 table = PrettyTable(["key", "attribute"])
5238 for k, v in list(resp.items()):
5239 if not filter or k in filter:
5240 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
5241 table.align = "l"
5242 print(table)
5243
5244
5245 ####################
5246 # Other operations
5247 ####################
5248
5249
5250 @cli_osm.command(name="version", short_help="shows client and server versions")
5251 @click.pass_context
5252 def get_version(ctx):
5253 """shows client and server versions"""
5254 # try:
5255 check_client_version(ctx.obj, "version")
5256 print("Server version: {}".format(ctx.obj.get_version()))
5257 print(
5258 "Client version: {}".format(pkg_resources.get_distribution("osmclient").version)
5259 )
5260 # except ClientException as e:
5261 # print(str(e))
5262 # exit(1)
5263
5264
5265 @cli_osm.command(
5266 name="upload-package", short_help="uploads a VNF package or NS package"
5267 )
5268 @click.argument("filename")
5269 @click.option(
5270 "--skip-charm-build",
5271 default=False,
5272 is_flag=True,
5273 help="the charm will not be compiled, it is assumed to already exist",
5274 )
5275 @click.pass_context
5276 def upload_package(ctx, filename, skip_charm_build):
5277 """uploads a vnf package or ns package
5278
5279 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
5280 """
5281 logger.debug("")
5282 # try:
5283 ctx.obj.package.upload(filename, skip_charm_build=skip_charm_build)
5284 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
5285 if fullclassname != "osmclient.sol005.client.Client":
5286 ctx.obj.package.wait_for_upload(filename)
5287 # except ClientException as e:
5288 # print(str(e))
5289 # exit(1)
5290
5291
5292 # @cli_osm.command(name='ns-scaling-show')
5293 # @click.argument('ns_name')
5294 # @click.pass_context
5295 # def show_ns_scaling(ctx, ns_name):
5296 # """shows the status of a NS scaling operation
5297 #
5298 # NS_NAME: name of the NS instance being scaled
5299 # """
5300 # try:
5301 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5302 # resp = ctx.obj.ns.list()
5303 # except ClientException as e:
5304 # print(str(e))
5305 # exit(1)
5306 #
5307 # table = PrettyTable(
5308 # ['group-name',
5309 # 'instance-id',
5310 # 'operational status',
5311 # 'create-time',
5312 # 'vnfr ids'])
5313 #
5314 # for ns in resp:
5315 # if ns_name == ns['name']:
5316 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
5317 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
5318 # for record in scaling_records:
5319 # if 'instance' in record:
5320 # instances = record['instance']
5321 # for inst in instances:
5322 # table.add_row(
5323 # [record['scaling-group-name-ref'],
5324 # inst['instance-id'],
5325 # inst['op-status'],
5326 # time.strftime('%Y-%m-%d %H:%M:%S',
5327 # time.localtime(
5328 # inst['create-time'])),
5329 # inst['vnfrs']])
5330 # table.align = 'l'
5331 # print(table)
5332
5333
5334 # @cli_osm.command(name='ns-scale')
5335 # @click.argument('ns_name')
5336 # @click.option('--ns_scale_group', prompt=True)
5337 # @click.option('--index', prompt=True)
5338 # @click.option('--wait',
5339 # required=False,
5340 # default=False,
5341 # is_flag=True,
5342 # help='do not return the control immediately, but keep it \
5343 # until the operation is completed, or timeout')
5344 # @click.pass_context
5345 # def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
5346 # """scales NS
5347 #
5348 # NS_NAME: name of the NS instance to be scaled
5349 # """
5350 # try:
5351 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5352 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
5353 # except ClientException as e:
5354 # print(str(e))
5355 # exit(1)
5356
5357
5358 # @cli_osm.command(name='config-agent-list')
5359 # @click.pass_context
5360 # def config_agent_list(ctx):
5361 # """list config agents"""
5362 # try:
5363 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5364 # except ClientException as e:
5365 # print(str(e))
5366 # exit(1)
5367 # table = PrettyTable(['name', 'account-type', 'details'])
5368 # for account in ctx.obj.vca.list():
5369 # table.add_row(
5370 # [account['name'],
5371 # account['account-type'],
5372 # account['juju']])
5373 # table.align = 'l'
5374 # print(table)
5375
5376
5377 # @cli_osm.command(name='config-agent-delete')
5378 # @click.argument('name')
5379 # @click.pass_context
5380 # def config_agent_delete(ctx, name):
5381 # """deletes a config agent
5382 #
5383 # NAME: name of the config agent to be deleted
5384 # """
5385 # try:
5386 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5387 # ctx.obj.vca.delete(name)
5388 # except ClientException as e:
5389 # print(str(e))
5390 # exit(1)
5391
5392
5393 # @cli_osm.command(name='config-agent-add')
5394 # @click.option('--name',
5395 # prompt=True)
5396 # @click.option('--account_type',
5397 # prompt=True)
5398 # @click.option('--server',
5399 # prompt=True)
5400 # @click.option('--user',
5401 # prompt=True)
5402 # @click.option('--secret',
5403 # prompt=True,
5404 # hide_input=True,
5405 # confirmation_prompt=True)
5406 # @click.pass_context
5407 # def config_agent_add(ctx, name, account_type, server, user, secret):
5408 # """adds a config agent"""
5409 # try:
5410 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5411 # ctx.obj.vca.create(name, account_type, server, user, secret)
5412 # except ClientException as e:
5413 # print(str(e))
5414 # exit(1)
5415
5416
5417 # @cli_osm.command(name='ro-dump')
5418 # @click.pass_context
5419 # def ro_dump(ctx):
5420 # """shows RO agent information"""
5421 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5422 # resp = ctx.obj.vim.get_resource_orchestrator()
5423 # table = PrettyTable(['key', 'attribute'])
5424 # for k, v in list(resp.items()):
5425 # table.add_row([k, json.dumps(v, indent=2)])
5426 # table.align = 'l'
5427 # print(table)
5428
5429
5430 # @cli_osm.command(name='vcs-list')
5431 # @click.pass_context
5432 # def vcs_list(ctx):
5433 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5434 # resp = ctx.obj.utils.get_vcs_info()
5435 # table = PrettyTable(['component name', 'state'])
5436 # for component in resp:
5437 # table.add_row([component['component_name'], component['state']])
5438 # table.align = 'l'
5439 # print(table)
5440
5441
5442 @cli_osm.command(
5443 name="ns-action", short_help="executes an action/primitive over a NS instance"
5444 )
5445 @click.argument("ns_name")
5446 @click.option(
5447 "--vnf_name",
5448 default=None,
5449 help="member-vnf-index if the target is a vnf instead of a ns)",
5450 )
5451 @click.option("--kdu_name", default=None, help="kdu-name if the target is a kdu)")
5452 @click.option("--vdu_id", default=None, help="vdu-id if the target is a vdu")
5453 @click.option(
5454 "--vdu_count", default=None, type=int, help="number of vdu instance of this vdu_id"
5455 )
5456 @click.option("--action_name", prompt=True, help="action name")
5457 @click.option("--params", default=None, help="action params in YAML/JSON inline string")
5458 @click.option("--params_file", default=None, help="YAML/JSON file with action params")
5459 @click.option(
5460 "--timeout", required=False, default=None, type=int, help="timeout in seconds"
5461 )
5462 @click.option(
5463 "--wait",
5464 required=False,
5465 default=False,
5466 is_flag=True,
5467 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5468 )
5469 @click.pass_context
5470 def ns_action(
5471 ctx,
5472 ns_name,
5473 vnf_name,
5474 kdu_name,
5475 vdu_id,
5476 vdu_count,
5477 action_name,
5478 params,
5479 params_file,
5480 timeout,
5481 wait,
5482 ):
5483 """executes an action/primitive over a NS instance
5484
5485 NS_NAME: name or ID of the NS instance
5486 """
5487 logger.debug("")
5488 # try:
5489 check_client_version(ctx.obj, ctx.command.name)
5490 op_data = {}
5491 if vnf_name:
5492 op_data["member_vnf_index"] = vnf_name
5493 if kdu_name:
5494 op_data["kdu_name"] = kdu_name
5495 if vdu_id:
5496 op_data["vdu_id"] = vdu_id
5497 if vdu_count is not None:
5498 op_data["vdu_count_index"] = vdu_count
5499 if timeout:
5500 op_data["timeout_ns_action"] = timeout
5501 op_data["primitive"] = action_name
5502 if params_file:
5503 with open(params_file, "r") as pf:
5504 params = pf.read()
5505 if params:
5506 op_data["primitive_params"] = yaml.safe_load(params)
5507 else:
5508 op_data["primitive_params"] = {}
5509 print(ctx.obj.ns.exec_op(ns_name, op_name="action", op_data=op_data, wait=wait))
5510
5511 # except ClientException as e:
5512 # print(str(e))
5513 # exit(1)
5514
5515
5516 @cli_osm.command(
5517 name="vnf-scale", short_help="executes a VNF scale (adding/removing VDUs)"
5518 )
5519 @click.argument("ns_name")
5520 @click.argument("vnf_name")
5521 @click.option(
5522 "--scaling-group", prompt=True, help="scaling-group-descriptor name to use"
5523 )
5524 @click.option(
5525 "--scale-in", default=False, is_flag=True, help="performs a scale in operation"
5526 )
5527 @click.option(
5528 "--scale-out",
5529 default=False,
5530 is_flag=True,
5531 help="performs a scale out operation (by default)",
5532 )
5533 @click.option(
5534 "--timeout", required=False, default=None, type=int, help="timeout in seconds"
5535 )
5536 @click.option(
5537 "--wait",
5538 required=False,
5539 default=False,
5540 is_flag=True,
5541 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5542 )
5543 @click.pass_context
5544 def vnf_scale(
5545 ctx, ns_name, vnf_name, scaling_group, scale_in, scale_out, timeout, wait
5546 ):
5547 """
5548 Executes a VNF scale (adding/removing VDUs)
5549
5550 \b
5551 NS_NAME: name or ID of the NS instance.
5552 VNF_NAME: member-vnf-index in the NS to be scaled.
5553 """
5554 logger.debug("")
5555 # try:
5556 check_client_version(ctx.obj, ctx.command.name)
5557 if not scale_in and not scale_out:
5558 scale_out = True
5559 ctx.obj.ns.scale_vnf(
5560 ns_name, vnf_name, scaling_group, scale_in, scale_out, wait, timeout
5561 )
5562 # except ClientException as e:
5563 # print(str(e))
5564 # exit(1)
5565
5566
5567 @cli_osm.command(
5568 name="ns-update", short_help="executes an update of a Network Service."
5569 )
5570 @click.argument("ns_name")
5571 @click.option(
5572 "--updatetype", required=True, type=str, help="available types: CHANGE_VNFPKG"
5573 )
5574 @click.option(
5575 "--config",
5576 required=True,
5577 type=str,
5578 help="extra information for update operation as YAML/JSON inline string as --config"
5579 " '{changeVnfPackageData:[{vnfInstanceId: xxx, vnfdId: yyy}]}'",
5580 )
5581 @click.option(
5582 "--timeout", required=False, default=None, type=int, help="timeout in seconds"
5583 )
5584 @click.option(
5585 "--wait",
5586 required=False,
5587 default=False,
5588 is_flag=True,
5589 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5590 )
5591 @click.pass_context
5592 def update(ctx, ns_name, updatetype, config, timeout, wait):
5593 """Executes an update of a Network Service.
5594
5595 The update will check new revisions of the Network Functions that are part of the
5596 Network Service, and it will update them if needed.
5597 Sample update command: osm ns-update ns_instance_id --updatetype CHANGE_VNFPKG
5598 --config '{changeVnfPackageData: [{vnfInstanceId: id_x,vnfdId: id_y}]}' --timeout 300 --wait
5599
5600 NS_NAME: Network service instance name or ID.
5601
5602 """
5603 op_data = {
5604 "timeout": timeout,
5605 "updateType": updatetype,
5606 }
5607 if config:
5608 op_data["config"] = yaml.safe_load(config)
5609
5610 check_client_version(ctx.obj, ctx.command.name)
5611 ctx.obj.ns.update(ns_name, op_data, wait=wait)
5612
5613
5614 @cli_osm.command(name="alarm-show", short_help="show alarm details")
5615 @click.argument("uuid")
5616 @click.pass_context
5617 def alarm_show(ctx, uuid):
5618 """Show alarm's detail information"""
5619
5620 check_client_version(ctx.obj, ctx.command.name)
5621 resp = ctx.obj.ns.get_alarm(uuid=uuid)
5622 alarm_filter = [
5623 "uuid",
5624 "name",
5625 "metric",
5626 "statistic",
5627 "threshold",
5628 "operation",
5629 "ns-id",
5630 "vnf-id",
5631 "vdu_name",
5632 "action",
5633 "status",
5634 ]
5635 table = PrettyTable(["key", "attribute"])
5636 try:
5637 # Arrange and return the response data
5638 resp = resp.replace("ObjectId", "")
5639 alarm = eval(resp)
5640 for key in alarm_filter:
5641 if key == "uuid":
5642 value = alarm.get(key)
5643 key = "alarm-id"
5644 elif key == "name":
5645 value = alarm.get(key)
5646 key = "alarm-name"
5647 elif key == "ns-id":
5648 value = alarm["tags"].get("ns_id")
5649 elif key == "vdu_name":
5650 value = alarm["tags"].get("vdu_name")
5651 elif key == "status":
5652 value = alarm["alarm_status"]
5653 else:
5654 value = alarm[key]
5655 table.add_row([key, wrap_text(text=json.dumps(value, indent=2), width=100)])
5656 table.align = "l"
5657 print(table)
5658 except Exception:
5659 print(resp)
5660
5661
5662 # List alarm
5663 @cli_osm.command(name="alarm-list", short_help="list all alarms")
5664 @click.option(
5665 "--ns_id", default=None, required=False, help="List out alarm for given ns id"
5666 )
5667 @click.pass_context
5668 def alarm_list(ctx, ns_id):
5669 """list all alarm"""
5670
5671 check_client_version(ctx.obj, ctx.command.name)
5672 project_name = os.getenv("OSM_PROJECT", "admin")
5673 resp = ctx.obj.ns.get_alarm(project_name=project_name, ns_id=ns_id)
5674
5675 table = PrettyTable(
5676 ["alarm-id", "metric", "threshold", "operation", "action", "status"]
5677 )
5678 if resp:
5679 # return the response data in a table
5680 resp = resp.replace("ObjectId", "")
5681 resp = eval(resp)
5682 for alarm in resp:
5683 table.add_row(
5684 [
5685 wrap_text(text=str(alarm["uuid"]), width=38),
5686 alarm["metric"],
5687 alarm["threshold"],
5688 alarm["operation"],
5689 wrap_text(text=alarm["action"], width=25),
5690 alarm["alarm_status"],
5691 ]
5692 )
5693 table.align = "l"
5694 print(table)
5695
5696
5697 # Update alarm
5698 @cli_osm.command(name="alarm-update", short_help="Update a alarm")
5699 @click.argument("uuid")
5700 @click.option("--threshold", default=None, help="Alarm threshold")
5701 @click.option("--is_enable", default=None, type=bool, help="enable or disable alarm")
5702 @click.pass_context
5703 def alarm_update(ctx, uuid, threshold, is_enable):
5704 """
5705 Update alarm
5706
5707 """
5708 if not threshold and is_enable is None:
5709 raise ClientException(
5710 "Please provide option to update i.e threshold or is_enable"
5711 )
5712 ctx.obj.ns.update_alarm(uuid, threshold, is_enable)
5713
5714
5715 ##############################
5716 # Role Management Operations #
5717 ##############################
5718
5719
5720 @cli_osm.command(name="role-create", short_help="creates a new role")
5721 @click.argument("name")
5722 @click.option("--permissions", default=None, help="role permissions using a dictionary")
5723 @click.pass_context
5724 def role_create(ctx, name, permissions):
5725 """
5726 Creates a new role.
5727
5728 \b
5729 NAME: Name or ID of the role.
5730 DEFINITION: Definition of grant/denial of access to resources.
5731 """
5732 logger.debug("")
5733 # try:
5734 check_client_version(ctx.obj, ctx.command.name)
5735 ctx.obj.role.create(name, permissions)
5736 # except ClientException as e:
5737 # print(str(e))
5738 # exit(1)
5739
5740
5741 @cli_osm.command(name="role-update", short_help="updates a role")
5742 @click.argument("name")
5743 @click.option("--set-name", default=None, help="change name of rle")
5744 # @click.option('--permissions',
5745 # default=None,
5746 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
5747 @click.option(
5748 "--add",
5749 default=None,
5750 help="yaml format dictionary with permission: True/False to access grant/denial",
5751 )
5752 @click.option("--remove", default=None, help="yaml format list to remove a permission")
5753 @click.pass_context
5754 def role_update(ctx, name, set_name, add, remove):
5755 """
5756 Updates a role.
5757
5758 \b
5759 NAME: Name or ID of the role.
5760 DEFINITION: Definition overwrites the old definition.
5761 ADD: Grant/denial of access to resource to add.
5762 REMOVE: Grant/denial of access to resource to remove.
5763 """
5764 logger.debug("")
5765 # try:
5766 check_client_version(ctx.obj, ctx.command.name)
5767 ctx.obj.role.update(name, set_name, None, add, remove)
5768 # except ClientException as e:
5769 # print(str(e))
5770 # exit(1)
5771
5772
5773 @cli_osm.command(name="role-delete", short_help="deletes a role")
5774 @click.argument("name")
5775 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
5776 @click.pass_context
5777 def role_delete(ctx, name):
5778 """
5779 Deletes a role.
5780
5781 \b
5782 NAME: Name or ID of the role.
5783 """
5784 logger.debug("")
5785 # try:
5786 check_client_version(ctx.obj, ctx.command.name)
5787 ctx.obj.role.delete(name)
5788 # except ClientException as e:
5789 # print(str(e))
5790 # exit(1)
5791
5792
5793 @cli_osm.command(name="role-list", short_help="list all roles")
5794 @click.option(
5795 "--filter",
5796 default=None,
5797 multiple=True,
5798 help="restricts the list to the projects matching the filter",
5799 )
5800 @click.pass_context
5801 def role_list(ctx, filter):
5802 """
5803 List all roles.
5804 """
5805 logger.debug("")
5806 # try:
5807 check_client_version(ctx.obj, ctx.command.name)
5808 if filter:
5809 filter = "&".join(filter)
5810 resp = ctx.obj.role.list(filter)
5811 # except ClientException as e:
5812 # print(str(e))
5813 # exit(1)
5814 table = PrettyTable(["name", "id"])
5815 for role in resp:
5816 table.add_row([role["name"], role["_id"]])
5817 table.align = "l"
5818 print(table)
5819
5820
5821 @cli_osm.command(name="role-show", short_help="show specific role")
5822 @click.argument("name")
5823 @click.pass_context
5824 def role_show(ctx, name):
5825 """
5826 Shows the details of a role.
5827
5828 \b
5829 NAME: Name or ID of the role.
5830 """
5831 logger.debug("")
5832 # try:
5833 check_client_version(ctx.obj, ctx.command.name)
5834 resp = ctx.obj.role.get(name)
5835 # except ClientException as e:
5836 # print(str(e))
5837 # exit(1)
5838
5839 table = PrettyTable(["key", "attribute"])
5840 for k, v in resp.items():
5841 table.add_row([k, json.dumps(v, indent=2)])
5842 table.align = "l"
5843 print(table)
5844
5845
5846 @cli_osm.command(name="package-create", short_help="Create empty NS package structure")
5847 @click.argument("package-type")
5848 @click.argument("package-name")
5849 @click.option(
5850 "--base-directory",
5851 default=".",
5852 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'),
5853 )
5854 @click.option(
5855 "--image",
5856 default="image-name",
5857 help='(VNF) Set the name of the vdu image. Default "image-name"',
5858 )
5859 @click.option(
5860 "--vdus", default=1, help="(VNF) Set the number of vdus in a VNF. Default 1"
5861 )
5862 @click.option(
5863 "--vcpu", default=1, help="(VNF) Set the number of virtual CPUs in a vdu. Default 1"
5864 )
5865 @click.option(
5866 "--memory",
5867 default=1024,
5868 help="(VNF) Set the memory size (MB) of the vdu. Default 1024",
5869 )
5870 @click.option(
5871 "--storage", default=10, help="(VNF) Set the disk size (GB) of the vdu. Default 10"
5872 )
5873 @click.option(
5874 "--interfaces",
5875 default=0,
5876 help="(VNF) Set the number of additional interfaces apart from the management interface. Default 0",
5877 )
5878 @click.option(
5879 "--vendor", default="OSM", help='(NS/VNF) Set the descriptor vendor. Default "OSM"'
5880 )
5881 @click.option(
5882 "--override",
5883 default=False,
5884 is_flag=True,
5885 help="(NS/VNF/NST) Flag for overriding the package if exists.",
5886 )
5887 @click.option(
5888 "--detailed",
5889 is_flag=True,
5890 default=False,
5891 help="(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options",
5892 )
5893 @click.option(
5894 "--netslice-subnets", default=1, help="(NST) Number of netslice subnets. Default 1"
5895 )
5896 @click.option(
5897 "--netslice-vlds", default=1, help="(NST) Number of netslice vlds. Default 1"
5898 )
5899 @click.option(
5900 "--old",
5901 default=False,
5902 is_flag=True,
5903 help="Flag to create a descriptor using the previous OSM format (pre SOL006, OSM<9)",
5904 )
5905 @click.pass_context
5906 def package_create(
5907 ctx,
5908 package_type,
5909 base_directory,
5910 package_name,
5911 override,
5912 image,
5913 vdus,
5914 vcpu,
5915 memory,
5916 storage,
5917 interfaces,
5918 vendor,
5919 detailed,
5920 netslice_subnets,
5921 netslice_vlds,
5922 old,
5923 ):
5924 """
5925 Creates an OSM NS, VNF, NST package
5926
5927 \b
5928 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
5929 PACKAGE_NAME: Name of the package to create the folder with the content.
5930 """
5931
5932 # try:
5933 logger.debug("")
5934 check_client_version(ctx.obj, ctx.command.name)
5935 print(
5936 "Creating the {} structure: {}/{}".format(
5937 package_type.upper(), base_directory, package_name
5938 )
5939 )
5940 resp = ctx.obj.package_tool.create(
5941 package_type,
5942 base_directory,
5943 package_name,
5944 override=override,
5945 image=image,
5946 vdus=vdus,
5947 vcpu=vcpu,
5948 memory=memory,
5949 storage=storage,
5950 interfaces=interfaces,
5951 vendor=vendor,
5952 detailed=detailed,
5953 netslice_subnets=netslice_subnets,
5954 netslice_vlds=netslice_vlds,
5955 old=old,
5956 )
5957 print(resp)
5958 # except ClientException as inst:
5959 # print("ERROR: {}".format(inst))
5960 # exit(1)
5961
5962
5963 @cli_osm.command(
5964 name="package-validate", short_help="Validate descriptors given a base directory"
5965 )
5966 @click.argument("base-directory", default=".", required=False)
5967 @click.option(
5968 "--recursive/--no-recursive",
5969 default=True,
5970 help="The activated recursive option will validate the yaml files"
5971 " within the indicated directory and in its subdirectories",
5972 )
5973 @click.option(
5974 "--old",
5975 is_flag=True,
5976 default=False,
5977 help="Validates also the descriptors using the previous OSM format (pre SOL006)",
5978 )
5979 @click.pass_context
5980 def package_validate(ctx, base_directory, recursive, old):
5981 """
5982 Validate descriptors given a base directory.
5983
5984 \b
5985 BASE_DIRECTORY: Base folder for NS, VNF or NST package.
5986 """
5987 # try:
5988 logger.debug("")
5989 check_client_version(ctx.obj, ctx.command.name)
5990 results = ctx.obj.package_tool.validate(base_directory, recursive, old)
5991 table = PrettyTable()
5992 table.field_names = ["TYPE", "PATH", "VALID", "ERROR"]
5993 # Print the dictionary generated by the validation function
5994 for result in results:
5995 table.add_row(
5996 [result["type"], result["path"], result["valid"], result["error"]]
5997 )
5998 table.sortby = "VALID"
5999 table.align["PATH"] = "l"
6000 table.align["TYPE"] = "l"
6001 table.align["ERROR"] = "l"
6002 print(table)
6003 # except ClientException as inst:
6004 # print("ERROR: {}".format(inst))
6005 # exit(1)
6006
6007
6008 @cli_osm.command(
6009 name="package-translate", short_help="Translate descriptors given a base directory"
6010 )
6011 @click.argument("base-directory", default=".", required=False)
6012 @click.option(
6013 "--recursive/--no-recursive",
6014 default=True,
6015 help="The activated recursive option will translate the yaml files"
6016 " within the indicated directory and in its subdirectories",
6017 )
6018 @click.option(
6019 "--dryrun",
6020 is_flag=True,
6021 default=False,
6022 help="Do not translate yet, only make a dry-run to test translation",
6023 )
6024 @click.pass_context
6025 def package_translate(ctx, base_directory, recursive, dryrun):
6026 """
6027 Translate descriptors given a base directory.
6028
6029 \b
6030 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
6031 """
6032 logger.debug("")
6033 check_client_version(ctx.obj, ctx.command.name)
6034 results = ctx.obj.package_tool.translate(base_directory, recursive, dryrun)
6035 table = PrettyTable()
6036 table.field_names = [
6037 "CURRENT TYPE",
6038 "NEW TYPE",
6039 "PATH",
6040 "VALID",
6041 "TRANSLATED",
6042 "ERROR",
6043 ]
6044 # Print the dictionary generated by the validation function
6045 for result in results:
6046 table.add_row(
6047 [
6048 result["current type"],
6049 result["new type"],
6050 result["path"],
6051 result["valid"],
6052 result["translated"],
6053 result["error"],
6054 ]
6055 )
6056 table.sortby = "TRANSLATED"
6057 table.align["PATH"] = "l"
6058 table.align["TYPE"] = "l"
6059 table.align["ERROR"] = "l"
6060 print(table)
6061 # except ClientException as inst:
6062 # print("ERROR: {}".format(inst))
6063 # exit(1)
6064
6065
6066 @cli_osm.command(name="package-build", short_help="Build the tar.gz of the package")
6067 @click.argument("package-folder")
6068 @click.option(
6069 "--skip-validation", default=False, is_flag=True, help="skip package validation"
6070 )
6071 @click.option(
6072 "--skip-charm-build",
6073 default=False,
6074 is_flag=True,
6075 help="the charm will not be compiled, it is assumed to already exist",
6076 )
6077 @click.pass_context
6078 def package_build(ctx, package_folder, skip_validation, skip_charm_build):
6079 """
6080 Build the package NS, VNF given the package_folder.
6081
6082 \b
6083 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
6084 """
6085 # try:
6086 logger.debug("")
6087 check_client_version(ctx.obj, ctx.command.name)
6088 results = ctx.obj.package_tool.build(
6089 package_folder,
6090 skip_validation=skip_validation,
6091 skip_charm_build=skip_charm_build,
6092 )
6093 print(results)
6094 # except ClientException as inst:
6095 # print("ERROR: {}".format(inst))
6096 # exit(1)
6097
6098
6099 @cli_osm.command(
6100 name="descriptor-translate",
6101 short_help="Translate input descriptor file from Rel EIGHT OSM descriptors to SOL006 and prints in standard output",
6102 )
6103 @click.argument("descriptor-file", required=True)
6104 @click.pass_context
6105 def descriptor_translate(ctx, descriptor_file):
6106 """
6107 Translate input descriptor.
6108
6109 \b
6110 DESCRIPTOR_FILE: Descriptor file for NS, VNF or Network Slice.
6111 """
6112 logger.debug("")
6113 check_client_version(ctx.obj, ctx.command.name)
6114 result = ctx.obj.package_tool.descriptor_translate(descriptor_file)
6115 print(result)
6116
6117
6118 def cli():
6119 try:
6120 cli_osm()
6121 exit(0)
6122 except pycurl.error as exc:
6123 print(exc)
6124 print(
6125 'Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified'
6126 )
6127 except ClientException as exc:
6128 print("ERROR: {}".format(exc))
6129 except (FileNotFoundError, PermissionError) as exc:
6130 print("Cannot open file: {}".format(exc))
6131 except yaml.YAMLError as exc:
6132 print("Invalid YAML format: {}".format(exc))
6133 exit(1)
6134 # TODO capture other controlled exceptions here
6135 # TODO remove the ClientException captures from all places, unless they do something different
6136
6137
6138 if __name__ == "__main__":
6139 cli()