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