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