Code Coverage

Cobertura Coverage Report > osmclient.scripts >

osm.py

Trend

File Coverage summary

NameClassesLinesConditionals
osm.py
100%
1/1
41%
1076/2612
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
osm.py
41%
1076/2612
N/A

Source

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