6245bb3ca5d658573bc25f0362c1948696448b19
[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['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['config-status'] if 'config-status' in nsr else 'Not found'
374 current_operation = "Unknown"
375 error_details = nsr['detailed-status'] if 'detailed-status' in nsr else '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):
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 # except ClientException as e:
1455 # print(str(e))
1456 # exit(1)
1457
1458
1459 @cli_osm.command(name='vnfd-create', short_help='creates a new VNFD/VNFpkg')
1460 @click.argument('filename')
1461 @click.option('--overwrite', 'overwrite', default=None,
1462 help='overwrite deprecated, use override')
1463 @click.option('--override', 'overwrite', default=None,
1464 help='overrides fields in descriptor, format: '
1465 '"key1.key2...=value[;key3...=value;...]"')
1466 @click.option('--skip-charm-build', default=False, is_flag=True,
1467 help='The charm will not be compiled, it is assumed to already exist')
1468 @click.pass_context
1469 def vnfd_create1(ctx, filename, overwrite, skip_charm_build):
1470 """creates a new VNFD/VNFpkg
1471
1472 FILENAME: VNFD yaml file or VNFpkg tar.gz file
1473 """
1474 logger.debug("")
1475 vnfd_create(ctx, filename, overwrite=overwrite, skip_charm_build=skip_charm_build)
1476
1477
1478 @cli_osm.command(name='vnfpkg-create', short_help='creates a new VNFD/VNFpkg')
1479 @click.argument('filename')
1480 @click.option('--overwrite', 'overwrite', default=None, # hidden=True,
1481 help='Deprecated. Use override')
1482 @click.option('--override', 'overwrite', default=None,
1483 help='overrides fields in descriptor, format: '
1484 '"key1.key2...=value[;key3...=value;...]"')
1485 @click.option('--skip-charm-build', default=False, is_flag=True,
1486 help='The charm will not be compiled, it is assumed to already exist')
1487 @click.pass_context
1488 def vnfd_create2(ctx, filename, overwrite, skip_charm_build):
1489 """creates a new VNFD/VNFpkg
1490
1491 FILENAME: NF Package Folder, NF Descriptor yaml file or NFpkg tar.gz file
1492 """
1493 logger.debug("")
1494 vnfd_create(ctx, filename, overwrite=overwrite, skip_charm_build=skip_charm_build)
1495
1496
1497 @cli_osm.command(name='nfpkg-create', short_help='creates a new NFpkg')
1498 @click.argument('filename')
1499 @click.option('--overwrite', 'overwrite', default=None, # hidden=True,
1500 help='Deprecated. Use override')
1501 @click.option('--override', 'overwrite', default=None,
1502 help='overrides fields in descriptor, format: '
1503 '"key1.key2...=value[;key3...=value;...]"')
1504 @click.option('--skip-charm-build', default=False, is_flag=True,
1505 help='The charm will not be compiled, it is assumed to already exist')
1506 @click.pass_context
1507 def nfpkg_create(ctx, filename, overwrite, skip_charm_build):
1508 """creates a new NFpkg
1509
1510 FILENAME: NF Package Folder, NF Descriptor yaml file or NFpkg tar.gz filems to build
1511 """
1512 logger.debug("")
1513 vnfd_create(ctx, filename, overwrite=overwrite, skip_charm_build=skip_charm_build)
1514
1515
1516 @cli_osm.command(name='ns-create', short_help='creates a new Network Service instance')
1517 @click.option('--ns_name',
1518 prompt=True, help='name of the NS instance')
1519 @click.option('--nsd_name',
1520 prompt=True, help='name of the NS descriptor')
1521 @click.option('--vim_account',
1522 prompt=True, help='default VIM account id or name for the deployment')
1523 @click.option('--admin_status',
1524 default='ENABLED',
1525 help='administration status')
1526 @click.option('--ssh_keys',
1527 default=None,
1528 help='comma separated list of public key files to inject to vnfs')
1529 @click.option('--config',
1530 default=None,
1531 help='ns specific yaml configuration')
1532 @click.option('--config_file',
1533 default=None,
1534 help='ns specific yaml configuration file')
1535 @click.option('--wait',
1536 required=False,
1537 default=False,
1538 is_flag=True,
1539 help='do not return the control immediately, but keep it '
1540 'until the operation is completed, or timeout')
1541 @click.pass_context
1542 def ns_create(ctx,
1543 nsd_name,
1544 ns_name,
1545 vim_account,
1546 admin_status,
1547 ssh_keys,
1548 config,
1549 config_file,
1550 wait):
1551 """creates a new NS instance"""
1552 logger.debug("")
1553 # try:
1554 if config_file:
1555 check_client_version(ctx.obj, '--config_file')
1556 if config:
1557 raise ClientException('"--config" option is incompatible with "--config_file" option')
1558 with open(config_file, 'r') as cf:
1559 config=cf.read()
1560 ctx.obj.ns.create(
1561 nsd_name,
1562 ns_name,
1563 config=config,
1564 ssh_keys=ssh_keys,
1565 account=vim_account,
1566 wait=wait)
1567 # except ClientException as e:
1568 # print(str(e))
1569 # exit(1)
1570
1571
1572 def nst_create(ctx, filename, overwrite):
1573 logger.debug("")
1574 # try:
1575 check_client_version(ctx.obj, ctx.command.name)
1576 ctx.obj.nst.create(filename, overwrite)
1577 # except ClientException as e:
1578 # print(str(e))
1579 # exit(1)
1580
1581
1582 @cli_osm.command(name='nst-create', short_help='creates a new Network Slice Template (NST)')
1583 @click.argument('filename')
1584 @click.option('--overwrite', 'overwrite', default=None, # hidden=True,
1585 help='Deprecated. Use override')
1586 @click.option('--override', 'overwrite', default=None,
1587 help='overrides fields in descriptor, format: '
1588 '"key1.key2...=value[;key3...=value;...]"')
1589 @click.pass_context
1590 def nst_create1(ctx, charm_folder, overwrite):
1591 """creates a new Network Slice Template (NST)
1592
1593 FILENAME: NST package folder, NST yaml file or NSTpkg tar.gz file
1594 """
1595 logger.debug("")
1596 nst_create(ctx, charm_folder, overwrite)
1597
1598
1599 @cli_osm.command(name='netslice-template-create', short_help='creates a new Network Slice Template (NST)')
1600 @click.argument('filename')
1601 @click.option('--overwrite', 'overwrite', default=None, # hidden=True,
1602 help='Deprecated. Use override')
1603 @click.option('--override', 'overwrite', default=None,
1604 help='overrides fields in descriptor, format: '
1605 '"key1.key2...=value[;key3...=value;...]"')
1606 @click.pass_context
1607 def nst_create2(ctx, filename, overwrite):
1608 """creates a new Network Slice Template (NST)
1609
1610 FILENAME: NST yaml file or NSTpkg tar.gz file
1611 """
1612 logger.debug("")
1613 nst_create(ctx, filename, overwrite)
1614
1615
1616 def nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1617 """creates a new Network Slice Instance (NSI)"""
1618 logger.debug("")
1619 # try:
1620 check_client_version(ctx.obj, ctx.command.name)
1621 if config_file:
1622 if config:
1623 raise ClientException('"--config" option is incompatible with "--config_file" option')
1624 with open(config_file, 'r') as cf:
1625 config=cf.read()
1626 ctx.obj.nsi.create(nst_name, nsi_name, config=config, ssh_keys=ssh_keys,
1627 account=vim_account, wait=wait)
1628 # except ClientException as e:
1629 # print(str(e))
1630 # exit(1)
1631
1632
1633 @cli_osm.command(name='nsi-create', short_help='creates a new Network Slice Instance')
1634 @click.option('--nsi_name', prompt=True, help='name of the Network Slice Instance')
1635 @click.option('--nst_name', prompt=True, help='name of the Network Slice Template')
1636 @click.option('--vim_account', prompt=True, help='default VIM account id or name for the deployment')
1637 @click.option('--ssh_keys', default=None,
1638 help='comma separated list of keys to inject to vnfs')
1639 @click.option('--config', default=None,
1640 help='Netslice specific yaml configuration:\n'
1641 'netslice_subnet: [\n'
1642 'id: TEXT, vim_account: TEXT,\n'
1643 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1644 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n'
1645 'additionalParamsForNsi: {param: value, ...}\n'
1646 'additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n'
1647 '],\n'
1648 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1649 )
1650 @click.option('--config_file',
1651 default=None,
1652 help='nsi specific yaml configuration file')
1653 @click.option('--wait',
1654 required=False,
1655 default=False,
1656 is_flag=True,
1657 help='do not return the control immediately, but keep it '
1658 'until the operation is completed, or timeout')
1659 @click.pass_context
1660 def nsi_create1(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1661 """creates a new Network Slice Instance (NSI)"""
1662 logger.debug("")
1663 nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
1664
1665
1666 @cli_osm.command(name='netslice-instance-create', short_help='creates a new Network Slice Instance')
1667 @click.option('--nsi_name', prompt=True, help='name of the Network Slice Instance')
1668 @click.option('--nst_name', prompt=True, help='name of the Network Slice Template')
1669 @click.option('--vim_account', prompt=True, help='default VIM account id or name for the deployment')
1670 @click.option('--ssh_keys', default=None,
1671 help='comma separated list of keys to inject to vnfs')
1672 @click.option('--config', default=None,
1673 help='Netslice specific yaml configuration:\n'
1674 'netslice_subnet: [\n'
1675 'id: TEXT, vim_account: TEXT,\n'
1676 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1677 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1678 '],\n'
1679 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1680 )
1681 @click.option('--config_file',
1682 default=None,
1683 help='nsi specific yaml configuration file')
1684 @click.option('--wait',
1685 required=False,
1686 default=False,
1687 is_flag=True,
1688 help='do not return the control immediately, but keep it '
1689 'until the operation is completed, or timeout')
1690 @click.pass_context
1691 def nsi_create2(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait):
1692 """creates a new Network Slice Instance (NSI)"""
1693 logger.debug("")
1694 nsi_create(ctx, nst_name, nsi_name, vim_account, ssh_keys, config, config_file, wait=wait)
1695
1696
1697 @cli_osm.command(name='pdu-create', short_help='adds a new Physical Deployment Unit to the catalog')
1698 @click.option('--name', help='name of the Physical Deployment Unit')
1699 @click.option('--pdu_type', help='type of PDU (e.g. router, firewall, FW001)')
1700 @click.option('--interface',
1701 help='interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>'+
1702 '[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]',
1703 multiple=True)
1704 @click.option('--description', help='human readable description')
1705 @click.option('--vim_account', help='list of VIM accounts (in the same VIM) that can reach this PDU', multiple=True)
1706 @click.option('--descriptor_file', default=None,
1707 help='PDU descriptor file (as an alternative to using the other arguments')
1708 @click.pass_context
1709 def pdu_create(ctx, name, pdu_type, interface, description, vim_account, descriptor_file):
1710 """creates a new Physical Deployment Unit (PDU)"""
1711 logger.debug("")
1712 # try:
1713 check_client_version(ctx.obj, ctx.command.name)
1714 pdu = {}
1715 if not descriptor_file:
1716 if not name:
1717 raise ClientException('in absence of descriptor file, option "--name" is mandatory')
1718 if not pdu_type:
1719 raise ClientException('in absence of descriptor file, option "--pdu_type" is mandatory')
1720 if not interface:
1721 raise ClientException('in absence of descriptor file, option "--interface" is mandatory (at least once)')
1722 if not vim_account:
1723 raise ClientException('in absence of descriptor file, option "--vim_account" is mandatory (at least once)')
1724 else:
1725 with open(descriptor_file, 'r') as df:
1726 pdu = yaml.safe_load(df.read())
1727 if name: pdu["name"] = name
1728 if pdu_type: pdu["type"] = pdu_type
1729 if description: pdu["description"] = description
1730 if vim_account: pdu["vim_accounts"] = vim_account
1731 if interface:
1732 ifaces_list = []
1733 for iface in interface:
1734 new_iface={k:v for k,v in [i.split('=') for i in iface.split(',')]}
1735 new_iface["mgmt"] = (new_iface.get("mgmt","false").lower() == "true")
1736 ifaces_list.append(new_iface)
1737 pdu["interfaces"] = ifaces_list
1738 ctx.obj.pdu.create(pdu)
1739 # except ClientException as e:
1740 # print(str(e))
1741 # exit(1)
1742
1743
1744 ####################
1745 # UPDATE operations
1746 ####################
1747
1748 def nsd_update(ctx, name, content):
1749 logger.debug("")
1750 # try:
1751 check_client_version(ctx.obj, ctx.command.name)
1752 ctx.obj.nsd.update(name, content)
1753 # except ClientException as e:
1754 # print(str(e))
1755 # exit(1)
1756
1757
1758 @cli_osm.command(name='nsd-update', short_help='updates a NSD/NSpkg')
1759 @click.argument('name')
1760 @click.option('--content', default=None,
1761 help='filename with the NSD/NSpkg replacing the current one')
1762 @click.pass_context
1763 def nsd_update1(ctx, name, content):
1764 """updates a NSD/NSpkg
1765
1766 NAME: name or ID of the NSD/NSpkg
1767 """
1768 logger.debug("")
1769 nsd_update(ctx, name, content)
1770
1771
1772 @cli_osm.command(name='nspkg-update', short_help='updates a NSD/NSpkg')
1773 @click.argument('name')
1774 @click.option('--content', default=None,
1775 help='filename with the NSD/NSpkg replacing the current one')
1776 @click.pass_context
1777 def nsd_update2(ctx, name, content):
1778 """updates a NSD/NSpkg
1779
1780 NAME: name or ID of the NSD/NSpkg
1781 """
1782 logger.debug("")
1783 nsd_update(ctx, name, content)
1784
1785
1786 def vnfd_update(ctx, name, content):
1787 logger.debug("")
1788 # try:
1789 check_client_version(ctx.obj, ctx.command.name)
1790 ctx.obj.vnfd.update(name, content)
1791 # except ClientException as e:
1792 # print(str(e))
1793 # exit(1)
1794
1795
1796 @cli_osm.command(name='vnfd-update', short_help='updates a new VNFD/VNFpkg')
1797 @click.argument('name')
1798 @click.option('--content', default=None,
1799 help='filename with the VNFD/VNFpkg replacing the current one')
1800 @click.pass_context
1801 def vnfd_update1(ctx, name, content):
1802 """updates a VNFD/VNFpkg
1803
1804 NAME: name or ID of the VNFD/VNFpkg
1805 """
1806 logger.debug("")
1807 vnfd_update(ctx, name, content)
1808
1809
1810 @cli_osm.command(name='vnfpkg-update', short_help='updates a VNFD/VNFpkg')
1811 @click.argument('name')
1812 @click.option('--content', default=None,
1813 help='filename with the VNFD/VNFpkg replacing the current one')
1814 @click.pass_context
1815 def vnfd_update2(ctx, name, content):
1816 """updates a VNFD/VNFpkg
1817
1818 NAME: VNFD yaml file or VNFpkg tar.gz file
1819 """
1820 logger.debug("")
1821 vnfd_update(ctx, name, content)
1822
1823
1824 @cli_osm.command(name='nfpkg-update', short_help='updates a NFpkg')
1825 @click.argument('name')
1826 @click.option('--content', default=None,
1827 help='filename with the NFpkg replacing the current one')
1828 @click.pass_context
1829 def nfpkg_update(ctx, name, content):
1830 """updates a NFpkg
1831
1832 NAME: NF Descriptor yaml file or NFpkg tar.gz file
1833 """
1834 logger.debug("")
1835 vnfd_update(ctx, name, content)
1836
1837
1838 def nst_update(ctx, name, content):
1839 logger.debug("")
1840 # try:
1841 check_client_version(ctx.obj, ctx.command.name)
1842 ctx.obj.nst.update(name, content)
1843 # except ClientException as e:
1844 # print(str(e))
1845 # exit(1)
1846
1847
1848 @cli_osm.command(name='nst-update', short_help='updates a Network Slice Template (NST)')
1849 @click.argument('name')
1850 @click.option('--content', default=None,
1851 help='filename with the NST/NSTpkg replacing the current one')
1852 @click.pass_context
1853 def nst_update1(ctx, name, content):
1854 """updates a Network Slice Template (NST)
1855
1856 NAME: name or ID of the NSD/NSpkg
1857 """
1858 logger.debug("")
1859 nst_update(ctx, name, content)
1860
1861
1862 @cli_osm.command(name='netslice-template-update', short_help='updates a Network Slice Template (NST)')
1863 @click.argument('name')
1864 @click.option('--content', default=None,
1865 help='filename with the NST/NSTpkg replacing the current one')
1866 @click.pass_context
1867 def nst_update2(ctx, name, content):
1868 """updates a Network Slice Template (NST)
1869
1870 NAME: name or ID of the NSD/NSpkg
1871 """
1872 logger.debug("")
1873 nst_update(ctx, name, content)
1874
1875
1876 ####################
1877 # DELETE operations
1878 ####################
1879
1880 def nsd_delete(ctx, name, force):
1881 logger.debug("")
1882 # try:
1883 if not force:
1884 ctx.obj.nsd.delete(name)
1885 else:
1886 check_client_version(ctx.obj, '--force')
1887 ctx.obj.nsd.delete(name, force)
1888 # except ClientException as e:
1889 # print(str(e))
1890 # exit(1)
1891
1892
1893 @cli_osm.command(name='nsd-delete', short_help='deletes a NSD/NSpkg')
1894 @click.argument('name')
1895 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1896 @click.pass_context
1897 def nsd_delete1(ctx, name, force):
1898 """deletes a NSD/NSpkg
1899
1900 NAME: name or ID of the NSD/NSpkg to be deleted
1901 """
1902 logger.debug("")
1903 nsd_delete(ctx, name, force)
1904
1905
1906 @cli_osm.command(name='nspkg-delete', short_help='deletes a NSD/NSpkg')
1907 @click.argument('name')
1908 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1909 @click.pass_context
1910 def nsd_delete2(ctx, name, force):
1911 """deletes a NSD/NSpkg
1912
1913 NAME: name or ID of the NSD/NSpkg to be deleted
1914 """
1915 logger.debug("")
1916 nsd_delete(ctx, name, force)
1917
1918
1919 def vnfd_delete(ctx, name, force):
1920 logger.debug("")
1921 # try:
1922 if not force:
1923 ctx.obj.vnfd.delete(name)
1924 else:
1925 check_client_version(ctx.obj, '--force')
1926 ctx.obj.vnfd.delete(name, force)
1927 # except ClientException as e:
1928 # print(str(e))
1929 # exit(1)
1930
1931
1932 @cli_osm.command(name='vnfd-delete', short_help='deletes a VNFD/VNFpkg')
1933 @click.argument('name')
1934 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1935 @click.pass_context
1936 def vnfd_delete1(ctx, name, force):
1937 """deletes a VNFD/VNFpkg
1938
1939 NAME: name or ID of the VNFD/VNFpkg to be deleted
1940 """
1941 logger.debug("")
1942 vnfd_delete(ctx, name, force)
1943
1944
1945 @cli_osm.command(name='vnfpkg-delete', short_help='deletes a VNFD/VNFpkg')
1946 @click.argument('name')
1947 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1948 @click.pass_context
1949 def vnfd_delete2(ctx, name, force):
1950 """deletes a VNFD/VNFpkg
1951
1952 NAME: name or ID of the VNFD/VNFpkg to be deleted
1953 """
1954 logger.debug("")
1955 vnfd_delete(ctx, name, force)
1956
1957
1958 @cli_osm.command(name='nfpkg-delete', short_help='deletes a NFpkg')
1959 @click.argument('name')
1960 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1961 @click.pass_context
1962 def nfpkg_delete(ctx, name, force):
1963 """deletes a NFpkg
1964
1965 NAME: name or ID of the NFpkg to be deleted
1966 """
1967 logger.debug("")
1968 vnfd_delete(ctx, name, force)
1969
1970
1971 @cli_osm.command(name='ns-delete', short_help='deletes a NS instance')
1972 @click.argument('name')
1973 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
1974 @click.option('--config', default=None,
1975 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
1976 "600, skip_terminate_primitives: True}'")
1977 @click.option('--wait',
1978 required=False,
1979 default=False,
1980 is_flag=True,
1981 help='do not return the control immediately, but keep it '
1982 'until the operation is completed, or timeout')
1983 @click.pass_context
1984 def ns_delete(ctx, name, force, config, wait):
1985 """deletes a NS instance
1986
1987 NAME: name or ID of the NS instance to be deleted
1988 """
1989 logger.debug("")
1990 # try:
1991 if not force:
1992 ctx.obj.ns.delete(name, config=config, wait=wait)
1993 else:
1994 check_client_version(ctx.obj, '--force')
1995 ctx.obj.ns.delete(name, force, config=config, wait=wait)
1996 # except ClientException as e:
1997 # print(str(e))
1998 # exit(1)
1999
2000
2001 def nst_delete(ctx, name, force):
2002 logger.debug("")
2003 # try:
2004 check_client_version(ctx.obj, ctx.command.name)
2005 ctx.obj.nst.delete(name, force)
2006 # except ClientException as e:
2007 # print(str(e))
2008 # exit(1)
2009
2010
2011 @cli_osm.command(name='nst-delete', short_help='deletes a Network Slice Template (NST)')
2012 @click.argument('name')
2013 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2014 @click.pass_context
2015 def nst_delete1(ctx, name, force):
2016 """deletes a Network Slice Template (NST)
2017
2018 NAME: name or ID of the NST/NSTpkg to be deleted
2019 """
2020 logger.debug("")
2021 nst_delete(ctx, name, force)
2022
2023
2024 @cli_osm.command(name='netslice-template-delete', short_help='deletes a Network Slice Template (NST)')
2025 @click.argument('name')
2026 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2027 @click.pass_context
2028 def nst_delete2(ctx, name, force):
2029 """deletes a Network Slice Template (NST)
2030
2031 NAME: name or ID of the NST/NSTpkg to be deleted
2032 """
2033 logger.debug("")
2034 nst_delete(ctx, name, force)
2035
2036
2037 def nsi_delete(ctx, name, force, wait):
2038 logger.debug("")
2039 # try:
2040 check_client_version(ctx.obj, ctx.command.name)
2041 ctx.obj.nsi.delete(name, force, wait=wait)
2042 # except ClientException as e:
2043 # print(str(e))
2044 # exit(1)
2045
2046
2047 @cli_osm.command(name='nsi-delete', short_help='deletes a Network Slice Instance (NSI)')
2048 @click.argument('name')
2049 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2050 @click.option('--wait',
2051 required=False,
2052 default=False,
2053 is_flag=True,
2054 help='do not return the control immediately, but keep it '
2055 'until the operation is completed, or timeout')
2056 @click.pass_context
2057 def nsi_delete1(ctx, name, force, wait):
2058 """deletes a Network Slice Instance (NSI)
2059
2060 NAME: name or ID of the Network Slice instance to be deleted
2061 """
2062 logger.debug("")
2063 nsi_delete(ctx, name, force, wait=wait)
2064
2065
2066 @cli_osm.command(name='netslice-instance-delete', short_help='deletes a Network Slice Instance (NSI)')
2067 @click.argument('name')
2068 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2069 @click.pass_context
2070 def nsi_delete2(ctx, name, force, wait):
2071 """deletes a Network Slice Instance (NSI)
2072
2073 NAME: name or ID of the Network Slice instance to be deleted
2074 """
2075 logger.debug("")
2076 nsi_delete(ctx, name, force, wait=wait)
2077
2078
2079 @cli_osm.command(name='pdu-delete', short_help='deletes a Physical Deployment Unit (PDU)')
2080 @click.argument('name')
2081 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2082 @click.pass_context
2083 def pdu_delete(ctx, name, force):
2084 """deletes a Physical Deployment Unit (PDU)
2085
2086 NAME: name or ID of the PDU to be deleted
2087 """
2088 logger.debug("")
2089 # try:
2090 check_client_version(ctx.obj, ctx.command.name)
2091 ctx.obj.pdu.delete(name, force)
2092 # except ClientException as e:
2093 # print(str(e))
2094 # exit(1)
2095
2096
2097 #################
2098 # VIM operations
2099 #################
2100
2101 @cli_osm.command(name='vim-create', short_help='creates a new VIM account')
2102 @click.option('--name',
2103 prompt=True,
2104 help='Name to create datacenter')
2105 @click.option('--user',
2106 prompt=True,
2107 help='VIM username')
2108 @click.option('--password',
2109 prompt=True,
2110 hide_input=True,
2111 confirmation_prompt=True,
2112 help='VIM password')
2113 @click.option('--auth_url',
2114 prompt=True,
2115 help='VIM url')
2116 @click.option('--tenant',
2117 prompt=True,
2118 help='VIM tenant name')
2119 @click.option('--config',
2120 default=None,
2121 help='VIM specific config parameters')
2122 @click.option('--account_type',
2123 default='openstack',
2124 help='VIM type')
2125 @click.option('--description',
2126 default=None,
2127 help='human readable description')
2128 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller associated to this VIM account')
2129 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
2130 @click.option('--wait',
2131 required=False,
2132 default=False,
2133 is_flag=True,
2134 help='do not return the control immediately, but keep it '
2135 'until the operation is completed, or timeout')
2136 @click.pass_context
2137 def vim_create(ctx,
2138 name,
2139 user,
2140 password,
2141 auth_url,
2142 tenant,
2143 config,
2144 account_type,
2145 description,
2146 sdn_controller,
2147 sdn_port_mapping,
2148 wait):
2149 """creates a new VIM account"""
2150 logger.debug("")
2151 # try:
2152 if sdn_controller:
2153 check_client_version(ctx.obj, '--sdn_controller')
2154 if sdn_port_mapping:
2155 check_client_version(ctx.obj, '--sdn_port_mapping')
2156 vim = {}
2157 vim['vim-username'] = user
2158 vim['vim-password'] = password
2159 vim['vim-url'] = auth_url
2160 vim['vim-tenant-name'] = tenant
2161 vim['vim-type'] = account_type
2162 vim['description'] = description
2163 vim['config'] = config
2164 if sdn_controller or sdn_port_mapping:
2165 ctx.obj.vim.create(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
2166 else:
2167 ctx.obj.vim.create(name, vim, wait=wait)
2168 # except ClientException as e:
2169 # print(str(e))
2170 # exit(1)
2171
2172
2173 @cli_osm.command(name='vim-update', short_help='updates a VIM account')
2174 @click.argument('name')
2175 @click.option('--newname', help='New name for the VIM account')
2176 @click.option('--user', help='VIM username')
2177 @click.option('--password', help='VIM password')
2178 @click.option('--auth_url', help='VIM url')
2179 @click.option('--tenant', help='VIM tenant name')
2180 @click.option('--config', help='VIM specific config parameters')
2181 @click.option('--account_type', help='VIM type')
2182 @click.option('--description', help='human readable description')
2183 @click.option('--sdn_controller', default=None, help='Name or id of the SDN controller to be associated with this VIM'
2184 'account. Use empty string to disassociate')
2185 @click.option('--sdn_port_mapping', default=None, help="File describing the port mapping between compute nodes' ports and switch ports")
2186 @click.option('--wait',
2187 required=False,
2188 default=False,
2189 is_flag=True,
2190 help='do not return the control immediately, but keep it '
2191 'until the operation is completed, or timeout')
2192 @click.pass_context
2193 def vim_update(ctx,
2194 name,
2195 newname,
2196 user,
2197 password,
2198 auth_url,
2199 tenant,
2200 config,
2201 account_type,
2202 description,
2203 sdn_controller,
2204 sdn_port_mapping,
2205 wait):
2206 """updates a VIM account
2207
2208 NAME: name or ID of the VIM account
2209 """
2210 logger.debug("")
2211 # try:
2212 check_client_version(ctx.obj, ctx.command.name)
2213 vim = {}
2214 if newname: vim['name'] = newname
2215 if user: vim['vim_user'] = user
2216 if password: vim['vim_password'] = password
2217 if auth_url: vim['vim_url'] = auth_url
2218 if tenant: vim['vim-tenant-name'] = tenant
2219 if account_type: vim['vim_type'] = account_type
2220 if description: vim['description'] = description
2221 if config: vim['config'] = config
2222 ctx.obj.vim.update(name, vim, sdn_controller, sdn_port_mapping, wait=wait)
2223 # except ClientException as e:
2224 # print(str(e))
2225 # exit(1)
2226
2227
2228 @cli_osm.command(name='vim-delete', short_help='deletes a VIM account')
2229 @click.argument('name')
2230 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2231 @click.option('--wait',
2232 required=False,
2233 default=False,
2234 is_flag=True,
2235 help='do not return the control immediately, but keep it '
2236 'until the operation is completed, or timeout')
2237 @click.pass_context
2238 def vim_delete(ctx, name, force, wait):
2239 """deletes a VIM account
2240
2241 NAME: name or ID of the VIM account to be deleted
2242 """
2243 logger.debug("")
2244 # try:
2245 if not force:
2246 ctx.obj.vim.delete(name, wait=wait)
2247 else:
2248 check_client_version(ctx.obj, '--force')
2249 ctx.obj.vim.delete(name, force, wait=wait)
2250 # except ClientException as e:
2251 # print(str(e))
2252 # exit(1)
2253
2254
2255 @cli_osm.command(name='vim-list', short_help='list all VIM accounts')
2256 #@click.option('--ro_update/--no_ro_update',
2257 # default=False,
2258 # help='update list from RO')
2259 @click.option('--filter', default=None,
2260 help='restricts the list to the VIM accounts matching the filter')
2261 @click.pass_context
2262 def vim_list(ctx, filter):
2263 """list all VIM accounts"""
2264 logger.debug("")
2265 if filter:
2266 check_client_version(ctx.obj, '--filter')
2267 # if ro_update:
2268 # check_client_version(ctx.obj, '--ro_update', 'v1')
2269 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
2270 if fullclassname == 'osmclient.sol005.client.Client':
2271 resp = ctx.obj.vim.list(filter)
2272 # else:
2273 # resp = ctx.obj.vim.list(ro_update)
2274 table = PrettyTable(['vim name', 'uuid'])
2275 for vim in resp:
2276 table.add_row([vim['name'], vim['uuid']])
2277 table.align = 'l'
2278 print(table)
2279
2280
2281 @cli_osm.command(name='vim-show', short_help='shows the details of a VIM account')
2282 @click.argument('name')
2283 @click.pass_context
2284 def vim_show(ctx, name):
2285 """shows the details of a VIM account
2286
2287 NAME: name or ID of the VIM account
2288 """
2289 logger.debug("")
2290 # try:
2291 resp = ctx.obj.vim.get(name)
2292 if 'vim_password' in resp:
2293 resp['vim_password']='********'
2294 # except ClientException as e:
2295 # print(str(e))
2296 # exit(1)
2297
2298 table = PrettyTable(['key', 'attribute'])
2299 for k, v in list(resp.items()):
2300 table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
2301 table.align = 'l'
2302 print(table)
2303
2304
2305 ####################
2306 # WIM operations
2307 ####################
2308
2309 @cli_osm.command(name='wim-create', short_help='creates a new WIM account')
2310 @click.option('--name',
2311 prompt=True,
2312 help='Name for the WIM account')
2313 @click.option('--user',
2314 help='WIM username')
2315 @click.option('--password',
2316 help='WIM password')
2317 @click.option('--url',
2318 prompt=True,
2319 help='WIM url')
2320 # @click.option('--tenant',
2321 # help='wIM tenant name')
2322 @click.option('--config',
2323 default=None,
2324 help='WIM specific config parameters')
2325 @click.option('--wim_type',
2326 help='WIM type')
2327 @click.option('--description',
2328 default=None,
2329 help='human readable description')
2330 @click.option('--wim_port_mapping', default=None,
2331 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
2332 "(WAN service endpoint id and info)")
2333 @click.option('--wait',
2334 required=False,
2335 default=False,
2336 is_flag=True,
2337 help='do not return the control immediately, but keep it '
2338 'until the operation is completed, or timeout')
2339 @click.pass_context
2340 def wim_create(ctx,
2341 name,
2342 user,
2343 password,
2344 url,
2345 # tenant,
2346 config,
2347 wim_type,
2348 description,
2349 wim_port_mapping,
2350 wait):
2351 """creates a new WIM account"""
2352 logger.debug("")
2353 # try:
2354 check_client_version(ctx.obj, ctx.command.name)
2355 # if sdn_controller:
2356 # check_client_version(ctx.obj, '--sdn_controller')
2357 # if sdn_port_mapping:
2358 # check_client_version(ctx.obj, '--sdn_port_mapping')
2359 wim = {}
2360 if user: wim['user'] = user
2361 if password: wim['password'] = password
2362 if url: wim['wim_url'] = url
2363 # if tenant: wim['tenant'] = tenant
2364 wim['wim_type'] = wim_type
2365 if description: wim['description'] = description
2366 if config: wim['config'] = config
2367 ctx.obj.wim.create(name, wim, wim_port_mapping, wait=wait)
2368 # except ClientException as e:
2369 # print(str(e))
2370 # exit(1)
2371
2372
2373 @cli_osm.command(name='wim-update', short_help='updates a WIM account')
2374 @click.argument('name')
2375 @click.option('--newname', help='New name for the WIM account')
2376 @click.option('--user', help='WIM username')
2377 @click.option('--password', help='WIM password')
2378 @click.option('--url', help='WIM url')
2379 @click.option('--config', help='WIM specific config parameters')
2380 @click.option('--wim_type', help='WIM type')
2381 @click.option('--description', help='human readable description')
2382 @click.option('--wim_port_mapping', default=None,
2383 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
2384 "(WAN service endpoint id and info)")
2385 @click.option('--wait',
2386 required=False,
2387 default=False,
2388 is_flag=True,
2389 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2390 @click.pass_context
2391 def wim_update(ctx,
2392 name,
2393 newname,
2394 user,
2395 password,
2396 url,
2397 config,
2398 wim_type,
2399 description,
2400 wim_port_mapping,
2401 wait):
2402 """updates a WIM account
2403
2404 NAME: name or ID of the WIM account
2405 """
2406 logger.debug("")
2407 # try:
2408 check_client_version(ctx.obj, ctx.command.name)
2409 wim = {}
2410 if newname: wim['name'] = newname
2411 if user: wim['user'] = user
2412 if password: wim['password'] = password
2413 if url: wim['url'] = url
2414 # if tenant: wim['tenant'] = tenant
2415 if wim_type: wim['wim_type'] = wim_type
2416 if description: wim['description'] = description
2417 if config: wim['config'] = config
2418 ctx.obj.wim.update(name, wim, wim_port_mapping, wait=wait)
2419 # except ClientException as e:
2420 # print(str(e))
2421 # exit(1)
2422
2423
2424 @cli_osm.command(name='wim-delete', short_help='deletes a WIM account')
2425 @click.argument('name')
2426 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2427 @click.option('--wait',
2428 required=False,
2429 default=False,
2430 is_flag=True,
2431 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2432 @click.pass_context
2433 def wim_delete(ctx, name, force, wait):
2434 """deletes a WIM account
2435
2436 NAME: name or ID of the WIM account to be deleted
2437 """
2438 logger.debug("")
2439 # try:
2440 check_client_version(ctx.obj, ctx.command.name)
2441 ctx.obj.wim.delete(name, force, wait=wait)
2442 # except ClientException as e:
2443 # print(str(e))
2444 # exit(1)
2445
2446
2447 @cli_osm.command(name='wim-list', short_help='list all WIM accounts')
2448 @click.option('--filter', default=None,
2449 help='restricts the list to the WIM accounts matching the filter')
2450 @click.pass_context
2451 def wim_list(ctx, filter):
2452 """list all WIM accounts"""
2453 logger.debug("")
2454 # try:
2455 check_client_version(ctx.obj, ctx.command.name)
2456 resp = ctx.obj.wim.list(filter)
2457 table = PrettyTable(['wim name', 'uuid'])
2458 for wim in resp:
2459 table.add_row([wim['name'], wim['uuid']])
2460 table.align = 'l'
2461 print(table)
2462 # except ClientException as e:
2463 # print(str(e))
2464 # exit(1)
2465
2466
2467 @cli_osm.command(name='wim-show', short_help='shows the details of a WIM account')
2468 @click.argument('name')
2469 @click.pass_context
2470 def wim_show(ctx, name):
2471 """shows the details of a WIM account
2472
2473 NAME: name or ID of the WIM account
2474 """
2475 logger.debug("")
2476 # try:
2477 check_client_version(ctx.obj, ctx.command.name)
2478 resp = ctx.obj.wim.get(name)
2479 if 'password' in resp:
2480 resp['wim_password']='********'
2481 # except ClientException as e:
2482 # print(str(e))
2483 # exit(1)
2484
2485 table = PrettyTable(['key', 'attribute'])
2486 for k, v in list(resp.items()):
2487 table.add_row([k, json.dumps(v, indent=2)])
2488 table.align = 'l'
2489 print(table)
2490
2491
2492 ####################
2493 # SDN controller operations
2494 ####################
2495
2496 @cli_osm.command(name='sdnc-create', short_help='creates a new SDN controller')
2497 @click.option('--name',
2498 prompt=True,
2499 help='Name to create sdn controller')
2500 @click.option('--type',
2501 prompt=True,
2502 help='SDN controller type')
2503 @click.option('--sdn_controller_version', # hidden=True,
2504 help='Deprecated. Use --config {version: sdn_controller_version}')
2505 @click.option('--url',
2506 help='URL in format http[s]://HOST:IP/')
2507 @click.option('--ip_address', # hidden=True,
2508 help='Deprecated. Use --url')
2509 @click.option('--port', # hidden=True,
2510 help='Deprecated. Use --url')
2511 @click.option('--switch_dpid', # hidden=True,
2512 help='Deprecated. Use --config {switch_id: DPID}')
2513 @click.option('--config',
2514 help='Extra information for SDN in yaml format, as {switch_id: identity used for the plugin (e.g. DPID: '
2515 'Openflow Datapath ID), version: version}')
2516 @click.option('--user',
2517 help='SDN controller username')
2518 @click.option('--password',
2519 hide_input=True,
2520 confirmation_prompt=True,
2521 help='SDN controller password')
2522 @click.option('--description', default=None, help='human readable description')
2523 @click.option('--wait',
2524 required=False,
2525 default=False,
2526 is_flag=True,
2527 help="do not return the control immediately, but keep it until the operation is completed, or timeout")
2528 @click.pass_context
2529 def sdnc_create(ctx, **kwargs):
2530 """creates a new SDN controller"""
2531 logger.debug("")
2532 sdncontroller = {x: kwargs[x] for x in kwargs if kwargs[x] and
2533 x not in ("wait", "ip_address", "port", "switch_dpid")}
2534 if kwargs.get("port"):
2535 print("option '--port' is deprecated, use '--url' instead")
2536 sdncontroller["port"] = int(kwargs["port"])
2537 if kwargs.get("ip_address"):
2538 print("option '--ip_address' is deprecated, use '--url' instead")
2539 sdncontroller["ip"] = kwargs["ip_address"]
2540 if kwargs.get("switch_dpid"):
2541 print("option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead")
2542 sdncontroller["dpid"] = kwargs["switch_dpid"]
2543 if kwargs.get("sdn_controller_version"):
2544 print("option '--sdn_controller_version' is deprecated, use '--config={version: SDN_CONTROLLER_VERSION}'"
2545 " instead")
2546 # try:
2547 check_client_version(ctx.obj, ctx.command.name)
2548 ctx.obj.sdnc.create(kwargs["name"], sdncontroller, wait=kwargs["wait"])
2549 # except ClientException as e:
2550 # print(str(e))
2551 # exit(1)
2552
2553 @cli_osm.command(name='sdnc-update', short_help='updates an SDN controller')
2554 @click.argument('name')
2555 @click.option('--newname', help='New name for the SDN controller')
2556 @click.option('--description', default=None, help='human readable description')
2557 @click.option('--type', help='SDN controller type')
2558 @click.option('--url', help='URL in format http[s]://HOST:IP/')
2559 @click.option('--config', help='Extra information for SDN in yaml format, as '
2560 '{switch_id: identity used for the plugin (e.g. DPID: '
2561 'Openflow Datapath ID), version: version}')
2562 @click.option('--user', help='SDN controller username')
2563 @click.option('--password', help='SDN controller password')
2564 @click.option('--ip_address', help='Deprecated. Use --url') # hidden=True
2565 @click.option('--port', help='Deprecated. Use --url') # hidden=True
2566 @click.option('--switch_dpid', help='Deprecated. Use --config {switch_dpid: DPID}') # hidden=True
2567 @click.option('--sdn_controller_version', help='Deprecated. Use --config {version: VERSION}') # hidden=True
2568 @click.option('--wait', required=False, default=False, is_flag=True,
2569 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2570 @click.pass_context
2571 def sdnc_update(ctx, **kwargs):
2572 """updates an SDN controller
2573
2574 NAME: name or ID of the SDN controller
2575 """
2576 logger.debug("")
2577 sdncontroller = {x: kwargs[x] for x in kwargs if kwargs[x] and
2578 x not in ("wait", "ip_address", "port", "switch_dpid", "new_name")}
2579 if kwargs.get("newname"):
2580 sdncontroller["name"] = kwargs["newname"]
2581 if kwargs.get("port"):
2582 print("option '--port' is deprecated, use '--url' instead")
2583 sdncontroller["port"] = int(kwargs["port"])
2584 if kwargs.get("ip_address"):
2585 print("option '--ip_address' is deprecated, use '--url' instead")
2586 sdncontroller["ip"] = kwargs["ip_address"]
2587 if kwargs.get("switch_dpid"):
2588 print("option '--switch_dpid' is deprecated, use '--config={switch_id: id|DPID}' instead")
2589 sdncontroller["dpid"] = kwargs["switch_dpid"]
2590 if kwargs.get("sdn_controller_version"):
2591 print("option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
2592 " instead")
2593
2594 # try:
2595 check_client_version(ctx.obj, ctx.command.name)
2596 ctx.obj.sdnc.update(kwargs["name"], sdncontroller, wait=kwargs["wait"])
2597 # except ClientException as e:
2598 # print(str(e))
2599 # exit(1)
2600
2601
2602 @cli_osm.command(name='sdnc-delete', short_help='deletes an SDN controller')
2603 @click.argument('name')
2604 @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
2605 @click.option('--wait', required=False, default=False, is_flag=True,
2606 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2607 @click.pass_context
2608 def sdnc_delete(ctx, name, force, wait):
2609 """deletes an SDN controller
2610
2611 NAME: name or ID of the SDN controller to be deleted
2612 """
2613 logger.debug("")
2614 # try:
2615 check_client_version(ctx.obj, ctx.command.name)
2616 ctx.obj.sdnc.delete(name, force, wait=wait)
2617 # except ClientException as e:
2618 # print(str(e))
2619 # exit(1)
2620
2621
2622 @cli_osm.command(name='sdnc-list', short_help='list all SDN controllers')
2623 @click.option('--filter', default=None,
2624 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'")
2625 @click.pass_context
2626 def sdnc_list(ctx, filter):
2627 """list all SDN controllers"""
2628 logger.debug("")
2629 # try:
2630 check_client_version(ctx.obj, ctx.command.name)
2631 resp = ctx.obj.sdnc.list(filter)
2632 # except ClientException as e:
2633 # print(str(e))
2634 # exit(1)
2635 table = PrettyTable(['sdnc name', 'id'])
2636 for sdnc in resp:
2637 table.add_row([sdnc['name'], sdnc['_id']])
2638 table.align = 'l'
2639 print(table)
2640
2641
2642 @cli_osm.command(name='sdnc-show', short_help='shows the details of an SDN controller')
2643 @click.argument('name')
2644 @click.pass_context
2645 def sdnc_show(ctx, name):
2646 """shows the details of an SDN controller
2647
2648 NAME: name or ID of the SDN controller
2649 """
2650 logger.debug("")
2651 # try:
2652 check_client_version(ctx.obj, ctx.command.name)
2653 resp = ctx.obj.sdnc.get(name)
2654 # except ClientException as e:
2655 # print(str(e))
2656 # exit(1)
2657
2658 table = PrettyTable(['key', 'attribute'])
2659 for k, v in list(resp.items()):
2660 table.add_row([k, json.dumps(v, indent=2)])
2661 table.align = 'l'
2662 print(table)
2663
2664
2665 ###########################
2666 # K8s cluster operations
2667 ###########################
2668
2669 @cli_osm.command(name='k8scluster-add', short_help='adds a K8s cluster to OSM')
2670 @click.argument('name')
2671 @click.option('--creds',
2672 prompt=True,
2673 help='credentials file, i.e. a valid `.kube/config` file')
2674 @click.option('--version',
2675 prompt=True,
2676 help='Kubernetes version')
2677 @click.option('--vim',
2678 prompt=True,
2679 help='VIM target, the VIM where the cluster resides')
2680 @click.option('--k8s-nets',
2681 prompt=True,
2682 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) ...]}"')
2683 @click.option('--description',
2684 default=None,
2685 help='human readable description')
2686 @click.option('--namespace',
2687 default='kube-system',
2688 help='namespace to be used for its operation, defaults to `kube-system`')
2689 @click.option('--cni',
2690 default=None,
2691 help='list of CNI plugins, in JSON inline format, used in the cluster')
2692 #@click.option('--skip-init',
2693 # is_flag=True,
2694 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
2695 #@click.option('--wait',
2696 # is_flag=True,
2697 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2698 @click.pass_context
2699 def k8scluster_add(ctx,
2700 name,
2701 creds,
2702 version,
2703 vim,
2704 k8s_nets,
2705 description,
2706 namespace,
2707 cni):
2708 """adds a K8s cluster to OSM
2709
2710 NAME: name of the K8s cluster
2711 """
2712 # try:
2713 check_client_version(ctx.obj, ctx.command.name)
2714 cluster = {}
2715 cluster['name'] = name
2716 with open(creds, 'r') as cf:
2717 cluster['credentials'] = yaml.safe_load(cf.read())
2718 cluster['k8s_version'] = version
2719 cluster['vim_account'] = vim
2720 cluster['nets'] = yaml.safe_load(k8s_nets)
2721 if description:
2722 cluster['description'] = description
2723 if namespace: cluster['namespace'] = namespace
2724 if cni: cluster['cni'] = yaml.safe_load(cni)
2725 ctx.obj.k8scluster.create(name, cluster)
2726 # except ClientException as e:
2727 # print(str(e))
2728 # exit(1)
2729
2730
2731 @cli_osm.command(name='k8scluster-update', short_help='updates a K8s cluster')
2732 @click.argument('name')
2733 @click.option('--newname', help='New name for the K8s cluster')
2734 @click.option('--creds', help='credentials file, i.e. a valid `.kube/config` file')
2735 @click.option('--version', help='Kubernetes version')
2736 @click.option('--vim', help='VIM target, the VIM where the cluster resides')
2737 @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) ...]}"')
2738 @click.option('--description', help='human readable description')
2739 @click.option('--namespace', help='namespace to be used for its operation, defaults to `kube-system`')
2740 @click.option('--cni', help='list of CNI plugins, in JSON inline format, used in the cluster')
2741 @click.pass_context
2742 def k8scluster_update(ctx,
2743 name,
2744 newname,
2745 creds,
2746 version,
2747 vim,
2748 k8s_nets,
2749 description,
2750 namespace,
2751 cni):
2752 """updates a K8s cluster
2753
2754 NAME: name or ID of the K8s cluster
2755 """
2756 # try:
2757 check_client_version(ctx.obj, ctx.command.name)
2758 cluster = {}
2759 if newname: cluster['name'] = newname
2760 if creds:
2761 with open(creds, 'r') as cf:
2762 cluster['credentials'] = yaml.safe_load(cf.read())
2763 if version: cluster['k8s_version'] = version
2764 if vim: cluster['vim_account'] = vim
2765 if k8s_nets: cluster['nets'] = yaml.safe_load(k8s_nets)
2766 if description: cluster['description'] = description
2767 if namespace: cluster['namespace'] = namespace
2768 if cni: cluster['cni'] = yaml.safe_load(cni)
2769 ctx.obj.k8scluster.update(name, cluster)
2770 # except ClientException as e:
2771 # print(str(e))
2772 # exit(1)
2773
2774
2775 @cli_osm.command(name='k8scluster-delete', short_help='deletes a K8s cluster')
2776 @click.argument('name')
2777 @click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
2778 #@click.option('--wait',
2779 # is_flag=True,
2780 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2781 @click.pass_context
2782 def k8scluster_delete(ctx, name, force):
2783 """deletes a K8s cluster
2784
2785 NAME: name or ID of the K8s cluster to be deleted
2786 """
2787 # try:
2788 check_client_version(ctx.obj, ctx.command.name)
2789 ctx.obj.k8scluster.delete(name, force=force)
2790 # except ClientException as e:
2791 # print(str(e))
2792 # exit(1)
2793
2794
2795 @cli_osm.command(name='k8scluster-list')
2796 @click.option('--filter', default=None,
2797 help='restricts the list to the K8s clusters matching the filter')
2798 @click.option('--literal', is_flag=True,
2799 help='print literally, no pretty table')
2800 @click.pass_context
2801 def k8scluster_list(ctx, filter, literal):
2802 """list all K8s clusters"""
2803 # try:
2804 check_client_version(ctx.obj, ctx.command.name)
2805 resp = ctx.obj.k8scluster.list(filter)
2806 if literal:
2807 print(yaml.safe_dump(resp))
2808 return
2809 table = PrettyTable(['Name', 'Id', 'Version', 'VIM', 'K8s-nets', 'Operational State', 'Description'])
2810 for cluster in resp:
2811 table.add_row([cluster['name'], cluster['_id'], cluster['k8s_version'], cluster['vim_account'],
2812 json.dumps(cluster['nets']), cluster["_admin"]["operationalState"],
2813 trunc_text(cluster.get('description',''),40)])
2814 table.align = 'l'
2815 print(table)
2816 # except ClientException as e:
2817 # print(str(e))
2818 # exit(1)
2819
2820
2821 @cli_osm.command(name='k8scluster-show', short_help='shows the details of a K8s cluster')
2822 @click.argument('name')
2823 @click.option('--literal', is_flag=True,
2824 help='print literally, no pretty table')
2825 @click.pass_context
2826 def k8scluster_show(ctx, name, literal):
2827 """shows the details of a K8s cluster
2828
2829 NAME: name or ID of the K8s cluster
2830 """
2831 # try:
2832 resp = ctx.obj.k8scluster.get(name)
2833 if literal:
2834 print(yaml.safe_dump(resp))
2835 return
2836 table = PrettyTable(['key', 'attribute'])
2837 for k, v in list(resp.items()):
2838 table.add_row([k, wrap_text(text=json.dumps(v, indent=2),width=100)])
2839 table.align = 'l'
2840 print(table)
2841 # except ClientException as e:
2842 # print(str(e))
2843 # exit(1)
2844
2845
2846
2847 ###########################
2848 # Repo operations
2849 ###########################
2850
2851 @cli_osm.command(name='repo-add', short_help='adds a repo to OSM')
2852 @click.argument('name')
2853 @click.argument('uri')
2854 @click.option('--type',
2855 type=click.Choice(['helm-chart', 'juju-bundle']),
2856 prompt=True,
2857 help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
2858 @click.option('--description',
2859 default=None,
2860 help='human readable description')
2861 #@click.option('--wait',
2862 # is_flag=True,
2863 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2864 @click.pass_context
2865 def repo_add(ctx,
2866 name,
2867 uri,
2868 type,
2869 description):
2870 """adds a repo to OSM
2871
2872 NAME: name of the repo
2873 URI: URI of the repo
2874 """
2875 # try:
2876 check_client_version(ctx.obj, ctx.command.name)
2877 repo = {}
2878 repo['name'] = name
2879 repo['url'] = uri
2880 repo['type'] = type
2881 if description:
2882 repo['description'] = description
2883 ctx.obj.repo.create(name, repo)
2884 # except ClientException as e:
2885 # print(str(e))
2886 # exit(1)
2887
2888
2889 @cli_osm.command(name='repo-update', short_help='updates a repo in OSM')
2890 @click.argument('name')
2891 @click.option('--newname', help='New name for the repo')
2892 @click.option('--uri', help='URI of the repo')
2893 @click.option('--type', type=click.Choice(['helm-chart', 'juju-bundle']),
2894 help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
2895 @click.option('--description', help='human readable description')
2896 #@click.option('--wait',
2897 # is_flag=True,
2898 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2899 @click.pass_context
2900 def repo_update(ctx,
2901 name,
2902 newname,
2903 uri,
2904 type,
2905 description):
2906 """updates a repo in OSM
2907
2908 NAME: name of the repo
2909 """
2910 # try:
2911 check_client_version(ctx.obj, ctx.command.name)
2912 repo = {}
2913 if newname: repo['name'] = newname
2914 if uri: repo['uri'] = uri
2915 if type: repo['type'] = type
2916 if description: repo['description'] = description
2917 ctx.obj.repo.update(name, repo)
2918 # except ClientException as e:
2919 # print(str(e))
2920 # exit(1)
2921
2922
2923 @cli_osm.command(name='repo-delete', short_help='deletes a repo')
2924 @click.argument('name')
2925 @click.option('--force', is_flag=True, help='forces the deletion from the DB (not recommended)')
2926 #@click.option('--wait',
2927 # is_flag=True,
2928 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2929 @click.pass_context
2930 def repo_delete(ctx, name, force):
2931 """deletes a repo
2932
2933 NAME: name or ID of the repo to be deleted
2934 """
2935 # try:
2936 check_client_version(ctx.obj, ctx.command.name)
2937 ctx.obj.repo.delete(name, force=force)
2938 # except ClientException as e:
2939 # print(str(e))
2940 # exit(1)
2941
2942
2943 @cli_osm.command(name='repo-list')
2944 @click.option('--filter', default=None,
2945 help='restricts the list to the repos matching the filter')
2946 @click.option('--literal', is_flag=True,
2947 help='print literally, no pretty table')
2948 @click.pass_context
2949 def repo_list(ctx, filter, literal):
2950 """list all repos"""
2951 # try:
2952 check_client_version(ctx.obj, ctx.command.name)
2953 resp = ctx.obj.repo.list(filter)
2954 if literal:
2955 print(yaml.safe_dump(resp))
2956 return
2957 table = PrettyTable(['Name', 'Id', 'Type', 'URI', 'Description'])
2958 for repo in resp:
2959 #cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
2960 table.add_row([repo['name'], repo['_id'], repo['type'], repo['url'], trunc_text(repo.get('description',''),40)])
2961 table.align = 'l'
2962 print(table)
2963 # except ClientException as e:
2964 # print(str(e))
2965 # exit(1)
2966
2967
2968 @cli_osm.command(name='repo-show', short_help='shows the details of a repo')
2969 @click.argument('name')
2970 @click.option('--literal', is_flag=True,
2971 help='print literally, no pretty table')
2972 @click.pass_context
2973 def repo_show(ctx, name, literal):
2974 """shows the details of a repo
2975
2976 NAME: name or ID of the repo
2977 """
2978 # try:
2979 resp = ctx.obj.repo.get(name)
2980 if literal:
2981 print(yaml.safe_dump(resp))
2982 return
2983 table = PrettyTable(['key', 'attribute'])
2984 for k, v in list(resp.items()):
2985 table.add_row([k, json.dumps(v, indent=2)])
2986 table.align = 'l'
2987 print(table)
2988 # except ClientException as e:
2989 # print(str(e))
2990 # exit(1)
2991
2992
2993
2994 ####################
2995 # Project mgmt operations
2996 ####################
2997
2998 @cli_osm.command(name='project-create', short_help='creates a new project')
2999 @click.argument('name')
3000 #@click.option('--description',
3001 # default='no description',
3002 # help='human readable description')
3003 @click.option('--domain-name', 'domain_name',
3004 default=None,
3005 help='assign to a domain')
3006 @click.pass_context
3007 def project_create(ctx, name, domain_name):
3008 """Creates a new project
3009
3010 NAME: name of the project
3011 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
3012 """
3013 logger.debug("")
3014 project = {}
3015 project['name'] = name
3016 if domain_name:
3017 project['domain_name'] = domain_name
3018 # try:
3019 check_client_version(ctx.obj, ctx.command.name)
3020 ctx.obj.project.create(name, project)
3021 # except ClientException as e:
3022 # print(str(e))
3023 # exit(1)
3024
3025
3026 @cli_osm.command(name='project-delete', short_help='deletes a project')
3027 @click.argument('name')
3028 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3029 @click.pass_context
3030 def project_delete(ctx, name):
3031 """deletes a project
3032
3033 NAME: name or ID of the project to be deleted
3034 """
3035 logger.debug("")
3036 # try:
3037 check_client_version(ctx.obj, ctx.command.name)
3038 ctx.obj.project.delete(name)
3039 # except ClientException as e:
3040 # print(str(e))
3041 # exit(1)
3042
3043
3044 @cli_osm.command(name='project-list', short_help='list all projects')
3045 @click.option('--filter', default=None,
3046 help='restricts the list to the projects matching the filter')
3047 @click.pass_context
3048 def project_list(ctx, filter):
3049 """list all projects"""
3050 logger.debug("")
3051 # try:
3052 check_client_version(ctx.obj, ctx.command.name)
3053 resp = ctx.obj.project.list(filter)
3054 # except ClientException as e:
3055 # print(str(e))
3056 # exit(1)
3057 table = PrettyTable(['name', 'id'])
3058 for proj in resp:
3059 table.add_row([proj['name'], proj['_id']])
3060 table.align = 'l'
3061 print(table)
3062
3063
3064 @cli_osm.command(name='project-show', short_help='shows the details of a project')
3065 @click.argument('name')
3066 @click.pass_context
3067 def project_show(ctx, name):
3068 """shows the details of a project
3069
3070 NAME: name or ID of the project
3071 """
3072 logger.debug("")
3073 # try:
3074 check_client_version(ctx.obj, ctx.command.name)
3075 resp = ctx.obj.project.get(name)
3076 # except ClientException as e:
3077 # print(str(e))
3078 # exit(1)
3079
3080 table = PrettyTable(['key', 'attribute'])
3081 for k, v in resp.items():
3082 table.add_row([k, json.dumps(v, indent=2)])
3083 table.align = 'l'
3084 print(table)
3085
3086
3087 @cli_osm.command(name='project-update', short_help='updates a project (only the name can be updated)')
3088 @click.argument('project')
3089 @click.option('--name',
3090 prompt=True,
3091 help='new name for the project')
3092
3093 @click.pass_context
3094 def project_update(ctx, project, name):
3095 """
3096 Update a project name
3097
3098 :param ctx:
3099 :param project: id or name of the project to modify
3100 :param name: new name for the project
3101 :return:
3102 """
3103 logger.debug("")
3104 project_changes = {}
3105 project_changes['name'] = name
3106
3107 # try:
3108 check_client_version(ctx.obj, ctx.command.name)
3109 ctx.obj.project.update(project, project_changes)
3110 # except ClientException as e:
3111 # print(str(e))
3112
3113
3114 ####################
3115 # User mgmt operations
3116 ####################
3117
3118 @cli_osm.command(name='user-create', short_help='creates a new user')
3119 @click.argument('username')
3120 @click.option('--password',
3121 prompt=True,
3122 hide_input=True,
3123 confirmation_prompt=True,
3124 help='user password')
3125 @click.option('--projects',
3126 # prompt="Comma separate list of projects",
3127 multiple=True,
3128 callback=lambda ctx, param, value: ''.join(value).split(',') if all(len(x)==1 for x in value) else value,
3129 help='list of project ids that the user belongs to')
3130 @click.option('--project-role-mappings', 'project_role_mappings',
3131 default=None, multiple=True,
3132 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'")
3133 @click.option('--domain-name', 'domain_name',
3134 default=None,
3135 help='assign to a domain')
3136 @click.pass_context
3137 def user_create(ctx, username, password, projects, project_role_mappings, domain_name):
3138 """Creates a new user
3139
3140 \b
3141 USERNAME: name of the user
3142 PASSWORD: password of the user
3143 PROJECTS: projects assigned to user (internal only)
3144 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
3145 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
3146 """
3147 logger.debug("")
3148 user = {}
3149 user['username'] = username
3150 user['password'] = password
3151 user['projects'] = projects
3152 user['project_role_mappings'] = project_role_mappings
3153 if domain_name:
3154 user['domain_name'] = domain_name
3155
3156 # try:
3157 check_client_version(ctx.obj, ctx.command.name)
3158 ctx.obj.user.create(username, user)
3159 # except ClientException as e:
3160 # print(str(e))
3161 # exit(1)
3162
3163
3164 @cli_osm.command(name='user-update', short_help='updates user information')
3165 @click.argument('username')
3166 @click.option('--password',
3167 # prompt=True,
3168 # hide_input=True,
3169 # confirmation_prompt=True,
3170 help='user password')
3171 @click.option('--set-username', 'set_username',
3172 default=None,
3173 help='change username')
3174 @click.option('--set-project', 'set_project',
3175 default=None, multiple=True,
3176 help="create/replace the roles for this project: 'project,role1[,role2,...]'")
3177 @click.option('--remove-project', 'remove_project',
3178 default=None, multiple=True,
3179 help="removes project from user: 'project'")
3180 @click.option('--add-project-role', 'add_project_role',
3181 default=None, multiple=True,
3182 help="assign role(s) in a project. Can be used several times: 'project,role1[,role2,...]'")
3183 @click.option('--remove-project-role', 'remove_project_role',
3184 default=None, multiple=True,
3185 help="remove role(s) in a project. Can be used several times: 'project,role1[,role2,...]'")
3186 @click.pass_context
3187 def user_update(ctx, username, password, set_username, set_project, remove_project,
3188 add_project_role, remove_project_role):
3189 """Update a user information
3190
3191 \b
3192 USERNAME: name of the user
3193 PASSWORD: new password
3194 SET_USERNAME: new username
3195 SET_PROJECT: creating mappings for project/role(s)
3196 REMOVE_PROJECT: deleting mappings for project/role(s)
3197 ADD_PROJECT_ROLE: adding mappings for project/role(s)
3198 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
3199 """
3200 logger.debug("")
3201 user = {}
3202 user['password'] = password
3203 user['username'] = set_username
3204 user['set-project'] = set_project
3205 user['remove-project'] = remove_project
3206 user['add-project-role'] = add_project_role
3207 user['remove-project-role'] = remove_project_role
3208
3209 # try:
3210 check_client_version(ctx.obj, ctx.command.name)
3211 ctx.obj.user.update(username, user)
3212 # except ClientException as e:
3213 # print(str(e))
3214 # exit(1)
3215
3216
3217 @cli_osm.command(name='user-delete', short_help='deletes a user')
3218 @click.argument('name')
3219 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3220 @click.pass_context
3221 def user_delete(ctx, name):
3222 """deletes a user
3223
3224 \b
3225 NAME: name or ID of the user to be deleted
3226 """
3227 logger.debug("")
3228 # try:
3229 check_client_version(ctx.obj, ctx.command.name)
3230 ctx.obj.user.delete(name)
3231 # except ClientException as e:
3232 # print(str(e))
3233 # exit(1)
3234
3235
3236 @cli_osm.command(name='user-list', short_help='list all users')
3237 @click.option('--filter', default=None,
3238 help='restricts the list to the users matching the filter')
3239 @click.pass_context
3240 def user_list(ctx, filter):
3241 """list all users"""
3242 # try:
3243 check_client_version(ctx.obj, ctx.command.name)
3244 resp = ctx.obj.user.list(filter)
3245 # except ClientException as e:
3246 # print(str(e))
3247 # exit(1)
3248 table = PrettyTable(['name', 'id'])
3249 for user in resp:
3250 table.add_row([user['username'], user['_id']])
3251 table.align = 'l'
3252 print(table)
3253
3254
3255 @cli_osm.command(name='user-show', short_help='shows the details of a user')
3256 @click.argument('name')
3257 @click.pass_context
3258 def user_show(ctx, name):
3259 """shows the details of a user
3260
3261 NAME: name or ID of the user
3262 """
3263 logger.debug("")
3264 # try:
3265 check_client_version(ctx.obj, ctx.command.name)
3266 resp = ctx.obj.user.get(name)
3267 if 'password' in resp:
3268 resp['password']='********'
3269 # except ClientException as e:
3270 # print(str(e))
3271 # exit(1)
3272
3273 table = PrettyTable(['key', 'attribute'])
3274 for k, v in resp.items():
3275 table.add_row([k, json.dumps(v, indent=2)])
3276 table.align = 'l'
3277 print(table)
3278
3279
3280 ####################
3281 # Fault Management operations
3282 ####################
3283
3284 @cli_osm.command(name='ns-alarm-create')
3285 @click.argument('name')
3286 @click.option('--ns', prompt=True, help='NS instance id or name')
3287 @click.option('--vnf', prompt=True,
3288 help='VNF name (VNF member index as declared in the NSD)')
3289 @click.option('--vdu', prompt=True,
3290 help='VDU name (VDU name as declared in the VNFD)')
3291 @click.option('--metric', prompt=True,
3292 help='Name of the metric (e.g. cpu_utilization)')
3293 @click.option('--severity', default='WARNING',
3294 help='severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)')
3295 @click.option('--threshold_value', prompt=True,
3296 help='threshold value that, when crossed, an alarm is triggered')
3297 @click.option('--threshold_operator', prompt=True,
3298 help='threshold operator describing the comparison (GE, LE, GT, LT, EQ)')
3299 @click.option('--statistic', default='AVERAGE',
3300 help='statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)')
3301 @click.pass_context
3302 def ns_alarm_create(ctx, name, ns, vnf, vdu, metric, severity,
3303 threshold_value, threshold_operator, statistic):
3304 """creates a new alarm for a NS instance"""
3305 # TODO: Check how to validate threshold_value.
3306 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
3307 logger.debug("")
3308 # try:
3309 ns_instance = ctx.obj.ns.get(ns)
3310 alarm = {}
3311 alarm['alarm_name'] = name
3312 alarm['ns_id'] = ns_instance['_id']
3313 alarm['correlation_id'] = ns_instance['_id']
3314 alarm['vnf_member_index'] = vnf
3315 alarm['vdu_name'] = vdu
3316 alarm['metric_name'] = metric
3317 alarm['severity'] = severity
3318 alarm['threshold_value'] = int(threshold_value)
3319 alarm['operation'] = threshold_operator
3320 alarm['statistic'] = statistic
3321 check_client_version(ctx.obj, ctx.command.name)
3322 ctx.obj.ns.create_alarm(alarm)
3323 # except ClientException as e:
3324 # print(str(e))
3325 # exit(1)
3326
3327
3328 #@cli_osm.command(name='ns-alarm-delete')
3329 #@click.argument('name')
3330 #@click.pass_context
3331 #def ns_alarm_delete(ctx, name):
3332 # """deletes an alarm
3333 #
3334 # NAME: name of the alarm to be deleted
3335 # """
3336 # try:
3337 # check_client_version(ctx.obj, ctx.command.name)
3338 # ctx.obj.ns.delete_alarm(name)
3339 # except ClientException as e:
3340 # print(str(e))
3341 # exit(1)
3342
3343
3344 ####################
3345 # Performance Management operations
3346 ####################
3347
3348 @cli_osm.command(name='ns-metric-export', short_help='exports a metric to the internal OSM bus, which can be read by other apps')
3349 @click.option('--ns', prompt=True, help='NS instance id or name')
3350 @click.option('--vnf', prompt=True,
3351 help='VNF name (VNF member index as declared in the NSD)')
3352 @click.option('--vdu', prompt=True,
3353 help='VDU name (VDU name as declared in the VNFD)')
3354 @click.option('--metric', prompt=True,
3355 help='name of the metric (e.g. cpu_utilization)')
3356 #@click.option('--period', default='1w',
3357 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
3358 @click.option('--interval', help='periodic interval (seconds) to export metrics continuously')
3359 @click.pass_context
3360 def ns_metric_export(ctx, ns, vnf, vdu, metric, interval):
3361 """exports a metric to the internal OSM bus, which can be read by other apps"""
3362 # TODO: Check how to validate interval.
3363 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
3364 logger.debug("")
3365 # try:
3366 ns_instance = ctx.obj.ns.get(ns)
3367 metric_data = {}
3368 metric_data['ns_id'] = ns_instance['_id']
3369 metric_data['correlation_id'] = ns_instance['_id']
3370 metric_data['vnf_member_index'] = vnf
3371 metric_data['vdu_name'] = vdu
3372 metric_data['metric_name'] = metric
3373 metric_data['collection_unit'] = 'WEEK'
3374 metric_data['collection_period'] = 1
3375 check_client_version(ctx.obj, ctx.command.name)
3376 if not interval:
3377 print('{}'.format(ctx.obj.ns.export_metric(metric_data)))
3378 else:
3379 i = 1
3380 while True:
3381 print('{} {}'.format(ctx.obj.ns.export_metric(metric_data),i))
3382 time.sleep(int(interval))
3383 i+=1
3384 # except ClientException as e:
3385 # print(str(e))
3386 # exit(1)
3387
3388
3389 ####################
3390 # Other operations
3391 ####################
3392
3393 @cli_osm.command(name='version', short_help='shows client and server versions')
3394 @click.pass_context
3395 def get_version(ctx):
3396 """shows client and server versions"""
3397 # try:
3398 check_client_version(ctx.obj, "version")
3399 print ("Server version: {}".format(ctx.obj.get_version()))
3400 print ("Client version: {}".format(pkg_resources.get_distribution("osmclient").version))
3401 # except ClientException as e:
3402 # print(str(e))
3403 # exit(1)
3404
3405 @cli_osm.command(name='upload-package', short_help='uploads a VNF package or NS package')
3406 @click.argument('filename')
3407 @click.option('--skip-charm-build', default=False, is_flag=True,
3408 help='the charm will not be compiled, it is assumed to already exist')
3409 @click.pass_context
3410 def upload_package(ctx, filename, skip_charm_build):
3411 """uploads a vnf package or ns package
3412
3413 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
3414 """
3415 logger.debug("")
3416 # try:
3417 ctx.obj.package.upload(filename, skip_charm_build=skip_charm_build)
3418 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
3419 if fullclassname != 'osmclient.sol005.client.Client':
3420 ctx.obj.package.wait_for_upload(filename)
3421 # except ClientException as e:
3422 # print(str(e))
3423 # exit(1)
3424
3425
3426 #@cli_osm.command(name='ns-scaling-show')
3427 #@click.argument('ns_name')
3428 #@click.pass_context
3429 #def show_ns_scaling(ctx, ns_name):
3430 # """shows the status of a NS scaling operation
3431 #
3432 # NS_NAME: name of the NS instance being scaled
3433 # """
3434 # try:
3435 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3436 # resp = ctx.obj.ns.list()
3437 # except ClientException as e:
3438 # print(str(e))
3439 # exit(1)
3440 #
3441 # table = PrettyTable(
3442 # ['group-name',
3443 # 'instance-id',
3444 # 'operational status',
3445 # 'create-time',
3446 # 'vnfr ids'])
3447 #
3448 # for ns in resp:
3449 # if ns_name == ns['name']:
3450 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
3451 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
3452 # for record in scaling_records:
3453 # if 'instance' in record:
3454 # instances = record['instance']
3455 # for inst in instances:
3456 # table.add_row(
3457 # [record['scaling-group-name-ref'],
3458 # inst['instance-id'],
3459 # inst['op-status'],
3460 # time.strftime('%Y-%m-%d %H:%M:%S',
3461 # time.localtime(
3462 # inst['create-time'])),
3463 # inst['vnfrs']])
3464 # table.align = 'l'
3465 # print(table)
3466
3467
3468 #@cli_osm.command(name='ns-scale')
3469 #@click.argument('ns_name')
3470 #@click.option('--ns_scale_group', prompt=True)
3471 #@click.option('--index', prompt=True)
3472 #@click.option('--wait',
3473 # required=False,
3474 # default=False,
3475 # is_flag=True,
3476 # help='do not return the control immediately, but keep it \
3477 # until the operation is completed, or timeout')
3478 #@click.pass_context
3479 #def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
3480 # """scales NS
3481 #
3482 # NS_NAME: name of the NS instance to be scaled
3483 # """
3484 # try:
3485 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3486 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
3487 # except ClientException as e:
3488 # print(str(e))
3489 # exit(1)
3490
3491
3492 #@cli_osm.command(name='config-agent-list')
3493 #@click.pass_context
3494 #def config_agent_list(ctx):
3495 # """list config agents"""
3496 # try:
3497 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3498 # except ClientException as e:
3499 # print(str(e))
3500 # exit(1)
3501 # table = PrettyTable(['name', 'account-type', 'details'])
3502 # for account in ctx.obj.vca.list():
3503 # table.add_row(
3504 # [account['name'],
3505 # account['account-type'],
3506 # account['juju']])
3507 # table.align = 'l'
3508 # print(table)
3509
3510
3511 #@cli_osm.command(name='config-agent-delete')
3512 #@click.argument('name')
3513 #@click.pass_context
3514 #def config_agent_delete(ctx, name):
3515 # """deletes a config agent
3516 #
3517 # NAME: name of the config agent to be deleted
3518 # """
3519 # try:
3520 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3521 # ctx.obj.vca.delete(name)
3522 # except ClientException as e:
3523 # print(str(e))
3524 # exit(1)
3525
3526
3527 #@cli_osm.command(name='config-agent-add')
3528 #@click.option('--name',
3529 # prompt=True)
3530 #@click.option('--account_type',
3531 # prompt=True)
3532 #@click.option('--server',
3533 # prompt=True)
3534 #@click.option('--user',
3535 # prompt=True)
3536 #@click.option('--secret',
3537 # prompt=True,
3538 # hide_input=True,
3539 # confirmation_prompt=True)
3540 #@click.pass_context
3541 #def config_agent_add(ctx, name, account_type, server, user, secret):
3542 # """adds a config agent"""
3543 # try:
3544 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3545 # ctx.obj.vca.create(name, account_type, server, user, secret)
3546 # except ClientException as e:
3547 # print(str(e))
3548 # exit(1)
3549
3550
3551 #@cli_osm.command(name='ro-dump')
3552 #@click.pass_context
3553 #def ro_dump(ctx):
3554 # """shows RO agent information"""
3555 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3556 # resp = ctx.obj.vim.get_resource_orchestrator()
3557 # table = PrettyTable(['key', 'attribute'])
3558 # for k, v in list(resp.items()):
3559 # table.add_row([k, json.dumps(v, indent=2)])
3560 # table.align = 'l'
3561 # print(table)
3562
3563
3564 #@cli_osm.command(name='vcs-list')
3565 #@click.pass_context
3566 #def vcs_list(ctx):
3567 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3568 # resp = ctx.obj.utils.get_vcs_info()
3569 # table = PrettyTable(['component name', 'state'])
3570 # for component in resp:
3571 # table.add_row([component['component_name'], component['state']])
3572 # table.align = 'l'
3573 # print(table)
3574
3575
3576 @cli_osm.command(name='ns-action', short_help='executes an action/primitive over a NS instance')
3577 @click.argument('ns_name')
3578 @click.option('--vnf_name', default=None, help='member-vnf-index if the target is a vnf instead of a ns)')
3579 @click.option('--kdu_name', default=None, help='kdu-name if the target is a kdu)')
3580 @click.option('--vdu_id', default=None, help='vdu-id if the target is a vdu')
3581 @click.option('--vdu_count', default=None, help='number of vdu instance of this vdu_id')
3582 @click.option('--action_name', prompt=True, help='action name')
3583 @click.option('--params', default=None, help='action params in YAML/JSON inline string')
3584 @click.option('--params_file', default=None, help='YAML/JSON file with action params')
3585 @click.option('--timeout', required=False, default=None, type=int, help='timeout in seconds')
3586 @click.option('--wait',
3587 required=False,
3588 default=False,
3589 is_flag=True,
3590 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3591 @click.pass_context
3592 def ns_action(ctx,
3593 ns_name,
3594 vnf_name,
3595 kdu_name,
3596 vdu_id,
3597 vdu_count,
3598 action_name,
3599 params,
3600 params_file,
3601 timeout,
3602 wait):
3603 """executes an action/primitive over a NS instance
3604
3605 NS_NAME: name or ID of the NS instance
3606 """
3607 logger.debug("")
3608 # try:
3609 check_client_version(ctx.obj, ctx.command.name)
3610 op_data = {}
3611 if vnf_name:
3612 op_data['member_vnf_index'] = vnf_name
3613 if kdu_name:
3614 op_data['kdu_name'] = kdu_name
3615 if vdu_id:
3616 op_data['vdu_id'] = vdu_id
3617 if vdu_count:
3618 op_data['vdu_count_index'] = vdu_count
3619 if timeout:
3620 op_data['timeout_ns_action'] = timeout
3621 op_data['primitive'] = action_name
3622 if params_file:
3623 with open(params_file, 'r') as pf:
3624 params = pf.read()
3625 if params:
3626 op_data['primitive_params'] = yaml.safe_load(params)
3627 else:
3628 op_data['primitive_params'] = {}
3629 print(ctx.obj.ns.exec_op(ns_name, op_name='action', op_data=op_data, wait=wait))
3630
3631 # except ClientException as e:
3632 # print(str(e))
3633 # exit(1)
3634
3635
3636 @cli_osm.command(name='vnf-scale', short_help='executes a VNF scale (adding/removing VDUs)')
3637 @click.argument('ns_name')
3638 @click.argument('vnf_name')
3639 @click.option('--scaling-group', prompt=True, help="scaling-group-descriptor name to use")
3640 @click.option('--scale-in', default=False, is_flag=True, help="performs a scale in operation")
3641 @click.option('--scale-out', default=False, is_flag=True, help="performs a scale out operation (by default)")
3642 @click.option('--timeout', required=False, default=None, type=int, help='timeout in seconds')
3643 @click.option('--wait', required=False, default=False, is_flag=True,
3644 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3645 @click.pass_context
3646 def vnf_scale(ctx,
3647 ns_name,
3648 vnf_name,
3649 scaling_group,
3650 scale_in,
3651 scale_out,
3652 timeout,
3653 wait):
3654 """
3655 Executes a VNF scale (adding/removing VDUs)
3656
3657 \b
3658 NS_NAME: name or ID of the NS instance.
3659 VNF_NAME: member-vnf-index in the NS to be scaled.
3660 """
3661 logger.debug("")
3662 # try:
3663 check_client_version(ctx.obj, ctx.command.name)
3664 if not scale_in and not scale_out:
3665 scale_out = True
3666 ctx.obj.ns.scale_vnf(ns_name, vnf_name, scaling_group, scale_in, scale_out, wait, timeout)
3667 # except ClientException as e:
3668 # print(str(e))
3669 # exit(1)
3670
3671
3672 ##############################
3673 # Role Management Operations #
3674 ##############################
3675
3676 @cli_osm.command(name='role-create', short_help='creates a new role')
3677 @click.argument('name')
3678 @click.option('--permissions',
3679 default=None,
3680 help='role permissions using a dictionary')
3681 @click.pass_context
3682 def role_create(ctx, name, permissions):
3683 """
3684 Creates a new role.
3685
3686 \b
3687 NAME: Name or ID of the role.
3688 DEFINITION: Definition of grant/denial of access to resources.
3689 """
3690 logger.debug("")
3691 # try:
3692 check_client_version(ctx.obj, ctx.command.name)
3693 ctx.obj.role.create(name, permissions)
3694 # except ClientException as e:
3695 # print(str(e))
3696 # exit(1)
3697
3698
3699 @cli_osm.command(name='role-update', short_help='updates a role')
3700 @click.argument('name')
3701 @click.option('--set-name',
3702 default=None,
3703 help='change name of rle')
3704 # @click.option('--permissions',
3705 # default=None,
3706 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
3707 @click.option('--add',
3708 default=None,
3709 help='yaml format dictionary with permission: True/False to access grant/denial')
3710 @click.option('--remove',
3711 default=None,
3712 help='yaml format list to remove a permission')
3713 @click.pass_context
3714 def role_update(ctx, name, set_name, add, remove):
3715 """
3716 Updates a role.
3717
3718 \b
3719 NAME: Name or ID of the role.
3720 DEFINITION: Definition overwrites the old definition.
3721 ADD: Grant/denial of access to resource to add.
3722 REMOVE: Grant/denial of access to resource to remove.
3723 """
3724 logger.debug("")
3725 # try:
3726 check_client_version(ctx.obj, ctx.command.name)
3727 ctx.obj.role.update(name, set_name, None, add, remove)
3728 # except ClientException as e:
3729 # print(str(e))
3730 # exit(1)
3731
3732
3733 @cli_osm.command(name='role-delete', short_help='deletes a role')
3734 @click.argument('name')
3735 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3736 @click.pass_context
3737 def role_delete(ctx, name):
3738 """
3739 Deletes a role.
3740
3741 \b
3742 NAME: Name or ID of the role.
3743 """
3744 logger.debug("")
3745 # try:
3746 check_client_version(ctx.obj, ctx.command.name)
3747 ctx.obj.role.delete(name)
3748 # except ClientException as e:
3749 # print(str(e))
3750 # exit(1)
3751
3752
3753 @cli_osm.command(name='role-list', short_help='list all roles')
3754 @click.option('--filter', default=None,
3755 help='restricts the list to the projects matching the filter')
3756 @click.pass_context
3757 def role_list(ctx, filter):
3758 """
3759 List all roles.
3760 """
3761 logger.debug("")
3762 # try:
3763 check_client_version(ctx.obj, ctx.command.name)
3764 resp = ctx.obj.role.list(filter)
3765 # except ClientException as e:
3766 # print(str(e))
3767 # exit(1)
3768 table = PrettyTable(['name', 'id'])
3769 for role in resp:
3770 table.add_row([role['name'], role['_id']])
3771 table.align = 'l'
3772 print(table)
3773
3774
3775 @cli_osm.command(name='role-show', short_help='show specific role')
3776 @click.argument('name')
3777 @click.pass_context
3778 def role_show(ctx, name):
3779 """
3780 Shows the details of a role.
3781
3782 \b
3783 NAME: Name or ID of the role.
3784 """
3785 logger.debug("")
3786 # try:
3787 check_client_version(ctx.obj, ctx.command.name)
3788 resp = ctx.obj.role.get(name)
3789 # except ClientException as e:
3790 # print(str(e))
3791 # exit(1)
3792
3793 table = PrettyTable(['key', 'attribute'])
3794 for k, v in resp.items():
3795 table.add_row([k, json.dumps(v, indent=2)])
3796 table.align = 'l'
3797 print(table)
3798
3799
3800 @cli_osm.command(name='package-create',
3801 short_help='Create a package descriptor')
3802 @click.argument('package-type')
3803 @click.argument('package-name')
3804 @click.option('--base-directory',
3805 default='.',
3806 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'))
3807 @click.option('--image',
3808 default="image-name",
3809 help='(VNF) Set the name of the vdu image. Default "image-name"')
3810 @click.option('--vdus',
3811 default=1,
3812 help='(VNF) Set the number of vdus in a VNF. Default 1')
3813 @click.option('--vcpu',
3814 default=1,
3815 help='(VNF) Set the number of virtual CPUs in a vdu. Default 1')
3816 @click.option('--memory',
3817 default=1024,
3818 help='(VNF) Set the memory size (MB) of the vdu. Default 1024')
3819 @click.option('--storage',
3820 default=10,
3821 help='(VNF) Set the disk size (GB) of the vdu. Default 10')
3822 @click.option('--interfaces',
3823 default=0,
3824 help='(VNF) Set the number of additional interfaces apart from the management interface. Default 0')
3825 @click.option('--vendor',
3826 default="OSM",
3827 help='(NS/VNF) Set the descriptor vendor. Default "OSM"')
3828 @click.option('--override',
3829 default=False,
3830 is_flag=True,
3831 help='(NS/VNF/NST) Flag for overriding the package if exists.')
3832 @click.option('--detailed',
3833 is_flag=True,
3834 default=False,
3835 help='(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options')
3836 @click.option('--netslice-subnets',
3837 default=1,
3838 help='(NST) Number of netslice subnets. Default 1')
3839 @click.option('--netslice-vlds',
3840 default=1,
3841 help='(NST) Number of netslice vlds. Default 1')
3842 @click.pass_context
3843 def package_create(ctx,
3844 package_type,
3845 base_directory,
3846 package_name,
3847 override,
3848 image,
3849 vdus,
3850 vcpu,
3851 memory,
3852 storage,
3853 interfaces,
3854 vendor,
3855 detailed,
3856 netslice_subnets,
3857 netslice_vlds):
3858 """
3859 Creates an OSM NS, VNF, NST package
3860
3861 \b
3862 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
3863 PACKAGE_NAME: Name of the package to create the folder with the content.
3864 """
3865
3866 # try:
3867 check_client_version(ctx.obj, ctx.command.name)
3868 print("Creating the {} structure: {}/{}".format(package_type.upper(), base_directory, package_name))
3869 resp = ctx.obj.package_tool.create(package_type,
3870 base_directory,
3871 package_name,
3872 override=override,
3873 image=image,
3874 vdus=vdus,
3875 vcpu=vcpu,
3876 memory=memory,
3877 storage=storage,
3878 interfaces=interfaces,
3879 vendor=vendor,
3880 detailed=detailed,
3881 netslice_subnets=netslice_subnets,
3882 netslice_vlds=netslice_vlds)
3883 print(resp)
3884 # except ClientException as inst:
3885 # print("ERROR: {}".format(inst))
3886 # exit(1)
3887
3888 @cli_osm.command(name='package-validate',
3889 short_help='Validate a package descriptor')
3890 @click.argument('base-directory',
3891 default=".",
3892 required=False)
3893 @click.option('--recursive/--no-recursive',
3894 default=True,
3895 help='The activated recursive option will validate the yaml files'
3896 ' within the indicated directory and in its subdirectories')
3897 @click.pass_context
3898 def package_validate(ctx,
3899 base_directory,
3900 recursive):
3901 """
3902 Validate descriptors given a base directory.
3903
3904 \b
3905 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
3906 """
3907 # try:
3908 check_client_version(ctx.obj, ctx.command.name)
3909 results = ctx.obj.package_tool.validate(base_directory, recursive)
3910 table = PrettyTable()
3911 table.field_names = ["TYPE", "PATH", "VALID", "ERROR"]
3912 # Print the dictionary generated by the validation function
3913 for result in results:
3914 table.add_row([result["type"], result["path"], result["valid"], result["error"]])
3915 table.sortby = "VALID"
3916 table.align["PATH"] = "l"
3917 table.align["TYPE"] = "l"
3918 table.align["ERROR"] = "l"
3919 print(table)
3920 # except ClientException as inst:
3921 # print("ERROR: {}".format(inst))
3922 # exit(1)
3923
3924 @cli_osm.command(name='package-build',
3925 short_help='Build the tar.gz of the package')
3926 @click.argument('package-folder')
3927 @click.option('--skip-validation',
3928 default=False,
3929 is_flag=True,
3930 help='skip package validation')
3931 @click.option('--skip-charm-build', default=False, is_flag=True,
3932 help='the charm will not be compiled, it is assumed to already exist')
3933 @click.pass_context
3934 def package_build(ctx,
3935 package_folder,
3936 skip_validation,
3937 skip_charm_build):
3938 """
3939 Build the package NS, VNF given the package_folder.
3940
3941 \b
3942 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
3943 """
3944 # try:
3945 check_client_version(ctx.obj, ctx.command.name)
3946 results = ctx.obj.package_tool.build(package_folder,
3947 skip_validation=skip_validation,
3948 skip_charm_build=skip_charm_build)
3949 print(results)
3950 # except ClientException as inst:
3951 # print("ERROR: {}".format(inst))
3952 # exit(1)
3953
3954
3955 def cli():
3956 try:
3957 cli_osm()
3958 exit(0)
3959 except pycurl.error as exc:
3960 print(exc)
3961 print('Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified')
3962 except ClientException as exc:
3963 print("ERROR: {}".format(exc))
3964 except (FileNotFoundError, PermissionError) as exc:
3965 print("Cannot open file: {}".format(exc))
3966 except yaml.YAMLError as exc:
3967 print("Invalid YAML format: {}".format(exc))
3968 exit(1)
3969 # TODO capture other controlled exceptions here
3970 # TODO remove the ClientException captures from all places, unless they do something different
3971
3972
3973 if __name__ == '__main__':
3974 cli()
3975