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