fix bugs in vnf-list and vnf-show for sol005 client
[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
29 def check_client_version(obj, what, version='sol005'):
30 '''
31 Checks the version of the client object and raises error if it not the expected.
32
33 :param obj: the client object
34 :what: the function or command under evaluation (used when an error is raised)
35 :return: -
36 :raises ClientError: if the specified version does not match the client version
37 '''
38 fullclassname = obj.__module__ + "." + obj.__class__.__name__
39 message = 'The following commands or options are only supported with the option "--sol005": {}'.format(what)
40 if version == 'v1':
41 message = 'The following commands or options are not supported when using option "--sol005": {}'.format(what)
42 if fullclassname != 'osmclient.{}.client.Client'.format(version):
43 raise ClientException(message)
44 return
45
46 @click.group()
47 @click.option('--hostname',
48 default=None,
49 envvar='OSM_HOSTNAME',
50 help='hostname of server. ' +
51 'Also can set OSM_HOSTNAME in environment')
52 @click.option('--so-port',
53 default=None,
54 envvar='OSM_SO_PORT',
55 help='hostname of server. ' +
56 'Also can set OSM_SO_PORT in environment')
57 @click.option('--so-project',
58 default=None,
59 envvar='OSM_SO_PROJECT',
60 help='Project Name in SO. ' +
61 'Also can set OSM_SO_PROJECT in environment')
62 @click.option('--ro-hostname',
63 default=None,
64 envvar='OSM_RO_HOSTNAME',
65 help='hostname of RO server. ' +
66 'Also can set OSM_RO_HOSTNAME in environment')
67 @click.option('--ro-port',
68 default=9090,
69 envvar='OSM_RO_PORT',
70 help='hostname of RO server. ' +
71 'Also can set OSM_RO_PORT in environment')
72 @click.option('--sol005',
73 is_flag=True,
74 envvar='OSM_SOL005',
75 help='Use ETSI NFV SOL005 API')
76 @click.pass_context
77 def cli(ctx, hostname, so_port, so_project, ro_hostname, ro_port, sol005):
78 if hostname is None:
79 print(
80 "either hostname option or OSM_HOSTNAME " +
81 "environment variable needs to be specified")
82 exit(1)
83 kwargs={}
84 if so_port is not None:
85 kwargs['so_port']=so_port
86 if so_project is not None:
87 kwargs['so_project']=so_project
88 if ro_hostname is not None:
89 kwargs['ro_host']=ro_hostname
90 if ro_port is not None:
91 kwargs['ro_port']=ro_port
92
93 ctx.obj = client.Client(host=hostname, sol005=sol005, **kwargs)
94
95
96 ####################
97 # LIST operations
98 ####################
99
100 @cli.command(name='ns-list')
101 @click.option('--filter', default=None,
102 help='restricts the list to the NS instances matching the filter')
103 @click.pass_context
104 def ns_list(ctx, filter):
105 '''list all NS instances'''
106 if filter:
107 check_client_version(ctx.obj, '--filter')
108 resp = ctx.obj.ns.list(filter)
109 else:
110 resp = ctx.obj.ns.list()
111 table = PrettyTable(
112 ['ns instance name',
113 'id',
114 'operational status',
115 'config status',
116 'detailed status'])
117 for ns in resp:
118 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
119 if fullclassname == 'osmclient.sol005.client.Client':
120 nsr = ns
121 nsr_name = nsr['name']
122 nsr_id = nsr['_id']
123 else:
124 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
125 nsr = nsopdata['nsr:nsr']
126 nsr_name = nsr['name-ref']
127 nsr_id = nsr['ns-instance-config-ref']
128 opstatus = nsr['operational-status'] if 'operational-status' in nsr else 'Not found'
129 configstatus = nsr['config-status'] if 'config-status' in nsr else 'Not found'
130 detailed_status = nsr['detailed-status'] if 'detailed-status' in nsr else 'Not found'
131 if configstatus == "config_not_needed":
132 configstatus = "configured (no charms)"
133 table.add_row(
134 [nsr_name,
135 nsr_id,
136 opstatus,
137 configstatus,
138 detailed_status])
139 table.align = 'l'
140 print(table)
141
142
143 def nsd_list(ctx, filter):
144 if filter:
145 check_client_version(ctx.obj, '--filter')
146 resp = ctx.obj.nsd.list(filter)
147 else:
148 resp = ctx.obj.nsd.list()
149 #print yaml.safe_dump(resp)
150 table = PrettyTable(['nsd name', 'id'])
151 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
152 if fullclassname == 'osmclient.sol005.client.Client':
153 for ns in resp:
154 name = ns['name'] if 'name' in ns else '-'
155 table.add_row([name, ns['_id']])
156 else:
157 for ns in resp:
158 table.add_row([ns['name'], ns['id']])
159 table.align = 'l'
160 print(table)
161
162
163 @cli.command(name='nsd-list')
164 @click.option('--filter', default=None,
165 help='restricts the list to the NSD/NSpkg matching the filter')
166 @click.pass_context
167 def nsd_list1(ctx, filter):
168 '''list all NSD/NSpkg in the system'''
169 nsd_list(ctx,filter)
170
171
172 @cli.command(name='nspkg-list')
173 @click.option('--filter', default=None,
174 help='restricts the list to the NSD/NSpkg matching the filter')
175 @click.pass_context
176 def nsd_list2(ctx, filter):
177 '''list all NSD/NSpkg in the system'''
178 nsd_list(ctx,filter)
179
180
181 def vnfd_list(ctx, filter):
182 if filter:
183 check_client_version(ctx.obj, '--filter')
184 resp = ctx.obj.vnfd.list(filter)
185 else:
186 resp = ctx.obj.vnfd.list()
187 #print yaml.safe_dump(resp)
188 table = PrettyTable(['vnfd name', 'id'])
189 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
190 if fullclassname == 'osmclient.sol005.client.Client':
191 for vnfd in resp:
192 name = vnfd['name'] if 'name' in vnfd else '-'
193 table.add_row([name, vnfd['_id']])
194 else:
195 for vnfd in resp:
196 table.add_row([vnfd['name'], vnfd['id']])
197 table.align = 'l'
198 print(table)
199
200
201 @cli.command(name='vnfd-list')
202 @click.option('--filter', default=None,
203 help='restricts the list to the VNFD/VNFpkg matching the filter')
204 @click.pass_context
205 def vnfd_list1(ctx, filter):
206 '''list all VNFD/VNFpkg in the system'''
207 vnfd_list(ctx,filter)
208
209
210 @cli.command(name='vnfpkg-list')
211 @click.option('--filter', default=None,
212 help='restricts the list to the VNFD/VNFpkg matching the filter')
213 @click.pass_context
214 def vnfd_list2(ctx, filter):
215 '''list all VNFD/VNFpkg in the system'''
216 vnfd_list(ctx,filter)
217
218
219 @cli.command(name='vnf-list')
220 @click.option('--ns', default=None, help='NS instance id or name to restrict the VNF list')
221 @click.pass_context
222 def vnf_list(ctx, ns):
223 ''' list all VNF instances'''
224 try:
225 if ns:
226 check_client_version(ctx.obj, '--ns')
227 resp = ctx.obj.vnf.list(ns)
228 else:
229 resp = ctx.obj.vnf.list()
230 except ClientException as inst:
231 print(inst.message)
232 exit(1)
233 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
234 if fullclassname == 'osmclient.sol005.client.Client':
235 table = PrettyTable(
236 ['vnf id',
237 'name',
238 'ns id',
239 'vnf member index',
240 'vnfd name',
241 'ip address'])
242 for vnfr in resp:
243 name = vnfr['name'] if 'name' in vnfr else '-'
244 table.add_row(
245 [vnfr['_id'],
246 name,
247 vnfr['nsr-id-ref'],
248 vnfr['member-vnf-index-ref'],
249 vnfr['vnfd-ref'],
250 vnfr['ip-address']])
251 else:
252 table = PrettyTable(
253 ['vnf name',
254 'id',
255 'operational status',
256 'config status'])
257 for vnfr in resp:
258 if 'mgmt-interface' not in vnfr:
259 vnfr['mgmt-interface'] = {}
260 vnfr['mgmt-interface']['ip-address'] = None
261 table.add_row(
262 [vnfr['name'],
263 vnfr['id'],
264 vnfr['operational-status'],
265 vnfr['config-status']])
266 table.align = 'l'
267 print(table)
268
269 @cli.command(name='ns-op-list')
270 @click.argument('name')
271 @click.pass_context
272 def ns_op_list(ctx, name):
273 '''shows the history of operations over a NS instance
274
275 NAME: name or ID of the NS instance
276 '''
277 try:
278 check_client_version(ctx.obj, ctx.command.name)
279 resp = ctx.obj.ns.list_op(name)
280 except ClientException as inst:
281 print(inst.message)
282 exit(1)
283
284 table = PrettyTable(['id', 'operation', 'status'])
285 for op in resp:
286 table.add_row([op['id'], op['lcmOperationType'],
287 op['operationState']])
288 table.align = 'l'
289 print(table)
290
291 ####################
292 # SHOW operations
293 ####################
294
295 def nsd_show(ctx, name, literal):
296 try:
297 resp = ctx.obj.nsd.get(name)
298 #resp = ctx.obj.nsd.get_individual(name)
299 except ClientException as inst:
300 print(inst.message)
301 exit(1)
302
303 if literal:
304 print yaml.safe_dump(resp)
305 return
306
307 table = PrettyTable(['field', 'value'])
308 for k, v in resp.items():
309 table.add_row([k, json.dumps(v, indent=2)])
310 table.align = 'l'
311 print(table)
312
313
314 @cli.command(name='nsd-show', short_help='shows the content of a NSD')
315 @click.option('--literal', is_flag=True,
316 help='print literally, no pretty table')
317 @click.argument('name')
318 @click.pass_context
319 def nsd_show1(ctx, name, literal):
320 '''shows the content of a NSD
321
322 NAME: name or ID of the NSD/NSpkg
323 '''
324 nsd_show(ctx, name, literal)
325
326
327 @cli.command(name='nspkg-show', short_help='shows the content of a NSD')
328 @click.option('--literal', is_flag=True,
329 help='print literally, no pretty table')
330 @click.argument('name')
331 @click.pass_context
332 def nsd_show2(ctx, name, literal):
333 '''shows the content of a NSD
334
335 NAME: name or ID of the NSD/NSpkg
336 '''
337 nsd_show(ctx, name, literal)
338
339
340 def vnfd_show(ctx, name, literal):
341 try:
342 resp = ctx.obj.vnfd.get(name)
343 #resp = ctx.obj.vnfd.get_individual(name)
344 except ClientException as inst:
345 print(inst.message)
346 exit(1)
347
348 if literal:
349 print yaml.safe_dump(resp)
350 return
351
352 table = PrettyTable(['field', 'value'])
353 for k, v in resp.items():
354 table.add_row([k, json.dumps(v, indent=2)])
355 table.align = 'l'
356 print(table)
357
358
359 @cli.command(name='vnfd-show', short_help='shows the content of a VNFD')
360 @click.option('--literal', is_flag=True,
361 help='print literally, no pretty table')
362 @click.argument('name')
363 @click.pass_context
364 def vnfd_show1(ctx, name, literal):
365 '''shows the content of a VNFD
366
367 NAME: name or ID of the VNFD/VNFpkg
368 '''
369 vnfd_show(ctx, name, literal)
370
371
372 @cli.command(name='vnfpkg-show', short_help='shows the content of a VNFD')
373 @click.option('--literal', is_flag=True,
374 help='print literally, no pretty table')
375 @click.argument('name')
376 @click.pass_context
377 def vnfd_show2(ctx, name, literal):
378 '''shows the content of a VNFD
379
380 NAME: name or ID of the VNFD/VNFpkg
381 '''
382 vnfd_show(ctx, name, literal)
383
384
385 @cli.command(name='ns-show', short_help='shows the info of a NS instance')
386 @click.argument('name')
387 @click.option('--literal', is_flag=True,
388 help='print literally, no pretty table')
389 @click.option('--filter', default=None)
390 @click.pass_context
391 def ns_show(ctx, name, literal, filter):
392 '''shows the info of a NS instance
393
394 NAME: name or ID of the NS instance
395 '''
396 try:
397 ns = ctx.obj.ns.get(name)
398 except ClientException as inst:
399 print(inst.message)
400 exit(1)
401
402 if literal:
403 print yaml.safe_dump(resp)
404 return
405
406 table = PrettyTable(['field', 'value'])
407
408 for k, v in ns.items():
409 if filter is None or filter in k:
410 table.add_row([k, json.dumps(v, indent=2)])
411
412 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
413 if fullclassname != 'osmclient.sol005.client.Client':
414 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
415 nsr_optdata = nsopdata['nsr:nsr']
416 for k, v in nsr_optdata.items():
417 if filter is None or filter in k:
418 table.add_row([k, json.dumps(v, indent=2)])
419 table.align = 'l'
420 print(table)
421
422
423 @cli.command(name='vnf-show', short_help='shows the info of a VNF instance')
424 @click.argument('name')
425 @click.option('--literal', is_flag=True,
426 help='print literally, no pretty table')
427 @click.option('--filter', default=None)
428 @click.pass_context
429 def vnf_show(ctx, name, literal, filter):
430 '''shows the info of a VNF instance
431
432 NAME: name or ID of the VNF instance
433 '''
434 try:
435 check_client_version(ctx.obj, ctx.command.name)
436 resp = ctx.obj.vnf.get(name)
437 except ClientException as inst:
438 print(inst.message)
439 exit(1)
440
441 if literal:
442 print yaml.safe_dump(resp)
443 return
444
445 table = PrettyTable(['field', 'value'])
446 for k, v in resp.items():
447 if filter is None or filter in k:
448 table.add_row([k, json.dumps(v, indent=2)])
449 table.align = 'l'
450 print(table)
451
452
453 @cli.command(name='vnf-monitoring-show')
454 @click.argument('vnf_name')
455 @click.pass_context
456 def vnf_monitoring_show(ctx, vnf_name):
457 try:
458 check_client_version(ctx.obj, ctx.command.name, 'v1')
459 resp = ctx.obj.vnf.get_monitoring(vnf_name)
460 except ClientException as inst:
461 print(inst.message)
462 exit(1)
463
464 table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
465 if resp is not None:
466 for monitor in resp:
467 table.add_row(
468 [vnf_name,
469 monitor['name'],
470 monitor['value-integer'],
471 monitor['units']])
472 table.align = 'l'
473 print(table)
474
475
476 @cli.command(name='ns-monitoring-show')
477 @click.argument('ns_name')
478 @click.pass_context
479 def ns_monitoring_show(ctx, ns_name):
480 try:
481 check_client_version(ctx.obj, ctx.command.name, 'v1')
482 resp = ctx.obj.ns.get_monitoring(ns_name)
483 except ClientException as inst:
484 print(inst.message)
485 exit(1)
486
487 table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
488 for key, val in resp.items():
489 for monitor in val:
490 table.add_row(
491 [key,
492 monitor['name'],
493 monitor['value-integer'],
494 monitor['units']])
495 table.align = 'l'
496 print(table)
497
498 @cli.command(name='ns-op-show', short_help='shows the info of an operation')
499 @click.argument('id')
500 @click.option('--filter', default=None)
501 @click.pass_context
502 def ns_op_show(ctx, id, filter):
503 '''shows the detailed info of an operation
504
505 ID: operation identifier
506 '''
507 try:
508 check_client_version(ctx.obj, ctx.command.name)
509 op_info = ctx.obj.ns.get_op(id)
510 except ClientException as inst:
511 print(inst.message)
512 exit(1)
513
514 table = PrettyTable(['field', 'value'])
515 for k, v in op_info.items():
516 if filter is None or filter in k:
517 table.add_row([k, json.dumps(v, indent=2)])
518 table.align = 'l'
519 print(table)
520
521
522 ####################
523 # CREATE operations
524 ####################
525
526 def nsd_create(ctx, filename, overwrite):
527 try:
528 check_client_version(ctx.obj, ctx.command.name)
529 ctx.obj.nsd.create(filename, overwrite)
530 except ClientException as inst:
531 print(inst.message)
532 exit(1)
533
534
535 @cli.command(name='nsd-create', short_help='creates a new NSD/NSpkg')
536 @click.argument('filename')
537 @click.option('--overwrite', default=None,
538 help='overwrites some fields in NSD')
539 @click.pass_context
540 def nsd_create1(ctx, filename, overwrite):
541 '''creates a new NSD/NSpkg
542
543 FILENAME: NSD yaml file or NSpkg tar.gz file
544 '''
545 nsd_create(ctx, filename, overwrite)
546
547
548 @cli.command(name='nspkg-create', short_help='creates a new NSD/NSpkg')
549 @click.argument('filename')
550 @click.option('--overwrite', default=None,
551 help='overwrites some fields in NSD')
552 @click.pass_context
553 def nsd_create2(ctx, filename, overwrite):
554 '''creates a new NSD/NSpkg
555
556 FILENAME: NSD yaml file or NSpkg tar.gz file
557 '''
558 nsd_create(ctx, filename, overwrite)
559
560
561 def vnfd_create(ctx, filename, overwrite):
562 try:
563 check_client_version(ctx.obj, ctx.command.name)
564 ctx.obj.vnfd.create(filename, overwrite)
565 except ClientException as inst:
566 print(inst.message)
567 exit(1)
568
569
570 @cli.command(name='vnfd-create', short_help='creates a new VNFD/VNFpkg')
571 @click.argument('filename')
572 @click.option('--overwrite', default=None,
573 help='overwrites some fields in VNFD')
574 @click.pass_context
575 def vnfd_create1(ctx, filename, overwrite):
576 '''creates a new VNFD/VNFpkg
577
578 FILENAME: VNFD yaml file or VNFpkg tar.gz file
579 '''
580 vnfd_create(ctx, filename, overwrite)
581
582
583 @cli.command(name='vnfpkg-create', short_help='creates a new VNFD/VNFpkg')
584 @click.argument('filename')
585 @click.option('--overwrite', default=None,
586 help='overwrites some fields in VNFD')
587 @click.pass_context
588 def vnfd_create2(ctx, filename, overwrite):
589 '''creates a new VNFD/VNFpkg
590
591 FILENAME: VNFD yaml file or VNFpkg tar.gz file
592 '''
593 vnfd_create(ctx, filename, overwrite)
594
595
596 @cli.command(name='ns-create')
597 @click.option('--ns_name',
598 prompt=True)
599 @click.option('--nsd_name',
600 prompt=True)
601 @click.option('--vim_account',
602 prompt=True)
603 @click.option('--admin_status',
604 default='ENABLED',
605 help='administration status')
606 @click.option('--ssh_keys',
607 default=None,
608 help='comma separated list of keys to inject to vnfs')
609 @click.option('--config',
610 default=None,
611 help='ns specific yaml configuration:\nvnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
612 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]')
613 @click.pass_context
614 def ns_create(ctx,
615 nsd_name,
616 ns_name,
617 vim_account,
618 admin_status,
619 ssh_keys,
620 config):
621 '''creates a new NS instance'''
622 try:
623 # if config:
624 # check_client_version(ctx.obj, '--config', 'v1')
625 ctx.obj.ns.create(
626 nsd_name,
627 ns_name,
628 config=config,
629 ssh_keys=ssh_keys,
630 account=vim_account)
631 except ClientException as inst:
632 print(inst.message)
633 exit(1)
634
635
636 ####################
637 # UPDATE operations
638 ####################
639
640 def nsd_update(ctx, name, content):
641 try:
642 check_client_version(ctx.obj, ctx.command.name)
643 ctx.obj.nsd.update(name, content)
644 except ClientException as inst:
645 print(inst.message)
646 exit(1)
647
648 @cli.command(name='nsd-update', short_help='updates a NSD/NSpkg')
649 @click.argument('name')
650 @click.option('--content', default=None,
651 help='filename with the NSD/NSpkg replacing the current one')
652 @click.pass_context
653 def nsd_update1(ctx, name, content):
654 '''updates a NSD/NSpkg
655
656 NAME: name or ID of the NSD/NSpkg
657 '''
658 nsd_update(ctx, name, content)
659
660
661 @cli.command(name='nspkg-update', short_help='updates a NSD/NSpkg')
662 @click.argument('name')
663 @click.option('--content', default=None,
664 help='filename with the NSD/NSpkg replacing the current one')
665 @click.pass_context
666 def nsd_update2(ctx, name, content):
667 '''updates a NSD/NSpkg
668
669 NAME: name or ID of the NSD/NSpkg
670 '''
671 nsd_update(ctx, name, content)
672
673
674 def vnfd_update(ctx, name, content):
675 try:
676 check_client_version(ctx.obj, ctx.command.name)
677 ctx.obj.vnfd.update(name, content)
678 except ClientException as inst:
679 print(inst.message)
680 exit(1)
681
682
683 @cli.command(name='vnfd-update', short_help='updates a new VNFD/VNFpkg')
684 @click.argument('name')
685 @click.option('--content', default=None,
686 help='filename with the VNFD/VNFpkg replacing the current one')
687 @click.pass_context
688 def vnfd_update1(ctx, name, content):
689 '''updates a VNFD/VNFpkg
690
691 NAME: name or ID of the VNFD/VNFpkg
692 '''
693 vnfd_update(ctx, name, content)
694
695
696 @cli.command(name='vnfpkg-update', short_help='updates a VNFD/VNFpkg')
697 @click.argument('name')
698 @click.option('--content', default=None,
699 help='filename with the VNFD/VNFpkg replacing the current one')
700 @click.pass_context
701 def vnfd_update2(ctx, name, content):
702 '''updates a VNFD/VNFpkg
703
704 NAME: VNFD yaml file or VNFpkg tar.gz file
705 '''
706 vnfd_update(ctx, name, content)
707
708
709 ####################
710 # DELETE operations
711 ####################
712
713 def nsd_delete(ctx, name, force):
714 try:
715 if not force:
716 ctx.obj.nsd.delete(name)
717 else:
718 check_client_version(ctx.obj, '--force')
719 ctx.obj.nsd.delete(name, force)
720 except ClientException as inst:
721 print(inst.message)
722 exit(1)
723
724
725 @cli.command(name='nsd-delete', short_help='deletes a NSD/NSpkg')
726 @click.argument('name')
727 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
728 @click.pass_context
729 def nsd_delete1(ctx, name, force):
730 '''deletes a NSD/NSpkg
731
732 NAME: name or ID of the NSD/NSpkg to be deleted
733 '''
734 nsd_delete(ctx, name, force)
735
736
737 @cli.command(name='nspkg-delete', short_help='deletes a NSD/NSpkg')
738 @click.argument('name')
739 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
740 @click.pass_context
741 def nsd_delete2(ctx, name, force):
742 '''deletes a NSD/NSpkg
743
744 NAME: name or ID of the NSD/NSpkg to be deleted
745 '''
746 nsd_delete(ctx, name, force)
747
748
749 def vnfd_delete(ctx, name, force):
750 try:
751 if not force:
752 ctx.obj.vnfd.delete(name)
753 else:
754 check_client_version(ctx.obj, '--force')
755 ctx.obj.vnfd.delete(name, force)
756 except ClientException as inst:
757 print(inst.message)
758 exit(1)
759
760
761 @cli.command(name='vnfd-delete', short_help='deletes a VNFD/VNFpkg')
762 @click.argument('name')
763 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
764 @click.pass_context
765 def vnfd_delete1(ctx, name, force):
766 '''deletes a VNFD/VNFpkg
767
768 NAME: name or ID of the VNFD/VNFpkg to be deleted
769 '''
770 vnfd_delete(ctx, name, force)
771
772
773 @cli.command(name='vnfpkg-delete', short_help='deletes a VNFD/VNFpkg')
774 @click.argument('name')
775 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
776 @click.pass_context
777 def vnfd_delete2(ctx, name, force):
778 '''deletes a VNFD/VNFpkg
779
780 NAME: name or ID of the VNFD/VNFpkg to be deleted
781 '''
782 vnfd_delete(ctx, name, force)
783
784
785 @cli.command(name='ns-delete', short_help='deletes a NS instance')
786 @click.argument('name')
787 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
788 @click.pass_context
789 def ns_delete(ctx, name, force):
790 '''deletes a NS instance
791
792 NAME: name or ID of the NS instance to be deleted
793 '''
794 try:
795 if not force:
796 ctx.obj.ns.delete(name)
797 else:
798 check_client_version(ctx.obj, '--force')
799 ctx.obj.ns.delete(name, force)
800 except ClientException as inst:
801 print(inst.message)
802 exit(1)
803
804
805 ####################
806 # VIM operations
807 ####################
808
809 @cli.command(name='vim-create')
810 @click.option('--name',
811 prompt=True,
812 help='Name to create datacenter')
813 @click.option('--user',
814 prompt=True,
815 help='VIM username')
816 @click.option('--password',
817 prompt=True,
818 hide_input=True,
819 confirmation_prompt=True,
820 help='VIM password')
821 @click.option('--auth_url',
822 prompt=True,
823 help='VIM url')
824 @click.option('--tenant',
825 prompt=True,
826 help='VIM tenant name')
827 @click.option('--config',
828 default=None,
829 help='VIM specific config parameters')
830 @click.option('--account_type',
831 default='openstack',
832 help='VIM type')
833 @click.option('--description',
834 default='no description',
835 help='human readable description')
836 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller associated to this VIM account')
837 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
838 @click.pass_context
839 def vim_create(ctx,
840 name,
841 user,
842 password,
843 auth_url,
844 tenant,
845 config,
846 account_type,
847 description,
848 sdn_controller,
849 sdn_port_mapping):
850 '''creates a new VIM account
851 '''
852 try:
853 if sdn_controller:
854 check_client_version(ctx.obj, '--sdn_controller')
855 if sdn_port_mapping:
856 check_client_version(ctx.obj, '--sdn_port_mapping')
857 vim = {}
858 vim['vim-username'] = user
859 vim['vim-password'] = password
860 vim['vim-url'] = auth_url
861 vim['vim-tenant-name'] = tenant
862 vim['vim-type'] = account_type
863 vim['description'] = description
864 vim ['config'] = config
865 if sdn_controller or sdn_port_mapping:
866 ctx.obj.vim.create(name, vim, sdn_controller, sdn_port_mapping)
867 else:
868 ctx.obj.vim.create(name, vim)
869 except ClientException as inst:
870 print(inst.message)
871 exit(1)
872
873
874 @cli.command(name='vim-update', short_help='updates a VIM account')
875 @click.argument('name')
876 @click.option('--newname', help='New name for the VIM account')
877 @click.option('--user', help='VIM username')
878 @click.option('--password', help='VIM password')
879 @click.option('--auth_url', help='VIM url')
880 @click.option('--tenant', help='VIM tenant name')
881 @click.option('--config', help='VIM specific config parameters')
882 @click.option('--account_type', help='VIM type')
883 @click.option('--description', help='human readable description')
884 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller associated to this VIM account')
885 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
886 @click.pass_context
887 def vim_update(ctx,
888 name,
889 newname,
890 user,
891 password,
892 auth_url,
893 tenant,
894 config,
895 account_type,
896 description,
897 sdn_controller,
898 sdn_port_mapping):
899 '''updates a VIM account
900
901 NAME: name or ID of the VIM account
902 '''
903 try:
904 check_client_version(ctx.obj, ctx.command.name)
905 vim = {}
906 if newname: vim['name'] = newname
907 if user: vim['vim_user'] = user
908 if password: vim['vim_password'] = password
909 if auth_url: vim['vim_url'] = auth_url
910 if tenant: vim['vim-tenant-name'] = tenant
911 if account_type: vim['vim_type'] = account_type
912 if description: vim['description'] = description
913 if config: vim['config'] = config
914 ctx.obj.vim.update(name, vim, sdn_controller, sdn_port_mapping)
915 except ClientException as inst:
916 print(inst.message)
917 exit(1)
918
919
920 @cli.command(name='vim-delete')
921 @click.argument('name')
922 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
923 @click.pass_context
924 def vim_delete(ctx, name, force):
925 '''deletes a VIM account
926
927 NAME: name or ID of the VIM account to be deleted
928 '''
929 try:
930 if not force:
931 ctx.obj.vim.delete(name)
932 else:
933 check_client_version(ctx.obj, '--force')
934 ctx.obj.vim.delete(name, force)
935 except ClientException as inst:
936 print(inst.message)
937 exit(1)
938
939
940 @cli.command(name='vim-list')
941 @click.option('--ro_update/--no_ro_update',
942 default=False,
943 help='update list from RO')
944 @click.option('--filter', default=None,
945 help='restricts the list to the VIM accounts matching the filter')
946 @click.pass_context
947 def vim_list(ctx, ro_update, filter):
948 '''list all VIM accounts'''
949 if filter:
950 check_client_version(ctx.obj, '--filter')
951 if ro_update:
952 check_client_version(ctx.obj, '--ro_update', 'v1')
953 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
954 if fullclassname == 'osmclient.sol005.client.Client':
955 resp = ctx.obj.vim.list(filter)
956 else:
957 resp = ctx.obj.vim.list(ro_update)
958 table = PrettyTable(['vim name', 'uuid'])
959 for vim in resp:
960 table.add_row([vim['name'], vim['uuid']])
961 table.align = 'l'
962 print(table)
963
964
965 @cli.command(name='vim-show')
966 @click.argument('name')
967 @click.pass_context
968 def vim_show(ctx, name):
969 '''shows the details of a VIM account
970
971 NAME: name or ID of the VIM account
972 '''
973 try:
974 resp = ctx.obj.vim.get(name)
975 if 'vim_password' in resp:
976 resp['vim_password']='********'
977 except ClientException as inst:
978 print(inst.message)
979 exit(1)
980
981 table = PrettyTable(['key', 'attribute'])
982 for k, v in resp.items():
983 table.add_row([k, json.dumps(v, indent=2)])
984 table.align = 'l'
985 print(table)
986
987
988 ####################
989 # SDN controller operations
990 ####################
991
992 @cli.command(name='sdnc-create')
993 @click.option('--name',
994 prompt=True,
995 help='Name to create sdn controller')
996 @click.option('--type',
997 prompt=True,
998 help='SDN controller type')
999 @click.option('--sdn_controller_version',
1000 help='SDN controller username')
1001 @click.option('--ip_address',
1002 prompt=True,
1003 help='SDN controller IP address')
1004 @click.option('--port',
1005 prompt=True,
1006 help='SDN controller port')
1007 @click.option('--switch_dpid',
1008 prompt=True,
1009 help='Switch DPID (Openflow Datapath ID)')
1010 @click.option('--user',
1011 help='SDN controller username')
1012 @click.option('--password',
1013 hide_input=True,
1014 confirmation_prompt=True,
1015 help='SDN controller password')
1016 #@click.option('--description',
1017 # default='no description',
1018 # help='human readable description')
1019 @click.pass_context
1020 def sdnc_create(ctx,
1021 name,
1022 type,
1023 sdn_controller_version,
1024 ip_address,
1025 port,
1026 switch_dpid,
1027 user,
1028 password):
1029 '''creates a new SDN controller
1030 '''
1031 sdncontroller = {}
1032 sdncontroller['name'] = name
1033 sdncontroller['type'] = type
1034 sdncontroller['ip'] = ip_address
1035 sdncontroller['port'] = int(port)
1036 sdncontroller['dpid'] = switch_dpid
1037 if sdn_controller_version:
1038 sdncontroller['version'] = sdn_controller_version
1039 if user:
1040 sdncontroller['user'] = user
1041 if password:
1042 sdncontroller['password'] = password
1043 # sdncontroller['description'] = description
1044 try:
1045 check_client_version(ctx.obj, ctx.command.name)
1046 ctx.obj.sdnc.create(name, sdncontroller)
1047 except ClientException as inst:
1048 print(inst.message)
1049
1050
1051 @cli.command(name='sdnc-update', short_help='updates an SDN controller')
1052 @click.argument('name')
1053 @click.option('--newname', help='New name for the SDN controller')
1054 @click.option('--type', help='SDN controller type')
1055 @click.option('--sdn_controller_version', help='SDN controller username')
1056 @click.option('--ip_address', help='SDN controller IP address')
1057 @click.option('--port', help='SDN controller port')
1058 @click.option('--switch_dpid', help='Switch DPID (Openflow Datapath ID)')
1059 @click.option('--user', help='SDN controller username')
1060 @click.option('--password', help='SDN controller password')
1061 #@click.option('--description', default=None, help='human readable description')
1062 @click.pass_context
1063 def sdnc_update(ctx,
1064 name,
1065 newname,
1066 type,
1067 sdn_controller_version,
1068 ip_address,
1069 port,
1070 switch_dpid,
1071 user,
1072 password):
1073 '''updates an SDN controller
1074
1075 NAME: name or ID of the SDN controller
1076 '''
1077 sdncontroller = {}
1078 if newname: sdncontroller['name'] = newname
1079 if type: sdncontroller['type'] = type
1080 if ip_address: sdncontroller['ip'] = ip_address
1081 if port: sdncontroller['port'] = int(port)
1082 if switch_dpid: sdncontroller['dpid'] = switch_dpid
1083 # sdncontroller['description'] = description
1084 if sdn_controller_version is not None:
1085 if sdn_controller_version=="":
1086 sdncontroller['version'] = None
1087 else:
1088 sdncontroller['version'] = sdn_controller_version
1089 if user is not None:
1090 if user=="":
1091 sdncontroller['user'] = None
1092 else:
1093 sdncontroller['user'] = user
1094 if password is not None:
1095 if password=="":
1096 sdncontroller['password'] = None
1097 else:
1098 sdncontroller['password'] = user
1099 try:
1100 check_client_version(ctx.obj, ctx.command.name)
1101 ctx.obj.sdnc.update(name, sdncontroller)
1102 except ClientException as inst:
1103 print(inst.message)
1104 exit(1)
1105
1106
1107 @cli.command(name='sdnc-delete')
1108 @click.argument('name')
1109 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1110 @click.pass_context
1111 def sdnc_delete(ctx, name, force):
1112 '''deletes an SDN controller
1113
1114 NAME: name or ID of the SDN controller to be deleted
1115 '''
1116 try:
1117 check_client_version(ctx.obj, ctx.command.name)
1118 ctx.obj.sdnc.delete(name, force)
1119 except ClientException as inst:
1120 print(inst.message)
1121 exit(1)
1122
1123
1124 @cli.command(name='sdnc-list')
1125 @click.option('--filter', default=None,
1126 help='restricts the list to the SDN controllers matching the filter')
1127 @click.pass_context
1128 def sdnc_list(ctx, filter):
1129 '''list all SDN controllers'''
1130 try:
1131 check_client_version(ctx.obj, ctx.command.name)
1132 resp = ctx.obj.sdnc.list(filter)
1133 except ClientException as inst:
1134 print(inst.message)
1135 exit(1)
1136 table = PrettyTable(['name', 'id'])
1137 for sdnc in resp:
1138 table.add_row([sdnc['name'], sdnc['_id']])
1139 table.align = 'l'
1140 print(table)
1141
1142
1143 @cli.command(name='sdnc-show')
1144 @click.argument('name')
1145 @click.pass_context
1146 def sdnc_show(ctx, name):
1147 '''shows the details of an SDN controller
1148
1149 NAME: name or ID of the SDN controller
1150 '''
1151 try:
1152 check_client_version(ctx.obj, ctx.command.name)
1153 resp = ctx.obj.sdnc.get(name)
1154 except ClientException as inst:
1155 print(inst.message)
1156 exit(1)
1157
1158 table = PrettyTable(['key', 'attribute'])
1159 for k, v in resp.items():
1160 table.add_row([k, json.dumps(v, indent=2)])
1161 table.align = 'l'
1162 print(table)
1163
1164
1165 ####################
1166 # Fault Management operations
1167 ####################
1168
1169 @cli.command(name='ns-alarm-create')
1170 @click.argument('name')
1171 @click.option('--ns', prompt=True, help='NS instance id or name')
1172 @click.option('--vnf', prompt=True,
1173 help='VNF name (VNF member index as declared in the NSD)')
1174 @click.option('--vdu', prompt=True,
1175 help='VDU name (VDU name as declared in the VNFD)')
1176 @click.option('--metric', prompt=True,
1177 help='Name of the metric (e.g. cpu_utilization)')
1178 @click.option('--severity', default='WARNING',
1179 help='severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)')
1180 @click.option('--threshold_value', prompt=True,
1181 help='threshold value that, when crossed, an alarm is triggered')
1182 @click.option('--threshold_operator', prompt=True,
1183 help='threshold operator describing the comparison (GE, LE, GT, LT, EQ)')
1184 @click.option('--statistic', default='AVERAGE',
1185 help='statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)')
1186 @click.pass_context
1187 def ns_alarm_create(ctx, name, ns, vnf, vdu, metric, severity,
1188 threshold_value, threshold_operator, statistic):
1189 '''creates a new alarm for a NS instance'''
1190 ns_instance = ctx.obj.ns.get(ns)
1191 alarm = {}
1192 alarm['alarm_name'] = name
1193 alarm['ns_id'] = ns_instance['_id']
1194 alarm['correlation_id'] = ns_instance['_id']
1195 alarm['vnf_member_index'] = vnf
1196 alarm['vdu_name'] = vdu
1197 alarm['metric_name'] = metric
1198 alarm['severity'] = severity
1199 alarm['threshold_value'] = int(threshold_value)
1200 alarm['operation'] = threshold_operator
1201 alarm['statistic'] = statistic
1202 try:
1203 check_client_version(ctx.obj, ctx.command.name)
1204 ctx.obj.ns.create_alarm(alarm)
1205 except ClientException as inst:
1206 print(inst.message)
1207 exit(1)
1208
1209
1210 #@cli.command(name='ns-alarm-delete')
1211 #@click.argument('name')
1212 #@click.pass_context
1213 #def ns_alarm_delete(ctx, name):
1214 # '''deletes an alarm
1215 #
1216 # NAME: name of the alarm to be deleted
1217 # '''
1218 # try:
1219 # check_client_version(ctx.obj, ctx.command.name)
1220 # ctx.obj.ns.delete_alarm(name)
1221 # except ClientException as inst:
1222 # print(inst.message)
1223 # exit(1)
1224
1225
1226 ####################
1227 # Performance Management operations
1228 ####################
1229
1230 @cli.command(name='ns-metric-export')
1231 @click.option('--ns', prompt=True, help='NS instance id or name')
1232 @click.option('--vnf', prompt=True,
1233 help='VNF name (VNF member index as declared in the NSD)')
1234 @click.option('--vdu', prompt=True,
1235 help='VDU name (VDU name as declared in the VNFD)')
1236 @click.option('--metric', prompt=True,
1237 help='name of the metric (e.g. cpu_utilization)')
1238 #@click.option('--period', default='1w',
1239 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
1240 @click.option('--interval', help='periodic interval (seconds) to export metrics continuously')
1241 @click.pass_context
1242 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
1243 '''exports a metric to the internal OSM bus, which can be read by other apps
1244 '''
1245 ns_instance = ctx.obj.ns.get(ns)
1246 metric_data = {}
1247 metric_data['ns_id'] = ns_instance['_id']
1248 metric_data['correlation_id'] = ns_instance['_id']
1249 metric_data['vnf_member_index'] = vnf
1250 metric_data['vdu_name'] = vdu
1251 metric_data['metric_name'] = metric
1252 metric_data['collection_unit'] = 'WEEK'
1253 metric_data['collection_period'] = 1
1254 try:
1255 check_client_version(ctx.obj, ctx.command.name)
1256 if not interval:
1257 print '{}'.format(ctx.obj.ns.export_metric(metric_data))
1258 else:
1259 i = 1
1260 while True:
1261 print '{} {}'.format(ctx.obj.ns.export_metric(metric_data),i)
1262 time.sleep(int(interval))
1263 i+=1
1264 except ClientException as inst:
1265 print(inst.message)
1266 exit(1)
1267
1268
1269 ####################
1270 # Other operations
1271 ####################
1272
1273 @cli.command(name='upload-package')
1274 @click.argument('filename')
1275 @click.pass_context
1276 def upload_package(ctx, filename):
1277 '''uploads a VNF package or NS package
1278
1279 FILENAME: VNF or NS package file (tar.gz)
1280 '''
1281 try:
1282 ctx.obj.package.upload(filename)
1283 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
1284 if fullclassname != 'osmclient.sol005.client.Client':
1285 ctx.obj.package.wait_for_upload(filename)
1286 except ClientException as inst:
1287 print(inst.message)
1288 exit(1)
1289
1290
1291 @cli.command(name='ns-scaling-show')
1292 @click.argument('ns_name')
1293 @click.pass_context
1294 def show_ns_scaling(ctx, ns_name):
1295 '''shows the status of a NS scaling operation
1296
1297 NS_NAME: name of the NS instance being scaled
1298 '''
1299 try:
1300 check_client_version(ctx.obj, ctx.command.name, 'v1')
1301 resp = ctx.obj.ns.list()
1302 except ClientException as inst:
1303 print(inst.message)
1304 exit(1)
1305
1306 table = PrettyTable(
1307 ['group-name',
1308 'instance-id',
1309 'operational status',
1310 'create-time',
1311 'vnfr ids'])
1312
1313 for ns in resp:
1314 if ns_name == ns['name']:
1315 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
1316 scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
1317 for record in scaling_records:
1318 if 'instance' in record:
1319 instances = record['instance']
1320 for inst in instances:
1321 table.add_row(
1322 [record['scaling-group-name-ref'],
1323 inst['instance-id'],
1324 inst['op-status'],
1325 time.strftime('%Y-%m-%d %H:%M:%S',
1326 time.localtime(
1327 inst['create-time'])),
1328 inst['vnfrs']])
1329 table.align = 'l'
1330 print(table)
1331
1332
1333 @cli.command(name='ns-scale')
1334 @click.argument('ns_name')
1335 @click.option('--ns_scale_group', prompt=True)
1336 @click.option('--index', prompt=True)
1337 @click.pass_context
1338 def ns_scale(ctx, ns_name, ns_scale_group, index):
1339 '''scales NS
1340
1341 NS_NAME: name of the NS instance to be scaled
1342 '''
1343 try:
1344 check_client_version(ctx.obj, ctx.command.name, 'v1')
1345 ctx.obj.ns.scale(ns_name, ns_scale_group, index)
1346 except ClientException as inst:
1347 print(inst.message)
1348 exit(1)
1349
1350
1351 @cli.command(name='config-agent-list')
1352 @click.pass_context
1353 def config_agent_list(ctx):
1354 '''list config agents'''
1355 try:
1356 check_client_version(ctx.obj, ctx.command.name, 'v1')
1357 except ClientException as inst:
1358 print(inst.message)
1359 exit(1)
1360 table = PrettyTable(['name', 'account-type', 'details'])
1361 for account in ctx.obj.vca.list():
1362 table.add_row(
1363 [account['name'],
1364 account['account-type'],
1365 account['juju']])
1366 table.align = 'l'
1367 print(table)
1368
1369
1370 @cli.command(name='config-agent-delete')
1371 @click.argument('name')
1372 @click.pass_context
1373 def config_agent_delete(ctx, name):
1374 '''deletes a config agent
1375
1376 NAME: name of the config agent to be deleted
1377 '''
1378 try:
1379 check_client_version(ctx.obj, ctx.command.name, 'v1')
1380 ctx.obj.vca.delete(name)
1381 except ClientException as inst:
1382 print(inst.message)
1383 exit(1)
1384
1385
1386 @cli.command(name='config-agent-add')
1387 @click.option('--name',
1388 prompt=True)
1389 @click.option('--account_type',
1390 prompt=True)
1391 @click.option('--server',
1392 prompt=True)
1393 @click.option('--user',
1394 prompt=True)
1395 @click.option('--secret',
1396 prompt=True,
1397 hide_input=True,
1398 confirmation_prompt=True)
1399 @click.pass_context
1400 def config_agent_add(ctx, name, account_type, server, user, secret):
1401 '''adds a config agent'''
1402 try:
1403 check_client_version(ctx.obj, ctx.command.name, 'v1')
1404 ctx.obj.vca.create(name, account_type, server, user, secret)
1405 except ClientException as inst:
1406 print(inst.message)
1407 exit(1)
1408
1409 @cli.command(name='ro-dump')
1410 @click.pass_context
1411 def ro_dump(ctx):
1412 '''shows RO agent information'''
1413 check_client_version(ctx.obj, ctx.command.name, 'v1')
1414 resp = ctx.obj.vim.get_resource_orchestrator()
1415 table = PrettyTable(['key', 'attribute'])
1416 for k, v in resp.items():
1417 table.add_row([k, json.dumps(v, indent=2)])
1418 table.align = 'l'
1419 print(table)
1420
1421
1422 @cli.command(name='vcs-list')
1423 @click.pass_context
1424 def vcs_list(ctx):
1425 check_client_version(ctx.obj, ctx.command.name, 'v1')
1426 resp = ctx.obj.utils.get_vcs_info()
1427 table = PrettyTable(['component name', 'state'])
1428 for component in resp:
1429 table.add_row([component['component_name'], component['state']])
1430 table.align = 'l'
1431 print(table)
1432
1433
1434 @cli.command(name='ns-action')
1435 @click.argument('ns_name')
1436 @click.option('--vnf_name', default=None)
1437 @click.option('--action_name', prompt=True)
1438 @click.option('--params', prompt=True)
1439 @click.pass_context
1440 def ns_action(ctx,
1441 ns_name,
1442 vnf_name,
1443 action_name,
1444 params):
1445 '''executes an action/primitive over a NS instance
1446
1447 NS_NAME: name or ID of the NS instance
1448 '''
1449 try:
1450 check_client_version(ctx.obj, ctx.command.name)
1451 op_data={}
1452 if vnf_name:
1453 op_data['vnf_member_index'] = vnf_name
1454 op_data['primitive'] = action_name
1455 op_data['primitive_params'] = yaml.load(params)
1456 ctx.obj.ns.exec_op(ns_name, op_name='action', op_data=op_data)
1457
1458 except ClientException as inst:
1459 print(inst.message)
1460 exit(1)
1461
1462
1463 if __name__ == '__main__':
1464 cli()