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