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