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