feb8c2f9e03f47ce5ea8bf43dd5a781a24bc7a57
[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",
2568 multiple=True,
2569 )
2570 @click.option(
2571 "--descriptor_file",
2572 default=None,
2573 help="PDU descriptor file (as an alternative to using the other arguments",
2574 )
2575 @click.pass_context
2576 def pdu_create(
2577 ctx, name, pdu_type, interface, description, vim_account, descriptor_file
2578 ):
2579 """creates a new Physical Deployment Unit (PDU)"""
2580 logger.debug("")
2581 # try:
2582 check_client_version(ctx.obj, ctx.command.name)
2583 pdu = {}
2584 if not descriptor_file:
2585 if not name:
2586 raise ClientException(
2587 'in absence of descriptor file, option "--name" is mandatory'
2588 )
2589 if not pdu_type:
2590 raise ClientException(
2591 'in absence of descriptor file, option "--pdu_type" is mandatory'
2592 )
2593 if not interface:
2594 raise ClientException(
2595 'in absence of descriptor file, option "--interface" is mandatory (at least once)'
2596 )
2597 if not vim_account:
2598 raise ClientException(
2599 'in absence of descriptor file, option "--vim_account" is mandatory (at least once)'
2600 )
2601 else:
2602 with open(descriptor_file, "r") as df:
2603 pdu = yaml.safe_load(df.read())
2604 if name:
2605 pdu["name"] = name
2606 if pdu_type:
2607 pdu["type"] = pdu_type
2608 if description:
2609 pdu["description"] = description
2610 if vim_account:
2611 pdu["vim_accounts"] = vim_account
2612 if interface:
2613 ifaces_list = []
2614 for iface in interface:
2615 new_iface = {k: v for k, v in [i.split("=") for i in iface.split(",")]}
2616 new_iface["mgmt"] = new_iface.get("mgmt", "false").lower() == "true"
2617 ifaces_list.append(new_iface)
2618 pdu["interfaces"] = ifaces_list
2619 ctx.obj.pdu.create(pdu)
2620 # except ClientException as e:
2621 # print(str(e))
2622 # exit(1)
2623
2624
2625 ####################
2626 # UPDATE operations
2627 ####################
2628
2629
2630 def nsd_update(ctx, name, content):
2631 logger.debug("")
2632 # try:
2633 check_client_version(ctx.obj, ctx.command.name)
2634 ctx.obj.nsd.update(name, content)
2635 # except ClientException as e:
2636 # print(str(e))
2637 # exit(1)
2638
2639
2640 @cli_osm.command(name="nsd-update", short_help="updates a NSD/NSpkg")
2641 @click.argument("name")
2642 @click.option(
2643 "--content",
2644 default=None,
2645 help="filename with the NSD/NSpkg replacing the current one",
2646 )
2647 @click.pass_context
2648 def nsd_update1(ctx, name, content):
2649 """updates a NSD/NSpkg
2650
2651 NAME: name or ID of the NSD/NSpkg
2652 """
2653 logger.debug("")
2654 nsd_update(ctx, name, content)
2655
2656
2657 @cli_osm.command(name="nspkg-update", short_help="updates a NSD/NSpkg")
2658 @click.argument("name")
2659 @click.option(
2660 "--content",
2661 default=None,
2662 help="filename with the NSD/NSpkg replacing the current one",
2663 )
2664 @click.pass_context
2665 def nsd_update2(ctx, name, content):
2666 """updates a NSD/NSpkg
2667
2668 NAME: name or ID of the NSD/NSpkg
2669 """
2670 logger.debug("")
2671 nsd_update(ctx, name, content)
2672
2673
2674 def vnfd_update(ctx, name, content):
2675 logger.debug("")
2676 # try:
2677 check_client_version(ctx.obj, ctx.command.name)
2678 ctx.obj.vnfd.update(name, content)
2679 # except ClientException as e:
2680 # print(str(e))
2681 # exit(1)
2682
2683
2684 @cli_osm.command(name="vnfd-update", short_help="updates a new VNFD/VNFpkg")
2685 @click.argument("name")
2686 @click.option(
2687 "--content",
2688 default=None,
2689 help="filename with the VNFD/VNFpkg replacing the current one",
2690 )
2691 @click.pass_context
2692 def vnfd_update1(ctx, name, content):
2693 """updates a VNFD/VNFpkg
2694
2695 NAME: name or ID of the VNFD/VNFpkg
2696 """
2697 logger.debug("")
2698 vnfd_update(ctx, name, content)
2699
2700
2701 @cli_osm.command(name="vnfpkg-update", short_help="updates a VNFD/VNFpkg")
2702 @click.argument("name")
2703 @click.option(
2704 "--content",
2705 default=None,
2706 help="filename with the VNFD/VNFpkg replacing the current one",
2707 )
2708 @click.pass_context
2709 def vnfd_update2(ctx, name, content):
2710 """updates a VNFD/VNFpkg
2711
2712 NAME: VNFD yaml file or VNFpkg tar.gz file
2713 """
2714 logger.debug("")
2715 vnfd_update(ctx, name, content)
2716
2717
2718 @cli_osm.command(name="nfpkg-update", short_help="updates a NFpkg")
2719 @click.argument("name")
2720 @click.option(
2721 "--content", default=None, help="filename with the NFpkg replacing the current one"
2722 )
2723 @click.pass_context
2724 def nfpkg_update(ctx, name, content):
2725 """updates a NFpkg
2726
2727 NAME: NF Descriptor yaml file or NFpkg tar.gz file
2728 """
2729 logger.debug("")
2730 vnfd_update(ctx, name, content)
2731
2732
2733 def nst_update(ctx, name, content):
2734 logger.debug("")
2735 # try:
2736 check_client_version(ctx.obj, ctx.command.name)
2737 ctx.obj.nst.update(name, content)
2738 # except ClientException as e:
2739 # print(str(e))
2740 # exit(1)
2741
2742
2743 @cli_osm.command(name="nst-update", short_help="updates a Network Slice Template (NST)")
2744 @click.argument("name")
2745 @click.option(
2746 "--content",
2747 default=None,
2748 help="filename with the NST/NSTpkg replacing the current one",
2749 )
2750 @click.pass_context
2751 def nst_update1(ctx, name, content):
2752 """updates a Network Slice Template (NST)
2753
2754 NAME: name or ID of the NSD/NSpkg
2755 """
2756 logger.debug("")
2757 nst_update(ctx, name, content)
2758
2759
2760 @cli_osm.command(
2761 name="netslice-template-update", short_help="updates a Network Slice Template (NST)"
2762 )
2763 @click.argument("name")
2764 @click.option(
2765 "--content",
2766 default=None,
2767 help="filename with the NST/NSTpkg replacing the current one",
2768 )
2769 @click.pass_context
2770 def nst_update2(ctx, name, content):
2771 """updates a Network Slice Template (NST)
2772
2773 NAME: name or ID of the NSD/NSpkg
2774 """
2775 logger.debug("")
2776 nst_update(ctx, name, content)
2777
2778
2779 ####################
2780 # DELETE operations
2781 ####################
2782
2783
2784 def nsd_delete(ctx, name, force):
2785 logger.debug("")
2786 # try:
2787 if not force:
2788 ctx.obj.nsd.delete(name)
2789 else:
2790 check_client_version(ctx.obj, "--force")
2791 ctx.obj.nsd.delete(name, force)
2792 # except ClientException as e:
2793 # print(str(e))
2794 # exit(1)
2795
2796
2797 @cli_osm.command(name="nsd-delete", short_help="deletes a NSD/NSpkg")
2798 @click.argument("name")
2799 @click.option(
2800 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2801 )
2802 @click.pass_context
2803 def nsd_delete1(ctx, name, force):
2804 """deletes a NSD/NSpkg
2805
2806 NAME: name or ID of the NSD/NSpkg to be deleted
2807 """
2808 logger.debug("")
2809 nsd_delete(ctx, name, force)
2810
2811
2812 @cli_osm.command(name="nspkg-delete", short_help="deletes a NSD/NSpkg")
2813 @click.argument("name")
2814 @click.option(
2815 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2816 )
2817 @click.pass_context
2818 def nsd_delete2(ctx, name, force):
2819 """deletes a NSD/NSpkg
2820
2821 NAME: name or ID of the NSD/NSpkg to be deleted
2822 """
2823 logger.debug("")
2824 nsd_delete(ctx, name, force)
2825
2826
2827 def vnfd_delete(ctx, name, force):
2828 logger.debug("")
2829 # try:
2830 if not force:
2831 ctx.obj.vnfd.delete(name)
2832 else:
2833 check_client_version(ctx.obj, "--force")
2834 ctx.obj.vnfd.delete(name, force)
2835 # except ClientException as e:
2836 # print(str(e))
2837 # exit(1)
2838
2839
2840 @cli_osm.command(name="vnfd-delete", short_help="deletes a VNFD/VNFpkg")
2841 @click.argument("name")
2842 @click.option(
2843 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2844 )
2845 @click.pass_context
2846 def vnfd_delete1(ctx, name, force):
2847 """deletes a VNFD/VNFpkg
2848
2849 NAME: name or ID of the VNFD/VNFpkg to be deleted
2850 """
2851 logger.debug("")
2852 vnfd_delete(ctx, name, force)
2853
2854
2855 @cli_osm.command(name="vnfpkg-delete", short_help="deletes a VNFD/VNFpkg")
2856 @click.argument("name")
2857 @click.option(
2858 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2859 )
2860 @click.pass_context
2861 def vnfd_delete2(ctx, name, force):
2862 """deletes a VNFD/VNFpkg
2863
2864 NAME: name or ID of the VNFD/VNFpkg to be deleted
2865 """
2866 logger.debug("")
2867 vnfd_delete(ctx, name, force)
2868
2869
2870 @cli_osm.command(name="nfpkg-delete", short_help="deletes a NFpkg")
2871 @click.argument("name")
2872 @click.option(
2873 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2874 )
2875 @click.pass_context
2876 def nfpkg_delete(ctx, name, force):
2877 """deletes a NFpkg
2878
2879 NAME: name or ID of the NFpkg to be deleted
2880 """
2881 logger.debug("")
2882 vnfd_delete(ctx, name, force)
2883
2884
2885 @cli_osm.command(name="ns-delete", short_help="deletes a NS instance")
2886 @click.argument("name")
2887 @click.option(
2888 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2889 )
2890 @click.option(
2891 "--config",
2892 default=None,
2893 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
2894 "600, skip_terminate_primitives: True}'",
2895 )
2896 @click.option(
2897 "--wait",
2898 required=False,
2899 default=False,
2900 is_flag=True,
2901 help="do not return the control immediately, but keep it "
2902 "until the operation is completed, or timeout",
2903 )
2904 @click.pass_context
2905 def ns_delete(ctx, name, force, config, wait):
2906 """deletes a NS instance
2907
2908 NAME: name or ID of the NS instance to be deleted
2909 """
2910 logger.debug("")
2911 # try:
2912 if not force:
2913 ctx.obj.ns.delete(name, config=config, wait=wait)
2914 else:
2915 check_client_version(ctx.obj, "--force")
2916 ctx.obj.ns.delete(name, force, config=config, wait=wait)
2917 # except ClientException as e:
2918 # print(str(e))
2919 # exit(1)
2920
2921
2922 def nst_delete(ctx, name, force):
2923 logger.debug("")
2924 # try:
2925 check_client_version(ctx.obj, ctx.command.name)
2926 ctx.obj.nst.delete(name, force)
2927 # except ClientException as e:
2928 # print(str(e))
2929 # exit(1)
2930
2931
2932 @cli_osm.command(name="nst-delete", short_help="deletes a Network Slice Template (NST)")
2933 @click.argument("name")
2934 @click.option(
2935 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2936 )
2937 @click.pass_context
2938 def nst_delete1(ctx, name, force):
2939 """deletes a Network Slice Template (NST)
2940
2941 NAME: name or ID of the NST/NSTpkg to be deleted
2942 """
2943 logger.debug("")
2944 nst_delete(ctx, name, force)
2945
2946
2947 @cli_osm.command(
2948 name="netslice-template-delete", short_help="deletes a Network Slice Template (NST)"
2949 )
2950 @click.argument("name")
2951 @click.option(
2952 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2953 )
2954 @click.pass_context
2955 def nst_delete2(ctx, name, force):
2956 """deletes a Network Slice Template (NST)
2957
2958 NAME: name or ID of the NST/NSTpkg to be deleted
2959 """
2960 logger.debug("")
2961 nst_delete(ctx, name, force)
2962
2963
2964 def nsi_delete(ctx, name, force, wait):
2965 logger.debug("")
2966 # try:
2967 check_client_version(ctx.obj, ctx.command.name)
2968 ctx.obj.nsi.delete(name, force, wait=wait)
2969 # except ClientException as e:
2970 # print(str(e))
2971 # exit(1)
2972
2973
2974 @cli_osm.command(name="nsi-delete", short_help="deletes a Network Slice Instance (NSI)")
2975 @click.argument("name")
2976 @click.option(
2977 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
2978 )
2979 @click.option(
2980 "--wait",
2981 required=False,
2982 default=False,
2983 is_flag=True,
2984 help="do not return the control immediately, but keep it "
2985 "until the operation is completed, or timeout",
2986 )
2987 @click.pass_context
2988 def nsi_delete1(ctx, name, force, wait):
2989 """deletes a Network Slice Instance (NSI)
2990
2991 NAME: name or ID of the Network Slice instance to be deleted
2992 """
2993 logger.debug("")
2994 nsi_delete(ctx, name, force, wait=wait)
2995
2996
2997 @cli_osm.command(
2998 name="netslice-instance-delete", short_help="deletes a Network Slice Instance (NSI)"
2999 )
3000 @click.argument("name")
3001 @click.option(
3002 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3003 )
3004 @click.pass_context
3005 def nsi_delete2(ctx, name, force, wait):
3006 """deletes a Network Slice Instance (NSI)
3007
3008 NAME: name or ID of the Network Slice instance to be deleted
3009 """
3010 logger.debug("")
3011 nsi_delete(ctx, name, force, wait=wait)
3012
3013
3014 @cli_osm.command(
3015 name="pdu-delete", short_help="deletes a Physical Deployment Unit (PDU)"
3016 )
3017 @click.argument("name")
3018 @click.option(
3019 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3020 )
3021 @click.pass_context
3022 def pdu_delete(ctx, name, force):
3023 """deletes a Physical Deployment Unit (PDU)
3024
3025 NAME: name or ID of the PDU to be deleted
3026 """
3027 logger.debug("")
3028 # try:
3029 check_client_version(ctx.obj, ctx.command.name)
3030 ctx.obj.pdu.delete(name, force)
3031 # except ClientException as e:
3032 # print(str(e))
3033 # exit(1)
3034
3035
3036 #################
3037 # VIM operations
3038 #################
3039
3040
3041 @cli_osm.command(name="vim-create", short_help="creates a new VIM account")
3042 @click.option("--name", prompt=True, help="Name to create datacenter")
3043 @click.option("--user", prompt=True, help="VIM username")
3044 @click.option(
3045 "--password",
3046 prompt=True,
3047 hide_input=True,
3048 confirmation_prompt=True,
3049 help="VIM password",
3050 )
3051 @click.option("--auth_url", prompt=True, help="VIM url")
3052 @click.option("--tenant", prompt=True, help="VIM tenant name")
3053 @click.option("--config", default=None, help="VIM specific config parameters")
3054 @click.option("--account_type", default="openstack", help="VIM type")
3055 @click.option("--description", default=None, help="human readable description")
3056 @click.option(
3057 "--sdn_controller",
3058 default=None,
3059 help="Name or id of the SDN controller associated to this VIM account",
3060 )
3061 @click.option(
3062 "--sdn_port_mapping",
3063 default=None,
3064 help="File describing the port mapping between compute nodes' ports and switch ports",
3065 )
3066 @click.option(
3067 "--wait",
3068 required=False,
3069 default=False,
3070 is_flag=True,
3071 help="do not return the control immediately, but keep it "
3072 "until the operation is completed, or timeout",
3073 )
3074 @click.option("--vca", default=None, help="VCA to be used in this VIM account")
3075 @click.pass_context
3076 def vim_create(
3077 ctx,
3078 name,
3079 user,
3080 password,
3081 auth_url,
3082 tenant,
3083 config,
3084 account_type,
3085 description,
3086 sdn_controller,
3087 sdn_port_mapping,
3088 wait,
3089 vca,
3090 ):
3091 """creates a new VIM account"""
3092 logger.debug("")
3093 # try:
3094 if sdn_controller:
3095 check_client_version(ctx.obj, "--sdn_controller")
3096 if sdn_port_mapping:
3097 check_client_version(ctx.obj, "--sdn_port_mapping")
3098 vim = {}
3099 vim["vim-username"] = user
3100 vim["vim-password"] = password
3101 vim["vim-url"] = auth_url
3102 vim["vim-tenant-name"] = tenant
3103 vim["vim-type"] = account_type
3104 vim["description"] = description
3105 vim["config"] = config
3106 if vca:
3107 vim["vca"] = vca
3108 if sdn_controller or sdn_port_mapping:
3109 ctx.obj.vim.create(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
3110 else:
3111 ctx.obj.vim.create(name, vim, wait=wait)
3112 # except ClientException as e:
3113 # print(str(e))
3114 # exit(1)
3115
3116
3117 @cli_osm.command(name="vim-update", short_help="updates a VIM account")
3118 @click.argument("name")
3119 @click.option("--newname", help="New name for the VIM account")
3120 @click.option("--user", help="VIM username")
3121 @click.option("--password", help="VIM password")
3122 @click.option("--auth_url", help="VIM url")
3123 @click.option("--tenant", help="VIM tenant name")
3124 @click.option("--config", help="VIM specific config parameters")
3125 @click.option("--account_type", help="VIM type")
3126 @click.option("--description", help="human readable description")
3127 @click.option(
3128 "--sdn_controller",
3129 default=None,
3130 help="Name or id of the SDN controller to be associated with this VIM"
3131 "account. Use empty string to disassociate",
3132 )
3133 @click.option(
3134 "--sdn_port_mapping",
3135 default=None,
3136 help="File describing the port mapping between compute nodes' ports and switch ports",
3137 )
3138 @click.option(
3139 "--wait",
3140 required=False,
3141 default=False,
3142 is_flag=True,
3143 help="do not return the control immediately, but keep it "
3144 "until the operation is completed, or timeout",
3145 )
3146 @click.pass_context
3147 def vim_update(
3148 ctx,
3149 name,
3150 newname,
3151 user,
3152 password,
3153 auth_url,
3154 tenant,
3155 config,
3156 account_type,
3157 description,
3158 sdn_controller,
3159 sdn_port_mapping,
3160 wait,
3161 ):
3162 """updates a VIM account
3163
3164 NAME: name or ID of the VIM account
3165 """
3166 logger.debug("")
3167 # try:
3168 check_client_version(ctx.obj, ctx.command.name)
3169 vim = {}
3170 if newname:
3171 vim["name"] = newname
3172 if user:
3173 vim["vim_user"] = user
3174 if password:
3175 vim["vim_password"] = password
3176 if auth_url:
3177 vim["vim_url"] = auth_url
3178 if tenant:
3179 vim["vim-tenant-name"] = tenant
3180 if account_type:
3181 vim["vim_type"] = account_type
3182 if description:
3183 vim["description"] = description
3184 if config:
3185 vim["config"] = config
3186 ctx.obj.vim.update(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
3187 # except ClientException as e:
3188 # print(str(e))
3189 # exit(1)
3190
3191
3192 @cli_osm.command(name="vim-delete", short_help="deletes a VIM account")
3193 @click.argument("name")
3194 @click.option(
3195 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3196 )
3197 @click.option(
3198 "--wait",
3199 required=False,
3200 default=False,
3201 is_flag=True,
3202 help="do not return the control immediately, but keep it "
3203 "until the operation is completed, or timeout",
3204 )
3205 @click.pass_context
3206 def vim_delete(ctx, name, force, wait):
3207 """deletes a VIM account
3208
3209 NAME: name or ID of the VIM account to be deleted
3210 """
3211 logger.debug("")
3212 # try:
3213 if not force:
3214 ctx.obj.vim.delete(name, wait=wait)
3215 else:
3216 check_client_version(ctx.obj, "--force")
3217 ctx.obj.vim.delete(name, force, wait=wait)
3218 # except ClientException as e:
3219 # print(str(e))
3220 # exit(1)
3221
3222
3223 @cli_osm.command(name="vim-list", short_help="list all VIM accounts")
3224 # @click.option('--ro_update/--no_ro_update',
3225 # default=False,
3226 # help='update list from RO')
3227 @click.option(
3228 "--filter",
3229 default=None,
3230 multiple=True,
3231 help="restricts the list to the VIM accounts matching the filter",
3232 )
3233 @click.option(
3234 "--long",
3235 is_flag=True,
3236 help="get more details of the NS (project, vim, deployment status, configuration status.",
3237 )
3238 @click.pass_context
3239 def vim_list(ctx, filter, long):
3240 """list all VIM accounts"""
3241 logger.debug("")
3242 if filter:
3243 filter = "&".join(filter)
3244 check_client_version(ctx.obj, "--filter")
3245 # if ro_update:
3246 # check_client_version(ctx.obj, '--ro_update', 'v1')
3247 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
3248 if fullclassname == "osmclient.sol005.client.Client":
3249 resp = ctx.obj.vim.list(filter)
3250 # else:
3251 # resp = ctx.obj.vim.list(ro_update)
3252 if long:
3253 table = PrettyTable(
3254 ["vim name", "uuid", "project", "operational state", "error details"]
3255 )
3256 project_list = ctx.obj.project.list()
3257 else:
3258 table = PrettyTable(["vim name", "uuid", "operational state"])
3259 for vim in resp:
3260 if long:
3261 if "vim_password" in vim:
3262 vim["vim_password"] = "********"
3263 logger.debug("VIM details: {}".format(yaml.safe_dump(vim)))
3264 vim_state = vim["_admin"].get("operationalState", "-")
3265 error_details = "N/A"
3266 if vim_state == "ERROR":
3267 error_details = vim["_admin"].get("detailed-status", "Not found")
3268 project_id, project_name = get_project(project_list, vim)
3269 # project_info = '{} ({})'.format(project_name, project_id)
3270 project_info = project_name
3271 table.add_row(
3272 [
3273 vim["name"],
3274 vim["uuid"],
3275 project_info,
3276 vim_state,
3277 wrap_text(text=error_details, width=80),
3278 ]
3279 )
3280 else:
3281 table.add_row(
3282 [vim["name"], vim["uuid"], vim["_admin"].get("operationalState", "-")]
3283 )
3284 table.align = "l"
3285 print(table)
3286
3287
3288 @cli_osm.command(name="vim-show", short_help="shows the details of a VIM account")
3289 @click.argument("name")
3290 @click.option(
3291 "--filter",
3292 multiple=True,
3293 help="restricts the information to the fields in the filter",
3294 )
3295 @click.pass_context
3296 def vim_show(ctx, name, filter):
3297 """shows the details of a VIM account
3298
3299 NAME: name or ID of the VIM account
3300 """
3301 logger.debug("")
3302 # try:
3303 resp = ctx.obj.vim.get(name)
3304 if "vim_password" in resp:
3305 resp["vim_password"] = "********"
3306 # except ClientException as e:
3307 # print(str(e))
3308 # exit(1)
3309
3310 table = PrettyTable(["key", "attribute"])
3311 for k, v in list(resp.items()):
3312 if not filter or k in filter:
3313 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
3314 table.align = "l"
3315 print(table)
3316
3317
3318 ####################
3319 # WIM operations
3320 ####################
3321
3322
3323 @cli_osm.command(name="wim-create", short_help="creates a new WIM account")
3324 @click.option("--name", prompt=True, help="Name for the WIM account")
3325 @click.option("--user", help="WIM username")
3326 @click.option("--password", help="WIM password")
3327 @click.option("--url", prompt=True, help="WIM url")
3328 # @click.option('--tenant',
3329 # help='wIM tenant name')
3330 @click.option("--config", default=None, help="WIM specific config parameters")
3331 @click.option("--wim_type", help="WIM type")
3332 @click.option("--description", default=None, help="human readable description")
3333 @click.option(
3334 "--wim_port_mapping",
3335 default=None,
3336 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3337 "(WAN service endpoint id and info)",
3338 )
3339 @click.option(
3340 "--wait",
3341 required=False,
3342 default=False,
3343 is_flag=True,
3344 help="do not return the control immediately, but keep it "
3345 "until the operation is completed, or timeout",
3346 )
3347 @click.pass_context
3348 def wim_create(
3349 ctx,
3350 name,
3351 user,
3352 password,
3353 url,
3354 # tenant,
3355 config,
3356 wim_type,
3357 description,
3358 wim_port_mapping,
3359 wait,
3360 ):
3361 """creates a new WIM account"""
3362 logger.debug("")
3363 # try:
3364 check_client_version(ctx.obj, ctx.command.name)
3365 # if sdn_controller:
3366 # check_client_version(ctx.obj, '--sdn_controller')
3367 # if sdn_port_mapping:
3368 # check_client_version(ctx.obj, '--sdn_port_mapping')
3369 wim = {}
3370 if user:
3371 wim["user"] = user
3372 if password:
3373 wim["password"] = password
3374 if url:
3375 wim["wim_url"] = url
3376 # if tenant: wim['tenant'] = tenant
3377 wim["wim_type"] = wim_type
3378 if description:
3379 wim["description"] = description
3380 if config:
3381 wim["config"] = config
3382 ctx.obj.wim.create(name, wim, wim_port_mapping, wait=wait)
3383 # except ClientException as e:
3384 # print(str(e))
3385 # exit(1)
3386
3387
3388 @cli_osm.command(name="wim-update", short_help="updates a WIM account")
3389 @click.argument("name")
3390 @click.option("--newname", help="New name for the WIM account")
3391 @click.option("--user", help="WIM username")
3392 @click.option("--password", help="WIM password")
3393 @click.option("--url", help="WIM url")
3394 @click.option("--config", help="WIM specific config parameters")
3395 @click.option("--wim_type", help="WIM type")
3396 @click.option("--description", help="human readable description")
3397 @click.option(
3398 "--wim_port_mapping",
3399 default=None,
3400 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
3401 "(WAN service endpoint id and info)",
3402 )
3403 @click.option(
3404 "--wait",
3405 required=False,
3406 default=False,
3407 is_flag=True,
3408 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3409 )
3410 @click.pass_context
3411 def wim_update(
3412 ctx,
3413 name,
3414 newname,
3415 user,
3416 password,
3417 url,
3418 config,
3419 wim_type,
3420 description,
3421 wim_port_mapping,
3422 wait,
3423 ):
3424 """updates a WIM account
3425
3426 NAME: name or ID of the WIM account
3427 """
3428 logger.debug("")
3429 # try:
3430 check_client_version(ctx.obj, ctx.command.name)
3431 wim = {}
3432 if newname:
3433 wim["name"] = newname
3434 if user:
3435 wim["user"] = user
3436 if password:
3437 wim["password"] = password
3438 if url:
3439 wim["url"] = url
3440 # if tenant: wim['tenant'] = tenant
3441 if wim_type:
3442 wim["wim_type"] = wim_type
3443 if description:
3444 wim["description"] = description
3445 if config:
3446 wim["config"] = config
3447 ctx.obj.wim.update(name, wim, wim_port_mapping, wait=wait)
3448 # except ClientException as e:
3449 # print(str(e))
3450 # exit(1)
3451
3452
3453 @cli_osm.command(name="wim-delete", short_help="deletes a WIM account")
3454 @click.argument("name")
3455 @click.option(
3456 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3457 )
3458 @click.option(
3459 "--wait",
3460 required=False,
3461 default=False,
3462 is_flag=True,
3463 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3464 )
3465 @click.pass_context
3466 def wim_delete(ctx, name, force, wait):
3467 """deletes a WIM account
3468
3469 NAME: name or ID of the WIM account to be deleted
3470 """
3471 logger.debug("")
3472 # try:
3473 check_client_version(ctx.obj, ctx.command.name)
3474 ctx.obj.wim.delete(name, force, wait=wait)
3475 # except ClientException as e:
3476 # print(str(e))
3477 # exit(1)
3478
3479
3480 @cli_osm.command(name="wim-list", short_help="list all WIM accounts")
3481 @click.option(
3482 "--filter",
3483 default=None,
3484 multiple=True,
3485 help="restricts the list to the WIM accounts matching the filter",
3486 )
3487 @click.pass_context
3488 def wim_list(ctx, filter):
3489 """list all WIM accounts"""
3490 logger.debug("")
3491 # try:
3492 check_client_version(ctx.obj, ctx.command.name)
3493 if filter:
3494 filter = "&".join(filter)
3495 resp = ctx.obj.wim.list(filter)
3496 table = PrettyTable(["wim name", "uuid"])
3497 for wim in resp:
3498 table.add_row([wim["name"], wim["uuid"]])
3499 table.align = "l"
3500 print(table)
3501 # except ClientException as e:
3502 # print(str(e))
3503 # exit(1)
3504
3505
3506 @cli_osm.command(name="wim-show", short_help="shows the details of a WIM account")
3507 @click.argument("name")
3508 @click.pass_context
3509 def wim_show(ctx, name):
3510 """shows the details of a WIM account
3511
3512 NAME: name or ID of the WIM account
3513 """
3514 logger.debug("")
3515 # try:
3516 check_client_version(ctx.obj, ctx.command.name)
3517 resp = ctx.obj.wim.get(name)
3518 if "password" in resp:
3519 resp["wim_password"] = "********"
3520 # except ClientException as e:
3521 # print(str(e))
3522 # exit(1)
3523
3524 table = PrettyTable(["key", "attribute"])
3525 for k, v in list(resp.items()):
3526 table.add_row([k, json.dumps(v, indent=2)])
3527 table.align = "l"
3528 print(table)
3529
3530
3531 ####################
3532 # SDN controller operations
3533 ####################
3534
3535
3536 @cli_osm.command(name="sdnc-create", short_help="creates a new SDN controller")
3537 @click.option("--name", prompt=True, help="Name to create sdn controller")
3538 @click.option("--type", prompt=True, help="SDN controller type")
3539 @click.option(
3540 "--sdn_controller_version", # hidden=True,
3541 help="Deprecated. Use --config {version: sdn_controller_version}",
3542 )
3543 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3544 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True,
3545 @click.option("--port", help="Deprecated. Use --url") # hidden=True,
3546 @click.option(
3547 "--switch_dpid", help="Deprecated. Use --config {switch_id: DPID}" # hidden=True,
3548 )
3549 @click.option(
3550 "--config",
3551 help="Extra information for SDN in yaml format, as {switch_id: identity used for the plugin (e.g. DPID: "
3552 "Openflow Datapath ID), version: version}",
3553 )
3554 @click.option("--user", help="SDN controller username")
3555 @click.option(
3556 "--password",
3557 hide_input=True,
3558 confirmation_prompt=True,
3559 help="SDN controller password",
3560 )
3561 @click.option("--description", default=None, help="human readable description")
3562 @click.option(
3563 "--wait",
3564 required=False,
3565 default=False,
3566 is_flag=True,
3567 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3568 )
3569 @click.pass_context
3570 def sdnc_create(ctx, **kwargs):
3571 """creates a new SDN controller"""
3572 logger.debug("")
3573 sdncontroller = {
3574 x: kwargs[x]
3575 for x in kwargs
3576 if kwargs[x] and x not in ("wait", "ip_address", "port", "switch_dpid")
3577 }
3578 if kwargs.get("port"):
3579 print("option '--port' is deprecated, use '--url' instead")
3580 sdncontroller["port"] = int(kwargs["port"])
3581 if kwargs.get("ip_address"):
3582 print("option '--ip_address' is deprecated, use '--url' instead")
3583 sdncontroller["ip"] = kwargs["ip_address"]
3584 if kwargs.get("switch_dpid"):
3585 print(
3586 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3587 )
3588 sdncontroller["dpid"] = kwargs["switch_dpid"]
3589 if kwargs.get("sdn_controller_version"):
3590 print(
3591 "option '--sdn_controller_version' is deprecated, use '--config={version: SDN_CONTROLLER_VERSION}'"
3592 " instead"
3593 )
3594 # try:
3595 check_client_version(ctx.obj, ctx.command.name)
3596 ctx.obj.sdnc.create(kwargs["name"], sdncontroller, wait=kwargs["wait"])
3597 # except ClientException as e:
3598 # print(str(e))
3599 # exit(1)
3600
3601
3602 @cli_osm.command(name="sdnc-update", short_help="updates an SDN controller")
3603 @click.argument("name")
3604 @click.option("--newname", help="New name for the SDN controller")
3605 @click.option("--description", default=None, help="human readable description")
3606 @click.option("--type", help="SDN controller type")
3607 @click.option("--url", help="URL in format http[s]://HOST:IP/")
3608 @click.option(
3609 "--config",
3610 help="Extra information for SDN in yaml format, as "
3611 "{switch_id: identity used for the plugin (e.g. DPID: "
3612 "Openflow Datapath ID), version: version}",
3613 )
3614 @click.option("--user", help="SDN controller username")
3615 @click.option("--password", help="SDN controller password")
3616 @click.option("--ip_address", help="Deprecated. Use --url") # hidden=True
3617 @click.option("--port", help="Deprecated. Use --url") # hidden=True
3618 @click.option(
3619 "--switch_dpid", help="Deprecated. Use --config {switch_dpid: DPID}"
3620 ) # hidden=True
3621 @click.option(
3622 "--sdn_controller_version", help="Deprecated. Use --config {version: VERSION}"
3623 ) # hidden=True
3624 @click.option(
3625 "--wait",
3626 required=False,
3627 default=False,
3628 is_flag=True,
3629 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3630 )
3631 @click.pass_context
3632 def sdnc_update(ctx, **kwargs):
3633 """updates an SDN controller
3634
3635 NAME: name or ID of the SDN controller
3636 """
3637 logger.debug("")
3638 sdncontroller = {
3639 x: kwargs[x]
3640 for x in kwargs
3641 if kwargs[x]
3642 and x not in ("wait", "ip_address", "port", "switch_dpid", "new_name")
3643 }
3644 if kwargs.get("newname"):
3645 sdncontroller["name"] = kwargs["newname"]
3646 if kwargs.get("port"):
3647 print("option '--port' is deprecated, use '--url' instead")
3648 sdncontroller["port"] = int(kwargs["port"])
3649 if kwargs.get("ip_address"):
3650 print("option '--ip_address' is deprecated, use '--url' instead")
3651 sdncontroller["ip"] = kwargs["ip_address"]
3652 if kwargs.get("switch_dpid"):
3653 print(
3654 "option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead"
3655 )
3656 sdncontroller["dpid"] = kwargs["switch_dpid"]
3657 if kwargs.get("sdn_controller_version"):
3658 print(
3659 "option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
3660 " instead"
3661 )
3662
3663 # try:
3664 check_client_version(ctx.obj, ctx.command.name)
3665 ctx.obj.sdnc.update(kwargs["name"], sdncontroller, wait=kwargs["wait"])
3666 # except ClientException as e:
3667 # print(str(e))
3668 # exit(1)
3669
3670
3671 @cli_osm.command(name="sdnc-delete", short_help="deletes an SDN controller")
3672 @click.argument("name")
3673 @click.option(
3674 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
3675 )
3676 @click.option(
3677 "--wait",
3678 required=False,
3679 default=False,
3680 is_flag=True,
3681 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
3682 )
3683 @click.pass_context
3684 def sdnc_delete(ctx, name, force, wait):
3685 """deletes an SDN controller
3686
3687 NAME: name or ID of the SDN controller to be deleted
3688 """
3689 logger.debug("")
3690 # try:
3691 check_client_version(ctx.obj, ctx.command.name)
3692 ctx.obj.sdnc.delete(name, force, wait=wait)
3693 # except ClientException as e:
3694 # print(str(e))
3695 # exit(1)
3696
3697
3698 @cli_osm.command(name="sdnc-list", short_help="list all SDN controllers")
3699 @click.option(
3700 "--filter",
3701 default=None,
3702 multiple=True,
3703 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'",
3704 )
3705 @click.pass_context
3706 def sdnc_list(ctx, filter):
3707 """list all SDN controllers"""
3708 logger.debug("")
3709 # try:
3710 check_client_version(ctx.obj, ctx.command.name)
3711 if filter:
3712 filter = "&".join(filter)
3713 resp = ctx.obj.sdnc.list(filter)
3714 # except ClientException as e:
3715 # print(str(e))
3716 # exit(1)
3717 table = PrettyTable(["sdnc name", "id"])
3718 for sdnc in resp:
3719 table.add_row([sdnc["name"], sdnc["_id"]])
3720 table.align = "l"
3721 print(table)
3722
3723
3724 @cli_osm.command(name="sdnc-show", short_help="shows the details of an SDN controller")
3725 @click.argument("name")
3726 @click.pass_context
3727 def sdnc_show(ctx, name):
3728 """shows the details of an SDN controller
3729
3730 NAME: name or ID of the SDN controller
3731 """
3732 logger.debug("")
3733 # try:
3734 check_client_version(ctx.obj, ctx.command.name)
3735 resp = ctx.obj.sdnc.get(name)
3736 # except ClientException as e:
3737 # print(str(e))
3738 # exit(1)
3739
3740 table = PrettyTable(["key", "attribute"])
3741 for k, v in list(resp.items()):
3742 table.add_row([k, json.dumps(v, indent=2)])
3743 table.align = "l"
3744 print(table)
3745
3746
3747 ###########################
3748 # K8s cluster operations
3749 ###########################
3750
3751
3752 @cli_osm.command(name="k8scluster-add", short_help="adds a K8s cluster to OSM")
3753 @click.argument("name")
3754 @click.option(
3755 "--creds", prompt=True, help="credentials file, i.e. a valid `.kube/config` file"
3756 )
3757 @click.option("--version", prompt=True, help="Kubernetes version")
3758 @click.option(
3759 "--vim", prompt=True, help="VIM target, the VIM where the cluster resides"
3760 )
3761 @click.option(
3762 "--k8s-nets",
3763 prompt=True,
3764 help='''list of VIM networks, in JSON inline format, where the cluster is
3765 accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3766 )
3767 @click.option("--description", default=None, help="human readable description")
3768 @click.option(
3769 "--namespace",
3770 default="kube-system",
3771 help="namespace to be used for its operation, defaults to `kube-system`",
3772 )
3773 @click.option(
3774 "--cni",
3775 default=None,
3776 help="list of CNI plugins, in JSON inline format, used in the cluster",
3777 )
3778 # @click.option('--skip-init',
3779 # is_flag=True,
3780 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
3781 # @click.option('--wait',
3782 # is_flag=True,
3783 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3784 @click.pass_context
3785 def k8scluster_add(
3786 ctx, name, creds, version, vim, k8s_nets, description, namespace, cni
3787 ):
3788 """adds a K8s cluster to OSM
3789
3790 NAME: name of the K8s cluster
3791 """
3792 # try:
3793 check_client_version(ctx.obj, ctx.command.name)
3794 cluster = {}
3795 cluster["name"] = name
3796 with open(creds, "r") as cf:
3797 cluster["credentials"] = yaml.safe_load(cf.read())
3798 cluster["k8s_version"] = version
3799 cluster["vim_account"] = vim
3800 cluster["nets"] = yaml.safe_load(k8s_nets)
3801 if description:
3802 cluster["description"] = description
3803 if namespace:
3804 cluster["namespace"] = namespace
3805 if cni:
3806 cluster["cni"] = yaml.safe_load(cni)
3807 ctx.obj.k8scluster.create(name, cluster)
3808 # except ClientException as e:
3809 # print(str(e))
3810 # exit(1)
3811
3812
3813 @cli_osm.command(name="k8scluster-update", short_help="updates a K8s cluster")
3814 @click.argument("name")
3815 @click.option("--newname", help="New name for the K8s cluster")
3816 @click.option("--creds", help="credentials file, i.e. a valid `.kube/config` file")
3817 @click.option("--version", help="Kubernetes version")
3818 @click.option("--vim", help="VIM target, the VIM where the cluster resides")
3819 @click.option(
3820 "--k8s-nets",
3821 help='''list of VIM networks, in JSON inline format, where the cluster is accessible
3822 via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"''',
3823 )
3824 @click.option("--description", help="human readable description")
3825 @click.option(
3826 "--namespace",
3827 help="namespace to be used for its operation, defaults to `kube-system`",
3828 )
3829 @click.option(
3830 "--cni", help="list of CNI plugins, in JSON inline format, used in the cluster"
3831 )
3832 @click.pass_context
3833 def k8scluster_update(
3834 ctx, name, newname, creds, version, vim, k8s_nets, description, namespace, cni
3835 ):
3836 """updates a K8s cluster
3837
3838 NAME: name or ID of the K8s cluster
3839 """
3840 # try:
3841 check_client_version(ctx.obj, ctx.command.name)
3842 cluster = {}
3843 if newname:
3844 cluster["name"] = newname
3845 if creds:
3846 with open(creds, "r") as cf:
3847 cluster["credentials"] = yaml.safe_load(cf.read())
3848 if version:
3849 cluster["k8s_version"] = version
3850 if vim:
3851 cluster["vim_account"] = vim
3852 if k8s_nets:
3853 cluster["nets"] = yaml.safe_load(k8s_nets)
3854 if description:
3855 cluster["description"] = description
3856 if namespace:
3857 cluster["namespace"] = namespace
3858 if cni:
3859 cluster["cni"] = yaml.safe_load(cni)
3860 ctx.obj.k8scluster.update(name, cluster)
3861 # except ClientException as e:
3862 # print(str(e))
3863 # exit(1)
3864
3865
3866 @cli_osm.command(name="k8scluster-delete", short_help="deletes a K8s cluster")
3867 @click.argument("name")
3868 @click.option(
3869 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
3870 )
3871 # @click.option('--wait',
3872 # is_flag=True,
3873 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3874 @click.pass_context
3875 def k8scluster_delete(ctx, name, force):
3876 """deletes a K8s cluster
3877
3878 NAME: name or ID of the K8s cluster to be deleted
3879 """
3880 # try:
3881 check_client_version(ctx.obj, ctx.command.name)
3882 ctx.obj.k8scluster.delete(name, force=force)
3883 # except ClientException as e:
3884 # print(str(e))
3885 # exit(1)
3886
3887
3888 @cli_osm.command(name="k8scluster-list")
3889 @click.option(
3890 "--filter",
3891 default=None,
3892 multiple=True,
3893 help="restricts the list to the K8s clusters matching the filter",
3894 )
3895 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
3896 @click.option("--long", is_flag=True, help="get more details")
3897 @click.pass_context
3898 def k8scluster_list(ctx, filter, literal, long):
3899 """list all K8s clusters"""
3900 # try:
3901 check_client_version(ctx.obj, ctx.command.name)
3902 if filter:
3903 filter = "&".join(filter)
3904 resp = ctx.obj.k8scluster.list(filter)
3905 if literal:
3906 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
3907 return
3908 if long:
3909 table = PrettyTable(
3910 [
3911 "Name",
3912 "Id",
3913 "Project",
3914 "Version",
3915 "VIM",
3916 "K8s-nets",
3917 "Operational State",
3918 "Op. state (details)",
3919 "Description",
3920 "Detailed status",
3921 ]
3922 )
3923 project_list = ctx.obj.project.list()
3924 else:
3925 table = PrettyTable(
3926 ["Name", "Id", "VIM", "Operational State", "Op. state details"]
3927 )
3928 try:
3929 vim_list = ctx.obj.vim.list()
3930 except Exception:
3931 vim_list = []
3932 for cluster in resp:
3933 logger.debug("Cluster details: {}".format(yaml.safe_dump(cluster)))
3934 vim_name = get_vim_name(vim_list, cluster["vim_account"])
3935 # vim_info = '{} ({})'.format(vim_name,cluster['vim_account'])
3936 vim_info = vim_name
3937 op_state_details = "Helm: {}\nJuju: {}".format(
3938 cluster["_admin"].get("helm-chart", {}).get("operationalState", "-"),
3939 cluster["_admin"].get("juju-bundle", {}).get("operationalState", "-"),
3940 )
3941 if long:
3942 project_id, project_name = get_project(project_list, cluster)
3943 # project_info = '{} ({})'.format(project_name, project_id)
3944 project_info = project_name
3945 detailed_status = cluster["_admin"].get("detailed-status", "-")
3946 table.add_row(
3947 [
3948 cluster["name"],
3949 cluster["_id"],
3950 project_info,
3951 cluster["k8s_version"],
3952 vim_info,
3953 json.dumps(cluster["nets"]),
3954 cluster["_admin"]["operationalState"],
3955 op_state_details,
3956 trunc_text(cluster.get("description") or "", 40),
3957 wrap_text(text=detailed_status, width=40),
3958 ]
3959 )
3960 else:
3961 table.add_row(
3962 [
3963 cluster["name"],
3964 cluster["_id"],
3965 vim_info,
3966 cluster["_admin"]["operationalState"],
3967 op_state_details,
3968 ]
3969 )
3970 table.align = "l"
3971 print(table)
3972 # except ClientException as e:
3973 # print(str(e))
3974 # exit(1)
3975
3976
3977 @cli_osm.command(
3978 name="k8scluster-show", short_help="shows the details of a K8s cluster"
3979 )
3980 @click.argument("name")
3981 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
3982 @click.pass_context
3983 def k8scluster_show(ctx, name, literal):
3984 """shows the details of a K8s cluster
3985
3986 NAME: name or ID of the K8s cluster
3987 """
3988 # try:
3989 resp = ctx.obj.k8scluster.get(name)
3990 if literal:
3991 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
3992 return
3993 table = PrettyTable(["key", "attribute"])
3994 for k, v in list(resp.items()):
3995 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
3996 table.align = "l"
3997 print(table)
3998 # except ClientException as e:
3999 # print(str(e))
4000 # exit(1)
4001
4002
4003 ###########################
4004 # VCA operations
4005 ###########################
4006
4007
4008 @cli_osm.command(name="vca-add", short_help="adds a VCA (Juju controller) to OSM")
4009 @click.argument("name")
4010 @click.option(
4011 "--endpoints",
4012 prompt=True,
4013 help="Comma-separated list of IP or hostnames of the Juju controller",
4014 )
4015 @click.option("--user", prompt=True, help="Username with admin priviledges")
4016 @click.option("--secret", prompt=True, help="Password of the specified username")
4017 @click.option("--cacert", prompt=True, help="CA certificate")
4018 @click.option(
4019 "--lxd-cloud",
4020 prompt=True,
4021 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4022 )
4023 @click.option(
4024 "--lxd-credentials",
4025 prompt=True,
4026 help="Name of the cloud credentialsto be used for the LXD cloud",
4027 )
4028 @click.option(
4029 "--k8s-cloud",
4030 prompt=True,
4031 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4032 )
4033 @click.option(
4034 "--k8s-credentials",
4035 prompt=True,
4036 help="Name of the cloud credentialsto be used for the K8s cloud",
4037 )
4038 @click.option(
4039 "--model-config",
4040 default={},
4041 help="Configuration options for the models",
4042 )
4043 @click.option("--description", default=None, help="human readable description")
4044 @click.pass_context
4045 def vca_add(
4046 ctx,
4047 name,
4048 endpoints,
4049 user,
4050 secret,
4051 cacert,
4052 lxd_cloud,
4053 lxd_credentials,
4054 k8s_cloud,
4055 k8s_credentials,
4056 model_config,
4057 description,
4058 ):
4059 """adds a VCA to OSM
4060
4061 NAME: name of the VCA
4062 """
4063 check_client_version(ctx.obj, ctx.command.name)
4064 vca = {}
4065 vca["name"] = name
4066 vca["endpoints"] = endpoints.split(",")
4067 vca["user"] = user
4068 vca["secret"] = secret
4069 vca["cacert"] = cacert
4070 vca["lxd-cloud"] = lxd_cloud
4071 vca["lxd-credentials"] = lxd_credentials
4072 vca["k8s-cloud"] = k8s_cloud
4073 vca["k8s-credentials"] = k8s_credentials
4074 if description:
4075 vca["description"] = description
4076 if model_config:
4077 model_config = load(model_config)
4078 vca["model-config"] = model_config
4079 ctx.obj.vca.create(name, vca)
4080
4081
4082 def load(data: Any):
4083 if os.path.isfile(data):
4084 return load_file(data)
4085 else:
4086 try:
4087 return json.loads(data)
4088 except ValueError as e:
4089 raise ClientException(e)
4090
4091
4092 def load_file(file_path: str) -> Dict:
4093 content = None
4094 with open(file_path, "r") as f:
4095 content = f.read()
4096 try:
4097 return yaml.safe_load(content)
4098 except yaml.scanner.ScannerError:
4099 pass
4100 try:
4101 return json.loads(content)
4102 except ValueError:
4103 pass
4104 raise ClientException(f"{file_path} must be a valid yaml or json file")
4105
4106
4107 @cli_osm.command(name="vca-update", short_help="updates a K8s cluster")
4108 @click.argument("name")
4109 @click.option(
4110 "--endpoints", help="Comma-separated list of IP or hostnames of the Juju controller"
4111 )
4112 @click.option("--user", help="Username with admin priviledges")
4113 @click.option("--secret", help="Password of the specified username")
4114 @click.option("--cacert", help="CA certificate")
4115 @click.option(
4116 "--lxd-cloud",
4117 help="Name of the cloud that will be used for LXD containers (LXD proxy charms)",
4118 )
4119 @click.option(
4120 "--lxd-credentials",
4121 help="Name of the cloud credentialsto be used for the LXD cloud",
4122 )
4123 @click.option(
4124 "--k8s-cloud",
4125 help="Name of the cloud that will be used for K8s containers (K8s proxy charms)",
4126 )
4127 @click.option(
4128 "--k8s-credentials",
4129 help="Name of the cloud credentialsto be used for the K8s cloud",
4130 )
4131 @click.option(
4132 "--model-config",
4133 help="Configuration options for the models",
4134 )
4135 @click.option("--description", default=None, help="human readable description")
4136 @click.pass_context
4137 def vca_update(
4138 ctx,
4139 name,
4140 endpoints,
4141 user,
4142 secret,
4143 cacert,
4144 lxd_cloud,
4145 lxd_credentials,
4146 k8s_cloud,
4147 k8s_credentials,
4148 model_config,
4149 description,
4150 ):
4151 """updates a K8s cluster
4152
4153 NAME: name or ID of the K8s cluster
4154 """
4155 check_client_version(ctx.obj, ctx.command.name)
4156 vca = {}
4157 vca["name"] = name
4158 if endpoints:
4159 vca["endpoints"] = endpoints.split(",")
4160 if user:
4161 vca["user"] = user
4162 if secret:
4163 vca["secret"] = secret
4164 if cacert:
4165 vca["cacert"] = cacert
4166 if lxd_cloud:
4167 vca["lxd-cloud"] = lxd_cloud
4168 if lxd_credentials:
4169 vca["lxd-credentials"] = lxd_credentials
4170 if k8s_cloud:
4171 vca["k8s-cloud"] = k8s_cloud
4172 if k8s_credentials:
4173 vca["k8s-credentials"] = k8s_credentials
4174 if description:
4175 vca["description"] = description
4176 if model_config:
4177 model_config = load(model_config)
4178 vca["model-config"] = model_config
4179 ctx.obj.vca.update(name, vca)
4180
4181
4182 @cli_osm.command(name="vca-delete", short_help="deletes a K8s cluster")
4183 @click.argument("name")
4184 @click.option(
4185 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
4186 )
4187 @click.pass_context
4188 def vca_delete(ctx, name, force):
4189 """deletes a K8s cluster
4190
4191 NAME: name or ID of the K8s cluster to be deleted
4192 """
4193 check_client_version(ctx.obj, ctx.command.name)
4194 ctx.obj.vca.delete(name, force=force)
4195
4196
4197 @cli_osm.command(name="vca-list")
4198 @click.option(
4199 "--filter",
4200 default=None,
4201 multiple=True,
4202 help="restricts the list to the VCAs matching the filter",
4203 )
4204 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4205 @click.option("--long", is_flag=True, help="get more details")
4206 @click.pass_context
4207 def vca_list(ctx, filter, literal, long):
4208 """list VCAs"""
4209 check_client_version(ctx.obj, ctx.command.name)
4210 if filter:
4211 filter = "&".join(filter)
4212 resp = ctx.obj.vca.list(filter)
4213 if literal:
4214 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4215 return
4216 if long:
4217 table = PrettyTable(
4218 ["Name", "Id", "Project", "Operational State", "Detailed Status"]
4219 )
4220 project_list = ctx.obj.project.list()
4221 else:
4222 table = PrettyTable(["Name", "Id", "Operational State"])
4223 for vca in resp:
4224 logger.debug("VCA details: {}".format(yaml.safe_dump(vca)))
4225 if long:
4226 project_id, project_name = get_project(project_list, vca)
4227 detailed_status = vca.get("_admin", {}).get("detailed-status", "-")
4228 table.add_row(
4229 [
4230 vca["name"],
4231 vca["_id"],
4232 project_name,
4233 vca.get("_admin", {}).get("operationalState", "-"),
4234 wrap_text(text=detailed_status, width=40),
4235 ]
4236 )
4237 else:
4238 table.add_row(
4239 [
4240 vca["name"],
4241 vca["_id"],
4242 vca.get("_admin", {}).get("operationalState", "-"),
4243 ]
4244 )
4245 table.align = "l"
4246 print(table)
4247
4248
4249 @cli_osm.command(name="vca-show", short_help="shows the details of a K8s cluster")
4250 @click.argument("name")
4251 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4252 @click.pass_context
4253 def vca_show(ctx, name, literal):
4254 """shows the details of a K8s cluster
4255
4256 NAME: name or ID of the K8s cluster
4257 """
4258 # try:
4259 resp = ctx.obj.vca.get(name)
4260 if literal:
4261 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4262 return
4263 table = PrettyTable(["key", "attribute"])
4264 for k, v in list(resp.items()):
4265 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
4266 table.align = "l"
4267 print(table)
4268
4269
4270 ###########################
4271 # Repo operations
4272 ###########################
4273
4274
4275 @cli_osm.command(name="repo-add", short_help="adds a repo to OSM")
4276 @click.argument("name")
4277 @click.argument("uri")
4278 @click.option(
4279 "--type",
4280 type=click.Choice(["helm-chart", "juju-bundle", "osm"]),
4281 default="osm",
4282 help="type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles, osm for OSM Repositories)",
4283 )
4284 @click.option("--description", default=None, help="human readable description")
4285 @click.option(
4286 "--user", default=None, help="OSM repository: The username of the OSM repository"
4287 )
4288 @click.option(
4289 "--password",
4290 default=None,
4291 help="OSM repository: The password of the OSM repository",
4292 )
4293 # @click.option('--wait',
4294 # is_flag=True,
4295 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4296 @click.pass_context
4297 def repo_add(ctx, **kwargs):
4298 """adds a repo to OSM
4299
4300 NAME: name of the repo
4301 URI: URI of the repo
4302 """
4303 # try:
4304 kwargs = {k: v for k, v in kwargs.items() if v is not None}
4305 repo = kwargs
4306 repo["url"] = repo.pop("uri")
4307 if repo["type"] in ["helm-chart", "juju-bundle"]:
4308 ctx.obj.repo.create(repo["name"], repo)
4309 else:
4310 ctx.obj.osmrepo.create(repo["name"], repo)
4311 # except ClientException as e:
4312 # print(str(e))
4313 # exit(1)
4314
4315
4316 @cli_osm.command(name="repo-update", short_help="updates a repo in OSM")
4317 @click.argument("name")
4318 @click.option("--newname", help="New name for the repo")
4319 @click.option("--uri", help="URI of the repo")
4320 @click.option("--description", help="human readable description")
4321 # @click.option('--wait',
4322 # is_flag=True,
4323 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4324 @click.pass_context
4325 def repo_update(ctx, name, newname, uri, description):
4326 """updates a repo in OSM
4327
4328 NAME: name of the repo
4329 """
4330 # try:
4331 check_client_version(ctx.obj, ctx.command.name)
4332 repo = {}
4333 if newname:
4334 repo["name"] = newname
4335 if uri:
4336 repo["uri"] = uri
4337 if description:
4338 repo["description"] = description
4339 try:
4340 ctx.obj.repo.update(name, repo)
4341 except NotFound:
4342 ctx.obj.osmrepo.update(name, repo)
4343
4344 # except ClientException as e:
4345 # print(str(e))
4346 # exit(1)
4347
4348
4349 @cli_osm.command(
4350 name="repo-index", short_help="Index a repository from a folder with artifacts"
4351 )
4352 @click.option(
4353 "--origin", default=".", help="origin path where the artifacts are located"
4354 )
4355 @click.option(
4356 "--destination", default=".", help="destination path where the index is deployed"
4357 )
4358 @click.pass_context
4359 def repo_index(ctx, origin, destination):
4360 """Index a repository
4361
4362 NAME: name or ID of the repo to be deleted
4363 """
4364 check_client_version(ctx.obj, ctx.command.name)
4365 ctx.obj.osmrepo.repo_index(origin, destination)
4366
4367
4368 @cli_osm.command(name="repo-delete", short_help="deletes a repo")
4369 @click.argument("name")
4370 @click.option(
4371 "--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
4372 )
4373 # @click.option('--wait',
4374 # is_flag=True,
4375 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
4376 @click.pass_context
4377 def repo_delete(ctx, name, force):
4378 """deletes a repo
4379
4380 NAME: name or ID of the repo to be deleted
4381 """
4382 logger.debug("")
4383 try:
4384 ctx.obj.repo.delete(name, force=force)
4385 except NotFound:
4386 ctx.obj.osmrepo.delete(name, force=force)
4387 # except ClientException as e:
4388 # print(str(e))
4389 # exit(1)
4390
4391
4392 @cli_osm.command(name="repo-list")
4393 @click.option(
4394 "--filter",
4395 default=None,
4396 multiple=True,
4397 help="restricts the list to the repos matching the filter",
4398 )
4399 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4400 @click.pass_context
4401 def repo_list(ctx, filter, literal):
4402 """list all repos"""
4403 # try:
4404 # K8s Repositories
4405 check_client_version(ctx.obj, ctx.command.name)
4406 if filter:
4407 filter = "&".join(filter)
4408 resp = ctx.obj.repo.list(filter)
4409 resp += ctx.obj.osmrepo.list(filter)
4410 if literal:
4411 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4412 return
4413 table = PrettyTable(["Name", "Id", "Type", "URI", "Description"])
4414 for repo in resp:
4415 # cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
4416 table.add_row(
4417 [
4418 repo["name"],
4419 repo["_id"],
4420 repo["type"],
4421 repo["url"],
4422 trunc_text(repo.get("description") or "", 40),
4423 ]
4424 )
4425 table.align = "l"
4426 print(table)
4427
4428 # except ClientException as e:
4429 # print(str(e))
4430 # exit(1)
4431
4432
4433 @cli_osm.command(name="repo-show", short_help="shows the details of a repo")
4434 @click.argument("name")
4435 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
4436 @click.pass_context
4437 def repo_show(ctx, name, literal):
4438 """shows the details of a repo
4439
4440 NAME: name or ID of the repo
4441 """
4442 try:
4443 resp = ctx.obj.repo.get(name)
4444 except NotFound:
4445 resp = ctx.obj.osmrepo.get(name)
4446
4447 if literal:
4448 if resp:
4449 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
4450 return
4451 table = PrettyTable(["key", "attribute"])
4452 if resp:
4453 for k, v in list(resp.items()):
4454 table.add_row([k, json.dumps(v, indent=2)])
4455
4456 table.align = "l"
4457 print(table)
4458 # except ClientException as e:
4459 # print(str(e))
4460 # exit(1)
4461
4462
4463 ####################
4464 # Project mgmt operations
4465 ####################
4466
4467
4468 @cli_osm.command(name="project-create", short_help="creates a new project")
4469 @click.argument("name")
4470 # @click.option('--description',
4471 # default='no description',
4472 # help='human readable description')
4473 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
4474 @click.option(
4475 "--quotas",
4476 "quotas",
4477 multiple=True,
4478 default=None,
4479 help="provide quotas. Can be used several times: 'quota1=number[,quota2=number,...]'. Quotas can be one "
4480 "of vnfds, nsds, nsts, pdus, nsrs, nsis, vim_accounts, wim_accounts, sdns, k8sclusters, k8srepos",
4481 )
4482 @click.pass_context
4483 def project_create(ctx, name, domain_name, quotas):
4484 """Creates a new project
4485
4486 NAME: name of the project
4487 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
4488 QUOTAS: set quotas for the project
4489 """
4490 logger.debug("")
4491 project = {"name": name}
4492 if domain_name:
4493 project["domain_name"] = domain_name
4494 quotas_dict = _process_project_quotas(quotas)
4495 if quotas_dict:
4496 project["quotas"] = quotas_dict
4497
4498 # try:
4499 check_client_version(ctx.obj, ctx.command.name)
4500 ctx.obj.project.create(name, project)
4501 # except ClientException as e:
4502 # print(str(e))
4503 # exit(1)
4504
4505
4506 def _process_project_quotas(quota_list):
4507 quotas_dict = {}
4508 if not quota_list:
4509 return quotas_dict
4510 try:
4511 for quota in quota_list:
4512 for single_quota in quota.split(","):
4513 k, v = single_quota.split("=")
4514 quotas_dict[k] = None if v in ("None", "null", "") else int(v)
4515 except (ValueError, TypeError):
4516 raise ClientException(
4517 "invalid format for 'quotas'. Use 'k1=v1,v1=v2'. v must be a integer or null"
4518 )
4519 return quotas_dict
4520
4521
4522 @cli_osm.command(name="project-delete", short_help="deletes a project")
4523 @click.argument("name")
4524 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4525 @click.pass_context
4526 def project_delete(ctx, name):
4527 """deletes a project
4528
4529 NAME: name or ID of the project to be deleted
4530 """
4531 logger.debug("")
4532 # try:
4533 check_client_version(ctx.obj, ctx.command.name)
4534 ctx.obj.project.delete(name)
4535 # except ClientException as e:
4536 # print(str(e))
4537 # exit(1)
4538
4539
4540 @cli_osm.command(name="project-list", short_help="list all projects")
4541 @click.option(
4542 "--filter",
4543 default=None,
4544 multiple=True,
4545 help="restricts the list to the projects matching the filter",
4546 )
4547 @click.pass_context
4548 def project_list(ctx, filter):
4549 """list all projects"""
4550 logger.debug("")
4551 # try:
4552 check_client_version(ctx.obj, ctx.command.name)
4553 if filter:
4554 filter = "&".join(filter)
4555 resp = ctx.obj.project.list(filter)
4556 # except ClientException as e:
4557 # print(str(e))
4558 # exit(1)
4559 table = PrettyTable(["name", "id"])
4560 for proj in resp:
4561 table.add_row([proj["name"], proj["_id"]])
4562 table.align = "l"
4563 print(table)
4564
4565
4566 @cli_osm.command(name="project-show", short_help="shows the details of a project")
4567 @click.argument("name")
4568 @click.pass_context
4569 def project_show(ctx, name):
4570 """shows the details of a project
4571
4572 NAME: name or ID of the project
4573 """
4574 logger.debug("")
4575 # try:
4576 check_client_version(ctx.obj, ctx.command.name)
4577 resp = ctx.obj.project.get(name)
4578 # except ClientException as e:
4579 # print(str(e))
4580 # exit(1)
4581
4582 table = PrettyTable(["key", "attribute"])
4583 for k, v in resp.items():
4584 table.add_row([k, json.dumps(v, indent=2)])
4585 table.align = "l"
4586 print(table)
4587
4588
4589 @cli_osm.command(
4590 name="project-update", short_help="updates a project (only the name can be updated)"
4591 )
4592 @click.argument("project")
4593 @click.option("--name", default=None, help="new name for the project")
4594 @click.option(
4595 "--quotas",
4596 "quotas",
4597 multiple=True,
4598 default=None,
4599 help="change quotas. Can be used several times: 'quota1=number|empty[,quota2=...]' "
4600 "(use empty to reset quota to default",
4601 )
4602 @click.pass_context
4603 def project_update(ctx, project, name, quotas):
4604 """
4605 Update a project name
4606
4607 :param ctx:
4608 :param project: id or name of the project to modify
4609 :param name: new name for the project
4610 :param quotas: change quotas of the project
4611 :return:
4612 """
4613 logger.debug("")
4614 project_changes = {}
4615 if name:
4616 project_changes["name"] = name
4617 quotas_dict = _process_project_quotas(quotas)
4618 if quotas_dict:
4619 project_changes["quotas"] = quotas_dict
4620
4621 # try:
4622 check_client_version(ctx.obj, ctx.command.name)
4623 ctx.obj.project.update(project, project_changes)
4624 # except ClientException as e:
4625 # print(str(e))
4626
4627
4628 ####################
4629 # User mgmt operations
4630 ####################
4631
4632
4633 @cli_osm.command(name="user-create", short_help="creates a new user")
4634 @click.argument("username")
4635 @click.option(
4636 "--password",
4637 prompt=True,
4638 hide_input=True,
4639 confirmation_prompt=True,
4640 help="user password",
4641 )
4642 @click.option(
4643 "--projects",
4644 # prompt="Comma separate list of projects",
4645 multiple=True,
4646 callback=lambda ctx, param, value: "".join(value).split(",")
4647 if all(len(x) == 1 for x in value)
4648 else value,
4649 help="list of project ids that the user belongs to",
4650 )
4651 @click.option(
4652 "--project-role-mappings",
4653 "project_role_mappings",
4654 default=None,
4655 multiple=True,
4656 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4657 )
4658 @click.option("--domain-name", "domain_name", default=None, help="assign to a domain")
4659 @click.pass_context
4660 def user_create(ctx, username, password, projects, project_role_mappings, domain_name):
4661 """Creates a new user
4662
4663 \b
4664 USERNAME: name of the user
4665 PASSWORD: password of the user
4666 PROJECTS: projects assigned to user (internal only)
4667 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
4668 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
4669 """
4670 logger.debug("")
4671 user = {}
4672 user["username"] = username
4673 user["password"] = password
4674 user["projects"] = projects
4675 user["project_role_mappings"] = project_role_mappings
4676 if domain_name:
4677 user["domain_name"] = domain_name
4678
4679 # try:
4680 check_client_version(ctx.obj, ctx.command.name)
4681 ctx.obj.user.create(username, user)
4682 # except ClientException as e:
4683 # print(str(e))
4684 # exit(1)
4685
4686
4687 @cli_osm.command(name="user-update", short_help="updates user information")
4688 @click.argument("username")
4689 @click.option(
4690 "--password",
4691 # prompt=True,
4692 # hide_input=True,
4693 # confirmation_prompt=True,
4694 help="user password",
4695 )
4696 @click.option("--set-username", "set_username", default=None, help="change username")
4697 @click.option(
4698 "--set-project",
4699 "set_project",
4700 default=None,
4701 multiple=True,
4702 help="create/replace the roles for this project: 'project,role1[,role2,...]'",
4703 )
4704 @click.option(
4705 "--remove-project",
4706 "remove_project",
4707 default=None,
4708 multiple=True,
4709 help="removes project from user: 'project'",
4710 )
4711 @click.option(
4712 "--add-project-role",
4713 "add_project_role",
4714 default=None,
4715 multiple=True,
4716 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4717 )
4718 @click.option(
4719 "--remove-project-role",
4720 "remove_project_role",
4721 default=None,
4722 multiple=True,
4723 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'",
4724 )
4725 @click.pass_context
4726 def user_update(
4727 ctx,
4728 username,
4729 password,
4730 set_username,
4731 set_project,
4732 remove_project,
4733 add_project_role,
4734 remove_project_role,
4735 ):
4736 """Update a user information
4737
4738 \b
4739 USERNAME: name of the user
4740 PASSWORD: new password
4741 SET_USERNAME: new username
4742 SET_PROJECT: creating mappings for project/role(s)
4743 REMOVE_PROJECT: deleting mappings for project/role(s)
4744 ADD_PROJECT_ROLE: adding mappings for project/role(s)
4745 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
4746 """
4747 logger.debug("")
4748 user = {}
4749 user["password"] = password
4750 user["username"] = set_username
4751 user["set-project"] = set_project
4752 user["remove-project"] = remove_project
4753 user["add-project-role"] = add_project_role
4754 user["remove-project-role"] = remove_project_role
4755
4756 # try:
4757 check_client_version(ctx.obj, ctx.command.name)
4758 ctx.obj.user.update(username, user)
4759 # except ClientException as e:
4760 # print(str(e))
4761 # exit(1)
4762
4763
4764 @cli_osm.command(name="user-delete", short_help="deletes a user")
4765 @click.argument("name")
4766 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
4767 @click.pass_context
4768 def user_delete(ctx, name):
4769 """deletes a user
4770
4771 \b
4772 NAME: name or ID of the user to be deleted
4773 """
4774 logger.debug("")
4775 # try:
4776 check_client_version(ctx.obj, ctx.command.name)
4777 ctx.obj.user.delete(name)
4778 # except ClientException as e:
4779 # print(str(e))
4780 # exit(1)
4781
4782
4783 @cli_osm.command(name="user-list", short_help="list all users")
4784 @click.option(
4785 "--filter",
4786 default=None,
4787 multiple=True,
4788 help="restricts the list to the users matching the filter",
4789 )
4790 @click.pass_context
4791 def user_list(ctx, filter):
4792 """list all users"""
4793 # try:
4794 check_client_version(ctx.obj, ctx.command.name)
4795 if filter:
4796 filter = "&".join(filter)
4797 resp = ctx.obj.user.list(filter)
4798 # except ClientException as e:
4799 # print(str(e))
4800 # exit(1)
4801 table = PrettyTable(["name", "id"])
4802 for user in resp:
4803 table.add_row([user["username"], user["_id"]])
4804 table.align = "l"
4805 print(table)
4806
4807
4808 @cli_osm.command(name="user-show", short_help="shows the details of a user")
4809 @click.argument("name")
4810 @click.pass_context
4811 def user_show(ctx, name):
4812 """shows the details of a user
4813
4814 NAME: name or ID of the user
4815 """
4816 logger.debug("")
4817 # try:
4818 check_client_version(ctx.obj, ctx.command.name)
4819 resp = ctx.obj.user.get(name)
4820 if "password" in resp:
4821 resp["password"] = "********"
4822 # except ClientException as e:
4823 # print(str(e))
4824 # exit(1)
4825
4826 table = PrettyTable(["key", "attribute"])
4827 for k, v in resp.items():
4828 table.add_row([k, json.dumps(v, indent=2)])
4829 table.align = "l"
4830 print(table)
4831
4832
4833 ####################
4834 # Fault Management operations
4835 ####################
4836
4837
4838 @cli_osm.command(name="ns-alarm-create")
4839 @click.argument("name")
4840 @click.option("--ns", prompt=True, help="NS instance id or name")
4841 @click.option(
4842 "--vnf", prompt=True, help="VNF name (VNF member index as declared in the NSD)"
4843 )
4844 @click.option("--vdu", prompt=True, help="VDU name (VDU name as declared in the VNFD)")
4845 @click.option("--metric", prompt=True, help="Name of the metric (e.g. cpu_utilization)")
4846 @click.option(
4847 "--severity",
4848 default="WARNING",
4849 help="severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)",
4850 )
4851 @click.option(
4852 "--threshold_value",
4853 prompt=True,
4854 help="threshold value that, when crossed, an alarm is triggered",
4855 )
4856 @click.option(
4857 "--threshold_operator",
4858 prompt=True,
4859 help="threshold operator describing the comparison (GE, LE, GT, LT, EQ)",
4860 )
4861 @click.option(
4862 "--statistic",
4863 default="AVERAGE",
4864 help="statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)",
4865 )
4866 @click.pass_context
4867 def ns_alarm_create(
4868 ctx,
4869 name,
4870 ns,
4871 vnf,
4872 vdu,
4873 metric,
4874 severity,
4875 threshold_value,
4876 threshold_operator,
4877 statistic,
4878 ):
4879 """creates a new alarm for a NS instance"""
4880 # TODO: Check how to validate threshold_value.
4881 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
4882 logger.debug("")
4883 # try:
4884 ns_instance = ctx.obj.ns.get(ns)
4885 alarm = {}
4886 alarm["alarm_name"] = name
4887 alarm["ns_id"] = ns_instance["_id"]
4888 alarm["correlation_id"] = ns_instance["_id"]
4889 alarm["vnf_member_index"] = vnf
4890 alarm["vdu_name"] = vdu
4891 alarm["metric_name"] = metric
4892 alarm["severity"] = severity
4893 alarm["threshold_value"] = int(threshold_value)
4894 alarm["operation"] = threshold_operator
4895 alarm["statistic"] = statistic
4896 check_client_version(ctx.obj, ctx.command.name)
4897 ctx.obj.ns.create_alarm(alarm)
4898 # except ClientException as e:
4899 # print(str(e))
4900 # exit(1)
4901
4902
4903 # @cli_osm.command(name='ns-alarm-delete')
4904 # @click.argument('name')
4905 # @click.pass_context
4906 # def ns_alarm_delete(ctx, name):
4907 # """deletes an alarm
4908 #
4909 # NAME: name of the alarm to be deleted
4910 # """
4911 # try:
4912 # check_client_version(ctx.obj, ctx.command.name)
4913 # ctx.obj.ns.delete_alarm(name)
4914 # except ClientException as e:
4915 # print(str(e))
4916 # exit(1)
4917
4918
4919 ####################
4920 # Performance Management operations
4921 ####################
4922
4923
4924 @cli_osm.command(
4925 name="ns-metric-export",
4926 short_help="exports a metric to the internal OSM bus, which can be read by other apps",
4927 )
4928 @click.option("--ns", prompt=True, help="NS instance id or name")
4929 @click.option(
4930 "--vnf", prompt=True, help="VNF name (VNF member index as declared in the NSD)"
4931 )
4932 @click.option("--vdu", prompt=True, help="VDU name (VDU name as declared in the VNFD)")
4933 @click.option("--metric", prompt=True, help="name of the metric (e.g. cpu_utilization)")
4934 # @click.option('--period', default='1w',
4935 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
4936 @click.option(
4937 "--interval", help="periodic interval (seconds) to export metrics continuously"
4938 )
4939 @click.pass_context
4940 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
4941 """exports a metric to the internal OSM bus, which can be read by other apps"""
4942 # TODO: Check how to validate interval.
4943 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
4944 logger.debug("")
4945 # try:
4946 ns_instance = ctx.obj.ns.get(ns)
4947 metric_data = {}
4948 metric_data["ns_id"] = ns_instance["_id"]
4949 metric_data["correlation_id"] = ns_instance["_id"]
4950 metric_data["vnf_member_index"] = vnf
4951 metric_data["vdu_name"] = vdu
4952 metric_data["metric_name"] = metric
4953 metric_data["collection_unit"] = "WEEK"
4954 metric_data["collection_period"] = 1
4955 check_client_version(ctx.obj, ctx.command.name)
4956 if not interval:
4957 print("{}".format(ctx.obj.ns.export_metric(metric_data)))
4958 else:
4959 i = 1
4960 while True:
4961 print("{} {}".format(ctx.obj.ns.export_metric(metric_data), i))
4962 time.sleep(int(interval))
4963 i += 1
4964 # except ClientException as e:
4965 # print(str(e))
4966 # exit(1)
4967
4968
4969 #################
4970 # Subscription operations
4971 #################
4972
4973
4974 @cli_osm.command(
4975 name="subscription-create",
4976 short_help="creates a new subscription to a specific event",
4977 )
4978 @click.option(
4979 "--event_type",
4980 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
4981 type=click.Choice(["ns"], case_sensitive=False),
4982 help="event type to be subscribed (for the moment, only ns is supported)",
4983 )
4984 @click.option("--event", default=None, help="specific yaml configuration for the event")
4985 @click.option(
4986 "--event_file", default=None, help="specific yaml configuration file for the event"
4987 )
4988 @click.pass_context
4989 def subscription_create(ctx, event_type, event, event_file):
4990 """creates a new subscription to a specific event"""
4991 logger.debug("")
4992 check_client_version(ctx.obj, ctx.command.name)
4993 if event_file:
4994 if event:
4995 raise ClientException(
4996 '"--event" option is incompatible with "--event_file" option'
4997 )
4998 with open(event_file, "r") as cf:
4999 event = cf.read()
5000 ctx.obj.subscription.create(event_type, event)
5001
5002
5003 @cli_osm.command(name="subscription-delete", short_help="deletes a subscription")
5004 @click.option(
5005 "--event_type",
5006 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5007 type=click.Choice(["ns"], case_sensitive=False),
5008 help="event type to be subscribed (for the moment, only ns is supported)",
5009 )
5010 @click.argument("subscription_id")
5011 @click.option(
5012 "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
5013 )
5014 @click.pass_context
5015 def subscription_delete(ctx, event_type, subscription_id, force):
5016 """deletes a subscription
5017
5018 SUBSCRIPTION_ID: ID of the subscription to be deleted
5019 """
5020 logger.debug("")
5021 check_client_version(ctx.obj, ctx.command.name)
5022 ctx.obj.subscription.delete(event_type, subscription_id, force)
5023
5024
5025 @cli_osm.command(name="subscription-list", short_help="list all subscriptions")
5026 @click.option(
5027 "--event_type",
5028 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5029 type=click.Choice(["ns"], case_sensitive=False),
5030 help="event type to be subscribed (for the moment, only ns is supported)",
5031 )
5032 @click.option(
5033 "--filter",
5034 default=None,
5035 multiple=True,
5036 help="restricts the list to the subscriptions matching the filter",
5037 )
5038 @click.pass_context
5039 def subscription_list(ctx, event_type, filter):
5040 """list all subscriptions"""
5041 logger.debug("")
5042 check_client_version(ctx.obj, ctx.command.name)
5043 if filter:
5044 filter = "&".join(filter)
5045 resp = ctx.obj.subscription.list(event_type, filter)
5046 table = PrettyTable(["id", "filter", "CallbackUri"])
5047 for sub in resp:
5048 table.add_row(
5049 [
5050 sub["_id"],
5051 wrap_text(text=json.dumps(sub["filter"], indent=2), width=70),
5052 sub["CallbackUri"],
5053 ]
5054 )
5055 table.align = "l"
5056 print(table)
5057
5058
5059 @cli_osm.command(
5060 name="subscription-show", short_help="shows the details of a subscription"
5061 )
5062 @click.argument("subscription_id")
5063 @click.option(
5064 "--event_type",
5065 # type=click.Choice(['ns', 'nspkg', 'vnfpkg'], case_sensitive=False))
5066 type=click.Choice(["ns"], case_sensitive=False),
5067 help="event type to be subscribed (for the moment, only ns is supported)",
5068 )
5069 @click.option(
5070 "--filter",
5071 multiple=True,
5072 help="restricts the information to the fields in the filter",
5073 )
5074 @click.pass_context
5075 def subscription_show(ctx, event_type, subscription_id, filter):
5076 """shows the details of a subscription
5077
5078 SUBSCRIPTION_ID: ID of the subscription
5079 """
5080 logger.debug("")
5081 # try:
5082 resp = ctx.obj.subscription.get(subscription_id)
5083 table = PrettyTable(["key", "attribute"])
5084 for k, v in list(resp.items()):
5085 if not filter or k in filter:
5086 table.add_row([k, wrap_text(text=json.dumps(v, indent=2), width=100)])
5087 table.align = "l"
5088 print(table)
5089
5090
5091 ####################
5092 # Other operations
5093 ####################
5094
5095
5096 @cli_osm.command(name="version", short_help="shows client and server versions")
5097 @click.pass_context
5098 def get_version(ctx):
5099 """shows client and server versions"""
5100 # try:
5101 check_client_version(ctx.obj, "version")
5102 print("Server version: {}".format(ctx.obj.get_version()))
5103 print(
5104 "Client version: {}".format(pkg_resources.get_distribution("osmclient").version)
5105 )
5106 # except ClientException as e:
5107 # print(str(e))
5108 # exit(1)
5109
5110
5111 @cli_osm.command(
5112 name="upload-package", short_help="uploads a VNF package or NS package"
5113 )
5114 @click.argument("filename")
5115 @click.option(
5116 "--skip-charm-build",
5117 default=False,
5118 is_flag=True,
5119 help="the charm will not be compiled, it is assumed to already exist",
5120 )
5121 @click.pass_context
5122 def upload_package(ctx, filename, skip_charm_build):
5123 """uploads a vnf package or ns package
5124
5125 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
5126 """
5127 logger.debug("")
5128 # try:
5129 ctx.obj.package.upload(filename, skip_charm_build=skip_charm_build)
5130 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
5131 if fullclassname != "osmclient.sol005.client.Client":
5132 ctx.obj.package.wait_for_upload(filename)
5133 # except ClientException as e:
5134 # print(str(e))
5135 # exit(1)
5136
5137
5138 # @cli_osm.command(name='ns-scaling-show')
5139 # @click.argument('ns_name')
5140 # @click.pass_context
5141 # def show_ns_scaling(ctx, ns_name):
5142 # """shows the status of a NS scaling operation
5143 #
5144 # NS_NAME: name of the NS instance being scaled
5145 # """
5146 # try:
5147 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5148 # resp = ctx.obj.ns.list()
5149 # except ClientException as e:
5150 # print(str(e))
5151 # exit(1)
5152 #
5153 # table = PrettyTable(
5154 # ['group-name',
5155 # 'instance-id',
5156 # 'operational status',
5157 # 'create-time',
5158 # 'vnfr ids'])
5159 #
5160 # for ns in resp:
5161 # if ns_name == ns['name']:
5162 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
5163 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
5164 # for record in scaling_records:
5165 # if 'instance' in record:
5166 # instances = record['instance']
5167 # for inst in instances:
5168 # table.add_row(
5169 # [record['scaling-group-name-ref'],
5170 # inst['instance-id'],
5171 # inst['op-status'],
5172 # time.strftime('%Y-%m-%d %H:%M:%S',
5173 # time.localtime(
5174 # inst['create-time'])),
5175 # inst['vnfrs']])
5176 # table.align = 'l'
5177 # print(table)
5178
5179
5180 # @cli_osm.command(name='ns-scale')
5181 # @click.argument('ns_name')
5182 # @click.option('--ns_scale_group', prompt=True)
5183 # @click.option('--index', prompt=True)
5184 # @click.option('--wait',
5185 # required=False,
5186 # default=False,
5187 # is_flag=True,
5188 # help='do not return the control immediately, but keep it \
5189 # until the operation is completed, or timeout')
5190 # @click.pass_context
5191 # def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
5192 # """scales NS
5193 #
5194 # NS_NAME: name of the NS instance to be scaled
5195 # """
5196 # try:
5197 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5198 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
5199 # except ClientException as e:
5200 # print(str(e))
5201 # exit(1)
5202
5203
5204 # @cli_osm.command(name='config-agent-list')
5205 # @click.pass_context
5206 # def config_agent_list(ctx):
5207 # """list config agents"""
5208 # try:
5209 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5210 # except ClientException as e:
5211 # print(str(e))
5212 # exit(1)
5213 # table = PrettyTable(['name', 'account-type', 'details'])
5214 # for account in ctx.obj.vca.list():
5215 # table.add_row(
5216 # [account['name'],
5217 # account['account-type'],
5218 # account['juju']])
5219 # table.align = 'l'
5220 # print(table)
5221
5222
5223 # @cli_osm.command(name='config-agent-delete')
5224 # @click.argument('name')
5225 # @click.pass_context
5226 # def config_agent_delete(ctx, name):
5227 # """deletes a config agent
5228 #
5229 # NAME: name of the config agent to be deleted
5230 # """
5231 # try:
5232 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5233 # ctx.obj.vca.delete(name)
5234 # except ClientException as e:
5235 # print(str(e))
5236 # exit(1)
5237
5238
5239 # @cli_osm.command(name='config-agent-add')
5240 # @click.option('--name',
5241 # prompt=True)
5242 # @click.option('--account_type',
5243 # prompt=True)
5244 # @click.option('--server',
5245 # prompt=True)
5246 # @click.option('--user',
5247 # prompt=True)
5248 # @click.option('--secret',
5249 # prompt=True,
5250 # hide_input=True,
5251 # confirmation_prompt=True)
5252 # @click.pass_context
5253 # def config_agent_add(ctx, name, account_type, server, user, secret):
5254 # """adds a config agent"""
5255 # try:
5256 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5257 # ctx.obj.vca.create(name, account_type, server, user, secret)
5258 # except ClientException as e:
5259 # print(str(e))
5260 # exit(1)
5261
5262
5263 # @cli_osm.command(name='ro-dump')
5264 # @click.pass_context
5265 # def ro_dump(ctx):
5266 # """shows RO agent information"""
5267 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5268 # resp = ctx.obj.vim.get_resource_orchestrator()
5269 # table = PrettyTable(['key', 'attribute'])
5270 # for k, v in list(resp.items()):
5271 # table.add_row([k, json.dumps(v, indent=2)])
5272 # table.align = 'l'
5273 # print(table)
5274
5275
5276 # @cli_osm.command(name='vcs-list')
5277 # @click.pass_context
5278 # def vcs_list(ctx):
5279 # check_client_version(ctx.obj, ctx.command.name, 'v1')
5280 # resp = ctx.obj.utils.get_vcs_info()
5281 # table = PrettyTable(['component name', 'state'])
5282 # for component in resp:
5283 # table.add_row([component['component_name'], component['state']])
5284 # table.align = 'l'
5285 # print(table)
5286
5287
5288 @cli_osm.command(
5289 name="ns-action", short_help="executes an action/primitive over a NS instance"
5290 )
5291 @click.argument("ns_name")
5292 @click.option(
5293 "--vnf_name",
5294 default=None,
5295 help="member-vnf-index if the target is a vnf instead of a ns)",
5296 )
5297 @click.option("--kdu_name", default=None, help="kdu-name if the target is a kdu)")
5298 @click.option("--vdu_id", default=None, help="vdu-id if the target is a vdu")
5299 @click.option(
5300 "--vdu_count", default=None, type=int, help="number of vdu instance of this vdu_id"
5301 )
5302 @click.option("--action_name", prompt=True, help="action name")
5303 @click.option("--params", default=None, help="action params in YAML/JSON inline string")
5304 @click.option("--params_file", default=None, help="YAML/JSON file with action params")
5305 @click.option(
5306 "--timeout", required=False, default=None, type=int, help="timeout in seconds"
5307 )
5308 @click.option(
5309 "--wait",
5310 required=False,
5311 default=False,
5312 is_flag=True,
5313 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5314 )
5315 @click.pass_context
5316 def ns_action(
5317 ctx,
5318 ns_name,
5319 vnf_name,
5320 kdu_name,
5321 vdu_id,
5322 vdu_count,
5323 action_name,
5324 params,
5325 params_file,
5326 timeout,
5327 wait,
5328 ):
5329 """executes an action/primitive over a NS instance
5330
5331 NS_NAME: name or ID of the NS instance
5332 """
5333 logger.debug("")
5334 # try:
5335 check_client_version(ctx.obj, ctx.command.name)
5336 op_data = {}
5337 if vnf_name:
5338 op_data["member_vnf_index"] = vnf_name
5339 if kdu_name:
5340 op_data["kdu_name"] = kdu_name
5341 if vdu_id:
5342 op_data["vdu_id"] = vdu_id
5343 if vdu_count is not None:
5344 op_data["vdu_count_index"] = vdu_count
5345 if timeout:
5346 op_data["timeout_ns_action"] = timeout
5347 op_data["primitive"] = action_name
5348 if params_file:
5349 with open(params_file, "r") as pf:
5350 params = pf.read()
5351 if params:
5352 op_data["primitive_params"] = yaml.safe_load(params)
5353 else:
5354 op_data["primitive_params"] = {}
5355 print(ctx.obj.ns.exec_op(ns_name, op_name="action", op_data=op_data, wait=wait))
5356
5357 # except ClientException as e:
5358 # print(str(e))
5359 # exit(1)
5360
5361
5362 @cli_osm.command(
5363 name="vnf-scale", short_help="executes a VNF scale (adding/removing VDUs)"
5364 )
5365 @click.argument("ns_name")
5366 @click.argument("vnf_name")
5367 @click.option(
5368 "--scaling-group", prompt=True, help="scaling-group-descriptor name to use"
5369 )
5370 @click.option(
5371 "--scale-in", default=False, is_flag=True, help="performs a scale in operation"
5372 )
5373 @click.option(
5374 "--scale-out",
5375 default=False,
5376 is_flag=True,
5377 help="performs a scale out operation (by default)",
5378 )
5379 @click.option(
5380 "--timeout", required=False, default=None, type=int, help="timeout in seconds"
5381 )
5382 @click.option(
5383 "--wait",
5384 required=False,
5385 default=False,
5386 is_flag=True,
5387 help="do not return the control immediately, but keep it until the operation is completed, or timeout",
5388 )
5389 @click.pass_context
5390 def vnf_scale(
5391 ctx, ns_name, vnf_name, scaling_group, scale_in, scale_out, timeout, wait
5392 ):
5393 """
5394 Executes a VNF scale (adding/removing VDUs)
5395
5396 \b
5397 NS_NAME: name or ID of the NS instance.
5398 VNF_NAME: member-vnf-index in the NS to be scaled.
5399 """
5400 logger.debug("")
5401 # try:
5402 check_client_version(ctx.obj, ctx.command.name)
5403 if not scale_in and not scale_out:
5404 scale_out = True
5405 ctx.obj.ns.scale_vnf(
5406 ns_name, vnf_name, scaling_group, scale_in, scale_out, wait, timeout
5407 )
5408 # except ClientException as e:
5409 # print(str(e))
5410 # exit(1)
5411
5412
5413 @cli_osm.command(name="alarm-show", short_help="show alarm details")
5414 @click.argument("uuid")
5415 @click.pass_context
5416 def alarm_show(ctx, uuid):
5417 """Show alarm's detail information"""
5418
5419 check_client_version(ctx.obj, ctx.command.name)
5420 resp = ctx.obj.ns.get_alarm(uuid=uuid)
5421 alarm_filter = [
5422 "uuid",
5423 "name",
5424 "metric",
5425 "statistic",
5426 "threshold",
5427 "operation",
5428 "ns-id",
5429 "vnf-id",
5430 "vdu_name",
5431 "action",
5432 "status",
5433 ]
5434 table = PrettyTable(["key", "attribute"])
5435 try:
5436 # Arrange and return the response data
5437 resp = resp.replace("ObjectId", "")
5438 alarm = eval(resp)
5439 for key in alarm_filter:
5440 if key == "uuid":
5441 value = alarm.get(key)
5442 key = "alarm-id"
5443 elif key == "name":
5444 value = alarm.get(key)
5445 key = "alarm-name"
5446 elif key == "ns-id":
5447 value = alarm["tags"].get("ns_id")
5448 elif key == "vdu_name":
5449 value = alarm["tags"].get("vdu_name")
5450 elif key == "status":
5451 value = alarm["alarm_status"]
5452 else:
5453 value = alarm[key]
5454 table.add_row([key, wrap_text(text=json.dumps(value, indent=2), width=100)])
5455 table.align = "l"
5456 print(table)
5457 except Exception:
5458 print(resp)
5459
5460
5461 # List alarm
5462 @cli_osm.command(name="alarm-list", short_help="list all alarms")
5463 @click.option(
5464 "--ns_id", default=None, required=False, help="List out alarm for given ns id"
5465 )
5466 @click.pass_context
5467 def alarm_list(ctx, ns_id):
5468 """list all alarm"""
5469
5470 check_client_version(ctx.obj, ctx.command.name)
5471 project_name = os.getenv("OSM_PROJECT", "admin")
5472 resp = ctx.obj.ns.get_alarm(project_name=project_name, ns_id=ns_id)
5473
5474 table = PrettyTable(
5475 ["alarm-id", "metric", "threshold", "operation", "action", "status"]
5476 )
5477 if resp:
5478 # return the response data in a table
5479 resp = resp.replace("ObjectId", "")
5480 resp = eval(resp)
5481 for alarm in resp:
5482 table.add_row(
5483 [
5484 wrap_text(text=str(alarm["uuid"]), width=38),
5485 alarm["metric"],
5486 alarm["threshold"],
5487 alarm["operation"],
5488 wrap_text(text=alarm["action"], width=25),
5489 alarm["alarm_status"],
5490 ]
5491 )
5492 table.align = "l"
5493 print(table)
5494
5495
5496 # Update alarm
5497 @cli_osm.command(name="alarm-update", short_help="Update a alarm")
5498 @click.argument("uuid")
5499 @click.option("--threshold", default=None, help="Alarm threshold")
5500 @click.option("--is_enable", default=None, type=bool, help="enable or disable alarm")
5501 @click.pass_context
5502 def alarm_update(ctx, uuid, threshold, is_enable):
5503 """
5504 Update alarm
5505
5506 """
5507 if not threshold and is_enable is None:
5508 raise ClientException(
5509 "Please provide option to update i.e threshold or is_enable"
5510 )
5511 ctx.obj.ns.update_alarm(uuid, threshold, is_enable)
5512
5513
5514 ##############################
5515 # Role Management Operations #
5516 ##############################
5517
5518
5519 @cli_osm.command(name="role-create", short_help="creates a new role")
5520 @click.argument("name")
5521 @click.option("--permissions", default=None, help="role permissions using a dictionary")
5522 @click.pass_context
5523 def role_create(ctx, name, permissions):
5524 """
5525 Creates a new role.
5526
5527 \b
5528 NAME: Name or ID of the role.
5529 DEFINITION: Definition of grant/denial of access to resources.
5530 """
5531 logger.debug("")
5532 # try:
5533 check_client_version(ctx.obj, ctx.command.name)
5534 ctx.obj.role.create(name, permissions)
5535 # except ClientException as e:
5536 # print(str(e))
5537 # exit(1)
5538
5539
5540 @cli_osm.command(name="role-update", short_help="updates a role")
5541 @click.argument("name")
5542 @click.option("--set-name", default=None, help="change name of rle")
5543 # @click.option('--permissions',
5544 # default=None,
5545 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
5546 @click.option(
5547 "--add",
5548 default=None,
5549 help="yaml format dictionary with permission: True/False to access grant/denial",
5550 )
5551 @click.option("--remove", default=None, help="yaml format list to remove a permission")
5552 @click.pass_context
5553 def role_update(ctx, name, set_name, add, remove):
5554 """
5555 Updates a role.
5556
5557 \b
5558 NAME: Name or ID of the role.
5559 DEFINITION: Definition overwrites the old definition.
5560 ADD: Grant/denial of access to resource to add.
5561 REMOVE: Grant/denial of access to resource to remove.
5562 """
5563 logger.debug("")
5564 # try:
5565 check_client_version(ctx.obj, ctx.command.name)
5566 ctx.obj.role.update(name, set_name, None, add, remove)
5567 # except ClientException as e:
5568 # print(str(e))
5569 # exit(1)
5570
5571
5572 @cli_osm.command(name="role-delete", short_help="deletes a role")
5573 @click.argument("name")
5574 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
5575 @click.pass_context
5576 def role_delete(ctx, name):
5577 """
5578 Deletes a role.
5579
5580 \b
5581 NAME: Name or ID of the role.
5582 """
5583 logger.debug("")
5584 # try:
5585 check_client_version(ctx.obj, ctx.command.name)
5586 ctx.obj.role.delete(name)
5587 # except ClientException as e:
5588 # print(str(e))
5589 # exit(1)
5590
5591
5592 @cli_osm.command(name="role-list", short_help="list all roles")
5593 @click.option(
5594 "--filter",
5595 default=None,
5596 multiple=True,
5597 help="restricts the list to the projects matching the filter",
5598 )
5599 @click.pass_context
5600 def role_list(ctx, filter):
5601 """
5602 List all roles.
5603 """
5604 logger.debug("")
5605 # try:
5606 check_client_version(ctx.obj, ctx.command.name)
5607 if filter:
5608 filter = "&".join(filter)
5609 resp = ctx.obj.role.list(filter)
5610 # except ClientException as e:
5611 # print(str(e))
5612 # exit(1)
5613 table = PrettyTable(["name", "id"])
5614 for role in resp:
5615 table.add_row([role["name"], role["_id"]])
5616 table.align = "l"
5617 print(table)
5618
5619
5620 @cli_osm.command(name="role-show", short_help="show specific role")
5621 @click.argument("name")
5622 @click.pass_context
5623 def role_show(ctx, name):
5624 """
5625 Shows the details of a role.
5626
5627 \b
5628 NAME: Name or ID of the role.
5629 """
5630 logger.debug("")
5631 # try:
5632 check_client_version(ctx.obj, ctx.command.name)
5633 resp = ctx.obj.role.get(name)
5634 # except ClientException as e:
5635 # print(str(e))
5636 # exit(1)
5637
5638 table = PrettyTable(["key", "attribute"])
5639 for k, v in resp.items():
5640 table.add_row([k, json.dumps(v, indent=2)])
5641 table.align = "l"
5642 print(table)
5643
5644
5645 @cli_osm.command(name="package-create", short_help="Create empty NS package structure")
5646 @click.argument("package-type")
5647 @click.argument("package-name")
5648 @click.option(
5649 "--base-directory",
5650 default=".",
5651 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'),
5652 )
5653 @click.option(
5654 "--image",
5655 default="image-name",
5656 help='(VNF) Set the name of the vdu image. Default "image-name"',
5657 )
5658 @click.option(
5659 "--vdus", default=1, help="(VNF) Set the number of vdus in a VNF. Default 1"
5660 )
5661 @click.option(
5662 "--vcpu", default=1, help="(VNF) Set the number of virtual CPUs in a vdu. Default 1"
5663 )
5664 @click.option(
5665 "--memory",
5666 default=1024,
5667 help="(VNF) Set the memory size (MB) of the vdu. Default 1024",
5668 )
5669 @click.option(
5670 "--storage", default=10, help="(VNF) Set the disk size (GB) of the vdu. Default 10"
5671 )
5672 @click.option(
5673 "--interfaces",
5674 default=0,
5675 help="(VNF) Set the number of additional interfaces apart from the management interface. Default 0",
5676 )
5677 @click.option(
5678 "--vendor", default="OSM", help='(NS/VNF) Set the descriptor vendor. Default "OSM"'
5679 )
5680 @click.option(
5681 "--override",
5682 default=False,
5683 is_flag=True,
5684 help="(NS/VNF/NST) Flag for overriding the package if exists.",
5685 )
5686 @click.option(
5687 "--detailed",
5688 is_flag=True,
5689 default=False,
5690 help="(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options",
5691 )
5692 @click.option(
5693 "--netslice-subnets", default=1, help="(NST) Number of netslice subnets. Default 1"
5694 )
5695 @click.option(
5696 "--netslice-vlds", default=1, help="(NST) Number of netslice vlds. Default 1"
5697 )
5698 @click.pass_context
5699 def package_create(
5700 ctx,
5701 package_type,
5702 base_directory,
5703 package_name,
5704 override,
5705 image,
5706 vdus,
5707 vcpu,
5708 memory,
5709 storage,
5710 interfaces,
5711 vendor,
5712 detailed,
5713 netslice_subnets,
5714 netslice_vlds,
5715 ):
5716 """
5717 Creates an OSM NS, VNF, NST package
5718
5719 \b
5720 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
5721 PACKAGE_NAME: Name of the package to create the folder with the content.
5722 """
5723
5724 # try:
5725 logger.debug("")
5726 check_client_version(ctx.obj, ctx.command.name)
5727 print(
5728 "Creating the {} structure: {}/{}".format(
5729 package_type.upper(), base_directory, package_name
5730 )
5731 )
5732 resp = ctx.obj.package_tool.create(
5733 package_type,
5734 base_directory,
5735 package_name,
5736 override=override,
5737 image=image,
5738 vdus=vdus,
5739 vcpu=vcpu,
5740 memory=memory,
5741 storage=storage,
5742 interfaces=interfaces,
5743 vendor=vendor,
5744 detailed=detailed,
5745 netslice_subnets=netslice_subnets,
5746 netslice_vlds=netslice_vlds,
5747 )
5748 print(resp)
5749 # except ClientException as inst:
5750 # print("ERROR: {}".format(inst))
5751 # exit(1)
5752
5753
5754 @cli_osm.command(
5755 name="package-validate", short_help="Validate descriptors given a base directory"
5756 )
5757 @click.argument("base-directory", default=".", required=False)
5758 @click.option(
5759 "--recursive/--no-recursive",
5760 default=True,
5761 help="The activated recursive option will validate the yaml files"
5762 " within the indicated directory and in its subdirectories",
5763 )
5764 @click.option(
5765 "--old",
5766 is_flag=True,
5767 default=False,
5768 help="Validates also the descriptors using the previous OSM format (pre SOL006)",
5769 )
5770 @click.pass_context
5771 def package_validate(ctx, base_directory, recursive, old):
5772 """
5773 Validate descriptors given a base directory.
5774
5775 \b
5776 BASE_DIRECTORY: Base folder for NS, VNF or NST package.
5777 """
5778 # try:
5779 logger.debug("")
5780 check_client_version(ctx.obj, ctx.command.name)
5781 results = ctx.obj.package_tool.validate(base_directory, recursive, old)
5782 table = PrettyTable()
5783 table.field_names = ["TYPE", "PATH", "VALID", "ERROR"]
5784 # Print the dictionary generated by the validation function
5785 for result in results:
5786 table.add_row(
5787 [result["type"], result["path"], result["valid"], result["error"]]
5788 )
5789 table.sortby = "VALID"
5790 table.align["PATH"] = "l"
5791 table.align["TYPE"] = "l"
5792 table.align["ERROR"] = "l"
5793 print(table)
5794 # except ClientException as inst:
5795 # print("ERROR: {}".format(inst))
5796 # exit(1)
5797
5798
5799 @cli_osm.command(
5800 name="package-translate", short_help="Translate descriptors given a base directory"
5801 )
5802 @click.argument("base-directory", default=".", required=False)
5803 @click.option(
5804 "--recursive/--no-recursive",
5805 default=True,
5806 help="The activated recursive option will translate the yaml files"
5807 " within the indicated directory and in its subdirectories",
5808 )
5809 @click.option(
5810 "--dryrun",
5811 is_flag=True,
5812 default=False,
5813 help="Do not translate yet, only make a dry-run to test translation",
5814 )
5815 @click.pass_context
5816 def package_translate(ctx, base_directory, recursive, dryrun):
5817 """
5818 Translate descriptors given a base directory.
5819
5820 \b
5821 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
5822 """
5823 logger.debug("")
5824 check_client_version(ctx.obj, ctx.command.name)
5825 results = ctx.obj.package_tool.translate(base_directory, recursive, dryrun)
5826 table = PrettyTable()
5827 table.field_names = [
5828 "CURRENT TYPE",
5829 "NEW TYPE",
5830 "PATH",
5831 "VALID",
5832 "TRANSLATED",
5833 "ERROR",
5834 ]
5835 # Print the dictionary generated by the validation function
5836 for result in results:
5837 table.add_row(
5838 [
5839 result["current type"],
5840 result["new type"],
5841 result["path"],
5842 result["valid"],
5843 result["translated"],
5844 result["error"],
5845 ]
5846 )
5847 table.sortby = "TRANSLATED"
5848 table.align["PATH"] = "l"
5849 table.align["TYPE"] = "l"
5850 table.align["ERROR"] = "l"
5851 print(table)
5852 # except ClientException as inst:
5853 # print("ERROR: {}".format(inst))
5854 # exit(1)
5855
5856
5857 @cli_osm.command(name="package-build", short_help="Build the tar.gz of the package")
5858 @click.argument("package-folder")
5859 @click.option(
5860 "--skip-validation", default=False, is_flag=True, help="skip package validation"
5861 )
5862 @click.option(
5863 "--skip-charm-build",
5864 default=False,
5865 is_flag=True,
5866 help="the charm will not be compiled, it is assumed to already exist",
5867 )
5868 @click.pass_context
5869 def package_build(ctx, package_folder, skip_validation, skip_charm_build):
5870 """
5871 Build the package NS, VNF given the package_folder.
5872
5873 \b
5874 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
5875 """
5876 # try:
5877 logger.debug("")
5878 check_client_version(ctx.obj, ctx.command.name)
5879 results = ctx.obj.package_tool.build(
5880 package_folder,
5881 skip_validation=skip_validation,
5882 skip_charm_build=skip_charm_build,
5883 )
5884 print(results)
5885 # except ClientException as inst:
5886 # print("ERROR: {}".format(inst))
5887 # exit(1)
5888
5889
5890 @cli_osm.command(
5891 name="descriptor-translate",
5892 short_help="Translate input descriptor file from Rel EIGHT OSM descriptors to SOL006 and prints in standard output",
5893 )
5894 @click.argument("descriptor-file", required=True)
5895 @click.pass_context
5896 def descriptor_translate(ctx, descriptor_file):
5897 """
5898 Translate input descriptor.
5899
5900 \b
5901 DESCRIPTOR_FILE: Descriptor file for NS, VNF or Network Slice.
5902 """
5903 logger.debug("")
5904 check_client_version(ctx.obj, ctx.command.name)
5905 result = ctx.obj.package_tool.descriptor_translate(descriptor_file)
5906 print(result)
5907
5908
5909 def cli():
5910 try:
5911 cli_osm()
5912 exit(0)
5913 except pycurl.error as exc:
5914 print(exc)
5915 print(
5916 'Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified'
5917 )
5918 except ClientException as exc:
5919 print("ERROR: {}".format(exc))
5920 except (FileNotFoundError, PermissionError) as exc:
5921 print("Cannot open file: {}".format(exc))
5922 except yaml.YAMLError as exc:
5923 print("Invalid YAML format: {}".format(exc))
5924 exit(1)
5925 # TODO capture other controlled exceptions here
5926 # TODO remove the ClientException captures from all places, unless they do something different
5927
5928
5929 if __name__ == "__main__":
5930 cli()