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