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