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