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