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