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