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