New commands for managing K8s cluster and repos
[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
24 from prettytable import PrettyTable
25 import yaml
26 import json
27 import time
28 import pycurl
29 import os
30 import textwrap
31
32
33 def wrap_text(text, width):
34 wrapper = textwrap.TextWrapper(width=width)
35 lines = text.splitlines()
36 return "\n".join(map(wrapper.fill, lines))
37
38
39 def trunc_text(text, length):
40 if len(text) > length:
41 return text[:(length - 3)] + '...'
42 else:
43 return text
44
45
46 def check_client_version(obj, what, version='sol005'):
47 """
48 Checks the version of the client object and raises error if it not the expected.
49
50 :param obj: the client object
51 :what: the function or command under evaluation (used when an error is raised)
52 :return: -
53 :raises ClientError: if the specified version does not match the client version
54 """
55 fullclassname = obj.__module__ + "." + obj.__class__.__name__
56 message = 'The following commands or options are only supported with the option "--sol005": {}'.format(what)
57 if version == 'v1':
58 message = 'The following commands or options are not supported when using option "--sol005": {}'.format(what)
59 if fullclassname != 'osmclient.{}.client.Client'.format(version):
60 raise ClientException(message)
61 return
62
63
64 CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=160)
65
66 @click.group(context_settings=CONTEXT_SETTINGS)
67 @click.option('--hostname',
68 default="127.0.0.1",
69 envvar='OSM_HOSTNAME',
70 help='hostname of server. ' +
71 'Also can set OSM_HOSTNAME in environment')
72 #@click.option('--sol005/--no-sol005',
73 # default=True,
74 # envvar='OSM_SOL005',
75 # help='Use ETSI NFV SOL005 API (default) or the previous SO API. ' +
76 # 'Also can set OSM_SOL005 in environment')
77 @click.option('--user',
78 default=None,
79 envvar='OSM_USER',
80 help='user (defaults to admin). ' +
81 'Also can set OSM_USER in environment')
82 @click.option('--password',
83 default=None,
84 envvar='OSM_PASSWORD',
85 help='password (defaults to admin). ' +
86 'Also can set OSM_PASSWORD in environment')
87 @click.option('--project',
88 default=None,
89 envvar='OSM_PROJECT',
90 help='project (defaults to admin). ' +
91 'Also can set OSM_PROJECT in environment')
92 #@click.option('--so-port',
93 # default=None,
94 # envvar='OSM_SO_PORT',
95 # help='hostname of server. ' +
96 # 'Also can set OSM_SO_PORT in environment')
97 #@click.option('--so-project',
98 # default=None,
99 # envvar='OSM_SO_PROJECT',
100 # help='Project Name in SO. ' +
101 # 'Also can set OSM_SO_PROJECT in environment')
102 #@click.option('--ro-hostname',
103 # default=None,
104 # envvar='OSM_RO_HOSTNAME',
105 # help='hostname of RO server. ' +
106 # 'Also can set OSM_RO_HOSTNAME in environment')
107 #@click.option('--ro-port',
108 # default=None,
109 # envvar='OSM_RO_PORT',
110 # help='hostname of RO server. ' +
111 # 'Also can set OSM_RO_PORT in environment')
112 @click.pass_context
113 def cli(ctx, hostname, user, password, project):
114 if hostname is None:
115 print((
116 "either hostname option or OSM_HOSTNAME " +
117 "environment variable needs to be specified"))
118 exit(1)
119 kwargs={}
120 # if so_port is not None:
121 # kwargs['so_port']=so_port
122 # if so_project is not None:
123 # kwargs['so_project']=so_project
124 # if ro_hostname is not None:
125 # kwargs['ro_host']=ro_hostname
126 # if ro_port is not None:
127 # kwargs['ro_port']=ro_port
128 sol005 = os.getenv('OSM_SOL005', True)
129 if user is not None:
130 kwargs['user']=user
131 if password is not None:
132 kwargs['password']=password
133 if project is not None:
134 kwargs['project']=project
135
136 ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs)
137
138
139 ####################
140 # LIST operations
141 ####################
142
143 @cli.command(name='ns-list', short_help='list all NS instances')
144 @click.option('--filter', default=None,
145 help='restricts the list to the NS instances matching the filter.')
146 @click.pass_context
147 def ns_list(ctx, filter):
148 """list all NS instances
149
150 \b
151 Options:
152 --filter filterExpr Restricts the list to the NS instances matching the filter
153
154 \b
155 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
156 concatenated using the "&" character:
157
158 \b
159 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
160 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
161 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
162 attrName := string
163 value := scalar value
164
165 \b
166 where:
167 * zero or more occurrences
168 ? zero or one occurrence
169 [] grouping of expressions to be used with ? and *
170 "" quotation marks for marking string constants
171 <> name separator
172
173 \b
174 "AttrName" is the name of one attribute in the data type that defines the representation
175 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
176 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
177 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
178 entries, it means that the operator "op" is applied to the attribute addressed by the last
179 <attrName> entry included in the concatenation. All simple filter expressions are combined
180 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
181 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
182 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
183 prefix". If an attribute referenced in an expression is an array, an object that contains a
184 corresponding array shall be considered to match the expression if any of the elements in the
185 array matches all expressions that have the same attribute prefix.
186
187 \b
188 Filter examples:
189 --filter admin-status=ENABLED
190 --filter nsd-ref=<NSD_NAME>
191 --filter nsd.vendor=<VENDOR>
192 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
193 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
194 """
195 if filter:
196 check_client_version(ctx.obj, '--filter')
197 resp = ctx.obj.ns.list(filter)
198 else:
199 resp = ctx.obj.ns.list()
200 table = PrettyTable(
201 ['ns instance name',
202 'id',
203 'operational status',
204 'config status',
205 'detailed status'])
206 for ns in resp:
207 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
208 if fullclassname == 'osmclient.sol005.client.Client':
209 nsr = ns
210 nsr_name = nsr['name']
211 nsr_id = nsr['_id']
212 else:
213 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
214 nsr = nsopdata['nsr:nsr']
215 nsr_name = nsr['name-ref']
216 nsr_id = nsr['ns-instance-config-ref']
217 opstatus = nsr['operational-status'] if 'operational-status' in nsr else 'Not found'
218 configstatus = nsr['config-status'] if 'config-status' in nsr else 'Not found'
219 detailed_status = nsr['detailed-status'] if 'detailed-status' in nsr else 'Not found'
220 detailed_status = wrap_text(text=detailed_status,width=50)
221 if configstatus == "config_not_needed":
222 configstatus = "configured (no charms)"
223
224 table.add_row(
225 [nsr_name,
226 nsr_id,
227 opstatus,
228 configstatus,
229 detailed_status])
230 table.align = 'l'
231 print(table)
232
233
234 def nsd_list(ctx, filter):
235 if filter:
236 check_client_version(ctx.obj, '--filter')
237 resp = ctx.obj.nsd.list(filter)
238 else:
239 resp = ctx.obj.nsd.list()
240 # print(yaml.safe_dump(resp))
241 table = PrettyTable(['nsd name', 'id'])
242 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
243 if fullclassname == 'osmclient.sol005.client.Client':
244 for ns in resp:
245 name = ns['name'] if 'name' in ns else '-'
246 table.add_row([name, ns['_id']])
247 else:
248 for ns in resp:
249 table.add_row([ns['name'], ns['id']])
250 table.align = 'l'
251 print(table)
252
253
254 @cli.command(name='nsd-list', short_help='list all NS packages')
255 @click.option('--filter', default=None,
256 help='restricts the list to the NSD/NSpkg matching the filter')
257 @click.pass_context
258 def nsd_list1(ctx, filter):
259 """list all NSD/NS pkg in the system"""
260 nsd_list(ctx, filter)
261
262
263 @cli.command(name='nspkg-list', short_help='list all NS packages')
264 @click.option('--filter', default=None,
265 help='restricts the list to the NSD/NSpkg matching the filter')
266 @click.pass_context
267 def nsd_list2(ctx, filter):
268 """list all NS packages"""
269 nsd_list(ctx, filter)
270
271
272 def vnfd_list(ctx, nf_type, filter):
273 if nf_type:
274 check_client_version(ctx.obj, '--nf_type')
275 elif filter:
276 check_client_version(ctx.obj, '--filter')
277 if nf_type:
278 if nf_type == "vnf":
279 nf_filter = "_admin.type=vnfd"
280 elif nf_type == "pnf":
281 nf_filter = "_admin.type=pnfd"
282 elif nf_type == "hnf":
283 nf_filter = "_admin.type=hnfd"
284 else:
285 raise ClientException('wrong value for "--nf_type" option, allowed values: vnf, pnf, hnf')
286 if filter:
287 filter = '{}&{}'.format(nf_filter, filter)
288 else:
289 filter = nf_filter
290 if filter:
291 resp = ctx.obj.vnfd.list(filter)
292 else:
293 resp = ctx.obj.vnfd.list()
294 # print(yaml.safe_dump(resp))
295 table = PrettyTable(['nfpkg name', 'id'])
296 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
297 if fullclassname == 'osmclient.sol005.client.Client':
298 for vnfd in resp:
299 name = vnfd['name'] if 'name' in vnfd else '-'
300 table.add_row([name, vnfd['_id']])
301 else:
302 for vnfd in resp:
303 table.add_row([vnfd['name'], vnfd['id']])
304 table.align = 'l'
305 print(table)
306
307
308 @cli.command(name='vnfd-list', short_help='list all xNF packages (VNF, HNF, PNF)')
309 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
310 @click.option('--filter', default=None,
311 help='restricts the list to the NF pkg matching the filter')
312 @click.pass_context
313 def vnfd_list1(ctx, nf_type, filter):
314 """list all xNF packages (VNF, HNF, PNF)"""
315 vnfd_list(ctx, nf_type, filter)
316
317
318 @cli.command(name='vnfpkg-list', short_help='list all xNF packages (VNF, HNF, PNF)')
319 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
320 @click.option('--filter', default=None,
321 help='restricts the list to the NFpkg matching the filter')
322 @click.pass_context
323 def vnfd_list2(ctx, nf_type, filter):
324 """list all xNF packages (VNF, HNF, PNF)"""
325 vnfd_list(ctx, nf_type, filter)
326
327
328 @cli.command(name='nfpkg-list', short_help='list all xNF packages (VNF, HNF, PNF)')
329 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
330 @click.option('--filter', default=None,
331 help='restricts the list to the NFpkg matching the filter')
332 @click.pass_context
333 def nfpkg_list(ctx, nf_type, filter):
334 """list all xNF packages (VNF, HNF, PNF)"""
335 try:
336 check_client_version(ctx.obj, ctx.command.name)
337 vnfd_list(ctx, nf_type, filter)
338 except ClientException as e:
339 print(str(e))
340 exit(1)
341
342
343 def vnf_list(ctx, ns, filter):
344 try:
345 if ns or filter:
346 if ns:
347 check_client_version(ctx.obj, '--ns')
348 if filter:
349 check_client_version(ctx.obj, '--filter')
350 resp = ctx.obj.vnf.list(ns, filter)
351 else:
352 resp = ctx.obj.vnf.list()
353 except ClientException as e:
354 print(str(e))
355 exit(1)
356 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
357 if fullclassname == 'osmclient.sol005.client.Client':
358 table = PrettyTable(
359 ['vnf id',
360 'name',
361 'ns id',
362 'vnf member index',
363 'vnfd name',
364 'vim account id',
365 'ip address'])
366 for vnfr in resp:
367 name = vnfr['name'] if 'name' in vnfr else '-'
368 table.add_row(
369 [vnfr['_id'],
370 name,
371 vnfr['nsr-id-ref'],
372 vnfr['member-vnf-index-ref'],
373 vnfr['vnfd-ref'],
374 vnfr['vim-account-id'],
375 vnfr['ip-address']])
376 else:
377 table = PrettyTable(
378 ['vnf name',
379 'id',
380 'operational status',
381 'config status'])
382 for vnfr in resp:
383 if 'mgmt-interface' not in vnfr:
384 vnfr['mgmt-interface'] = {}
385 vnfr['mgmt-interface']['ip-address'] = None
386 table.add_row(
387 [vnfr['name'],
388 vnfr['id'],
389 vnfr['operational-status'],
390 vnfr['config-status']])
391 table.align = 'l'
392 print(table)
393
394
395 @cli.command(name='vnf-list', short_help='list all NF instances')
396 @click.option('--ns', default=None, help='NS instance id or name to restrict the NF list')
397 @click.option('--filter', default=None,
398 help='restricts the list to the NF instances matching the filter.')
399 @click.pass_context
400 def vnf_list1(ctx, ns, filter):
401 """list all NF instances"""
402 vnf_list(ctx, ns, filter)
403
404
405 @cli.command(name='nf-list', short_help='list all NF instances')
406 @click.option('--ns', default=None, help='NS instance id or name to restrict the NF list')
407 @click.option('--filter', default=None,
408 help='restricts the list to the NF instances matching the filter.')
409 @click.pass_context
410 def nf_list(ctx, ns, filter):
411 """list all NF instances
412
413 \b
414 Options:
415 --ns TEXT NS instance id or name to restrict the VNF list
416 --filter filterExpr Restricts the list to the VNF instances matching the filter
417
418 \b
419 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
420 concatenated using the "&" character:
421
422 \b
423 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
424 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
425 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
426 attrName := string
427 value := scalar value
428
429 \b
430 where:
431 * zero or more occurrences
432 ? zero or one occurrence
433 [] grouping of expressions to be used with ? and *
434 "" quotation marks for marking string constants
435 <> name separator
436
437 \b
438 "AttrName" is the name of one attribute in the data type that defines the representation
439 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
440 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
441 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
442 entries, it means that the operator "op" is applied to the attribute addressed by the last
443 <attrName> entry included in the concatenation. All simple filter expressions are combined
444 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
445 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
446 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
447 prefix". If an attribute referenced in an expression is an array, an object that contains a
448 corresponding array shall be considered to match the expression if any of the elements in the
449 array matches all expressions that have the same attribute prefix.
450
451 \b
452 Filter examples:
453 --filter vim-account-id=<VIM_ACCOUNT_ID>
454 --filter vnfd-ref=<VNFD_NAME>
455 --filter vdur.ip-address=<IP_ADDRESS>
456 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
457 """
458 vnf_list(ctx, ns, filter)
459
460
461 @cli.command(name='ns-op-list', short_help='shows the history of operations over a NS instance')
462 @click.argument('name')
463 @click.pass_context
464 def ns_op_list(ctx, name):
465 """shows the history of operations over a NS instance
466
467 NAME: name or ID of the NS instance
468 """
469 try:
470 check_client_version(ctx.obj, ctx.command.name)
471 resp = ctx.obj.ns.list_op(name)
472 except ClientException as e:
473 print(str(e))
474 exit(1)
475
476 table = PrettyTable(['id', 'operation', 'action_name', 'status'])
477 #print(yaml.safe_dump(resp))
478 for op in resp:
479 action_name = "N/A"
480 if op['lcmOperationType']=='action':
481 action_name = op['operationParams']['primitive']
482 table.add_row([op['id'], op['lcmOperationType'], action_name,
483 op['operationState']])
484 table.align = 'l'
485 print(table)
486
487
488 def nsi_list(ctx, filter):
489 """list all Network Slice Instances"""
490 try:
491 check_client_version(ctx.obj, ctx.command.name)
492 resp = ctx.obj.nsi.list(filter)
493 except ClientException as e:
494 print(str(e))
495 exit(1)
496 table = PrettyTable(
497 ['netslice instance name',
498 'id',
499 'operational status',
500 'config status',
501 'detailed status'])
502 for nsi in resp:
503 nsi_name = nsi['name']
504 nsi_id = nsi['_id']
505 opstatus = nsi['operational-status'] if 'operational-status' in nsi else 'Not found'
506 configstatus = nsi['config-status'] if 'config-status' in nsi else 'Not found'
507 detailed_status = nsi['detailed-status'] if 'detailed-status' in nsi else 'Not found'
508 if configstatus == "config_not_needed":
509 configstatus = "configured (no charms)"
510 table.add_row(
511 [nsi_name,
512 nsi_id,
513 opstatus,
514 configstatus,
515 detailed_status])
516 table.align = 'l'
517 print(table)
518
519
520 @cli.command(name='nsi-list', short_help='list all Network Slice Instances (NSI)')
521 @click.option('--filter', default=None,
522 help='restricts the list to the Network Slice Instances matching the filter')
523 @click.pass_context
524 def nsi_list1(ctx, filter):
525 """list all Network Slice Instances (NSI)"""
526 nsi_list(ctx, filter)
527
528
529 @cli.command(name='netslice-instance-list', short_help='list all Network Slice Instances (NSI)')
530 @click.option('--filter', default=None,
531 help='restricts the list to the Network Slice Instances matching the filter')
532 @click.pass_context
533 def nsi_list2(ctx, filter):
534 """list all Network Slice Instances (NSI)"""
535 nsi_list(ctx, filter)
536
537
538 def nst_list(ctx, filter):
539 try:
540 check_client_version(ctx.obj, ctx.command.name)
541 resp = ctx.obj.nst.list(filter)
542 except ClientException as e:
543 print(str(e))
544 exit(1)
545 # print(yaml.safe_dump(resp))
546 table = PrettyTable(['nst name', 'id'])
547 for nst in resp:
548 name = nst['name'] if 'name' in nst else '-'
549 table.add_row([name, nst['_id']])
550 table.align = 'l'
551 print(table)
552
553
554 @cli.command(name='nst-list', short_help='list all Network Slice Templates (NST)')
555 @click.option('--filter', default=None,
556 help='restricts the list to the NST matching the filter')
557 @click.pass_context
558 def nst_list1(ctx, filter):
559 """list all Network Slice Templates (NST) in the system"""
560 nst_list(ctx, filter)
561
562
563 @cli.command(name='netslice-template-list', short_help='list all Network Slice Templates (NST)')
564 @click.option('--filter', default=None,
565 help='restricts the list to the NST matching the filter')
566 @click.pass_context
567 def nst_list2(ctx, filter):
568 """list all Network Slice Templates (NST) in the system"""
569 nst_list(ctx, filter)
570
571
572 def nsi_op_list(ctx, name):
573 try:
574 check_client_version(ctx.obj, ctx.command.name)
575 resp = ctx.obj.nsi.list_op(name)
576 except ClientException as e:
577 print(str(e))
578 exit(1)
579 table = PrettyTable(['id', 'operation', 'status'])
580 for op in resp:
581 table.add_row([op['id'], op['lcmOperationType'],
582 op['operationState']])
583 table.align = 'l'
584 print(table)
585
586
587 @cli.command(name='nsi-op-list', short_help='shows the history of operations over a Network Slice Instance (NSI)')
588 @click.argument('name')
589 @click.pass_context
590 def nsi_op_list1(ctx, name):
591 """shows the history of operations over a Network Slice Instance (NSI)
592
593 NAME: name or ID of the Network Slice Instance
594 """
595 nsi_op_list(ctx, name)
596
597
598 @cli.command(name='netslice-instance-op-list', short_help='shows the history of operations over a Network Slice Instance (NSI)')
599 @click.argument('name')
600 @click.pass_context
601 def nsi_op_list2(ctx, name):
602 """shows the history of operations over a Network Slice Instance (NSI)
603
604 NAME: name or ID of the Network Slice Instance
605 """
606 nsi_op_list(ctx, name)
607
608
609 @cli.command(name='pdu-list', short_help='list all Physical Deployment Units (PDU)')
610 @click.option('--filter', default=None,
611 help='restricts the list to the Physical Deployment Units matching the filter')
612 @click.pass_context
613 def pdu_list(ctx, filter):
614 """list all Physical Deployment Units (PDU)"""
615 try:
616 check_client_version(ctx.obj, ctx.command.name)
617 resp = ctx.obj.pdu.list(filter)
618 except ClientException as e:
619 print(str(e))
620 exit(1)
621 table = PrettyTable(
622 ['pdu name',
623 'id',
624 'type',
625 'mgmt ip address'])
626 for pdu in resp:
627 pdu_name = pdu['name']
628 pdu_id = pdu['_id']
629 pdu_type = pdu['type']
630 pdu_ipaddress = "None"
631 for iface in pdu['interfaces']:
632 if iface['mgmt']:
633 pdu_ipaddress = iface['ip-address']
634 break
635 table.add_row(
636 [pdu_name,
637 pdu_id,
638 pdu_type,
639 pdu_ipaddress])
640 table.align = 'l'
641 print(table)
642
643
644 ####################
645 # SHOW operations
646 ####################
647
648 def nsd_show(ctx, name, literal):
649 try:
650 resp = ctx.obj.nsd.get(name)
651 # resp = ctx.obj.nsd.get_individual(name)
652 except ClientException as e:
653 print(str(e))
654 exit(1)
655
656 if literal:
657 print(yaml.safe_dump(resp))
658 return
659
660 table = PrettyTable(['field', 'value'])
661 for k, v in list(resp.items()):
662 table.add_row([k, json.dumps(v, indent=2)])
663 table.align = 'l'
664 print(table)
665
666
667 @cli.command(name='nsd-show', short_help='shows the content of a NSD')
668 @click.option('--literal', is_flag=True,
669 help='print literally, no pretty table')
670 @click.argument('name')
671 @click.pass_context
672 def nsd_show1(ctx, name, literal):
673 """shows the content of a NSD
674
675 NAME: name or ID of the NSD/NSpkg
676 """
677 nsd_show(ctx, name, literal)
678
679
680 @cli.command(name='nspkg-show', short_help='shows the content of a NSD')
681 @click.option('--literal', is_flag=True,
682 help='print literally, no pretty table')
683 @click.argument('name')
684 @click.pass_context
685 def nsd_show2(ctx, name, literal):
686 """shows the content of a NSD
687
688 NAME: name or ID of the NSD/NSpkg
689 """
690 nsd_show(ctx, name, literal)
691
692
693 def vnfd_show(ctx, name, literal):
694 try:
695 resp = ctx.obj.vnfd.get(name)
696 # resp = ctx.obj.vnfd.get_individual(name)
697 except ClientException as e:
698 print(str(e))
699 exit(1)
700
701 if literal:
702 print(yaml.safe_dump(resp))
703 return
704
705 table = PrettyTable(['field', 'value'])
706 for k, v in list(resp.items()):
707 table.add_row([k, json.dumps(v, indent=2)])
708 table.align = 'l'
709 print(table)
710
711
712 @cli.command(name='vnfd-show', short_help='shows the content of a VNFD')
713 @click.option('--literal', is_flag=True,
714 help='print literally, no pretty table')
715 @click.argument('name')
716 @click.pass_context
717 def vnfd_show1(ctx, name, literal):
718 """shows the content of a VNFD
719
720 NAME: name or ID of the VNFD/VNFpkg
721 """
722 vnfd_show(ctx, name, literal)
723
724
725 @cli.command(name='vnfpkg-show', short_help='shows the content of a VNFD')
726 @click.option('--literal', is_flag=True,
727 help='print literally, no pretty table')
728 @click.argument('name')
729 @click.pass_context
730 def vnfd_show2(ctx, name, literal):
731 """shows the content of a VNFD
732
733 NAME: name or ID of the VNFD/VNFpkg
734 """
735 vnfd_show(ctx, name, literal)
736
737
738 @cli.command(name='nfpkg-show', short_help='shows the content of a NF Descriptor')
739 @click.option('--literal', is_flag=True,
740 help='print literally, no pretty table')
741 @click.argument('name')
742 @click.pass_context
743 def nfpkg_show(ctx, name, literal):
744 """shows the content of a NF Descriptor
745
746 NAME: name or ID of the NFpkg
747 """
748 vnfd_show(ctx, name, literal)
749
750
751 @cli.command(name='ns-show', short_help='shows the info of a NS instance')
752 @click.argument('name')
753 @click.option('--literal', is_flag=True,
754 help='print literally, no pretty table')
755 @click.option('--filter', default=None)
756 @click.pass_context
757 def ns_show(ctx, name, literal, filter):
758 """shows the info of a NS instance
759
760 NAME: name or ID of the NS instance
761 """
762 try:
763 ns = ctx.obj.ns.get(name)
764 except ClientException as e:
765 print(str(e))
766 exit(1)
767
768 if literal:
769 print(yaml.safe_dump(ns))
770 return
771
772 table = PrettyTable(['field', 'value'])
773
774 for k, v in list(ns.items()):
775 if filter is None or filter in k:
776 table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
777
778 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
779 if fullclassname != 'osmclient.sol005.client.Client':
780 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
781 nsr_optdata = nsopdata['nsr:nsr']
782 for k, v in list(nsr_optdata.items()):
783 if filter is None or filter in k:
784 table.add_row([k, wrap_text(json.dumps(v, indent=2),width=100)])
785 table.align = 'l'
786 print(table)
787
788
789 @cli.command(name='vnf-show', short_help='shows the info of a VNF instance')
790 @click.argument('name')
791 @click.option('--literal', is_flag=True,
792 help='print literally, no pretty table')
793 @click.option('--filter', default=None, help='restricts the information to the fields in the filter')
794 @click.option('--kdu', default=None, help='KDU name (whose status will be shown)')
795 @click.pass_context
796 def vnf_show(ctx, name, literal, filter, kdu):
797 """shows the info of a VNF instance
798
799 NAME: name or ID of the VNF instance
800 """
801 if kdu:
802 if literal:
803 raise ClientException('"--literal" option is incompatible with "--kdu" option')
804 if filter:
805 raise ClientException('"--filter" option is incompatible with "--kdu" option')
806
807 try:
808 check_client_version(ctx.obj, ctx.command.name)
809 resp = ctx.obj.vnf.get(name)
810
811 if kdu:
812 ns_id = resp['nsr-id-ref']
813 op_data={}
814 op_data['member_vnf_index'] = resp['member-vnf-index-ref']
815 op_data['kdu_name'] = kdu
816 op_data['primitive'] = 'status'
817 op_data['primitive_params'] = {}
818 op_id = ctx.obj.ns.exec_op(ns_id, op_name='action', op_data=op_data, wait=False)
819 t = 0
820 while t<30:
821 op_info = ctx.obj.ns.get_op(op_id)
822 if op_info['operationState'] == 'COMPLETED':
823 print(op_info['detailed-status'])
824 return
825 time.sleep(5)
826 t += 5
827 print ("Could not determine KDU status")
828
829 if literal:
830 print(yaml.safe_dump(resp))
831 return
832
833 table = PrettyTable(['field', 'value'])
834
835 for k, v in list(resp.items()):
836 if filter is None or filter in k:
837 table.add_row([k, wrap_text(text=json.dumps(v,indent=2),width=100)])
838 table.align = 'l'
839 print(table)
840 except ClientException as e:
841 print(str(e))
842 exit(1)
843
844
845 #@cli.command(name='vnf-monitoring-show')
846 #@click.argument('vnf_name')
847 #@click.pass_context
848 #def vnf_monitoring_show(ctx, vnf_name):
849 # try:
850 # check_client_version(ctx.obj, ctx.command.name, 'v1')
851 # resp = ctx.obj.vnf.get_monitoring(vnf_name)
852 # except ClientException as e:
853 # print(str(e))
854 # exit(1)
855 #
856 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
857 # if resp is not None:
858 # for monitor in resp:
859 # table.add_row(
860 # [vnf_name,
861 # monitor['name'],
862 # monitor['value-integer'],
863 # monitor['units']])
864 # table.align = 'l'
865 # print(table)
866
867
868 #@cli.command(name='ns-monitoring-show')
869 #@click.argument('ns_name')
870 #@click.pass_context
871 #def ns_monitoring_show(ctx, ns_name):
872 # try:
873 # check_client_version(ctx.obj, ctx.command.name, 'v1')
874 # resp = ctx.obj.ns.get_monitoring(ns_name)
875 # except ClientException as e:
876 # print(str(e))
877 # exit(1)
878 #
879 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
880 # for key, val in list(resp.items()):
881 # for monitor in val:
882 # table.add_row(
883 # [key,
884 # monitor['name'],
885 # monitor['value-integer'],
886 # monitor['units']])
887 # table.align = 'l'
888 # print(table)
889
890
891 @cli.command(name='ns-op-show', short_help='shows the info of a NS operation')
892 @click.argument('id')
893 @click.option('--filter', default=None)
894 @click.option('--literal', is_flag=True,
895 help='print literally, no pretty table')
896 @click.pass_context
897 def ns_op_show(ctx, id, filter, literal):
898 """shows the detailed info of a NS operation
899
900 ID: operation identifier
901 """
902 try:
903 check_client_version(ctx.obj, ctx.command.name)
904 op_info = ctx.obj.ns.get_op(id)
905 except ClientException as e:
906 print(str(e))
907 exit(1)
908
909 if literal:
910 print(yaml.safe_dump(op_info))
911 return
912
913 table = PrettyTable(['field', 'value'])
914 for k, v in list(op_info.items()):
915 if filter is None or filter in k:
916 table.add_row([k, wrap_text(json.dumps(v, indent=2), 100)])
917 table.align = 'l'
918 print(table)
919
920
921 def nst_show(ctx, name, literal):
922 try:
923 check_client_version(ctx.obj, ctx.command.name)
924 resp = ctx.obj.nst.get(name)
925 #resp = ctx.obj.nst.get_individual(name)
926 except ClientException as e:
927 print(str(e))
928 exit(1)
929
930 if literal:
931 print(yaml.safe_dump(resp))
932 return
933
934 table = PrettyTable(['field', 'value'])
935 for k, v in list(resp.items()):
936 table.add_row([k, wrap_text(json.dumps(v, indent=2), 100)])
937 table.align = 'l'
938 print(table)
939
940
941 @cli.command(name='nst-show', short_help='shows the content of a Network Slice Template (NST)')
942 @click.option('--literal', is_flag=True,
943 help='print literally, no pretty table')
944 @click.argument('name')
945 @click.pass_context
946 def nst_show1(ctx, name, literal):
947 """shows the content of a Network Slice Template (NST)
948
949 NAME: name or ID of the NST
950 """
951 nst_show(ctx, name, literal)
952
953
954 @cli.command(name='netslice-template-show', short_help='shows the content of a Network Slice Template (NST)')
955 @click.option('--literal', is_flag=True,
956 help='print literally, no pretty table')
957 @click.argument('name')
958 @click.pass_context
959 def nst_show2(ctx, name, literal):
960 """shows the content of a Network Slice Template (NST)
961
962 NAME: name or ID of the NST
963 """
964 nst_show(ctx, name, literal)
965
966
967 def nsi_show(ctx, name, literal, filter):
968 try:
969 check_client_version(ctx.obj, ctx.command.name)
970 nsi = ctx.obj.nsi.get(name)
971 except ClientException as e:
972 print(str(e))
973 exit(1)
974
975 if literal:
976 print(yaml.safe_dump(nsi))
977 return
978
979 table = PrettyTable(['field', 'value'])
980
981 for k, v in list(nsi.items()):
982 if filter is None or filter in k:
983 table.add_row([k, json.dumps(v, indent=2)])
984
985 table.align = 'l'
986 print(table)
987
988
989 @cli.command(name='nsi-show', short_help='shows the content of a Network Slice Instance (NSI)')
990 @click.argument('name')
991 @click.option('--literal', is_flag=True,
992 help='print literally, no pretty table')
993 @click.option('--filter', default=None)
994 @click.pass_context
995 def nsi_show1(ctx, name, literal, filter):
996 """shows the content of a Network Slice Instance (NSI)
997
998 NAME: name or ID of the Network Slice Instance
999 """
1000 nsi_show(ctx, name, literal, filter)
1001
1002
1003 @cli.command(name='netslice-instance-show', short_help='shows the content of a Network Slice Instance (NSI)')
1004 @click.argument('name')
1005 @click.option('--literal', is_flag=True,
1006 help='print literally, no pretty table')
1007 @click.option('--filter', default=None)
1008 @click.pass_context
1009 def nsi_show2(ctx, name, literal, filter):
1010 """shows the content of a Network Slice Instance (NSI)
1011
1012 NAME: name or ID of the Network Slice Instance
1013 """
1014 nsi_show(ctx, name, literal, filter)
1015
1016
1017 def nsi_op_show(ctx, id, filter):
1018 try:
1019 check_client_version(ctx.obj, ctx.command.name)
1020 op_info = ctx.obj.nsi.get_op(id)
1021 except ClientException as e:
1022 print(str(e))
1023 exit(1)
1024
1025 table = PrettyTable(['field', 'value'])
1026 for k, v in list(op_info.items()):
1027 if filter is None or filter in k:
1028 table.add_row([k, json.dumps(v, indent=2)])
1029 table.align = 'l'
1030 print(table)
1031
1032
1033 @cli.command(name='nsi-op-show', short_help='shows the info of an operation over a Network Slice Instance(NSI)')
1034 @click.argument('id')
1035 @click.option('--filter', default=None)
1036 @click.pass_context
1037 def nsi_op_show1(ctx, id, filter):
1038 """shows the info of an operation over a Network Slice Instance(NSI)
1039
1040 ID: operation identifier
1041 """
1042 nsi_op_show(ctx, id, filter)
1043
1044
1045 @cli.command(name='netslice-instance-op-show', short_help='shows the info of an operation over a Network Slice Instance(NSI)')
1046 @click.argument('id')
1047 @click.option('--filter', default=None)
1048 @click.pass_context
1049 def nsi_op_show2(ctx, id, filter):
1050 """shows the info of an operation over a Network Slice Instance(NSI)
1051
1052 ID: operation identifier
1053 """
1054 nsi_op_show(ctx, id, filter)
1055
1056
1057 @cli.command(name='pdu-show', short_help='shows the content of a Physical Deployment Unit (PDU)')
1058 @click.argument('name')
1059 @click.option('--literal', is_flag=True,
1060 help='print literally, no pretty table')
1061 @click.option('--filter', default=None)
1062 @click.pass_context
1063 def pdu_show(ctx, name, literal, filter):
1064 """shows the content of a Physical Deployment Unit (PDU)
1065
1066 NAME: name or ID of the PDU
1067 """
1068 try:
1069 check_client_version(ctx.obj, ctx.command.name)
1070 pdu = ctx.obj.pdu.get(name)
1071 except ClientException as e:
1072 print(str(e))
1073 exit(1)
1074
1075 if literal:
1076 print(yaml.safe_dump(pdu))
1077 return
1078
1079 table = PrettyTable(['field', 'value'])
1080
1081 for k, v in list(pdu.items()):
1082 if filter is None or filter in k:
1083 table.add_row([k, json.dumps(v, indent=2)])
1084
1085 table.align = 'l'
1086 print(table)
1087
1088
1089 ####################
1090 # CREATE operations
1091 ####################
1092
1093 def nsd_create(ctx, filename, overwrite):
1094 try:
1095 check_client_version(ctx.obj, ctx.command.name)
1096 ctx.obj.nsd.create(filename, overwrite)
1097 except ClientException as e:
1098 print(str(e))
1099 exit(1)
1100
1101
1102 @cli.command(name='nsd-create', short_help='creates a new NSD/NSpkg')
1103 @click.argument('filename')
1104 @click.option('--overwrite', 'overwrite', default=None,
1105 help='overwrite deprecated, use override')
1106 @click.option('--override', 'overwrite', default=None,
1107 help='overrides fields in descriptor, format: '
1108 '"key1.key2...=value[;key3...=value;...]"')
1109 @click.pass_context
1110 def nsd_create1(ctx, filename, overwrite):
1111 """creates a new NSD/NSpkg
1112
1113 FILENAME: NSD yaml file or NSpkg tar.gz file
1114 """
1115 nsd_create(ctx, filename, overwrite)
1116
1117
1118 @cli.command(name='nspkg-create', short_help='creates a new NSD/NSpkg')
1119 @click.argument('filename')
1120 @click.option('--overwrite', 'overwrite', default=None,
1121 help='overwrite deprecated, use override')
1122 @click.option('--override', 'overwrite', default=None,
1123 help='overrides fields in descriptor, format: '
1124 '"key1.key2...=value[;key3...=value;...]"')
1125 @click.pass_context
1126 def nsd_create2(ctx, filename, overwrite):
1127 """creates a new NSD/NSpkg
1128
1129 FILENAME: NSD yaml file or NSpkg tar.gz file
1130 """
1131 nsd_create(ctx, filename, overwrite)
1132
1133
1134 def vnfd_create(ctx, filename, overwrite):
1135 try:
1136 check_client_version(ctx.obj, ctx.command.name)
1137 ctx.obj.vnfd.create(filename, overwrite)
1138 except ClientException as e:
1139 print(str(e))
1140 exit(1)
1141
1142
1143 @cli.command(name='vnfd-create', short_help='creates a new VNFD/VNFpkg')
1144 @click.argument('filename')
1145 @click.option('--overwrite', 'overwrite', default=None,
1146 help='overwrite deprecated, use override')
1147 @click.option('--override', 'overwrite', default=None,
1148 help='overrides fields in descriptor, format: '
1149 '"key1.key2...=value[;key3...=value;...]"')
1150 @click.pass_context
1151 def vnfd_create1(ctx, filename, overwrite):
1152 """creates a new VNFD/VNFpkg
1153
1154 FILENAME: VNFD yaml file or VNFpkg tar.gz file
1155 """
1156 vnfd_create(ctx, filename, overwrite)
1157
1158
1159 @cli.command(name='vnfpkg-create', short_help='creates a new VNFD/VNFpkg')
1160 @click.argument('filename')
1161 @click.option('--overwrite', 'overwrite', default=None,
1162 help='overwrite deprecated, use override')
1163 @click.option('--override', 'overwrite', default=None,
1164 help='overrides fields in descriptor, format: '
1165 '"key1.key2...=value[;key3...=value;...]"')
1166 @click.pass_context
1167 def vnfd_create2(ctx, filename, overwrite):
1168 """creates a new VNFD/VNFpkg
1169
1170 FILENAME: VNFD yaml file or VNFpkg tar.gz file
1171 """
1172 vnfd_create(ctx, filename, overwrite)
1173
1174
1175 @cli.command(name='nfpkg-create', short_help='creates a new NFpkg')
1176 @click.argument('filename')
1177 @click.option('--overwrite', 'overwrite', default=None,
1178 help='overwrite deprecated, use override')
1179 @click.option('--override', 'overwrite', default=None,
1180 help='overrides fields in descriptor, format: '
1181 '"key1.key2...=value[;key3...=value;...]"')
1182 @click.pass_context
1183 def nfpkg_create(ctx, filename, overwrite):
1184 """creates a new NFpkg
1185
1186 FILENAME: NF Descriptor yaml file or NFpkg tar.gz file
1187 """
1188 vnfd_create(ctx, filename, overwrite)
1189
1190
1191 @cli.command(name='ns-create', short_help='creates a new Network Service instance')
1192 @click.option('--ns_name',
1193 prompt=True, help='name of the NS instance')
1194 @click.option('--nsd_name',
1195 prompt=True, help='name of the NS descriptor')
1196 @click.option('--vim_account',
1197 prompt=True, help='default VIM account id or name for the deployment')
1198 @click.option('--admin_status',
1199 default='ENABLED',
1200 help='administration status')
1201 @click.option('--ssh_keys',
1202 default=None,
1203 help='comma separated list of public key files to inject to vnfs')
1204 @click.option('--config',
1205 default=None,
1206 help='ns specific yaml configuration')
1207 @click.option('--config_file',
1208 default=None,
1209 help='ns specific yaml configuration file')
1210 @click.option('--wait',
1211 required=False,
1212 default=False,
1213 is_flag=True,
1214 help='do not return the control immediately, but keep it \
1215 until the operation is completed, or timeout')
1216 @click.pass_context
1217 def ns_create(ctx,
1218 nsd_name,
1219 ns_name,
1220 vim_account,
1221 admin_status,
1222 ssh_keys,
1223 config,
1224 config_file,
1225 wait):
1226 """creates a new NS instance"""
1227 try:
1228 if config_file:
1229 check_client_version(ctx.obj, '--config_file')
1230 if config:
1231 raise ClientException('"--config" option is incompatible with "--config_file" option')
1232 with open(config_file, 'r') as cf:
1233 config=cf.read()
1234 ctx.obj.ns.create(
1235 nsd_name,
1236 ns_name,
1237 config=config,
1238 ssh_keys=ssh_keys,
1239 account=vim_account,
1240 wait=wait)
1241 except ClientException as e:
1242 print(str(e))
1243 exit(1)
1244
1245
1246 def nst_create(ctx, filename, overwrite):
1247 try:
1248 check_client_version(ctx.obj, ctx.command.name)
1249 ctx.obj.nst.create(filename, overwrite)
1250 except ClientException as e:
1251 print(str(e))
1252 exit(1)
1253
1254
1255 @cli.command(name='nst-create', short_help='creates a new Network Slice Template (NST)')
1256 @click.argument('filename')
1257 @click.option('--overwrite', 'overwrite', default=None,
1258 help='overwrites deprecated use override')
1259 @click.option('--override', 'overwrite' ,default=None,
1260 help='overrides fields in descriptor, format: '
1261 '"key1.key2...=value[;key3...=value;...]"')
1262 @click.pass_context
1263 def nst_create1(ctx, filename, overwrite):
1264 """creates a new Network Slice Template (NST)
1265
1266 FILENAME: NST yaml file or NSTpkg tar.gz file
1267 """
1268 nst_create(ctx, filename, overwrite)
1269
1270
1271 @cli.command(name='netslice-template-create', short_help='creates a new Network Slice Template (NST)')
1272 @click.argument('filename')
1273 @click.option('--overwrite', 'overwrite', default=None,
1274 help='overwrites deprecated use override')
1275 @click.option('--override', 'overwrite', default=None,
1276 help='overrides fields in descriptor, format: '
1277 '"key1.key2...=value[;key3...=value;...]"')
1278 @click.pass_context
1279 def nst_create2(ctx, filename, overwrite):
1280 """creates a new Network Slice Template (NST)
1281
1282 FILENAME: NST yaml file or NSTpkg tar.gz file
1283 """
1284 nst_create(ctx, filename, overwrite)
1285
1286
1287 def nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1288 """creates a new Network Slice Instance (NSI)"""
1289 try:
1290 check_client_version(ctx.obj, ctx.command.name)
1291 if config_file:
1292 if config:
1293 raise ClientException('"--config" option is incompatible with "--config_file" option')
1294 with open(config_file, 'r') as cf:
1295 config=cf.read()
1296 ctx.obj.nsi.create(nst_name, nsi_name, config=config, ssh_keys=ssh_keys,
1297 account=vim_account, wait=wait)
1298 except ClientException as e:
1299 print(str(e))
1300 exit(1)
1301
1302
1303 @cli.command(name='nsi-create', short_help='creates a new Network Slice Instance')
1304 @click.option('--nsi_name', prompt=True, help='name of the Network Slice Instance')
1305 @click.option('--nst_name', prompt=True, help='name of the Network Slice Template')
1306 @click.option('--vim_account', prompt=True, help='default VIM account id or name for the deployment')
1307 @click.option('--ssh_keys', default=None,
1308 help='comma separated list of keys to inject to vnfs')
1309 @click.option('--config', default=None,
1310 help='Netslice specific yaml configuration:\n'
1311 'netslice_subnet: [\n'
1312 'id: TEXT, vim_account: TEXT,\n'
1313 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1314 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n'
1315 'additionalParamsForNsi: {param: value, ...}\n'
1316 'additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n'
1317 '],\n'
1318 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1319 )
1320 @click.option('--config_file',
1321 default=None,
1322 help='nsi specific yaml configuration file')
1323 @click.option('--wait',
1324 required=False,
1325 default=False,
1326 is_flag=True,
1327 help='do not return the control immediately, but keep it \
1328 until the operation is completed, or timeout')
1329 @click.pass_context
1330 def nsi_create1(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1331 """creates a new Network Slice Instance (NSI)"""
1332 nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
1333
1334
1335 @cli.command(name='netslice-instance-create', short_help='creates a new Network Slice Instance')
1336 @click.option('--nsi_name', prompt=True, help='name of the Network Slice Instance')
1337 @click.option('--nst_name', prompt=True, help='name of the Network Slice Template')
1338 @click.option('--vim_account', prompt=True, help='default VIM account id or name for the deployment')
1339 @click.option('--ssh_keys', default=None,
1340 help='comma separated list of keys to inject to vnfs')
1341 @click.option('--config', default=None,
1342 help='Netslice specific yaml configuration:\n'
1343 'netslice_subnet: [\n'
1344 'id: TEXT, vim_account: TEXT,\n'
1345 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1346 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1347 '],\n'
1348 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1349 )
1350 @click.option('--config_file',
1351 default=None,
1352 help='nsi specific yaml configuration file')
1353 @click.option('--wait',
1354 required=False,
1355 default=False,
1356 is_flag=True,
1357 help='do not return the control immediately, but keep it \
1358 until the operation is completed, or timeout')
1359 @click.pass_context
1360 def nsi_create2(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1361 """creates a new Network Slice Instance (NSI)"""
1362 nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
1363
1364
1365 @cli.command(name='pdu-create', short_help='adds a new Physical Deployment Unit to the catalog')
1366 @click.option('--name', help='name of the Physical Deployment Unit')
1367 @click.option('--pdu_type', help='type of PDU (e.g. router, firewall, FW001)')
1368 @click.option('--interface',
1369 help='interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>'+
1370 '[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]',
1371 multiple=True)
1372 @click.option('--description', help='human readable description')
1373 @click.option('--vim_account', help='list of VIM accounts (in the same VIM) that can reach this PDU', multiple=True)
1374 @click.option('--descriptor_file', default=None, help='PDU descriptor file (as an alternative to using the other arguments')
1375 @click.pass_context
1376 def pdu_create(ctx, name, pdu_type, interface, description, vim_account, descriptor_file):
1377 """creates a new Physical Deployment Unit (PDU)"""
1378 try:
1379 check_client_version(ctx.obj, ctx.command.name)
1380 pdu = {}
1381 if not descriptor_file:
1382 if not name:
1383 raise ClientException('in absence of descriptor file, option "--name" is mandatory')
1384 if not pdu_type:
1385 raise ClientException('in absence of descriptor file, option "--pdu_type" is mandatory')
1386 if not interface:
1387 raise ClientException('in absence of descriptor file, option "--interface" is mandatory (at least once)')
1388 if not vim_account:
1389 raise ClientException('in absence of descriptor file, option "--vim_account" is mandatory (at least once)')
1390 else:
1391 with open(descriptor_file, 'r') as df:
1392 pdu = yaml.safe_load(df.read())
1393 if name: pdu["name"] = name
1394 if pdu_type: pdu["type"] = pdu_type
1395 if description: pdu["description"] = description
1396 if vim_account: pdu["vim_accounts"] = vim_account
1397 if interface:
1398 ifaces_list = []
1399 for iface in interface:
1400 new_iface={k:v for k,v in [i.split('=') for i in iface.split(',')]}
1401 new_iface["mgmt"] = (new_iface.get("mgmt","false").lower() == "true")
1402 ifaces_list.append(new_iface)
1403 pdu["interfaces"] = ifaces_list
1404 ctx.obj.pdu.create(pdu)
1405 except ClientException as e:
1406 print(str(e))
1407 exit(1)
1408
1409 ####################
1410 # UPDATE operations
1411 ####################
1412
1413 def nsd_update(ctx, name, content):
1414 try:
1415 check_client_version(ctx.obj, ctx.command.name)
1416 ctx.obj.nsd.update(name, content)
1417 except ClientException as e:
1418 print(str(e))
1419 exit(1)
1420
1421
1422 @cli.command(name='nsd-update', short_help='updates a NSD/NSpkg')
1423 @click.argument('name')
1424 @click.option('--content', default=None,
1425 help='filename with the NSD/NSpkg replacing the current one')
1426 @click.pass_context
1427 def nsd_update1(ctx, name, content):
1428 """updates a NSD/NSpkg
1429
1430 NAME: name or ID of the NSD/NSpkg
1431 """
1432 nsd_update(ctx, name, content)
1433
1434
1435 @cli.command(name='nspkg-update', short_help='updates a NSD/NSpkg')
1436 @click.argument('name')
1437 @click.option('--content', default=None,
1438 help='filename with the NSD/NSpkg replacing the current one')
1439 @click.pass_context
1440 def nsd_update2(ctx, name, content):
1441 """updates a NSD/NSpkg
1442
1443 NAME: name or ID of the NSD/NSpkg
1444 """
1445 nsd_update(ctx, name, content)
1446
1447
1448 def vnfd_update(ctx, name, content):
1449 try:
1450 check_client_version(ctx.obj, ctx.command.name)
1451 ctx.obj.vnfd.update(name, content)
1452 except ClientException as e:
1453 print(str(e))
1454 exit(1)
1455
1456
1457 @cli.command(name='vnfd-update', short_help='updates a new VNFD/VNFpkg')
1458 @click.argument('name')
1459 @click.option('--content', default=None,
1460 help='filename with the VNFD/VNFpkg replacing the current one')
1461 @click.pass_context
1462 def vnfd_update1(ctx, name, content):
1463 """updates a VNFD/VNFpkg
1464
1465 NAME: name or ID of the VNFD/VNFpkg
1466 """
1467 vnfd_update(ctx, name, content)
1468
1469
1470 @cli.command(name='vnfpkg-update', short_help='updates a VNFD/VNFpkg')
1471 @click.argument('name')
1472 @click.option('--content', default=None,
1473 help='filename with the VNFD/VNFpkg replacing the current one')
1474 @click.pass_context
1475 def vnfd_update2(ctx, name, content):
1476 """updates a VNFD/VNFpkg
1477
1478 NAME: VNFD yaml file or VNFpkg tar.gz file
1479 """
1480 vnfd_update(ctx, name, content)
1481
1482
1483 @cli.command(name='nfpkg-update', short_help='updates a NFpkg')
1484 @click.argument('name')
1485 @click.option('--content', default=None,
1486 help='filename with the NFpkg replacing the current one')
1487 @click.pass_context
1488 def nfpkg_update(ctx, name, content):
1489 """updates a NFpkg
1490
1491 NAME: NF Descriptor yaml file or NFpkg tar.gz file
1492 """
1493 vnfd_update(ctx, name, content)
1494
1495
1496 def nst_update(ctx, name, content):
1497 try:
1498 check_client_version(ctx.obj, ctx.command.name)
1499 ctx.obj.nst.update(name, content)
1500 except ClientException as e:
1501 print(str(e))
1502 exit(1)
1503
1504
1505 @cli.command(name='nst-update', short_help='updates a Network Slice Template (NST)')
1506 @click.argument('name')
1507 @click.option('--content', default=None,
1508 help='filename with the NST/NSTpkg replacing the current one')
1509 @click.pass_context
1510 def nst_update1(ctx, name, content):
1511 """updates a Network Slice Template (NST)
1512
1513 NAME: name or ID of the NSD/NSpkg
1514 """
1515 nst_update(ctx, name, content)
1516
1517
1518 @cli.command(name='netslice-template-update', short_help='updates a Network Slice Template (NST)')
1519 @click.argument('name')
1520 @click.option('--content', default=None,
1521 help='filename with the NST/NSTpkg replacing the current one')
1522 @click.pass_context
1523 def nst_update2(ctx, name, content):
1524 """updates a Network Slice Template (NST)
1525
1526 NAME: name or ID of the NSD/NSpkg
1527 """
1528 nst_update(ctx, name, content)
1529
1530
1531 ####################
1532 # DELETE operations
1533 ####################
1534
1535 def nsd_delete(ctx, name, force):
1536 try:
1537 if not force:
1538 ctx.obj.nsd.delete(name)
1539 else:
1540 check_client_version(ctx.obj, '--force')
1541 ctx.obj.nsd.delete(name, force)
1542 except ClientException as e:
1543 print(str(e))
1544 exit(1)
1545
1546
1547 @cli.command(name='nsd-delete', short_help='deletes a NSD/NSpkg')
1548 @click.argument('name')
1549 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1550 @click.pass_context
1551 def nsd_delete1(ctx, name, force):
1552 """deletes a NSD/NSpkg
1553
1554 NAME: name or ID of the NSD/NSpkg to be deleted
1555 """
1556 nsd_delete(ctx, name, force)
1557
1558
1559 @cli.command(name='nspkg-delete', short_help='deletes a NSD/NSpkg')
1560 @click.argument('name')
1561 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1562 @click.pass_context
1563 def nsd_delete2(ctx, name, force):
1564 """deletes a NSD/NSpkg
1565
1566 NAME: name or ID of the NSD/NSpkg to be deleted
1567 """
1568 nsd_delete(ctx, name, force)
1569
1570
1571 def vnfd_delete(ctx, name, force):
1572 try:
1573 if not force:
1574 ctx.obj.vnfd.delete(name)
1575 else:
1576 check_client_version(ctx.obj, '--force')
1577 ctx.obj.vnfd.delete(name, force)
1578 except ClientException as e:
1579 print(str(e))
1580 exit(1)
1581
1582
1583 @cli.command(name='vnfd-delete', short_help='deletes a VNFD/VNFpkg')
1584 @click.argument('name')
1585 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1586 @click.pass_context
1587 def vnfd_delete1(ctx, name, force):
1588 """deletes a VNFD/VNFpkg
1589
1590 NAME: name or ID of the VNFD/VNFpkg to be deleted
1591 """
1592 vnfd_delete(ctx, name, force)
1593
1594
1595 @cli.command(name='vnfpkg-delete', short_help='deletes a VNFD/VNFpkg')
1596 @click.argument('name')
1597 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1598 @click.pass_context
1599 def vnfd_delete2(ctx, name, force):
1600 """deletes a VNFD/VNFpkg
1601
1602 NAME: name or ID of the VNFD/VNFpkg to be deleted
1603 """
1604 vnfd_delete(ctx, name, force)
1605
1606
1607 @cli.command(name='nfpkg-delete', short_help='deletes a NFpkg')
1608 @click.argument('name')
1609 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1610 @click.pass_context
1611 def nfpkg_delete(ctx, name, force):
1612 """deletes a NFpkg
1613
1614 NAME: name or ID of the NFpkg to be deleted
1615 """
1616 vnfd_delete(ctx, name, force)
1617
1618
1619 @cli.command(name='ns-delete', short_help='deletes a NS instance')
1620 @click.argument('name')
1621 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1622 @click.option('--wait',
1623 required=False,
1624 default=False,
1625 is_flag=True,
1626 help='do not return the control immediately, but keep it \
1627 until the operation is completed, or timeout')
1628 @click.pass_context
1629 def ns_delete(ctx, name, force, wait):
1630 """deletes a NS instance
1631
1632 NAME: name or ID of the NS instance to be deleted
1633 """
1634 try:
1635 if not force:
1636 ctx.obj.ns.delete(name, wait=wait)
1637 else:
1638 check_client_version(ctx.obj, '--force')
1639 ctx.obj.ns.delete(name, force, wait=wait)
1640 except ClientException as e:
1641 print(str(e))
1642 exit(1)
1643
1644
1645 def nst_delete(ctx, name, force):
1646 try:
1647 check_client_version(ctx.obj, ctx.command.name)
1648 ctx.obj.nst.delete(name, force)
1649 except ClientException as e:
1650 print(str(e))
1651 exit(1)
1652
1653
1654 @cli.command(name='nst-delete', short_help='deletes a Network Slice Template (NST)')
1655 @click.argument('name')
1656 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1657 @click.pass_context
1658 def nst_delete1(ctx, name, force):
1659 """deletes a Network Slice Template (NST)
1660
1661 NAME: name or ID of the NST/NSTpkg to be deleted
1662 """
1663 nst_delete(ctx, name, force)
1664
1665
1666 @cli.command(name='netslice-template-delete', short_help='deletes a Network Slice Template (NST)')
1667 @click.argument('name')
1668 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1669 @click.pass_context
1670 def nst_delete2(ctx, name, force):
1671 """deletes a Network Slice Template (NST)
1672
1673 NAME: name or ID of the NST/NSTpkg to be deleted
1674 """
1675 nst_delete(ctx, name, force)
1676
1677
1678 def nsi_delete(ctx, name, force, wait):
1679 try:
1680 check_client_version(ctx.obj, ctx.command.name)
1681 ctx.obj.nsi.delete(name, force, wait=wait)
1682 except ClientException as e:
1683 print(str(e))
1684 exit(1)
1685
1686
1687 @cli.command(name='nsi-delete', short_help='deletes a Network Slice Instance (NSI)')
1688 @click.argument('name')
1689 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1690 @click.option('--wait',
1691 required=False,
1692 default=False,
1693 is_flag=True,
1694 help='do not return the control immediately, but keep it \
1695 until the operation is completed, or timeout')
1696 @click.pass_context
1697 def nsi_delete1(ctx, name, force, wait):
1698 """deletes a Network Slice Instance (NSI)
1699
1700 NAME: name or ID of the Network Slice instance to be deleted
1701 """
1702 nsi_delete(ctx, name, force, wait=wait)
1703
1704
1705 @cli.command(name='netslice-instance-delete', short_help='deletes a Network Slice Instance (NSI)')
1706 @click.argument('name')
1707 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1708 @click.pass_context
1709 def nsi_delete2(ctx, name, force, wait):
1710 """deletes a Network Slice Instance (NSI)
1711
1712 NAME: name or ID of the Network Slice instance to be deleted
1713 """
1714 nsi_delete(ctx, name, force, wait=wait)
1715
1716
1717 @cli.command(name='pdu-delete', short_help='deletes a Physical Deployment Unit (PDU)')
1718 @click.argument('name')
1719 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1720 @click.pass_context
1721 def pdu_delete(ctx, name, force):
1722 """deletes a Physical Deployment Unit (PDU)
1723
1724 NAME: name or ID of the PDU to be deleted
1725 """
1726 try:
1727 check_client_version(ctx.obj, ctx.command.name)
1728 ctx.obj.pdu.delete(name, force)
1729 except ClientException as e:
1730 print(str(e))
1731 exit(1)
1732
1733
1734 #################
1735 # VIM operations
1736 #################
1737
1738 @cli.command(name='vim-create', short_help='creates a new VIM account')
1739 @click.option('--name',
1740 prompt=True,
1741 help='Name to create datacenter')
1742 @click.option('--user',
1743 prompt=True,
1744 help='VIM username')
1745 @click.option('--password',
1746 prompt=True,
1747 hide_input=True,
1748 confirmation_prompt=True,
1749 help='VIM password')
1750 @click.option('--auth_url',
1751 prompt=True,
1752 help='VIM url')
1753 @click.option('--tenant',
1754 prompt=True,
1755 help='VIM tenant name')
1756 @click.option('--config',
1757 default=None,
1758 help='VIM specific config parameters')
1759 @click.option('--account_type',
1760 default='openstack',
1761 help='VIM type')
1762 @click.option('--description',
1763 default='no description',
1764 help='human readable description')
1765 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller associated to this VIM account')
1766 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
1767 @click.option('--wait',
1768 required=False,
1769 default=False,
1770 is_flag=True,
1771 help='do not return the control immediately, but keep it \
1772 until the operation is completed, or timeout')
1773 @click.pass_context
1774 def vim_create(ctx,
1775 name,
1776 user,
1777 password,
1778 auth_url,
1779 tenant,
1780 config,
1781 account_type,
1782 description,
1783 sdn_controller,
1784 sdn_port_mapping,
1785 wait):
1786 """creates a new VIM account"""
1787 try:
1788 if sdn_controller:
1789 check_client_version(ctx.obj, '--sdn_controller')
1790 if sdn_port_mapping:
1791 check_client_version(ctx.obj, '--sdn_port_mapping')
1792 vim = {}
1793 vim['vim-username'] = user
1794 vim['vim-password'] = password
1795 vim['vim-url'] = auth_url
1796 vim['vim-tenant-name'] = tenant
1797 vim['vim-type'] = account_type
1798 vim['description'] = description
1799 vim['config'] = config
1800 if sdn_controller or sdn_port_mapping:
1801 ctx.obj.vim.create(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
1802 else:
1803 ctx.obj.vim.create(name, vim, wait=wait)
1804 except ClientException as e:
1805 print(str(e))
1806 exit(1)
1807
1808
1809 @cli.command(name='vim-update', short_help='updates a VIM account')
1810 @click.argument('name')
1811 @click.option('--newname', help='New name for the VIM account')
1812 @click.option('--user', help='VIM username')
1813 @click.option('--password', help='VIM password')
1814 @click.option('--auth_url', help='VIM url')
1815 @click.option('--tenant', help='VIM tenant name')
1816 @click.option('--config', help='VIM specific config parameters')
1817 @click.option('--account_type', help='VIM type')
1818 @click.option('--description', help='human readable description')
1819 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller associated to this VIM account')
1820 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
1821 @click.option('--wait',
1822 required=False,
1823 default=False,
1824 is_flag=True,
1825 help='do not return the control immediately, but keep it \
1826 until the operation is completed, or timeout')
1827 @click.pass_context
1828 def vim_update(ctx,
1829 name,
1830 newname,
1831 user,
1832 password,
1833 auth_url,
1834 tenant,
1835 config,
1836 account_type,
1837 description,
1838 sdn_controller,
1839 sdn_port_mapping,
1840 wait):
1841 """updates a VIM account
1842
1843 NAME: name or ID of the VIM account
1844 """
1845 try:
1846 check_client_version(ctx.obj, ctx.command.name)
1847 vim = {}
1848 if newname: vim['name'] = newname
1849 if user: vim['vim_user'] = user
1850 if password: vim['vim_password'] = password
1851 if auth_url: vim['vim_url'] = auth_url
1852 if tenant: vim['vim-tenant-name'] = tenant
1853 if account_type: vim['vim_type'] = account_type
1854 if description: vim['description'] = description
1855 if config: vim['config'] = config
1856 ctx.obj.vim.update(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
1857 except ClientException as e:
1858 print(str(e))
1859 exit(1)
1860
1861
1862 @cli.command(name='vim-delete', short_help='deletes a VIM account')
1863 @click.argument('name')
1864 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1865 @click.option('--wait',
1866 required=False,
1867 default=False,
1868 is_flag=True,
1869 help='do not return the control immediately, but keep it \
1870 until the operation is completed, or timeout')
1871 @click.pass_context
1872 def vim_delete(ctx, name, force, wait):
1873 """deletes a VIM account
1874
1875 NAME: name or ID of the VIM account to be deleted
1876 """
1877 try:
1878 if not force:
1879 ctx.obj.vim.delete(name, wait=wait)
1880 else:
1881 check_client_version(ctx.obj, '--force')
1882 ctx.obj.vim.delete(name, force, wait=wait)
1883 except ClientException as e:
1884 print(str(e))
1885 exit(1)
1886
1887
1888 @cli.command(name='vim-list', short_help='list all VIM accounts')
1889 #@click.option('--ro_update/--no_ro_update',
1890 # default=False,
1891 # help='update list from RO')
1892 @click.option('--filter', default=None,
1893 help='restricts the list to the VIM accounts matching the filter')
1894 @click.pass_context
1895 def vim_list(ctx, filter):
1896 """list all VIM accounts"""
1897 if filter:
1898 check_client_version(ctx.obj, '--filter')
1899 # if ro_update:
1900 # check_client_version(ctx.obj, '--ro_update', 'v1')
1901 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
1902 if fullclassname == 'osmclient.sol005.client.Client':
1903 resp = ctx.obj.vim.list(filter)
1904 # else:
1905 # resp = ctx.obj.vim.list(ro_update)
1906 table = PrettyTable(['vim name', 'uuid'])
1907 for vim in resp:
1908 table.add_row([vim['name'], vim['uuid']])
1909 table.align = 'l'
1910 print(table)
1911
1912
1913 @cli.command(name='vim-show', short_help='shows the details of a VIM account')
1914 @click.argument('name')
1915 @click.pass_context
1916 def vim_show(ctx, name):
1917 """shows the details of a VIM account
1918
1919 NAME: name or ID of the VIM account
1920 """
1921 try:
1922 resp = ctx.obj.vim.get(name)
1923 if 'vim_password' in resp:
1924 resp['vim_password']='********'
1925 except ClientException as e:
1926 print(str(e))
1927 exit(1)
1928
1929 table = PrettyTable(['key', 'attribute'])
1930 for k, v in list(resp.items()):
1931 table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
1932 table.align = 'l'
1933 print(table)
1934
1935
1936 ####################
1937 # WIM operations
1938 ####################
1939
1940 @cli.command(name='wim-create', short_help='creates a new WIM account')
1941 @click.option('--name',
1942 prompt=True,
1943 help='Name for the WIM account')
1944 @click.option('--user',
1945 help='WIM username')
1946 @click.option('--password',
1947 help='WIM password')
1948 @click.option('--url',
1949 prompt=True,
1950 help='WIM url')
1951 # @click.option('--tenant',
1952 # help='wIM tenant name')
1953 @click.option('--config',
1954 default=None,
1955 help='WIM specific config parameters')
1956 @click.option('--wim_type',
1957 help='WIM type')
1958 @click.option('--description',
1959 default='no description',
1960 help='human readable description')
1961 @click.option('--wim_port_mapping', default=None, help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge (WAN service endpoint id and info)")
1962 @click.option('--wait',
1963 required=False,
1964 default=False,
1965 is_flag=True,
1966 help='do not return the control immediately, but keep it \
1967 until the operation is completed, or timeout')
1968 @click.pass_context
1969 def wim_create(ctx,
1970 name,
1971 user,
1972 password,
1973 url,
1974 # tenant,
1975 config,
1976 wim_type,
1977 description,
1978 wim_port_mapping,
1979 wait):
1980 """creates a new WIM account"""
1981 try:
1982 check_client_version(ctx.obj, ctx.command.name)
1983 # if sdn_controller:
1984 # check_client_version(ctx.obj, '--sdn_controller')
1985 # if sdn_port_mapping:
1986 # check_client_version(ctx.obj, '--sdn_port_mapping')
1987 wim = {}
1988 if user: wim['user'] = user
1989 if password: wim['password'] = password
1990 if url: wim['wim_url'] = url
1991 # if tenant: wim['tenant'] = tenant
1992 wim['wim_type'] = wim_type
1993 if description: wim['description'] = description
1994 if config: wim['config'] = config
1995 ctx.obj.wim.create(name, wim, wim_port_mapping, wait=wait)
1996 except ClientException as e:
1997 print(str(e))
1998 exit(1)
1999
2000
2001 @cli.command(name='wim-update', short_help='updates a WIM account')
2002 @click.argument('name')
2003 @click.option('--newname', help='New name for the WIM account')
2004 @click.option('--user', help='WIM username')
2005 @click.option('--password', help='WIM password')
2006 @click.option('--url', help='WIM url')
2007 @click.option('--config', help='WIM specific config parameters')
2008 @click.option('--wim_type', help='WIM type')
2009 @click.option('--description', help='human readable description')
2010 @click.option('--wim_port_mapping', default=None, help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge (WAN service endpoint id and info)")
2011 @click.option('--wait',
2012 required=False,
2013 default=False,
2014 is_flag=True,
2015 help='do not return the control immediately, but keep it \
2016 until the operation is completed, or timeout')
2017 @click.pass_context
2018 def wim_update(ctx,
2019 name,
2020 newname,
2021 user,
2022 password,
2023 url,
2024 config,
2025 wim_type,
2026 description,
2027 wim_port_mapping,
2028 wait):
2029 """updates a WIM account
2030
2031 NAME: name or ID of the WIM account
2032 """
2033 try:
2034 check_client_version(ctx.obj, ctx.command.name)
2035 wim = {}
2036 if newname: wim['name'] = newname
2037 if user: wim['user'] = user
2038 if password: wim['password'] = password
2039 if url: wim['url'] = url
2040 # if tenant: wim['tenant'] = tenant
2041 if wim_type: wim['wim_type'] = wim_type
2042 if description: wim['description'] = description
2043 if config: wim['config'] = config
2044 ctx.obj.wim.update(name, wim, wim_port_mapping, wait=wait)
2045 except ClientException as e:
2046 print(str(e))
2047 exit(1)
2048
2049
2050 @cli.command(name='wim-delete', short_help='deletes a WIM account')
2051 @click.argument('name')
2052 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2053 @click.option('--wait',
2054 required=False,
2055 default=False,
2056 is_flag=True,
2057 help='do not return the control immediately, but keep it \
2058 until the operation is completed, or timeout')
2059 @click.pass_context
2060 def wim_delete(ctx, name, force, wait):
2061 """deletes a WIM account
2062
2063 NAME: name or ID of the WIM account to be deleted
2064 """
2065 try:
2066 check_client_version(ctx.obj, ctx.command.name)
2067 ctx.obj.wim.delete(name, force, wait=wait)
2068 except ClientException as e:
2069 print(str(e))
2070 exit(1)
2071
2072
2073 @cli.command(name='wim-list', short_help='list all WIM accounts')
2074 @click.option('--filter', default=None,
2075 help='restricts the list to the WIM accounts matching the filter')
2076 @click.pass_context
2077 def wim_list(ctx, filter):
2078 """list all WIM accounts"""
2079 try:
2080 check_client_version(ctx.obj, ctx.command.name)
2081 resp = ctx.obj.wim.list(filter)
2082 table = PrettyTable(['wim name', 'uuid'])
2083 for wim in resp:
2084 table.add_row([wim['name'], wim['uuid']])
2085 table.align = 'l'
2086 print(table)
2087 except ClientException as e:
2088 print(str(e))
2089 exit(1)
2090
2091
2092 @cli.command(name='wim-show', short_help='shows the details of a WIM account')
2093 @click.argument('name')
2094 @click.pass_context
2095 def wim_show(ctx, name):
2096 """shows the details of a WIM account
2097
2098 NAME: name or ID of the WIM account
2099 """
2100 try:
2101 check_client_version(ctx.obj, ctx.command.name)
2102 resp = ctx.obj.wim.get(name)
2103 if 'password' in resp:
2104 resp['wim_password']='********'
2105 except ClientException as e:
2106 print(str(e))
2107 exit(1)
2108
2109 table = PrettyTable(['key', 'attribute'])
2110 for k, v in list(resp.items()):
2111 table.add_row([k, json.dumps(v, indent=2)])
2112 table.align = 'l'
2113 print(table)
2114
2115
2116 ####################
2117 # SDN controller operations
2118 ####################
2119
2120 @cli.command(name='sdnc-create', short_help='creates a new SDN controller')
2121 @click.option('--name',
2122 prompt=True,
2123 help='Name to create sdn controller')
2124 @click.option('--type',
2125 prompt=True,
2126 help='SDN controller type')
2127 @click.option('--sdn_controller_version',
2128 help='SDN controller version')
2129 @click.option('--ip_address',
2130 prompt=True,
2131 help='SDN controller IP address')
2132 @click.option('--port',
2133 prompt=True,
2134 help='SDN controller port')
2135 @click.option('--switch_dpid',
2136 prompt=True,
2137 help='Switch DPID (Openflow Datapath ID)')
2138 @click.option('--user',
2139 help='SDN controller username')
2140 @click.option('--password',
2141 hide_input=True,
2142 confirmation_prompt=True,
2143 help='SDN controller password')
2144 #@click.option('--description',
2145 # default='no description',
2146 # help='human readable description')
2147 @click.option('--wait',
2148 required=False,
2149 default=False,
2150 is_flag=True,
2151 help='do not return the control immediately, but keep it \
2152 until the operation is completed, or timeout')
2153 @click.pass_context
2154 def sdnc_create(ctx,
2155 name,
2156 type,
2157 sdn_controller_version,
2158 ip_address,
2159 port,
2160 switch_dpid,
2161 user,
2162 password,
2163 wait):
2164 """creates a new SDN controller"""
2165 sdncontroller = {}
2166 sdncontroller['name'] = name
2167 sdncontroller['type'] = type
2168 sdncontroller['ip'] = ip_address
2169 sdncontroller['port'] = int(port)
2170 sdncontroller['dpid'] = switch_dpid
2171 if sdn_controller_version:
2172 sdncontroller['version'] = sdn_controller_version
2173 if user:
2174 sdncontroller['user'] = user
2175 if password:
2176 sdncontroller['password'] = password
2177 # sdncontroller['description'] = description
2178 try:
2179 check_client_version(ctx.obj, ctx.command.name)
2180 ctx.obj.sdnc.create(name, sdncontroller, wait=wait)
2181 except ClientException as e:
2182 print(str(e))
2183 exit(1)
2184
2185 @cli.command(name='sdnc-update', short_help='updates an SDN controller')
2186 @click.argument('name')
2187 @click.option('--newname', help='New name for the SDN controller')
2188 @click.option('--type', help='SDN controller type')
2189 @click.option('--sdn_controller_version', help='SDN controller username')
2190 @click.option('--ip_address', help='SDN controller IP address')
2191 @click.option('--port', help='SDN controller port')
2192 @click.option('--switch_dpid', help='Switch DPID (Openflow Datapath ID)')
2193 @click.option('--user', help='SDN controller username')
2194 @click.option('--password', help='SDN controller password')
2195 #@click.option('--description', default=None, help='human readable description')
2196 @click.option('--wait',
2197 required=False,
2198 default=False,
2199 is_flag=True,
2200 help='do not return the control immediately, but keep it \
2201 until the operation is completed, or timeout')
2202 @click.pass_context
2203 def sdnc_update(ctx,
2204 name,
2205 newname,
2206 type,
2207 sdn_controller_version,
2208 ip_address,
2209 port,
2210 switch_dpid,
2211 user,
2212 password,
2213 wait):
2214 """updates an SDN controller
2215
2216 NAME: name or ID of the SDN controller
2217 """
2218 sdncontroller = {}
2219 if newname: sdncontroller['name'] = newname
2220 if type: sdncontroller['type'] = type
2221 if ip_address: sdncontroller['ip'] = ip_address
2222 if port: sdncontroller['port'] = int(port)
2223 if switch_dpid: sdncontroller['dpid'] = switch_dpid
2224 # sdncontroller['description'] = description
2225 if sdn_controller_version is not None:
2226 if sdn_controller_version=="":
2227 sdncontroller['version'] = None
2228 else:
2229 sdncontroller['version'] = sdn_controller_version
2230 if user is not None:
2231 if user=="":
2232 sdncontroller['user'] = None
2233 else:
2234 sdncontroller['user'] = user
2235 if password is not None:
2236 if password=="":
2237 sdncontroller['password'] = None
2238 else:
2239 sdncontroller['password'] = user
2240 try:
2241 check_client_version(ctx.obj, ctx.command.name)
2242 ctx.obj.sdnc.update(name, sdncontroller, wait=wait)
2243 except ClientException as e:
2244 print(str(e))
2245 exit(1)
2246
2247
2248 @cli.command(name='sdnc-delete', short_help='deletes an SDN controller')
2249 @click.argument('name')
2250 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2251 @click.option('--wait',
2252 required=False,
2253 default=False,
2254 is_flag=True,
2255 help='do not return the control immediately, but keep it \
2256 until the operation is completed, or timeout')
2257 @click.pass_context
2258 def sdnc_delete(ctx, name, force, wait):
2259 """deletes an SDN controller
2260
2261 NAME: name or ID of the SDN controller to be deleted
2262 """
2263 try:
2264 check_client_version(ctx.obj, ctx.command.name)
2265 ctx.obj.sdnc.delete(name, force, wait=wait)
2266 except ClientException as e:
2267 print(str(e))
2268 exit(1)
2269
2270
2271 @cli.command(name='sdnc-list', short_help='list all SDN controllers')
2272 @click.option('--filter', default=None,
2273 help='restricts the list to the SDN controllers matching the filter')
2274 @click.pass_context
2275 def sdnc_list(ctx, filter):
2276 """list all SDN controllers"""
2277 try:
2278 check_client_version(ctx.obj, ctx.command.name)
2279 resp = ctx.obj.sdnc.list(filter)
2280 except ClientException as e:
2281 print(str(e))
2282 exit(1)
2283 table = PrettyTable(['sdnc name', 'id'])
2284 for sdnc in resp:
2285 table.add_row([sdnc['name'], sdnc['_id']])
2286 table.align = 'l'
2287 print(table)
2288
2289
2290 @cli.command(name='sdnc-show', short_help='shows the details of an SDN controller')
2291 @click.argument('name')
2292 @click.pass_context
2293 def sdnc_show(ctx, name):
2294 """shows the details of an SDN controller
2295
2296 NAME: name or ID of the SDN controller
2297 """
2298 try:
2299 check_client_version(ctx.obj, ctx.command.name)
2300 resp = ctx.obj.sdnc.get(name)
2301 except ClientException as e:
2302 print(str(e))
2303 exit(1)
2304
2305 table = PrettyTable(['key', 'attribute'])
2306 for k, v in list(resp.items()):
2307 table.add_row([k, json.dumps(v, indent=2)])
2308 table.align = 'l'
2309 print(table)
2310
2311
2312 ###########################
2313 # K8s cluster operations
2314 ###########################
2315
2316 @cli.command(name='k8scluster-add')
2317 @click.argument('name')
2318 @click.option('--creds',
2319 prompt=True,
2320 help='credentials file, i.e. a valid `.kube/config` file')
2321 @click.option('--version',
2322 prompt=True,
2323 help='Kubernetes version')
2324 @click.option('--vim',
2325 prompt=True,
2326 help='VIM target, the VIM where the cluster resides')
2327 @click.option('--k8s-nets',
2328 prompt=True,
2329 help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"')
2330 @click.option('--description',
2331 default='',
2332 help='human readable description')
2333 @click.option('--namespace',
2334 default='kube-system',
2335 help='namespace to be used for its operation, defaults to `kube-system`')
2336 @click.option('--cni',
2337 default=None,
2338 help='list of CNI plugins, in JSON inline format, used in the cluster')
2339 #@click.option('--skip-init',
2340 # is_flag=True,
2341 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
2342 #@click.option('--wait',
2343 # is_flag=True,
2344 # help='do not return the control immediately, but keep it \
2345 # until the operation is completed, or timeout')
2346 @click.pass_context
2347 def k8scluster_add(ctx,
2348 name,
2349 creds,
2350 version,
2351 vim,
2352 k8s_nets,
2353 description,
2354 namespace,
2355 cni):
2356 """adds a K8s cluster to OSM
2357
2358 NAME: name of the K8s cluster
2359 """
2360 try:
2361 check_client_version(ctx.obj, ctx.command.name)
2362 cluster = {}
2363 cluster['name'] = name
2364 with open(creds, 'r') as cf:
2365 cluster['credentials'] = yaml.safe_load(cf.read())
2366 cluster['k8s_version'] = version
2367 cluster['vim_account'] = vim
2368 cluster['nets'] = yaml.safe_load(k8s_nets)
2369 cluster['description'] = description
2370 if namespace: cluster['namespace'] = namespace
2371 if cni: cluster['cni'] = yaml.safe_load(cni)
2372 ctx.obj.k8scluster.create(name, cluster)
2373 except ClientException as e:
2374 print(str(e))
2375 exit(1)
2376
2377
2378 @cli.command(name='k8scluster-update', short_help='updates a K8s cluster')
2379 @click.argument('name')
2380 @click.option('--newname', help='New name for the K8s cluster')
2381 @click.option('--creds', help='credentials file, i.e. a valid `.kube/config` file')
2382 @click.option('--version', help='Kubernetes version')
2383 @click.option('--vim', help='VIM target, the VIM where the cluster resides')
2384 @click.option('--k8s-nets', help='list of VIM networks, in JSON inline format, where the cluster is accessible via L3 routing, e.g. "{(k8s_net1:vim_network1) [,(k8s_net2:vim_network2) ...]}"')
2385 @click.option('--description', help='human readable description')
2386 @click.option('--namespace', help='namespace to be used for its operation, defaults to `kube-system`')
2387 @click.option('--cni', help='list of CNI plugins, in JSON inline format, used in the cluster')
2388 @click.pass_context
2389 def k8scluster_update(ctx,
2390 name,
2391 newname,
2392 creds,
2393 version,
2394 vim,
2395 k8s_nets,
2396 description,
2397 namespace,
2398 cni):
2399 """updates a K8s cluster
2400
2401 NAME: name or ID of the K8s cluster
2402 """
2403 try:
2404 check_client_version(ctx.obj, ctx.command.name)
2405 cluster = {}
2406 if newname: cluster['name'] = newname
2407 if creds:
2408 with open(creds, 'r') as cf:
2409 cluster['credentials'] = yaml.safe_load(cf.read())
2410 if version: cluster['k8s_version'] = version
2411 if vim: cluster['vim_account'] = vim
2412 if k8s_nets: cluster['nets'] = yaml.safe_load(k8s_nets)
2413 if description: cluster['description'] = description
2414 if namespace: cluster['namespace'] = namespace
2415 if cni: cluster['cni'] = yaml.safe_load(cni)
2416 ctx.obj.k8scluster.update(name, cluster)
2417 except ClientException as e:
2418 print(str(e))
2419 exit(1)
2420
2421
2422 @cli.command(name='k8scluster-delete')
2423 @click.argument('name')
2424 @click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
2425 #@click.option('--wait',
2426 # is_flag=True,
2427 # help='do not return the control immediately, but keep it \
2428 # until the operation is completed, or timeout')
2429 @click.pass_context
2430 def k8scluster_delete(ctx, name, force):
2431 """deletes a K8s cluster
2432
2433 NAME: name or ID of the K8s cluster to be deleted
2434 """
2435 try:
2436 check_client_version(ctx.obj, ctx.command.name)
2437 ctx.obj.k8scluster.delete(name, force=force)
2438 except ClientException as e:
2439 print(str(e))
2440 exit(1)
2441
2442
2443 @cli.command(name='k8scluster-list')
2444 @click.option('--filter', default=None,
2445 help='restricts the list to the K8s clusters matching the filter')
2446 @click.option('--literal', is_flag=True,
2447 help='print literally, no pretty table')
2448 @click.pass_context
2449 def k8scluster_list(ctx, filter, literal):
2450 """list all K8s clusters"""
2451 try:
2452 check_client_version(ctx.obj, ctx.command.name)
2453 resp = ctx.obj.k8scluster.list(filter)
2454 if literal:
2455 print(yaml.safe_dump(resp))
2456 return
2457 table = PrettyTable(['Name', 'Id', 'Version', 'VIM', 'K8s-nets', 'Description'])
2458 for cluster in resp:
2459 table.add_row([cluster['name'], cluster['_id'], cluster['k8s_version'], cluster['vim_account'],
2460 json.dumps(cluster['nets']), trunc_text(cluster.get('description',''),40)
2461 ])
2462 table.align = 'l'
2463 print(table)
2464 except ClientException as e:
2465 print(str(e))
2466 exit(1)
2467
2468
2469 @cli.command(name='k8scluster-show')
2470 @click.argument('name')
2471 @click.option('--literal', is_flag=True,
2472 help='print literally, no pretty table')
2473 @click.pass_context
2474 def k8scluster_show(ctx, name, literal):
2475 """shows the details of a K8s cluster
2476
2477 NAME: name or ID of the K8s cluster
2478 """
2479 try:
2480 resp = ctx.obj.k8scluster.get(name)
2481 if literal:
2482 print(yaml.safe_dump(resp))
2483 return
2484 table = PrettyTable(['key', 'attribute'])
2485 for k, v in list(resp.items()):
2486 table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
2487 table.align = 'l'
2488 print(table)
2489 except ClientException as e:
2490 print(str(e))
2491 exit(1)
2492
2493
2494
2495 ###########################
2496 # Repo operations
2497 ###########################
2498
2499 @cli.command(name='repo-add')
2500 @click.argument('name')
2501 @click.argument('uri')
2502 @click.option('--type',
2503 type=click.Choice(['chart', 'bundle']),
2504 prompt=True,
2505 help='type of repo (chart for helm-charts, bundle for juju-bundles)')
2506 @click.option('--description',
2507 default='',
2508 help='human readable description')
2509 #@click.option('--wait',
2510 # is_flag=True,
2511 # help='do not return the control immediately, but keep it \
2512 # until the operation is completed, or timeout')
2513 @click.pass_context
2514 def repo_add(ctx,
2515 name,
2516 uri,
2517 type,
2518 description):
2519 """adds a repo to OSM
2520
2521 NAME: name of the repo
2522 URI: URI of the repo
2523 """
2524 try:
2525 check_client_version(ctx.obj, ctx.command.name)
2526 repo = {}
2527 repo['name'] = name
2528 repo['url'] = uri
2529 repo['type'] = type
2530 repo['description'] = description
2531 ctx.obj.repo.create(name, repo)
2532 except ClientException as e:
2533 print(str(e))
2534 exit(1)
2535
2536
2537 @cli.command(name='repo-update')
2538 @click.argument('name')
2539 @click.option('--newname', help='New name for the repo')
2540 @click.option('--uri', help='URI of the repo')
2541 @click.option('--type', type=click.Choice(['chart', 'bundle']),
2542 help='type of repo (chart for helm-charts, bundle for juju-bundles)')
2543 @click.option('--description', help='human readable description')
2544 #@click.option('--wait',
2545 # is_flag=True,
2546 # help='do not return the control immediately, but keep it \
2547 # until the operation is completed, or timeout')
2548 @click.pass_context
2549 def repo_update(ctx,
2550 name,
2551 newname,
2552 uri,
2553 type,
2554 description):
2555 """updates a repo in OSM
2556
2557 NAME: name of the repo
2558 """
2559 try:
2560 check_client_version(ctx.obj, ctx.command.name)
2561 repo = {}
2562 if newname: repo['name'] = newname
2563 if uri: repo['uri'] = uri
2564 if type: repo['type'] = type
2565 if description: repo['description'] = description
2566 ctx.obj.repo.update(name, repo)
2567 except ClientException as e:
2568 print(str(e))
2569 exit(1)
2570
2571
2572 @cli.command(name='repo-delete')
2573 @click.argument('name')
2574 @click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
2575 #@click.option('--wait',
2576 # is_flag=True,
2577 # help='do not return the control immediately, but keep it \
2578 # until the operation is completed, or timeout')
2579 @click.pass_context
2580 def repo_delete(ctx, name, force):
2581 """deletes a repo
2582
2583 NAME: name or ID of the repo to be deleted
2584 """
2585 try:
2586 check_client_version(ctx.obj, ctx.command.name)
2587 ctx.obj.repo.delete(name, force=force)
2588 except ClientException as e:
2589 print(str(e))
2590 exit(1)
2591
2592
2593 @cli.command(name='repo-list')
2594 @click.option('--filter', default=None,
2595 help='restricts the list to the repos matching the filter')
2596 @click.option('--literal', is_flag=True,
2597 help='print literally, no pretty table')
2598 @click.pass_context
2599 def repo_list(ctx, filter, literal):
2600 """list all repos"""
2601 try:
2602 check_client_version(ctx.obj, ctx.command.name)
2603 resp = ctx.obj.repo.list(filter)
2604 if literal:
2605 print(yaml.safe_dump(resp))
2606 return
2607 table = PrettyTable(['Name', 'Id', 'Type', 'URI', 'Description'])
2608 for repo in resp:
2609 #cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
2610 table.add_row([repo['name'], repo['_id'], repo['type'], repo['url'], trunc_text(repo.get('description',''),40)])
2611 table.align = 'l'
2612 print(table)
2613 except ClientException as e:
2614 print(str(e))
2615 exit(1)
2616
2617
2618 @cli.command(name='repo-show')
2619 @click.argument('name')
2620 @click.option('--literal', is_flag=True,
2621 help='print literally, no pretty table')
2622 @click.pass_context
2623 def repo_show(ctx, name, literal):
2624 """shows the details of a repo
2625
2626 NAME: name or ID of the repo
2627 """
2628 try:
2629 resp = ctx.obj.repo.get(name)
2630 if literal:
2631 print(yaml.safe_dump(resp))
2632 return
2633 table = PrettyTable(['key', 'attribute'])
2634 for k, v in list(resp.items()):
2635 table.add_row([k, json.dumps(v, indent=2)])
2636 table.align = 'l'
2637 print(table)
2638 except ClientException as e:
2639 print(str(e))
2640 exit(1)
2641
2642
2643
2644 ####################
2645 # Project mgmt operations
2646 ####################
2647
2648 @cli.command(name='project-create', short_help='creates a new project')
2649 @click.argument('name')
2650 #@click.option('--description',
2651 # default='no description',
2652 # help='human readable description')
2653 @click.pass_context
2654 def project_create(ctx, name):
2655 """Creates a new project
2656
2657 NAME: name of the project
2658 """
2659 project = {}
2660 project['name'] = name
2661 try:
2662 check_client_version(ctx.obj, ctx.command.name)
2663 ctx.obj.project.create(name, project)
2664 except ClientException as e:
2665 print(str(e))
2666 exit(1)
2667
2668
2669 @cli.command(name='project-delete', short_help='deletes a project')
2670 @click.argument('name')
2671 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2672 @click.pass_context
2673 def project_delete(ctx, name):
2674 """deletes a project
2675
2676 NAME: name or ID of the project to be deleted
2677 """
2678 try:
2679 check_client_version(ctx.obj, ctx.command.name)
2680 ctx.obj.project.delete(name)
2681 except ClientException as e:
2682 print(str(e))
2683 exit(1)
2684
2685
2686 @cli.command(name='project-list', short_help='list all projects')
2687 @click.option('--filter', default=None,
2688 help='restricts the list to the projects matching the filter')
2689 @click.pass_context
2690 def project_list(ctx, filter):
2691 """list all projects"""
2692 try:
2693 check_client_version(ctx.obj, ctx.command.name)
2694 resp = ctx.obj.project.list(filter)
2695 except ClientException as e:
2696 print(str(e))
2697 exit(1)
2698 table = PrettyTable(['name', 'id'])
2699 for proj in resp:
2700 table.add_row([proj['name'], proj['_id']])
2701 table.align = 'l'
2702 print(table)
2703
2704
2705 @cli.command(name='project-show', short_help='shows the details of a project')
2706 @click.argument('name')
2707 @click.pass_context
2708 def project_show(ctx, name):
2709 """shows the details of a project
2710
2711 NAME: name or ID of the project
2712 """
2713 try:
2714 check_client_version(ctx.obj, ctx.command.name)
2715 resp = ctx.obj.project.get(name)
2716 except ClientException as e:
2717 print(str(e))
2718 exit(1)
2719
2720 table = PrettyTable(['key', 'attribute'])
2721 for k, v in resp.items():
2722 table.add_row([k, json.dumps(v, indent=2)])
2723 table.align = 'l'
2724 print(table)
2725
2726
2727 @cli.command(name='project-update', short_help='updates a project (only the name can be updated)')
2728 @click.argument('project')
2729 @click.option('--name',
2730 prompt=True,
2731 help='new name for the project')
2732
2733 @click.pass_context
2734 def project_update(ctx, project, name):
2735 """
2736 Update a project name
2737
2738 :param ctx:
2739 :param project: id or name of the project to modify
2740 :param name: new name for the project
2741 :return:
2742 """
2743
2744 project_changes = {}
2745 project_changes['name'] = name
2746
2747 try:
2748 check_client_version(ctx.obj, ctx.command.name)
2749 ctx.obj.project.update(project, project_changes)
2750 except ClientException as e:
2751 print(str(e))
2752
2753
2754 ####################
2755 # User mgmt operations
2756 ####################
2757
2758 @cli.command(name='user-create', short_help='creates a new user')
2759 @click.argument('username')
2760 @click.option('--password',
2761 prompt=True,
2762 hide_input=True,
2763 confirmation_prompt=True,
2764 help='user password')
2765 @click.option('--projects',
2766 # prompt="Comma separate list of projects",
2767 multiple=True,
2768 callback=lambda ctx, param, value: ''.join(value).split(',') if all(len(x)==1 for x in value) else value,
2769 help='list of project ids that the user belongs to')
2770 @click.option('--project-role-mappings', 'project_role_mappings',
2771 default=None, multiple=True,
2772 help='creating user project/role(s) mapping')
2773 @click.pass_context
2774 def user_create(ctx, username, password, projects, project_role_mappings):
2775 """Creates a new user
2776
2777 \b
2778 USERNAME: name of the user
2779 PASSWORD: password of the user
2780 PROJECTS: projects assigned to user (internal only)
2781 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
2782 """
2783 user = {}
2784 user['username'] = username
2785 user['password'] = password
2786 user['projects'] = projects
2787 user['project_role_mappings'] = project_role_mappings
2788
2789 try:
2790 check_client_version(ctx.obj, ctx.command.name)
2791 ctx.obj.user.create(username, user)
2792 except ClientException as e:
2793 print(str(e))
2794 exit(1)
2795
2796
2797 @cli.command(name='user-update', short_help='updates user information')
2798 @click.argument('username')
2799 @click.option('--password',
2800 # prompt=True,
2801 # hide_input=True,
2802 # confirmation_prompt=True,
2803 help='user password')
2804 @click.option('--set-username', 'set_username',
2805 default=None,
2806 help='change username')
2807 @click.option('--set-project', 'set_project',
2808 default=None, multiple=True,
2809 help='create/replace the project,role(s) mapping for this project: \'project,role1,role2,...\'')
2810 @click.option('--remove-project', 'remove_project',
2811 default=None, multiple=True,
2812 help='removes project from user: \'project\'')
2813 @click.option('--add-project-role', 'add_project_role',
2814 default=None, multiple=True,
2815 help='adds project,role(s) mapping: \'project,role1,role2,...\'')
2816 @click.option('--remove-project-role', 'remove_project_role',
2817 default=None, multiple=True,
2818 help='removes project,role(s) mapping: \'project,role1,role2,...\'')
2819 @click.pass_context
2820 def user_update(ctx, username, password, set_username, set_project, remove_project,
2821 add_project_role, remove_project_role):
2822 """Update a user information
2823
2824 \b
2825 USERNAME: name of the user
2826 PASSWORD: new password
2827 SET_USERNAME: new username
2828 SET_PROJECT: creating mappings for project/role(s)
2829 REMOVE_PROJECT: deleting mappings for project/role(s)
2830 ADD_PROJECT_ROLE: adding mappings for project/role(s)
2831 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
2832 """
2833 user = {}
2834 user['password'] = password
2835 user['username'] = set_username
2836 user['set-project'] = set_project
2837 user['remove-project'] = remove_project
2838 user['add-project-role'] = add_project_role
2839 user['remove-project-role'] = remove_project_role
2840
2841 try:
2842 check_client_version(ctx.obj, ctx.command.name)
2843 ctx.obj.user.update(username, user)
2844 except ClientException as e:
2845 print(str(e))
2846 exit(1)
2847
2848
2849 @cli.command(name='user-delete', short_help='deletes a user')
2850 @click.argument('name')
2851 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2852 @click.pass_context
2853 def user_delete(ctx, name):
2854 """deletes a user
2855
2856 \b
2857 NAME: name or ID of the user to be deleted
2858 """
2859 try:
2860 check_client_version(ctx.obj, ctx.command.name)
2861 ctx.obj.user.delete(name)
2862 except ClientException as e:
2863 print(str(e))
2864 exit(1)
2865
2866
2867 @cli.command(name='user-list', short_help='list all users')
2868 @click.option('--filter', default=None,
2869 help='restricts the list to the users matching the filter')
2870 @click.pass_context
2871 def user_list(ctx, filter):
2872 """list all users"""
2873 try:
2874 check_client_version(ctx.obj, ctx.command.name)
2875 resp = ctx.obj.user.list(filter)
2876 except ClientException as e:
2877 print(str(e))
2878 exit(1)
2879 table = PrettyTable(['name', 'id'])
2880 for user in resp:
2881 table.add_row([user['username'], user['_id']])
2882 table.align = 'l'
2883 print(table)
2884
2885
2886 @cli.command(name='user-show', short_help='shows the details of a user')
2887 @click.argument('name')
2888 @click.pass_context
2889 def user_show(ctx, name):
2890 """shows the details of a user
2891
2892 NAME: name or ID of the user
2893 """
2894 try:
2895 check_client_version(ctx.obj, ctx.command.name)
2896 resp = ctx.obj.user.get(name)
2897 if 'password' in resp:
2898 resp['password']='********'
2899 except ClientException as e:
2900 print(str(e))
2901 exit(1)
2902
2903 table = PrettyTable(['key', 'attribute'])
2904 for k, v in resp.items():
2905 table.add_row([k, json.dumps(v, indent=2)])
2906 table.align = 'l'
2907 print(table)
2908
2909
2910 ####################
2911 # Fault Management operations
2912 ####################
2913
2914 @cli.command(name='ns-alarm-create')
2915 @click.argument('name')
2916 @click.option('--ns', prompt=True, help='NS instance id or name')
2917 @click.option('--vnf', prompt=True,
2918 help='VNF name (VNF member index as declared in the NSD)')
2919 @click.option('--vdu', prompt=True,
2920 help='VDU name (VDU name as declared in the VNFD)')
2921 @click.option('--metric', prompt=True,
2922 help='Name of the metric (e.g. cpu_utilization)')
2923 @click.option('--severity', default='WARNING',
2924 help='severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)')
2925 @click.option('--threshold_value', prompt=True,
2926 help='threshold value that, when crossed, an alarm is triggered')
2927 @click.option('--threshold_operator', prompt=True,
2928 help='threshold operator describing the comparison (GE, LE, GT, LT, EQ)')
2929 @click.option('--statistic', default='AVERAGE',
2930 help='statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)')
2931 @click.pass_context
2932 def ns_alarm_create(ctx, name, ns, vnf, vdu, metric, severity,
2933 threshold_value, threshold_operator, statistic):
2934 """creates a new alarm for a NS instance"""
2935 # TODO: Check how to validate threshold_value.
2936 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
2937 try:
2938 ns_instance = ctx.obj.ns.get(ns)
2939 alarm = {}
2940 alarm['alarm_name'] = name
2941 alarm['ns_id'] = ns_instance['_id']
2942 alarm['correlation_id'] = ns_instance['_id']
2943 alarm['vnf_member_index'] = vnf
2944 alarm['vdu_name'] = vdu
2945 alarm['metric_name'] = metric
2946 alarm['severity'] = severity
2947 alarm['threshold_value'] = int(threshold_value)
2948 alarm['operation'] = threshold_operator
2949 alarm['statistic'] = statistic
2950 check_client_version(ctx.obj, ctx.command.name)
2951 ctx.obj.ns.create_alarm(alarm)
2952 except ClientException as e:
2953 print(str(e))
2954 exit(1)
2955
2956
2957 #@cli.command(name='ns-alarm-delete')
2958 #@click.argument('name')
2959 #@click.pass_context
2960 #def ns_alarm_delete(ctx, name):
2961 # """deletes an alarm
2962 #
2963 # NAME: name of the alarm to be deleted
2964 # """
2965 # try:
2966 # check_client_version(ctx.obj, ctx.command.name)
2967 # ctx.obj.ns.delete_alarm(name)
2968 # except ClientException as e:
2969 # print(str(e))
2970 # exit(1)
2971
2972
2973 ####################
2974 # Performance Management operations
2975 ####################
2976
2977 @cli.command(name='ns-metric-export', short_help='exports a metric to the internal OSM bus, which can be read by other apps')
2978 @click.option('--ns', prompt=True, help='NS instance id or name')
2979 @click.option('--vnf', prompt=True,
2980 help='VNF name (VNF member index as declared in the NSD)')
2981 @click.option('--vdu', prompt=True,
2982 help='VDU name (VDU name as declared in the VNFD)')
2983 @click.option('--metric', prompt=True,
2984 help='name of the metric (e.g. cpu_utilization)')
2985 #@click.option('--period', default='1w',
2986 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
2987 @click.option('--interval', help='periodic interval (seconds) to export metrics continuously')
2988 @click.pass_context
2989 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
2990 """exports a metric to the internal OSM bus, which can be read by other apps"""
2991 # TODO: Check how to validate interval.
2992 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
2993 try:
2994 ns_instance = ctx.obj.ns.get(ns)
2995 metric_data = {}
2996 metric_data['ns_id'] = ns_instance['_id']
2997 metric_data['correlation_id'] = ns_instance['_id']
2998 metric_data['vnf_member_index'] = vnf
2999 metric_data['vdu_name'] = vdu
3000 metric_data['metric_name'] = metric
3001 metric_data['collection_unit'] = 'WEEK'
3002 metric_data['collection_period'] = 1
3003 check_client_version(ctx.obj, ctx.command.name)
3004 if not interval:
3005 print('{}'.format(ctx.obj.ns.export_metric(metric_data)))
3006 else:
3007 i = 1
3008 while True:
3009 print('{} {}'.format(ctx.obj.ns.export_metric(metric_data),i))
3010 time.sleep(int(interval))
3011 i+=1
3012 except ClientException as e:
3013 print(str(e))
3014 exit(1)
3015
3016
3017 ####################
3018 # Other operations
3019 ####################
3020
3021 @cli.command(name='upload-package', short_help='uploads a VNF package or NS package')
3022 @click.argument('filename')
3023 @click.pass_context
3024 def upload_package(ctx, filename):
3025 """uploads a VNF package or NS package
3026
3027 FILENAME: VNF or NS package file (tar.gz)
3028 """
3029 try:
3030 ctx.obj.package.upload(filename)
3031 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
3032 if fullclassname != 'osmclient.sol005.client.Client':
3033 ctx.obj.package.wait_for_upload(filename)
3034 except ClientException as e:
3035 print(str(e))
3036 exit(1)
3037
3038
3039 #@cli.command(name='ns-scaling-show')
3040 #@click.argument('ns_name')
3041 #@click.pass_context
3042 #def show_ns_scaling(ctx, ns_name):
3043 # """shows the status of a NS scaling operation
3044 #
3045 # NS_NAME: name of the NS instance being scaled
3046 # """
3047 # try:
3048 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3049 # resp = ctx.obj.ns.list()
3050 # except ClientException as e:
3051 # print(str(e))
3052 # exit(1)
3053 #
3054 # table = PrettyTable(
3055 # ['group-name',
3056 # 'instance-id',
3057 # 'operational status',
3058 # 'create-time',
3059 # 'vnfr ids'])
3060 #
3061 # for ns in resp:
3062 # if ns_name == ns['name']:
3063 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
3064 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
3065 # for record in scaling_records:
3066 # if 'instance' in record:
3067 # instances = record['instance']
3068 # for inst in instances:
3069 # table.add_row(
3070 # [record['scaling-group-name-ref'],
3071 # inst['instance-id'],
3072 # inst['op-status'],
3073 # time.strftime('%Y-%m-%d %H:%M:%S',
3074 # time.localtime(
3075 # inst['create-time'])),
3076 # inst['vnfrs']])
3077 # table.align = 'l'
3078 # print(table)
3079
3080
3081 #@cli.command(name='ns-scale')
3082 #@click.argument('ns_name')
3083 #@click.option('--ns_scale_group', prompt=True)
3084 #@click.option('--index', prompt=True)
3085 #@click.option('--wait',
3086 # required=False,
3087 # default=False,
3088 # is_flag=True,
3089 # help='do not return the control immediately, but keep it \
3090 # until the operation is completed, or timeout')
3091 #@click.pass_context
3092 #def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
3093 # """scales NS
3094 #
3095 # NS_NAME: name of the NS instance to be scaled
3096 # """
3097 # try:
3098 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3099 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
3100 # except ClientException as e:
3101 # print(str(e))
3102 # exit(1)
3103
3104
3105 #@cli.command(name='config-agent-list')
3106 #@click.pass_context
3107 #def config_agent_list(ctx):
3108 # """list config agents"""
3109 # try:
3110 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3111 # except ClientException as e:
3112 # print(str(e))
3113 # exit(1)
3114 # table = PrettyTable(['name', 'account-type', 'details'])
3115 # for account in ctx.obj.vca.list():
3116 # table.add_row(
3117 # [account['name'],
3118 # account['account-type'],
3119 # account['juju']])
3120 # table.align = 'l'
3121 # print(table)
3122
3123
3124 #@cli.command(name='config-agent-delete')
3125 #@click.argument('name')
3126 #@click.pass_context
3127 #def config_agent_delete(ctx, name):
3128 # """deletes a config agent
3129 #
3130 # NAME: name of the config agent to be deleted
3131 # """
3132 # try:
3133 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3134 # ctx.obj.vca.delete(name)
3135 # except ClientException as e:
3136 # print(str(e))
3137 # exit(1)
3138
3139
3140 #@cli.command(name='config-agent-add')
3141 #@click.option('--name',
3142 # prompt=True)
3143 #@click.option('--account_type',
3144 # prompt=True)
3145 #@click.option('--server',
3146 # prompt=True)
3147 #@click.option('--user',
3148 # prompt=True)
3149 #@click.option('--secret',
3150 # prompt=True,
3151 # hide_input=True,
3152 # confirmation_prompt=True)
3153 #@click.pass_context
3154 #def config_agent_add(ctx, name, account_type, server, user, secret):
3155 # """adds a config agent"""
3156 # try:
3157 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3158 # ctx.obj.vca.create(name, account_type, server, user, secret)
3159 # except ClientException as e:
3160 # print(str(e))
3161 # exit(1)
3162
3163
3164 #@cli.command(name='ro-dump')
3165 #@click.pass_context
3166 #def ro_dump(ctx):
3167 # """shows RO agent information"""
3168 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3169 # resp = ctx.obj.vim.get_resource_orchestrator()
3170 # table = PrettyTable(['key', 'attribute'])
3171 # for k, v in list(resp.items()):
3172 # table.add_row([k, json.dumps(v, indent=2)])
3173 # table.align = 'l'
3174 # print(table)
3175
3176
3177 #@cli.command(name='vcs-list')
3178 #@click.pass_context
3179 #def vcs_list(ctx):
3180 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3181 # resp = ctx.obj.utils.get_vcs_info()
3182 # table = PrettyTable(['component name', 'state'])
3183 # for component in resp:
3184 # table.add_row([component['component_name'], component['state']])
3185 # table.align = 'l'
3186 # print(table)
3187
3188
3189 @cli.command(name='ns-action', short_help='executes an action/primitive over a NS instance')
3190 @click.argument('ns_name')
3191 @click.option('--vnf_name', default=None, help='member-vnf-index if the target is a vnf instead of a ns)')
3192 @click.option('--kdu_name', default=None, help='kdu-name if the target is a kdu)')
3193 @click.option('--vdu_id', default=None, help='vdu-id if the target is a vdu')
3194 @click.option('--vdu_count', default=None, help='number of vdu instance of this vdu_id')
3195 @click.option('--action_name', prompt=True, help='action name')
3196 @click.option('--params', default=None, help='action params in YAML/JSON inline string')
3197 @click.option('--params_file', default=None, help='YAML/JSON file with action params')
3198 @click.option('--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 @click.pass_context
3205 def ns_action(ctx,
3206 ns_name,
3207 vnf_name,
3208 kdu_name,
3209 vdu_id,
3210 vdu_count,
3211 action_name,
3212 params,
3213 params_file,
3214 wait):
3215 """executes an action/primitive over a NS instance
3216
3217 NS_NAME: name or ID of the NS instance
3218 """
3219 try:
3220 check_client_version(ctx.obj, ctx.command.name)
3221 op_data = {}
3222 if vnf_name:
3223 op_data['member_vnf_index'] = vnf_name
3224 if kdu_name:
3225 op_data['kdu_name'] = kdu_name
3226 if vdu_id:
3227 op_data['vdu_id'] = vdu_id
3228 if vdu_count:
3229 op_data['vdu_count_index'] = vdu_count
3230 op_data['primitive'] = action_name
3231 if params_file:
3232 with open(params_file, 'r') as pf:
3233 params = pf.read()
3234 if params:
3235 op_data['primitive_params'] = yaml.safe_load(params)
3236 else:
3237 op_data['primitive_params'] = {}
3238 print(ctx.obj.ns.exec_op(ns_name, op_name='action', op_data=op_data, wait=wait))
3239
3240 except ClientException as e:
3241 print(str(e))
3242 exit(1)
3243
3244
3245 @cli.command(name='vnf-scale', short_help='executes a VNF scale (adding/removing VDUs)')
3246 @click.argument('ns_name')
3247 @click.argument('vnf_name')
3248 @click.option('--scaling-group', prompt=True, help="scaling-group-descriptor name to use")
3249 @click.option('--scale-in', default=False, is_flag=True, help="performs a scale in operation")
3250 @click.option('--scale-out', default=False, is_flag=True, help="performs a scale out operation (by default)")
3251 @click.pass_context
3252 def vnf_scale(ctx,
3253 ns_name,
3254 vnf_name,
3255 scaling_group,
3256 scale_in,
3257 scale_out):
3258 """
3259 Executes a VNF scale (adding/removing VDUs)
3260
3261 \b
3262 NS_NAME: name or ID of the NS instance.
3263 VNF_NAME: member-vnf-index in the NS to be scaled.
3264 """
3265 try:
3266 check_client_version(ctx.obj, ctx.command.name)
3267 if not scale_in and not scale_out:
3268 scale_out = True
3269 ctx.obj.ns.scale_vnf(ns_name, vnf_name, scaling_group, scale_in, scale_out)
3270 except ClientException as e:
3271 print(str(e))
3272 exit(1)
3273
3274
3275 ##############################
3276 # Role Management Operations #
3277 ##############################
3278
3279 @cli.command(name='role-create', short_help='creates a new role')
3280 @click.argument('name')
3281 @click.option('--permissions',
3282 default=None,
3283 help='role permissions using a dictionary')
3284 @click.pass_context
3285 def role_create(ctx, name, permissions):
3286 """
3287 Creates a new role.
3288
3289 \b
3290 NAME: Name or ID of the role.
3291 DEFINITION: Definition of grant/denial of access to resources.
3292 """
3293 try:
3294 check_client_version(ctx.obj, ctx.command.name)
3295 ctx.obj.role.create(name, permissions)
3296 except ClientException as e:
3297 print(str(e))
3298 exit(1)
3299
3300
3301 @cli.command(name='role-update', short_help='updates a role')
3302 @click.argument('name')
3303 @click.option('--set-name',
3304 default=None,
3305 help='change name of rle')
3306 # @click.option('--permissions',
3307 # default=None,
3308 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
3309 @click.option('--add',
3310 default=None,
3311 help='yaml format dictionary with permission: True/False to access grant/denial')
3312 @click.option('--remove',
3313 default=None,
3314 help='yaml format list to remove a permission')
3315 @click.pass_context
3316 def role_update(ctx, name, set_name, add, remove):
3317 """
3318 Updates a role.
3319
3320 \b
3321 NAME: Name or ID of the role.
3322 DEFINITION: Definition overwrites the old definition.
3323 ADD: Grant/denial of access to resource to add.
3324 REMOVE: Grant/denial of access to resource to remove.
3325 """
3326 try:
3327 check_client_version(ctx.obj, ctx.command.name)
3328 ctx.obj.role.update(name, set_name, None, add, remove)
3329 except ClientException as e:
3330 print(str(e))
3331 exit(1)
3332
3333
3334 @cli.command(name='role-delete', short_help='deletes a role')
3335 @click.argument('name')
3336 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3337 @click.pass_context
3338 def role_delete(ctx, name):
3339 """
3340 Deletes a role.
3341
3342 \b
3343 NAME: Name or ID of the role.
3344 """
3345 try:
3346 check_client_version(ctx.obj, ctx.command.name)
3347 ctx.obj.role.delete(name)
3348 except ClientException as e:
3349 print(str(e))
3350 exit(1)
3351
3352
3353 @cli.command(name='role-list', short_help='list all roles')
3354 @click.option('--filter', default=None,
3355 help='restricts the list to the projects matching the filter')
3356 @click.pass_context
3357 def role_list(ctx, filter):
3358 """
3359 List all roles.
3360 """
3361 try:
3362 check_client_version(ctx.obj, ctx.command.name)
3363 resp = ctx.obj.role.list(filter)
3364 except ClientException as e:
3365 print(str(e))
3366 exit(1)
3367 table = PrettyTable(['name', 'id'])
3368 for role in resp:
3369 table.add_row([role['name'], role['_id']])
3370 table.align = 'l'
3371 print(table)
3372
3373
3374 @cli.command(name='role-show', short_help='show specific role')
3375 @click.argument('name')
3376 @click.pass_context
3377 def role_show(ctx, name):
3378 """
3379 Shows the details of a role.
3380
3381 \b
3382 NAME: Name or ID of the role.
3383 """
3384 try:
3385 check_client_version(ctx.obj, ctx.command.name)
3386 resp = ctx.obj.role.get(name)
3387 except ClientException as e:
3388 print(str(e))
3389 exit(1)
3390
3391 table = PrettyTable(['key', 'attribute'])
3392 for k, v in resp.items():
3393 table.add_row([k, json.dumps(v, indent=2)])
3394 table.align = 'l'
3395 print(table)
3396
3397
3398 @cli.command(name='package-create',
3399 short_help='Create a package descriptor')
3400 @click.argument('package-type')
3401 @click.argument('package-name')
3402 @click.option('--base-directory',
3403 default='.',
3404 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'))
3405 @click.option('--image',
3406 default="image-name",
3407 help='(VNF) Set the name of the vdu image. Default "image-name"')
3408 @click.option('--vdus',
3409 default=1,
3410 help='(VNF) Set the number of vdus in a VNF. Default 1')
3411 @click.option('--vcpu',
3412 default=1,
3413 help='(VNF) Set the number of virtual CPUs in a vdu. Default 1')
3414 @click.option('--memory',
3415 default=1024,
3416 help='(VNF) Set the memory size (MB) of the vdu. Default 1024')
3417 @click.option('--storage',
3418 default=10,
3419 help='(VNF) Set the disk size (GB) of the vdu. Default 10')
3420 @click.option('--interfaces',
3421 default=0,
3422 help='(VNF) Set the number of additional interfaces apart from the management interface. Default 0')
3423 @click.option('--vendor',
3424 default="OSM",
3425 help='(NS/VNF) Set the descriptor vendor. Default "OSM"')
3426 @click.option('--override',
3427 default=False,
3428 is_flag=True,
3429 help='(NS/VNF/NST) Flag for overriding the package if exists.')
3430 @click.option('--detailed',
3431 is_flag=True,
3432 default=False,
3433 help='(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options')
3434 @click.option('--netslice-subnets',
3435 default=1,
3436 help='(NST) Number of netslice subnets. Default 1')
3437 @click.option('--netslice-vlds',
3438 default=1,
3439 help='(NST) Number of netslice vlds. Default 1')
3440 @click.pass_context
3441 def package_create(ctx,
3442 package_type,
3443 base_directory,
3444 package_name,
3445 override,
3446 image,
3447 vdus,
3448 vcpu,
3449 memory,
3450 storage,
3451 interfaces,
3452 vendor,
3453 detailed,
3454 netslice_subnets,
3455 netslice_vlds):
3456 """
3457 Creates an OSM NS, VNF, NST package
3458
3459 \b
3460 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
3461 PACKAGE_NAME: Name of the package to create the folder with the content.
3462 """
3463
3464 try:
3465 check_client_version(ctx.obj, ctx.command.name)
3466 print("Creating the {} structure: {}/{}".format(package_type.upper(), base_directory, package_name))
3467 resp = ctx.obj.package_tool.create(package_type,
3468 base_directory,
3469 package_name,
3470 override=override,
3471 image=image,
3472 vdus=vdus,
3473 vcpu=vcpu,
3474 memory=memory,
3475 storage=storage,
3476 interfaces=interfaces,
3477 vendor=vendor,
3478 detailed=detailed,
3479 netslice_subnets=netslice_subnets,
3480 netslice_vlds=netslice_vlds)
3481 print(resp)
3482 except ClientException as inst:
3483 print("ERROR: {}".format(inst))
3484 exit(1)
3485
3486 @cli.command(name='package-validate',
3487 short_help='Validate a package descriptor')
3488 @click.argument('base-directory',
3489 default=".",
3490 required=False)
3491 @click.pass_context
3492 def package_validate(ctx,
3493 base_directory):
3494 """
3495 Validate descriptors given a base directory.
3496
3497 \b
3498 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
3499 """
3500 try:
3501 check_client_version(ctx.obj, ctx.command.name)
3502 results = ctx.obj.package_tool.validate(base_directory)
3503 table = PrettyTable()
3504 table.field_names = ["TYPE", "PATH", "VALID", "ERROR"]
3505 # Print the dictionary generated by the validation function
3506 for result in results:
3507 table.add_row([result["type"], result["path"], result["valid"], result["error"]])
3508 table.sortby = "VALID"
3509 table.align["PATH"] = "l"
3510 table.align["TYPE"] = "l"
3511 table.align["ERROR"] = "l"
3512 print(table)
3513 except ClientException as inst:
3514 print("ERROR: {}".format(inst))
3515 exit(1)
3516
3517 @cli.command(name='package-build',
3518 short_help='Build the tar.gz of the package')
3519 @click.argument('package-folder')
3520 @click.option('--skip-validation',
3521 default=False,
3522 is_flag=True,
3523 help='skip package validation')
3524 @click.pass_context
3525 def package_build(ctx,
3526 package_folder,
3527 skip_validation):
3528 """
3529 Build the package NS, VNF given the package_folder.
3530
3531 \b
3532 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
3533 """
3534 try:
3535 check_client_version(ctx.obj, ctx.command.name)
3536 results = ctx.obj.package_tool.build(package_folder, skip_validation)
3537 print(results)
3538 except ClientException as inst:
3539 print("ERROR: {}".format(inst))
3540 exit(1)
3541
3542
3543 if __name__ == '__main__':
3544 try:
3545 cli()
3546 except pycurl.error as e:
3547 print(e)
3548 print('Maybe "--hostname" option or OSM_HOSTNAME' +
3549 'environment variable needs to be specified')
3550 exit(1)