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