vim-update dealing with SDN controller and port mapping
[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', help='New name for the VIM account')
843 @click.option('--user', help='VIM username')
844 @click.option('--password', help='VIM password')
845 @click.option('--auth_url', help='VIM url')
846 @click.option('--tenant', help='VIM tenant name')
847 @click.option('--config', help='VIM specific config parameters')
848 @click.option('--account_type', help='VIM type')
849 @click.option('--sdn_controller', help='Name or id of the SDN controller associated to this VIM account')
850 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
851 @click.option('--description', help='human readable description')
852 @click.pass_context
853 def vim_update(ctx,
854 name,
855 newname,
856 user,
857 password,
858 auth_url,
859 tenant,
860 config,
861 account_type,
862 description):
863 '''updates a VIM account
864
865 NAME: name or ID of the VIM account
866 '''
867 vim = {}
868 if newname: vim['name'] = newname
869 if user: vim['vim_user'] = user
870 if password: vim['vim_password'] = password
871 if auth_url: vim['vim_url'] = auth_url
872 if tenant: vim['vim-tenant-name'] = tenant
873 if account_type: vim['vim_type'] = account_type
874 if description: vim['description'] = description
875 config_dict = {}
876 if config is not None:
877 if config=="" and (sdncontroller or sdn_port_mapping):
878 raise ClientException("clearing config is incompatible with updating SDN info")
879 if config=="":
880 vim['config'] = None
881 else:
882 config_dict = yaml.safe_load(config)
883 if sdn_controller: config_dict['sdn_controller'] = sdn_controller
884 if sdn_port_mapping:
885 with open(sdn_port_mapping, 'r') as f:
886 config_dict['sdn_port_mapping'] = yaml.safe_load(f.read())
887 if 'config' not in vim and config_dict:
888 vim['config'] = yaml.safe_dump(config_dict)
889 try:
890 check_client_version(ctx.obj, ctx.command.name)
891 ctx.obj.vim.update(name, vim)
892 except ClientException as inst:
893 print(inst.message)
894 exit(1)
895
896
897 @cli.command(name='vim-delete')
898 @click.argument('name')
899 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
900 @click.pass_context
901 def vim_delete(ctx, name, force):
902 '''deletes a VIM account
903
904 NAME: name or ID of the VIM account to be deleted
905 '''
906 try:
907 if not force:
908 ctx.obj.vim.delete(name)
909 else:
910 check_client_version(ctx.obj, '--force')
911 ctx.obj.vim.delete(name, force)
912 except ClientException as inst:
913 print(inst.message)
914 exit(1)
915
916
917 @cli.command(name='vim-list')
918 @click.option('--ro_update/--no_ro_update',
919 default=False,
920 help='update list from RO')
921 @click.option('--filter', default=None,
922 help='restricts the list to the VIM accounts matching the filter')
923 @click.pass_context
924 def vim_list(ctx, ro_update, filter):
925 '''list all VIM accounts'''
926 if filter:
927 check_client_version(ctx.obj, '--filter')
928 if ro_update:
929 check_client_version(ctx.obj, '--ro_update', 'v1')
930 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
931 if fullclassname == 'osmclient.sol005.client.Client':
932 resp = ctx.obj.vim.list(filter)
933 else:
934 resp = ctx.obj.vim.list(ro_update)
935 table = PrettyTable(['vim name', 'uuid'])
936 for vim in resp:
937 table.add_row([vim['name'], vim['uuid']])
938 table.align = 'l'
939 print(table)
940
941
942 @cli.command(name='vim-show')
943 @click.argument('name')
944 @click.pass_context
945 def vim_show(ctx, name):
946 '''shows the details of a VIM account
947
948 NAME: name or ID of the VIM account
949 '''
950 try:
951 resp = ctx.obj.vim.get(name)
952 if 'vim_password' in resp:
953 resp['vim_password']='********'
954 except ClientException as inst:
955 print(inst.message)
956 exit(1)
957
958 table = PrettyTable(['key', 'attribute'])
959 for k, v in resp.items():
960 table.add_row([k, json.dumps(v, indent=2)])
961 table.align = 'l'
962 print(table)
963
964
965 ####################
966 # SDN controller operations
967 ####################
968
969 @cli.command(name='sdnc-create')
970 @click.option('--name',
971 prompt=True,
972 help='Name to create sdn controller')
973 @click.option('--type',
974 prompt=True,
975 help='SDN controller type')
976 @click.option('--sdn_controller_version',
977 help='SDN controller username')
978 @click.option('--ip_address',
979 prompt=True,
980 help='SDN controller IP address')
981 @click.option('--port',
982 prompt=True,
983 help='SDN controller port')
984 @click.option('--switch_dpid',
985 prompt=True,
986 help='Switch DPID (Openflow Datapath ID)')
987 @click.option('--user',
988 help='SDN controller username')
989 @click.option('--password',
990 hide_input=True,
991 confirmation_prompt=True,
992 help='SDN controller password')
993 #@click.option('--description',
994 # default='no description',
995 # help='human readable description')
996 @click.pass_context
997 def sdnc_create(ctx,
998 name,
999 type,
1000 sdn_controller_version,
1001 ip_address,
1002 port,
1003 switch_dpid,
1004 user,
1005 password):
1006 '''creates a new SDN controller
1007 '''
1008 sdncontroller = {}
1009 sdncontroller['name'] = name
1010 sdncontroller['type'] = type
1011 sdncontroller['ip'] = ip_address
1012 sdncontroller['port'] = int(port)
1013 sdncontroller['dpid'] = switch_dpid
1014 if sdn_controller_version:
1015 sdncontroller['version'] = sdn_controller_version
1016 if user:
1017 sdncontroller['user'] = user
1018 if password:
1019 sdncontroller['password'] = password
1020 # sdncontroller['description'] = description
1021 try:
1022 check_client_version(ctx.obj, ctx.command.name)
1023 ctx.obj.sdnc.create(name, sdncontroller)
1024 except ClientException as inst:
1025 print(inst.message)
1026
1027
1028 @cli.command(name='sdnc-update', short_help='updates an SDN controller')
1029 @click.argument('name')
1030 @click.option('--newname', help='New name for the SDN controller')
1031 @click.option('--type', help='SDN controller type')
1032 @click.option('--sdn_controller_version', help='SDN controller username')
1033 @click.option('--ip_address', help='SDN controller IP address')
1034 @click.option('--port', help='SDN controller port')
1035 @click.option('--switch_dpid', help='Switch DPID (Openflow Datapath ID)')
1036 @click.option('--user', help='SDN controller username')
1037 @click.option('--password', help='SDN controller password')
1038 #@click.option('--description', default=None, help='human readable description')
1039 @click.pass_context
1040 def sdnc_update(ctx,
1041 name,
1042 newname,
1043 type,
1044 sdn_controller_version,
1045 ip_address,
1046 port,
1047 switch_dpid,
1048 user,
1049 password):
1050 '''updates an SDN controller
1051
1052 NAME: name or ID of the SDN controller
1053 '''
1054 sdncontroller = {}
1055 if newname: sdncontroller['name'] = newname
1056 if type: sdncontroller['type'] = type
1057 if ip_address: sdncontroller['ip'] = ip_address
1058 if port: sdncontroller['port'] = int(port)
1059 if switch_dpid: sdncontroller['dpid'] = switch_dpid
1060 # sdncontroller['description'] = description
1061 if sdn_controller_version is not None:
1062 if sdn_controller_version=="":
1063 sdncontroller['version'] = None
1064 else:
1065 sdncontroller['version'] = sdn_controller_version
1066 if user is not None:
1067 if user=="":
1068 sdncontroller['user'] = None
1069 else:
1070 sdncontroller['user'] = user
1071 if password is not None:
1072 if password=="":
1073 sdncontroller['password'] = None
1074 else:
1075 sdncontroller['password'] = user
1076 try:
1077 check_client_version(ctx.obj, ctx.command.name)
1078 ctx.obj.sdnc.update(name, sdncontroller)
1079 except ClientException as inst:
1080 print(inst.message)
1081 exit(1)
1082
1083
1084 @cli.command(name='sdnc-delete')
1085 @click.argument('name')
1086 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1087 @click.pass_context
1088 def sdnc_delete(ctx, name, force):
1089 '''deletes an SDN controller
1090
1091 NAME: name or ID of the SDN controller to be deleted
1092 '''
1093 try:
1094 check_client_version(ctx.obj, ctx.command.name)
1095 ctx.obj.sdnc.delete(name, force)
1096 except ClientException as inst:
1097 print(inst.message)
1098 exit(1)
1099
1100
1101 @cli.command(name='sdnc-list')
1102 @click.option('--filter', default=None,
1103 help='restricts the list to the SDN controllers matching the filter')
1104 @click.pass_context
1105 def sdnc_list(ctx, filter):
1106 '''list all SDN controllers'''
1107 try:
1108 check_client_version(ctx.obj, ctx.command.name)
1109 resp = ctx.obj.sdnc.list(filter)
1110 except ClientException as inst:
1111 print(inst.message)
1112 exit(1)
1113 table = PrettyTable(['name', 'id'])
1114 for sdnc in resp:
1115 table.add_row([sdnc['name'], sdnc['_id']])
1116 table.align = 'l'
1117 print(table)
1118
1119
1120 @cli.command(name='sdnc-show')
1121 @click.argument('name')
1122 @click.pass_context
1123 def sdnc_show(ctx, name):
1124 '''shows the details of an SDN controller
1125
1126 NAME: name or ID of the SDN controller
1127 '''
1128 try:
1129 check_client_version(ctx.obj, ctx.command.name)
1130 resp = ctx.obj.sdnc.get(name)
1131 except ClientException as inst:
1132 print(inst.message)
1133 exit(1)
1134
1135 table = PrettyTable(['key', 'attribute'])
1136 for k, v in resp.items():
1137 table.add_row([k, json.dumps(v, indent=2)])
1138 table.align = 'l'
1139 print(table)
1140
1141
1142 ####################
1143 # Fault Management operations
1144 ####################
1145
1146 @cli.command(name='ns-alarm-create')
1147 @click.argument('name')
1148 @click.option('--ns', prompt=True, help='NS instance id or name')
1149 @click.option('--vnf', prompt=True,
1150 help='VNF name (VNF member index as declared in the NSD)')
1151 @click.option('--vdu', prompt=True,
1152 help='VDU name (VDU name as declared in the VNFD)')
1153 @click.option('--metric', prompt=True,
1154 help='Name of the metric (e.g. cpu_utilization)')
1155 @click.option('--severity', default='WARNING',
1156 help='severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)')
1157 @click.option('--threshold_value', prompt=True,
1158 help='threshold value that, when crossed, an alarm is triggered')
1159 @click.option('--threshold_operator', prompt=True,
1160 help='threshold operator describing the comparison (GE, LE, GT, LT, EQ)')
1161 @click.option('--statistic', default='AVERAGE',
1162 help='statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)')
1163 @click.pass_context
1164 def ns_alarm_create(ctx, name, ns, vnf, vdu, metric, severity,
1165 threshold_value, threshold_operator, statistic):
1166 '''creates a new alarm for a NS instance'''
1167 ns_instance = ctx.obj.ns.get(ns)
1168 alarm = {}
1169 alarm['alarm_name'] = name
1170 alarm['ns_id'] = ns_instance['_id']
1171 alarm['correlation_id'] = ns_instance['_id']
1172 alarm['vnf_member_index'] = vnf
1173 alarm['vdu_name'] = vdu
1174 alarm['metric_name'] = metric
1175 alarm['severity'] = severity
1176 alarm['threshold_value'] = int(threshold_value)
1177 alarm['operation'] = threshold_operator
1178 alarm['statistic'] = statistic
1179 try:
1180 check_client_version(ctx.obj, ctx.command.name)
1181 ctx.obj.ns.create_alarm(alarm)
1182 except ClientException as inst:
1183 print(inst.message)
1184 exit(1)
1185
1186
1187 #@cli.command(name='ns-alarm-delete')
1188 #@click.argument('name')
1189 #@click.pass_context
1190 #def ns_alarm_delete(ctx, name):
1191 # '''deletes an alarm
1192 #
1193 # NAME: name of the alarm to be deleted
1194 # '''
1195 # try:
1196 # check_client_version(ctx.obj, ctx.command.name)
1197 # ctx.obj.ns.delete_alarm(name)
1198 # except ClientException as inst:
1199 # print(inst.message)
1200 # exit(1)
1201
1202
1203 ####################
1204 # Performance Management operations
1205 ####################
1206
1207 @cli.command(name='ns-metric-export')
1208 @click.option('--ns', prompt=True, help='NS instance id or name')
1209 @click.option('--vnf', prompt=True,
1210 help='VNF name (VNF member index as declared in the NSD)')
1211 @click.option('--vdu', prompt=True,
1212 help='VDU name (VDU name as declared in the VNFD)')
1213 @click.option('--metric', prompt=True,
1214 help='name of the metric (e.g. cpu_utilization)')
1215 #@click.option('--period', default='1w',
1216 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
1217 @click.option('--interval', help='periodic interval (seconds) to export metrics continuously')
1218 @click.pass_context
1219 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
1220 '''exports a metric to the internal OSM bus, which can be read by other apps
1221 '''
1222 ns_instance = ctx.obj.ns.get(ns)
1223 metric_data = {}
1224 metric_data['ns_id'] = ns_instance['_id']
1225 metric_data['correlation_id'] = ns_instance['_id']
1226 metric_data['vnf_member_index'] = vnf
1227 metric_data['vdu_name'] = vdu
1228 metric_data['metric_name'] = metric
1229 metric_data['collection_unit'] = 'WEEK'
1230 metric_data['collection_period'] = 1
1231 try:
1232 check_client_version(ctx.obj, ctx.command.name)
1233 if not interval:
1234 print '{}'.format(ctx.obj.ns.export_metric(metric_data))
1235 else:
1236 i = 1
1237 while True:
1238 print '{} {}'.format(ctx.obj.ns.export_metric(metric_data),i)
1239 time.sleep(int(interval))
1240 i+=1
1241 except ClientException as inst:
1242 print(inst.message)
1243 exit(1)
1244
1245
1246 ####################
1247 # Other operations
1248 ####################
1249
1250 @cli.command(name='upload-package')
1251 @click.argument('filename')
1252 @click.pass_context
1253 def upload_package(ctx, filename):
1254 '''uploads a VNF package or NS package
1255
1256 FILENAME: VNF or NS package file (tar.gz)
1257 '''
1258 try:
1259 ctx.obj.package.upload(filename)
1260 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
1261 if fullclassname != 'osmclient.sol005.client.Client':
1262 ctx.obj.package.wait_for_upload(filename)
1263 except ClientException as inst:
1264 print(inst.message)
1265 exit(1)
1266
1267
1268 @cli.command(name='ns-scaling-show')
1269 @click.argument('ns_name')
1270 @click.pass_context
1271 def show_ns_scaling(ctx, ns_name):
1272 '''shows the status of a NS scaling operation
1273
1274 NS_NAME: name of the NS instance being scaled
1275 '''
1276 try:
1277 check_client_version(ctx.obj, ctx.command.name, 'v1')
1278 resp = ctx.obj.ns.list()
1279 except ClientException as inst:
1280 print(inst.message)
1281 exit(1)
1282
1283 table = PrettyTable(
1284 ['group-name',
1285 'instance-id',
1286 'operational status',
1287 'create-time',
1288 'vnfr ids'])
1289
1290 for ns in resp:
1291 if ns_name == ns['name']:
1292 nsopdata = ctx.obj.ns.get_opdata(ns['id'])
1293 scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
1294 for record in scaling_records:
1295 if 'instance' in record:
1296 instances = record['instance']
1297 for inst in instances:
1298 table.add_row(
1299 [record['scaling-group-name-ref'],
1300 inst['instance-id'],
1301 inst['op-status'],
1302 time.strftime('%Y-%m-%d %H:%M:%S',
1303 time.localtime(
1304 inst['create-time'])),
1305 inst['vnfrs']])
1306 table.align = 'l'
1307 print(table)
1308
1309
1310 @cli.command(name='ns-scale')
1311 @click.argument('ns_name')
1312 @click.option('--ns_scale_group', prompt=True)
1313 @click.option('--index', prompt=True)
1314 @click.pass_context
1315 def ns_scale(ctx, ns_name, ns_scale_group, index):
1316 '''scales NS
1317
1318 NS_NAME: name of the NS instance to be scaled
1319 '''
1320 try:
1321 check_client_version(ctx.obj, ctx.command.name, 'v1')
1322 ctx.obj.ns.scale(ns_name, ns_scale_group, index)
1323 except ClientException as inst:
1324 print(inst.message)
1325 exit(1)
1326
1327
1328 @cli.command(name='config-agent-list')
1329 @click.pass_context
1330 def config_agent_list(ctx):
1331 '''list config agents'''
1332 try:
1333 check_client_version(ctx.obj, ctx.command.name, 'v1')
1334 except ClientException as inst:
1335 print(inst.message)
1336 exit(1)
1337 table = PrettyTable(['name', 'account-type', 'details'])
1338 for account in ctx.obj.vca.list():
1339 table.add_row(
1340 [account['name'],
1341 account['account-type'],
1342 account['juju']])
1343 table.align = 'l'
1344 print(table)
1345
1346
1347 @cli.command(name='config-agent-delete')
1348 @click.argument('name')
1349 @click.pass_context
1350 def config_agent_delete(ctx, name):
1351 '''deletes a config agent
1352
1353 NAME: name of the config agent to be deleted
1354 '''
1355 try:
1356 check_client_version(ctx.obj, ctx.command.name, 'v1')
1357 ctx.obj.vca.delete(name)
1358 except ClientException as inst:
1359 print(inst.message)
1360 exit(1)
1361
1362
1363 @cli.command(name='config-agent-add')
1364 @click.option('--name',
1365 prompt=True)
1366 @click.option('--account_type',
1367 prompt=True)
1368 @click.option('--server',
1369 prompt=True)
1370 @click.option('--user',
1371 prompt=True)
1372 @click.option('--secret',
1373 prompt=True,
1374 hide_input=True,
1375 confirmation_prompt=True)
1376 @click.pass_context
1377 def config_agent_add(ctx, name, account_type, server, user, secret):
1378 '''adds a config agent'''
1379 try:
1380 check_client_version(ctx.obj, ctx.command.name, 'v1')
1381 ctx.obj.vca.create(name, account_type, server, user, secret)
1382 except ClientException as inst:
1383 print(inst.message)
1384 exit(1)
1385
1386 @cli.command(name='ro-dump')
1387 @click.pass_context
1388 def ro_dump(ctx):
1389 '''shows RO agent information'''
1390 check_client_version(ctx.obj, ctx.command.name, 'v1')
1391 resp = ctx.obj.vim.get_resource_orchestrator()
1392 table = PrettyTable(['key', 'attribute'])
1393 for k, v in resp.items():
1394 table.add_row([k, json.dumps(v, indent=2)])
1395 table.align = 'l'
1396 print(table)
1397
1398
1399 @cli.command(name='vcs-list')
1400 @click.pass_context
1401 def vcs_list(ctx):
1402 check_client_version(ctx.obj, ctx.command.name, 'v1')
1403 resp = ctx.obj.utils.get_vcs_info()
1404 table = PrettyTable(['component name', 'state'])
1405 for component in resp:
1406 table.add_row([component['component_name'], component['state']])
1407 table.align = 'l'
1408 print(table)
1409
1410
1411 @cli.command(name='ns-action')
1412 @click.argument('ns_name')
1413 @click.option('--vnf_name', default=None)
1414 @click.option('--action_name', prompt=True)
1415 @click.option('--params', prompt=True)
1416 @click.pass_context
1417 def ns_action(ctx,
1418 ns_name,
1419 vnf_name,
1420 action_name,
1421 params):
1422 '''executes an action/primitive over a NS instance
1423
1424 NS_NAME: name or ID of the NS instance
1425 '''
1426 try:
1427 check_client_version(ctx.obj, ctx.command.name)
1428 op_data={}
1429 if vnf_name:
1430 op_data['vnf_member_index'] = vnf_name
1431 op_data['primitive'] = action_name
1432 op_data['primitive_params'] = yaml.load(params)
1433 ctx.obj.ns.exec_op(ns_name, op_name='action', op_data=op_data)
1434
1435 except ClientException as inst:
1436 print(inst.message)
1437 exit(1)
1438
1439
1440 if __name__ == '__main__':
1441 cli()