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