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