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