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