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