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