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