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