2e36e4b04d38f91b4ae7be6030a9de79bd3ec6bf
1 # Copyright 2017-2018 Sandvine
2 # Copyright 2018 Telefonica
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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
22 from osmclient
import client
23 from osmclient
.common
.exceptions
import ClientException
24 from prettytable
import PrettyTable
33 from datetime
import datetime
38 CONTEXT_SETTINGS
= dict(help_option_names
=['-h', '--help'], max_content_width
=160)
40 def wrap_text(text
, width
):
41 wrapper
= textwrap
.TextWrapper(width
=width
)
42 lines
= text
.splitlines()
43 return "\n".join(map(wrapper
.fill
, lines
))
46 def trunc_text(text
, length
):
47 if len(text
) > length
:
48 return text
[:(length
- 3)] + '...'
53 def check_client_version(obj
, what
, version
='sol005'):
55 Checks the version of the client object and raises error if it not the expected.
57 :param obj: the client object
58 :what: the function or command under evaluation (used when an error is raised)
60 :raises ClientError: if the specified version does not match the client version
63 fullclassname
= obj
.__module
__ + "." + obj
.__class
__.__name
__
64 message
= 'The following commands or options are only supported with the option "--sol005": {}'.format(what
)
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
)
72 @click.group(context_settings
=dict(help_option_names
=['-h', '--help'], max_content_width
=160))
73 @click.option('--hostname',
75 envvar
='OSM_HOSTNAME',
76 help='hostname of server. ' +
77 'Also can set OSM_HOSTNAME in environment')
78 #@click.option('--sol005/--no-sol005',
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',
86 help='user (defaults to admin). ' +
87 'Also can set OSM_USER in environment')
88 @click.option('--password',
90 envvar
='OSM_PASSWORD',
91 help='password (defaults to admin). ' +
92 'Also can set OSM_PASSWORD in environment')
93 @click.option('--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',
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',
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',
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',
118 # envvar='OSM_SO_PORT',
119 # help='hostname of server. ' +
120 # 'Also can set OSM_SO_PORT in environment')
121 #@click.option('--so-project',
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',
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',
133 # envvar='OSM_RO_PORT',
134 # help='hostname of RO server. ' +
135 # 'Also can set OSM_RO_PORT in environment')
137 def cli_osm(ctx
, **kwargs
):
139 hostname
= kwargs
.pop("hostname", None)
142 "either hostname option or OSM_HOSTNAME " +
143 "environment variable needs to be specified"))
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
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')
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.')
180 def ns_list(ctx
, filter, long):
181 """list all NS instances
185 --filter filterExpr Restricts the list to the NS instances matching the filter
188 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
189 concatenated using the "&" character:
192 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
193 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
194 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
196 value := scalar value
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
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.
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>
228 def summarize_deployment_status(status_dict
):
233 net_list
= status_dict
['nets']
236 if net
['status'] not in status_nets
:
237 status_nets
[net
['status']] = 1
239 status_nets
[net
['status']] +=1
241 for k
,v
in status_nets
.items():
242 message
+= "{}:{},".format(k
,v
)
243 message
+= "TOTAL:{}".format(n_nets
)
244 summary
+= "{}".format(message
)
249 vnf_list
= status_dict
['vnfs']
251 member_vnf_index
= vnf
['member_vnf_index']
252 if member_vnf_index
not in status_vnfs
:
253 status_vnfs
[member_vnf_index
] = {}
254 for vm
in vnf
['vms']:
256 if vm
['status'] not in status_vms
:
257 status_vms
[vm
['status']] = 1
259 status_vms
[vm
['status']] +=1
260 if vm
['status'] not in status_vnfs
[member_vnf_index
]:
261 status_vnfs
[member_vnf_index
][vm
['status']] = 1
263 status_vnfs
[member_vnf_index
][vm
['status']] += 1
265 for k
,v
in status_vms
.items():
266 message
+= "{}:{},".format(k
,v
)
267 message
+= "TOTAL:{}".format(n_vms
)
268 summary
+= "\n{}".format(message
)
270 for k
,v
in status_vnfs
.items():
272 message
= "\n {} VMs: ".format(k
)
273 for k2
,v2
in v
.items():
274 message
+= "{}:{},".format(k2
,v2
)
276 message
+= "TOTAL:{}".format(total
)
280 def summarize_config_status(ee_list
):
285 if ee
['elementType'] not in status_ee
:
286 status_ee
[ee
['elementType']] = {}
287 status_ee
[ee
['elementType']][ee
['status']] = 1
289 if ee
['status'] in status_ee
[ee
['elementType']]:
290 status_ee
[ee
['elementType']][ee
['status']] += 1
292 status_ee
[ee
['elementType']][ee
['status']] = 1
294 for elementType
in ["KDU", "VDU", "PDU", "VNF", "NS"]:
295 if elementType
in status_ee
:
298 for k
,v
in status_ee
[elementType
].items():
299 message
+= "{}:{},".format(k
,v
)
301 message
+= "TOTAL:{}\n".format(total
)
302 summary
+= "{}: {}".format(elementType
, message
)
303 summary
+= "TOTAL Exec. Env.: {}".format(n_ee
)
307 check_client_version(ctx
.obj
, '--filter')
308 resp
= ctx
.obj
.ns
.list(filter)
310 resp
= ctx
.obj
.ns
.list()
322 'configuration status'])
323 project_list
= ctx
.obj
.project
.list()
324 vim_list
= ctx
.obj
.vim
.list()
334 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
335 if fullclassname
== 'osmclient.sol005.client.Client':
337 nsr_name
= nsr
['name']
339 date
= datetime
.fromtimestamp(nsr
['create-time']).strftime("%Y-%m-%dT%H:%M:%S")
340 ns_state
= nsr
['nsState']
342 deployment_status
= summarize_deployment_status(nsr
['deploymentStatus'])
343 config_status
= summarize_config_status(nsr
['configurationStatus'])
344 project_id
= nsr
.get('_admin').get('projects_read')[0]
346 for p
in project_list
:
347 if p
['_id'] == project_id
:
348 project_name
= p
['name']
350 #project = '{} ({})'.format(project_name, project_id)
351 project
= project_name
352 vim_id
= nsr
.get('datacenter')
355 if v
['uuid'] == vim_id
:
358 #vim = '{} ({})'.format(vim_name, vim_id)
360 current_operation
= "{} ({})".format(nsr
['currentOperation'],nsr
['currentOperationID'])
361 error_details
= "N/A"
362 if ns_state
== "BROKEN" or ns_state
== "DEGRADED":
363 error_details
= "{}\nDetail: {}".format(nsr
['errorDescription'],nsr
['errorDetail'])
365 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
['id'])
366 nsr
= nsopdata
['nsr:nsr']
367 nsr_name
= nsr
['name-ref']
368 nsr_id
= nsr
['ns-instance-config-ref']
371 deployment_status
= nsr
['operational-status'] if 'operational-status' in nsr
else 'Not found'
372 ns_state
= deployment_status
373 config_status
= nsr
['config-status'] if 'config-status' in nsr
else 'Not found'
374 current_operation
= "Unknown"
375 error_details
= nsr
['detailed-status'] if 'detailed-status' in nsr
else 'Not found'
376 if config_status
== "config_not_needed":
377 config_status
= "configured (no charms)"
386 wrap_text(text
=error_details
,width
=40),
398 wrap_text(text
=error_details
,width
=40)])
401 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
402 print('For more details on the current operation, run "osm ns-op-show OPERATION_ID"')
404 def nsd_list(ctx
, filter, long):
407 check_client_version(ctx
.obj
, '--filter')
408 resp
= ctx
.obj
.nsd
.list(filter)
410 resp
= ctx
.obj
.nsd
.list()
411 # print(yaml.safe_dump(resp))
412 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
413 if fullclassname
== 'osmclient.sol005.client.Client':
415 table
= PrettyTable(['nsd name', 'id', 'onboarding state', 'operational state',
416 'usage state', 'date', 'last update'])
418 table
= PrettyTable(['nsd name', 'id'])
420 name
= nsd
.get('name','-')
422 onb_state
= nsd
['_admin'].get('onboardingState','-')
423 op_state
= nsd
['_admin'].get('operationalState','-')
424 usage_state
= nsd
['_admin'].get('usageState','-')
425 date
= datetime
.fromtimestamp(nsd
['_admin']['created']).strftime("%Y-%m-%dT%H:%M:%S")
426 last_update
= datetime
.fromtimestamp(nsd
['_admin']['modified']).strftime("%Y-%m-%dT%H:%M:%S")
427 table
.add_row([name
, nsd
['_id'], onb_state
, op_state
, usage_state
, date
, last_update
])
429 table
.add_row([name
, nsd
['_id']])
431 table
= PrettyTable(['nsd name', 'id'])
433 table
.add_row([nsd
['name'], nsd
['id']])
438 @cli_osm.command(name
='nsd-list', short_help
='list all NS packages')
439 @click.option('--filter', default
=None,
440 help='restricts the list to the NSD/NSpkg matching the filter')
441 @click.option('--long', is_flag
=True, help='get more details')
443 def nsd_list1(ctx
, filter, long):
444 """list all NSD/NS pkg in the system"""
446 nsd_list(ctx
, filter, long)
449 @cli_osm.command(name
='nspkg-list', short_help
='list all NS packages')
450 @click.option('--filter', default
=None,
451 help='restricts the list to the NSD/NSpkg matching the filter')
452 @click.option('--long', is_flag
=True, help='get more details')
454 def nsd_list2(ctx
, filter, long):
455 """list all NS packages"""
457 nsd_list(ctx
, filter, long)
460 def vnfd_list(ctx
, nf_type
, filter, long):
463 check_client_version(ctx
.obj
, '--nf_type')
465 check_client_version(ctx
.obj
, '--filter')
468 nf_filter
= "_admin.type=vnfd"
469 elif nf_type
== "pnf":
470 nf_filter
= "_admin.type=pnfd"
471 elif nf_type
== "hnf":
472 nf_filter
= "_admin.type=hnfd"
474 raise ClientException('wrong value for "--nf_type" option, allowed values: vnf, pnf, hnf')
476 filter = '{}&{}'.format(nf_filter
, filter)
480 resp
= ctx
.obj
.vnfd
.list(filter)
482 resp
= ctx
.obj
.vnfd
.list()
483 # print(yaml.safe_dump(resp))
484 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
485 if fullclassname
== 'osmclient.sol005.client.Client':
487 table
= PrettyTable(['nfpkg name', 'id', 'onboarding state', 'operational state',
488 'usage state', 'date', 'last update'])
490 table
= PrettyTable(['nfpkg name', 'id'])
492 name
= vnfd
['name'] if 'name' in vnfd
else '-'
494 onb_state
= vnfd
['_admin'].get('onboardingState','-')
495 op_state
= vnfd
['_admin'].get('operationalState','-')
496 usage_state
= vnfd
['_admin'].get('usageState','-')
497 date
= datetime
.fromtimestamp(vnfd
['_admin']['created']).strftime("%Y-%m-%dT%H:%M:%S")
498 last_update
= datetime
.fromtimestamp(vnfd
['_admin']['modified']).strftime("%Y-%m-%dT%H:%M:%S")
499 table
.add_row([name
, vnfd
['_id'], onb_state
, op_state
, usage_state
, date
, last_update
])
501 table
.add_row([name
, vnfd
['_id']])
503 table
= PrettyTable(['nfpkg name', 'id'])
505 table
.add_row([vnfd
['name'], vnfd
['id']])
510 @cli_osm.command(name
='vnfd-list', short_help
='list all xNF packages (VNF, HNF, PNF)')
511 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
512 @click.option('--filter', default
=None,
513 help='restricts the list to the NF pkg matching the filter')
514 @click.option('--long', is_flag
=True, help='get more details')
516 def vnfd_list1(ctx
, nf_type
, filter, long):
517 """list all xNF packages (VNF, HNF, PNF)"""
519 vnfd_list(ctx
, nf_type
, filter, long)
522 @cli_osm.command(name
='vnfpkg-list', short_help
='list all xNF packages (VNF, HNF, PNF)')
523 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
524 @click.option('--filter', default
=None,
525 help='restricts the list to the NFpkg matching the filter')
526 @click.option('--long', is_flag
=True, help='get more details')
528 def vnfd_list2(ctx
, nf_type
, filter, long):
529 """list all xNF packages (VNF, HNF, PNF)"""
531 vnfd_list(ctx
, nf_type
, filter, long)
534 @cli_osm.command(name
='nfpkg-list', short_help
='list all xNF packages (VNF, HNF, PNF)')
535 @click.option('--nf_type', help='type of NF (vnf, pnf, hnf)')
536 @click.option('--filter', default
=None,
537 help='restricts the list to the NFpkg matching the filter')
538 @click.option('--long', is_flag
=True, help='get more details')
540 def nfpkg_list(ctx
, nf_type
, filter, long):
541 """list all xNF packages (VNF, HNF, PNF)"""
544 check_client_version(ctx
.obj
, ctx
.command
.name
)
545 vnfd_list(ctx
, nf_type
, filter, long)
546 # except ClientException as e:
551 def vnf_list(ctx
, ns
, filter, long):
555 check_client_version(ctx
.obj
, '--ns')
557 check_client_version(ctx
.obj
, '--filter')
558 resp
= ctx
.obj
.vnf
.list(ns
, filter)
560 resp
= ctx
.obj
.vnf
.list()
561 # except ClientException as e:
564 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
565 if fullclassname
== 'osmclient.sol005.client.Client':
566 field_names
= ['vnf id', 'name', 'ns id', 'vnf member index',
567 'vnfd name', 'vim account id', 'ip address']
569 field_names
= ['vnf id', 'name', 'ns id', 'vnf member index',
570 'vnfd name', 'vim account id', 'ip address',
571 'date', 'last update']
572 table
= PrettyTable(field_names
)
574 name
= vnfr
['name'] if 'name' in vnfr
else '-'
575 new_row
= [vnfr
['_id'], name
, vnfr
['nsr-id-ref'],
576 vnfr
['member-vnf-index-ref'], vnfr
['vnfd-ref'],
577 vnfr
['vim-account-id'], vnfr
['ip-address']]
579 date
= datetime
.fromtimestamp(vnfr
['_admin']['created']).strftime("%Y-%m-%dT%H:%M:%S")
580 last_update
= datetime
.fromtimestamp(vnfr
['_admin']['modified']).strftime("%Y-%m-%dT%H:%M:%S")
581 new_row
.extend([date
, last_update
])
582 table
.add_row(new_row
)
587 'operational status',
590 if 'mgmt-interface' not in vnfr
:
591 vnfr
['mgmt-interface'] = {}
592 vnfr
['mgmt-interface']['ip-address'] = None
596 vnfr
['operational-status'],
597 vnfr
['config-status']])
602 @cli_osm.command(name
='vnf-list', short_help
='list all NF instances')
603 @click.option('--ns', default
=None, help='NS instance id or name to restrict the NF list')
604 @click.option('--filter', default
=None,
605 help='restricts the list to the NF instances matching the filter.')
606 @click.option('--long', is_flag
=True, help='get more details')
608 def vnf_list1(ctx
, ns
, filter, long):
609 """list all NF instances"""
611 vnf_list(ctx
, ns
, filter, long)
614 @cli_osm.command(name
='nf-list', short_help
='list all NF instances')
615 @click.option('--ns', default
=None, help='NS instance id or name to restrict the NF list')
616 @click.option('--filter', default
=None,
617 help='restricts the list to the NF instances matching the filter.')
618 @click.option('--long', is_flag
=True, help='get more details')
620 def nf_list(ctx
, ns
, filter, long):
621 """list all NF instances
625 --ns TEXT NS instance id or name to restrict the VNF list
626 --filter filterExpr Restricts the list to the VNF instances matching the filter
629 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
630 concatenated using the "&" character:
633 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
634 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
635 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
637 value := scalar value
641 * zero or more occurrences
642 ? zero or one occurrence
643 [] grouping of expressions to be used with ? and *
644 "" quotation marks for marking string constants
648 "AttrName" is the name of one attribute in the data type that defines the representation
649 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
650 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
651 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
652 entries, it means that the operator "op" is applied to the attribute addressed by the last
653 <attrName> entry included in the concatenation. All simple filter expressions are combined
654 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
655 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
656 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
657 prefix". If an attribute referenced in an expression is an array, an object that contains a
658 corresponding array shall be considered to match the expression if any of the elements in the
659 array matches all expressions that have the same attribute prefix.
663 --filter vim-account-id=<VIM_ACCOUNT_ID>
664 --filter vnfd-ref=<VNFD_NAME>
665 --filter vdur.ip-address=<IP_ADDRESS>
666 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
669 vnf_list(ctx
, ns
, filter)
672 @cli_osm.command(name
='ns-op-list', short_help
='shows the history of operations over a NS instance')
673 @click.argument('name')
674 @click.option('--long', is_flag
=True,
675 help='get more details of the NS operation (date, ).')
677 def ns_op_list(ctx
, name
, long):
678 """shows the history of operations over a NS instance
680 NAME: name or ID of the NS instance
682 def formatParams(params
):
683 if params
['lcmOperationType']=='instantiate':
684 params
.pop('nsDescription')
688 elif params
['lcmOperationType']=='action':
689 params
.pop('primitive')
690 params
.pop('lcmOperationType')
691 params
.pop('nsInstanceId')
696 check_client_version(ctx
.obj
, ctx
.command
.name
)
697 resp
= ctx
.obj
.ns
.list_op(name
)
698 # except ClientException as e:
703 table
= PrettyTable(['id', 'operation', 'action_name', 'operation_params', 'status', 'date', 'last update', 'detail'])
705 table
= PrettyTable(['id', 'operation', 'action_name', 'status', 'date', 'detail'])
707 #print(yaml.safe_dump(resp))
710 if op
['lcmOperationType']=='action':
711 action_name
= op
['operationParams']['primitive']
713 if op
['operationState']=='PROCESSING':
714 if op
['lcmOperationType']=='instantiate':
718 detail
= "In queue. Current position: {}".format(op
['queuePosition'])
719 elif op
['operationState']=='FAILED' or op
['operationState']=='FAILED_TEMP':
720 detail
= op
['errorMessage']
721 date
= datetime
.fromtimestamp(op
['startTime']).strftime("%Y-%m-%dT%H:%M:%S")
722 last_update
= datetime
.fromtimestamp(op
['statusEnteredTime']).strftime("%Y-%m-%dT%H:%M:%S")
724 table
.add_row([op
['id'],
725 op
['lcmOperationType'],
727 wrap_text(text
=json
.dumps(formatParams(op
['operationParams']),indent
=2),width
=50),
728 op
['operationState'],
731 wrap_text(text
=detail
,width
=50)])
733 table
.add_row([op
['id'], op
['lcmOperationType'], action_name
,
734 op
['operationState'], date
, wrap_text(text
=detail
,width
=50)])
739 def nsi_list(ctx
, filter):
740 """list all Network Slice Instances"""
743 check_client_version(ctx
.obj
, ctx
.command
.name
)
744 resp
= ctx
.obj
.nsi
.list(filter)
745 # except ClientException as e:
749 ['netslice instance name',
751 'operational status',
755 nsi_name
= nsi
['name']
757 opstatus
= nsi
['operational-status'] if 'operational-status' in nsi
else 'Not found'
758 configstatus
= nsi
['config-status'] if 'config-status' in nsi
else 'Not found'
759 detailed_status
= nsi
['detailed-status'] if 'detailed-status' in nsi
else 'Not found'
760 if configstatus
== "config_not_needed":
761 configstatus
= "configured (no charms)"
772 @cli_osm.command(name
='nsi-list', short_help
='list all Network Slice Instances (NSI)')
773 @click.option('--filter', default
=None,
774 help='restricts the list to the Network Slice Instances matching the filter')
776 def nsi_list1(ctx
, filter):
777 """list all Network Slice Instances (NSI)"""
779 nsi_list(ctx
, filter)
782 @cli_osm.command(name
='netslice-instance-list', short_help
='list all Network Slice Instances (NSI)')
783 @click.option('--filter', default
=None,
784 help='restricts the list to the Network Slice Instances matching the filter')
786 def nsi_list2(ctx
, filter):
787 """list all Network Slice Instances (NSI)"""
789 nsi_list(ctx
, filter)
792 def nst_list(ctx
, filter):
795 check_client_version(ctx
.obj
, ctx
.command
.name
)
796 resp
= ctx
.obj
.nst
.list(filter)
797 # except ClientException as e:
800 # print(yaml.safe_dump(resp))
801 table
= PrettyTable(['nst name', 'id'])
803 name
= nst
['name'] if 'name' in nst
else '-'
804 table
.add_row([name
, nst
['_id']])
809 @cli_osm.command(name
='nst-list', short_help
='list all Network Slice Templates (NST)')
810 @click.option('--filter', default
=None,
811 help='restricts the list to the NST matching the filter')
813 def nst_list1(ctx
, filter):
814 """list all Network Slice Templates (NST) in the system"""
816 nst_list(ctx
, filter)
819 @cli_osm.command(name
='netslice-template-list', short_help
='list all Network Slice Templates (NST)')
820 @click.option('--filter', default
=None,
821 help='restricts the list to the NST matching the filter')
823 def nst_list2(ctx
, filter):
824 """list all Network Slice Templates (NST) in the system"""
826 nst_list(ctx
, filter)
829 def nsi_op_list(ctx
, name
):
832 check_client_version(ctx
.obj
, ctx
.command
.name
)
833 resp
= ctx
.obj
.nsi
.list_op(name
)
834 # except ClientException as e:
837 table
= PrettyTable(['id', 'operation', 'status'])
839 table
.add_row([op
['id'], op
['lcmOperationType'],
840 op
['operationState']])
845 @cli_osm.command(name
='nsi-op-list', short_help
='shows the history of operations over a Network Slice Instance (NSI)')
846 @click.argument('name')
848 def nsi_op_list1(ctx
, name
):
849 """shows the history of operations over a Network Slice Instance (NSI)
851 NAME: name or ID of the Network Slice Instance
854 nsi_op_list(ctx
, name
)
857 @cli_osm.command(name
='netslice-instance-op-list', short_help
='shows the history of operations over a Network Slice Instance (NSI)')
858 @click.argument('name')
860 def nsi_op_list2(ctx
, name
):
861 """shows the history of operations over a Network Slice Instance (NSI)
863 NAME: name or ID of the Network Slice Instance
866 nsi_op_list(ctx
, name
)
869 @cli_osm.command(name
='pdu-list', short_help
='list all Physical Deployment Units (PDU)')
870 @click.option('--filter', default
=None,
871 help='restricts the list to the Physical Deployment Units matching the filter')
873 def pdu_list(ctx
, filter):
874 """list all Physical Deployment Units (PDU)"""
877 check_client_version(ctx
.obj
, ctx
.command
.name
)
878 resp
= ctx
.obj
.pdu
.list(filter)
879 # except ClientException as e:
888 pdu_name
= pdu
['name']
890 pdu_type
= pdu
['type']
891 pdu_ipaddress
= "None"
892 for iface
in pdu
['interfaces']:
894 pdu_ipaddress
= iface
['ip-address']
909 def nsd_show(ctx
, name
, literal
):
912 resp
= ctx
.obj
.nsd
.get(name
)
913 # resp = ctx.obj.nsd.get_individual(name)
914 # except ClientException as e:
919 print(yaml
.safe_dump(resp
))
922 table
= PrettyTable(['field', 'value'])
923 for k
, v
in list(resp
.items()):
924 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2),width
=100)])
929 @cli_osm.command(name
='nsd-show', short_help
='shows the content of a NSD')
930 @click.option('--literal', is_flag
=True,
931 help='print literally, no pretty table')
932 @click.argument('name')
934 def nsd_show1(ctx
, name
, literal
):
935 """shows the content of a NSD
937 NAME: name or ID of the NSD/NSpkg
940 nsd_show(ctx
, name
, literal
)
943 @cli_osm.command(name
='nspkg-show', short_help
='shows the content of a NSD')
944 @click.option('--literal', is_flag
=True,
945 help='print literally, no pretty table')
946 @click.argument('name')
948 def nsd_show2(ctx
, name
, literal
):
949 """shows the content of a NSD
951 NAME: name or ID of the NSD/NSpkg
954 nsd_show(ctx
, name
, literal
)
957 def vnfd_show(ctx
, name
, literal
):
960 resp
= ctx
.obj
.vnfd
.get(name
)
961 # resp = ctx.obj.vnfd.get_individual(name)
962 # except ClientException as e:
967 print(yaml
.safe_dump(resp
))
970 table
= PrettyTable(['field', 'value'])
971 for k
, v
in list(resp
.items()):
972 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2),width
=100)])
977 @cli_osm.command(name
='vnfd-show', short_help
='shows the content of a VNFD')
978 @click.option('--literal', is_flag
=True,
979 help='print literally, no pretty table')
980 @click.argument('name')
982 def vnfd_show1(ctx
, name
, literal
):
983 """shows the content of a VNFD
985 NAME: name or ID of the VNFD/VNFpkg
988 vnfd_show(ctx
, name
, literal
)
991 @cli_osm.command(name
='vnfpkg-show', short_help
='shows the content of a VNFD')
992 @click.option('--literal', is_flag
=True,
993 help='print literally, no pretty table')
994 @click.argument('name')
996 def vnfd_show2(ctx
, name
, literal
):
997 """shows the content of a VNFD
999 NAME: name or ID of the VNFD/VNFpkg
1002 vnfd_show(ctx
, name
, literal
)
1005 @cli_osm.command(name
='nfpkg-show', short_help
='shows the content of a NF Descriptor')
1006 @click.option('--literal', is_flag
=True,
1007 help='print literally, no pretty table')
1008 @click.argument('name')
1010 def nfpkg_show(ctx
, name
, literal
):
1011 """shows the content of a NF Descriptor
1013 NAME: name or ID of the NFpkg
1016 vnfd_show(ctx
, name
, literal
)
1019 @cli_osm.command(name
='ns-show', short_help
='shows the info of a NS instance')
1020 @click.argument('name')
1021 @click.option('--literal', is_flag
=True,
1022 help='print literally, no pretty table')
1023 @click.option('--filter', default
=None)
1025 def ns_show(ctx
, name
, literal
, filter):
1026 """shows the info of a NS instance
1028 NAME: name or ID of the NS instance
1032 ns
= ctx
.obj
.ns
.get(name
)
1033 # except ClientException as e:
1038 print(yaml
.safe_dump(ns
))
1041 table
= PrettyTable(['field', 'value'])
1043 for k
, v
in list(ns
.items()):
1044 if filter is None or filter in k
:
1045 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2),width
=100)])
1047 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
1048 if fullclassname
!= 'osmclient.sol005.client.Client':
1049 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
['id'])
1050 nsr_optdata
= nsopdata
['nsr:nsr']
1051 for k
, v
in list(nsr_optdata
.items()):
1052 if filter is None or filter in k
:
1053 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2),width
=100)])
1058 @cli_osm.command(name
='vnf-show', short_help
='shows the info of a VNF instance')
1059 @click.argument('name')
1060 @click.option('--literal', is_flag
=True,
1061 help='print literally, no pretty table')
1062 @click.option('--filter', default
=None, help='restricts the information to the fields in the filter')
1063 @click.option('--kdu', default
=None, help='KDU name (whose status will be shown)')
1065 def vnf_show(ctx
, name
, literal
, filter, kdu
):
1066 """shows the info of a VNF instance
1068 NAME: name or ID of the VNF instance
1070 def print_kdu_status(op_info_status
):
1071 """print KDU status properly formatted
1074 op_status
= yaml
.safe_load(op_info_status
)
1075 if "namespace" in op_status
and "info" in op_status
and \
1076 "last_deployed" in op_status
["info"] and "status" in op_status
["info"] and \
1077 "code" in op_status
["info"]["status"] and "resources" in op_status
["info"]["status"] and \
1078 "notes" in op_status
["info"]["status"] and "seconds" in op_status
["info"]["last_deployed"]:
1079 last_deployed_time
= datetime
.fromtimestamp(op_status
["info"]["last_deployed"]["seconds"]).strftime("%a %b %d %I:%M:%S %Y")
1080 print("LAST DEPLOYED: {}".format(last_deployed_time
))
1081 print("NAMESPACE: {}".format(op_status
["namespace"]))
1082 status_code
= "UNKNOWN"
1083 if op_status
["info"]["status"]["code"]==1:
1084 status_code
= "DEPLOYED"
1085 print("STATUS: {}".format(status_code
))
1088 print(op_status
["info"]["status"]["resources"])
1090 print(op_status
["info"]["status"]["notes"])
1092 print(op_info_status
)
1094 print(op_info_status
)
1099 raise ClientException('"--literal" option is incompatible with "--kdu" option')
1101 raise ClientException('"--filter" option is incompatible with "--kdu" option')
1104 check_client_version(ctx
.obj
, ctx
.command
.name
)
1105 resp
= ctx
.obj
.vnf
.get(name
)
1108 ns_id
= resp
['nsr-id-ref']
1110 op_data
['member_vnf_index'] = resp
['member-vnf-index-ref']
1111 op_data
['kdu_name'] = kdu
1112 op_data
['primitive'] = 'status'
1113 op_data
['primitive_params'] = {}
1114 op_id
= ctx
.obj
.ns
.exec_op(ns_id
, op_name
='action', op_data
=op_data
, wait
=False)
1117 op_info
= ctx
.obj
.ns
.get_op(op_id
)
1118 if op_info
['operationState'] == 'COMPLETED':
1119 print_kdu_status(op_info
['detailed-status'])
1123 print ("Could not determine KDU status")
1126 print(yaml
.safe_dump(resp
))
1129 table
= PrettyTable(['field', 'value'])
1131 for k
, v
in list(resp
.items()):
1132 if filter is None or filter in k
:
1133 table
.add_row([k
, wrap_text(text
=json
.dumps(v
,indent
=2),width
=100)])
1136 # except ClientException as e:
1141 #@cli_osm.command(name='vnf-monitoring-show')
1142 #@click.argument('vnf_name')
1143 #@click.pass_context
1144 #def vnf_monitoring_show(ctx, vnf_name):
1146 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1147 # resp = ctx.obj.vnf.get_monitoring(vnf_name)
1148 # except ClientException as e:
1152 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1153 # if resp is not None:
1154 # for monitor in resp:
1158 # monitor['value-integer'],
1159 # monitor['units']])
1164 #@cli_osm.command(name='ns-monitoring-show')
1165 #@click.argument('ns_name')
1166 #@click.pass_context
1167 #def ns_monitoring_show(ctx, ns_name):
1169 # check_client_version(ctx.obj, ctx.command.name, 'v1')
1170 # resp = ctx.obj.ns.get_monitoring(ns_name)
1171 # except ClientException as e:
1175 # table = PrettyTable(['vnf name', 'monitoring name', 'value', 'units'])
1176 # for key, val in list(resp.items()):
1177 # for monitor in val:
1181 # monitor['value-integer'],
1182 # monitor['units']])
1187 @cli_osm.command(name
='ns-op-show', short_help
='shows the info of a NS operation')
1188 @click.argument('id')
1189 @click.option('--filter', default
=None)
1190 @click.option('--literal', is_flag
=True,
1191 help='print literally, no pretty table')
1193 def ns_op_show(ctx
, id, filter, literal
):
1194 """shows the detailed info of a NS operation
1196 ID: operation identifier
1200 check_client_version(ctx
.obj
, ctx
.command
.name
)
1201 op_info
= ctx
.obj
.ns
.get_op(id)
1202 # except ClientException as e:
1207 print(yaml
.safe_dump(op_info
))
1210 table
= PrettyTable(['field', 'value'])
1211 for k
, v
in list(op_info
.items()):
1212 if filter is None or filter in k
:
1213 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1218 def nst_show(ctx
, name
, literal
):
1221 check_client_version(ctx
.obj
, ctx
.command
.name
)
1222 resp
= ctx
.obj
.nst
.get(name
)
1223 #resp = ctx.obj.nst.get_individual(name)
1224 # except ClientException as e:
1229 print(yaml
.safe_dump(resp
))
1232 table
= PrettyTable(['field', 'value'])
1233 for k
, v
in list(resp
.items()):
1234 table
.add_row([k
, wrap_text(json
.dumps(v
, indent
=2), 100)])
1239 @cli_osm.command(name
='nst-show', short_help
='shows the content of a Network Slice Template (NST)')
1240 @click.option('--literal', is_flag
=True,
1241 help='print literally, no pretty table')
1242 @click.argument('name')
1244 def nst_show1(ctx
, name
, literal
):
1245 """shows the content of a Network Slice Template (NST)
1247 NAME: name or ID of the NST
1250 nst_show(ctx
, name
, literal
)
1253 @cli_osm.command(name
='netslice-template-show', short_help
='shows the content of a Network Slice Template (NST)')
1254 @click.option('--literal', is_flag
=True,
1255 help='print literally, no pretty table')
1256 @click.argument('name')
1258 def nst_show2(ctx
, name
, literal
):
1259 """shows the content of a Network Slice Template (NST)
1261 NAME: name or ID of the NST
1264 nst_show(ctx
, name
, literal
)
1267 def nsi_show(ctx
, name
, literal
, filter):
1270 check_client_version(ctx
.obj
, ctx
.command
.name
)
1271 nsi
= ctx
.obj
.nsi
.get(name
)
1272 # except ClientException as e:
1277 print(yaml
.safe_dump(nsi
))
1280 table
= PrettyTable(['field', 'value'])
1282 for k
, v
in list(nsi
.items()):
1283 if filter is None or filter in k
:
1284 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1290 @cli_osm.command(name
='nsi-show', short_help
='shows the content of a Network Slice Instance (NSI)')
1291 @click.argument('name')
1292 @click.option('--literal', is_flag
=True,
1293 help='print literally, no pretty table')
1294 @click.option('--filter', default
=None)
1296 def nsi_show1(ctx
, name
, literal
, filter):
1297 """shows the content of a Network Slice Instance (NSI)
1299 NAME: name or ID of the Network Slice Instance
1302 nsi_show(ctx
, name
, literal
, filter)
1305 @cli_osm.command(name
='netslice-instance-show', short_help
='shows the content of a Network Slice Instance (NSI)')
1306 @click.argument('name')
1307 @click.option('--literal', is_flag
=True,
1308 help='print literally, no pretty table')
1309 @click.option('--filter', default
=None)
1311 def nsi_show2(ctx
, name
, literal
, filter):
1312 """shows the content of a Network Slice Instance (NSI)
1314 NAME: name or ID of the Network Slice Instance
1317 nsi_show(ctx
, name
, literal
, filter)
1320 def nsi_op_show(ctx
, id, filter):
1323 check_client_version(ctx
.obj
, ctx
.command
.name
)
1324 op_info
= ctx
.obj
.nsi
.get_op(id)
1325 # except ClientException as e:
1329 table
= PrettyTable(['field', 'value'])
1330 for k
, v
in list(op_info
.items()):
1331 if filter is None or filter in k
:
1332 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1337 @cli_osm.command(name
='nsi-op-show', short_help
='shows the info of an operation over a Network Slice Instance(NSI)')
1338 @click.argument('id')
1339 @click.option('--filter', default
=None)
1341 def nsi_op_show1(ctx
, id, filter):
1342 """shows the info of an operation over a Network Slice Instance(NSI)
1344 ID: operation identifier
1347 nsi_op_show(ctx
, id, filter)
1350 @cli_osm.command(name
='netslice-instance-op-show', short_help
='shows the info of an operation over a Network Slice Instance(NSI)')
1351 @click.argument('id')
1352 @click.option('--filter', default
=None)
1354 def nsi_op_show2(ctx
, id, filter):
1355 """shows the info of an operation over a Network Slice Instance(NSI)
1357 ID: operation identifier
1360 nsi_op_show(ctx
, id, filter)
1363 @cli_osm.command(name
='pdu-show', short_help
='shows the content of a Physical Deployment Unit (PDU)')
1364 @click.argument('name')
1365 @click.option('--literal', is_flag
=True,
1366 help='print literally, no pretty table')
1367 @click.option('--filter', default
=None)
1369 def pdu_show(ctx
, name
, literal
, filter):
1370 """shows the content of a Physical Deployment Unit (PDU)
1372 NAME: name or ID of the PDU
1376 check_client_version(ctx
.obj
, ctx
.command
.name
)
1377 pdu
= ctx
.obj
.pdu
.get(name
)
1378 # except ClientException as e:
1383 print(yaml
.safe_dump(pdu
))
1386 table
= PrettyTable(['field', 'value'])
1388 for k
, v
in list(pdu
.items()):
1389 if filter is None or filter in k
:
1390 table
.add_row([k
, json
.dumps(v
, indent
=2)])
1396 ####################
1398 ####################
1400 def nsd_create(ctx
, filename
, overwrite
, skip_charm_build
):
1403 check_client_version(ctx
.obj
, ctx
.command
.name
)
1404 ctx
.obj
.nsd
.create(filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1405 # except ClientException as e:
1410 @cli_osm.command(name
='nsd-create', short_help
='creates a new NSD/NSpkg')
1411 @click.argument('filename')
1412 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1413 help='Deprecated. Use override')
1414 @click.option('--override', 'overwrite', default
=None,
1415 help='overrides fields in descriptor, format: '
1416 '"key1.key2...=value[;key3...=value;...]"')
1417 @click.option('--skip-charm-build', default
=False, is_flag
=True,
1418 help='The charm will not be compiled, it is assumed to already exist')
1420 def nsd_create1(ctx
, filename
, overwrite
, skip_charm_build
):
1421 """creates a new NSD/NSpkg
1423 FILENAME: NSD yaml file or NSpkg tar.gz file
1426 nsd_create(ctx
, filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1429 @cli_osm.command(name
='nspkg-create', short_help
='creates a new NSD/NSpkg')
1430 @click.argument('filename')
1431 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1432 help='Deprecated. Use override')
1433 @click.option('--override', 'overwrite', default
=None,
1434 help='overrides fields in descriptor, format: '
1435 '"key1.key2...=value[;key3...=value;...]"')
1436 @click.option('--skip-charm-build', default
=False, is_flag
=True,
1437 help='The charm will not be compiled, it is assumed to already exist')
1439 def nsd_create2(ctx
, filename
, overwrite
, skip_charm_build
):
1440 """creates a new NSD/NSpkg
1442 FILENAME: NSD folder, NSD yaml file or NSpkg tar.gz file
1445 nsd_create(ctx
, filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1448 def vnfd_create(ctx
, filename
, overwrite
, skip_charm_build
):
1451 check_client_version(ctx
.obj
, ctx
.command
.name
)
1452 ctx
.obj
.vnfd
.create(filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1453 # except ClientException as e:
1458 @cli_osm.command(name
='vnfd-create', short_help
='creates a new VNFD/VNFpkg')
1459 @click.argument('filename')
1460 @click.option('--overwrite', 'overwrite', default
=None,
1461 help='overwrite deprecated, use override')
1462 @click.option('--override', 'overwrite', default
=None,
1463 help='overrides fields in descriptor, format: '
1464 '"key1.key2...=value[;key3...=value;...]"')
1465 @click.option('--skip-charm-build', default
=False, is_flag
=True,
1466 help='The charm will not be compiled, it is assumed to already exist')
1468 def vnfd_create1(ctx
, filename
, overwrite
, skip_charm_build
):
1469 """creates a new VNFD/VNFpkg
1471 FILENAME: VNFD yaml file or VNFpkg tar.gz file
1474 vnfd_create(ctx
, filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1477 @cli_osm.command(name
='vnfpkg-create', short_help
='creates a new VNFD/VNFpkg')
1478 @click.argument('filename')
1479 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1480 help='Deprecated. Use override')
1481 @click.option('--override', 'overwrite', default
=None,
1482 help='overrides fields in descriptor, format: '
1483 '"key1.key2...=value[;key3...=value;...]"')
1484 @click.option('--skip-charm-build', default
=False, is_flag
=True,
1485 help='The charm will not be compiled, it is assumed to already exist')
1487 def vnfd_create2(ctx
, filename
, overwrite
, skip_charm_build
):
1488 """creates a new VNFD/VNFpkg
1490 FILENAME: NF Package Folder, NF Descriptor yaml file or NFpkg tar.gz file
1493 vnfd_create(ctx
, filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1496 @cli_osm.command(name
='nfpkg-create', short_help
='creates a new NFpkg')
1497 @click.argument('filename')
1498 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1499 help='Deprecated. Use override')
1500 @click.option('--override', 'overwrite', default
=None,
1501 help='overrides fields in descriptor, format: '
1502 '"key1.key2...=value[;key3...=value;...]"')
1503 @click.option('--skip-charm-build', default
=False, is_flag
=True,
1504 help='The charm will not be compiled, it is assumed to already exist')
1506 def nfpkg_create(ctx
, filename
, overwrite
, skip_charm_build
):
1507 """creates a new NFpkg
1509 FILENAME: NF Package Folder, NF Descriptor yaml file or NFpkg tar.gz filems to build
1512 vnfd_create(ctx
, filename
, overwrite
=overwrite
, skip_charm_build
=skip_charm_build
)
1515 @cli_osm.command(name
='ns-create', short_help
='creates a new Network Service instance')
1516 @click.option('--ns_name',
1517 prompt
=True, help='name of the NS instance')
1518 @click.option('--nsd_name',
1519 prompt
=True, help='name of the NS descriptor')
1520 @click.option('--vim_account',
1521 prompt
=True, help='default VIM account id or name for the deployment')
1522 @click.option('--admin_status',
1524 help='administration status')
1525 @click.option('--ssh_keys',
1527 help='comma separated list of public key files to inject to vnfs')
1528 @click.option('--config',
1530 help='ns specific yaml configuration')
1531 @click.option('--config_file',
1533 help='ns specific yaml configuration file')
1534 @click.option('--wait',
1538 help='do not return the control immediately, but keep it '
1539 'until the operation is completed, or timeout')
1550 """creates a new NS instance"""
1554 check_client_version(ctx
.obj
, '--config_file')
1556 raise ClientException('"--config" option is incompatible with "--config_file" option')
1557 with
open(config_file
, 'r') as cf
:
1564 account
=vim_account
,
1566 # except ClientException as e:
1571 def nst_create(ctx
, filename
, overwrite
):
1574 check_client_version(ctx
.obj
, ctx
.command
.name
)
1575 ctx
.obj
.nst
.create(filename
, overwrite
)
1576 # except ClientException as e:
1581 @cli_osm.command(name
='nst-create', short_help
='creates a new Network Slice Template (NST)')
1582 @click.argument('filename')
1583 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1584 help='Deprecated. Use override')
1585 @click.option('--override', 'overwrite', default
=None,
1586 help='overrides fields in descriptor, format: '
1587 '"key1.key2...=value[;key3...=value;...]"')
1589 def nst_create1(ctx
, charm_folder
, overwrite
):
1590 """creates a new Network Slice Template (NST)
1592 FILENAME: NST package folder, NST yaml file or NSTpkg tar.gz file
1595 nst_create(ctx
, charm_folder
, overwrite
)
1598 @cli_osm.command(name
='netslice-template-create', short_help
='creates a new Network Slice Template (NST)')
1599 @click.argument('filename')
1600 @click.option('--overwrite', 'overwrite', default
=None, # hidden=True,
1601 help='Deprecated. Use override')
1602 @click.option('--override', 'overwrite', default
=None,
1603 help='overrides fields in descriptor, format: '
1604 '"key1.key2...=value[;key3...=value;...]"')
1606 def nst_create2(ctx
, filename
, overwrite
):
1607 """creates a new Network Slice Template (NST)
1609 FILENAME: NST yaml file or NSTpkg tar.gz file
1612 nst_create(ctx
, filename
, overwrite
)
1615 def nsi_create(ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
):
1616 """creates a new Network Slice Instance (NSI)"""
1619 check_client_version(ctx
.obj
, ctx
.command
.name
)
1622 raise ClientException('"--config" option is incompatible with "--config_file" option')
1623 with
open(config_file
, 'r') as cf
:
1625 ctx
.obj
.nsi
.create(nst_name
, nsi_name
, config
=config
, ssh_keys
=ssh_keys
,
1626 account
=vim_account
, wait
=wait
)
1627 # except ClientException as e:
1632 @cli_osm.command(name
='nsi-create', short_help
='creates a new Network Slice Instance')
1633 @click.option('--nsi_name', prompt
=True, help='name of the Network Slice Instance')
1634 @click.option('--nst_name', prompt
=True, help='name of the Network Slice Template')
1635 @click.option('--vim_account', prompt
=True, help='default VIM account id or name for the deployment')
1636 @click.option('--ssh_keys', default
=None,
1637 help='comma separated list of keys to inject to vnfs')
1638 @click.option('--config', default
=None,
1639 help='Netslice specific yaml configuration:\n'
1640 'netslice_subnet: [\n'
1641 'id: TEXT, vim_account: TEXT,\n'
1642 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1643 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]\n'
1644 'additionalParamsForNsi: {param: value, ...}\n'
1645 'additionalParamsForsubnet: [{id: SUBNET_ID, additionalParamsForNs: {}, additionalParamsForVnf: {}}]\n'
1647 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1649 @click.option('--config_file',
1651 help='nsi specific yaml configuration file')
1652 @click.option('--wait',
1656 help='do not return the control immediately, but keep it '
1657 'until the operation is completed, or timeout')
1659 def nsi_create1(ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
):
1660 """creates a new Network Slice Instance (NSI)"""
1662 nsi_create(ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
)
1665 @cli_osm.command(name
='netslice-instance-create', short_help
='creates a new Network Slice Instance')
1666 @click.option('--nsi_name', prompt
=True, help='name of the Network Slice Instance')
1667 @click.option('--nst_name', prompt
=True, help='name of the Network Slice Template')
1668 @click.option('--vim_account', prompt
=True, help='default VIM account id or name for the deployment')
1669 @click.option('--ssh_keys', default
=None,
1670 help='comma separated list of keys to inject to vnfs')
1671 @click.option('--config', default
=None,
1672 help='Netslice specific yaml configuration:\n'
1673 'netslice_subnet: [\n'
1674 'id: TEXT, vim_account: TEXT,\n'
1675 'vnf: [member-vnf-index: TEXT, vim_account: TEXT]\n'
1676 'vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1678 'netslice-vld: [name: TEXT, vim-network-name: TEXT or DICT with vim_account, vim_net entries]'
1680 @click.option('--config_file',
1682 help='nsi specific yaml configuration file')
1683 @click.option('--wait',
1687 help='do not return the control immediately, but keep it '
1688 'until the operation is completed, or timeout')
1690 def nsi_create2(ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
):
1691 """creates a new Network Slice Instance (NSI)"""
1693 nsi_create(ctx
, nst_name
, nsi_name
, vim_account
, ssh_keys
, config
, config_file
, wait
=wait
)
1696 @cli_osm.command(name
='pdu-create', short_help
='adds a new Physical Deployment Unit to the catalog')
1697 @click.option('--name', help='name of the Physical Deployment Unit')
1698 @click.option('--pdu_type', help='type of PDU (e.g. router, firewall, FW001)')
1699 @click.option('--interface',
1700 help='interface(s) of the PDU: name=<NAME>,mgmt=<true|false>,ip-address=<IP_ADDRESS>'+
1701 '[,type=<overlay|underlay>][,mac-address=<MAC_ADDRESS>][,vim-network-name=<VIM_NET_NAME>]',
1703 @click.option('--description', help='human readable description')
1704 @click.option('--vim_account', help='list of VIM accounts (in the same VIM) that can reach this PDU', multiple
=True)
1705 @click.option('--descriptor_file', default
=None,
1706 help='PDU descriptor file (as an alternative to using the other arguments')
1708 def pdu_create(ctx
, name
, pdu_type
, interface
, description
, vim_account
, descriptor_file
):
1709 """creates a new Physical Deployment Unit (PDU)"""
1712 check_client_version(ctx
.obj
, ctx
.command
.name
)
1714 if not descriptor_file
:
1716 raise ClientException('in absence of descriptor file, option "--name" is mandatory')
1718 raise ClientException('in absence of descriptor file, option "--pdu_type" is mandatory')
1720 raise ClientException('in absence of descriptor file, option "--interface" is mandatory (at least once)')
1722 raise ClientException('in absence of descriptor file, option "--vim_account" is mandatory (at least once)')
1724 with
open(descriptor_file
, 'r') as df
:
1725 pdu
= yaml
.safe_load(df
.read())
1726 if name
: pdu
["name"] = name
1727 if pdu_type
: pdu
["type"] = pdu_type
1728 if description
: pdu
["description"] = description
1729 if vim_account
: pdu
["vim_accounts"] = vim_account
1732 for iface
in interface
:
1733 new_iface
={k
:v
for k
,v
in [i
.split('=') for i
in iface
.split(',')]}
1734 new_iface
["mgmt"] = (new_iface
.get("mgmt","false").lower() == "true")
1735 ifaces_list
.append(new_iface
)
1736 pdu
["interfaces"] = ifaces_list
1737 ctx
.obj
.pdu
.create(pdu
)
1738 # except ClientException as e:
1743 ####################
1745 ####################
1747 def nsd_update(ctx
, name
, content
):
1750 check_client_version(ctx
.obj
, ctx
.command
.name
)
1751 ctx
.obj
.nsd
.update(name
, content
)
1752 # except ClientException as e:
1757 @cli_osm.command(name
='nsd-update', short_help
='updates a NSD/NSpkg')
1758 @click.argument('name')
1759 @click.option('--content', default
=None,
1760 help='filename with the NSD/NSpkg replacing the current one')
1762 def nsd_update1(ctx
, name
, content
):
1763 """updates a NSD/NSpkg
1765 NAME: name or ID of the NSD/NSpkg
1768 nsd_update(ctx
, name
, content
)
1771 @cli_osm.command(name
='nspkg-update', short_help
='updates a NSD/NSpkg')
1772 @click.argument('name')
1773 @click.option('--content', default
=None,
1774 help='filename with the NSD/NSpkg replacing the current one')
1776 def nsd_update2(ctx
, name
, content
):
1777 """updates a NSD/NSpkg
1779 NAME: name or ID of the NSD/NSpkg
1782 nsd_update(ctx
, name
, content
)
1785 def vnfd_update(ctx
, name
, content
):
1788 check_client_version(ctx
.obj
, ctx
.command
.name
)
1789 ctx
.obj
.vnfd
.update(name
, content
)
1790 # except ClientException as e:
1795 @cli_osm.command(name
='vnfd-update', short_help
='updates a new VNFD/VNFpkg')
1796 @click.argument('name')
1797 @click.option('--content', default
=None,
1798 help='filename with the VNFD/VNFpkg replacing the current one')
1800 def vnfd_update1(ctx
, name
, content
):
1801 """updates a VNFD/VNFpkg
1803 NAME: name or ID of the VNFD/VNFpkg
1806 vnfd_update(ctx
, name
, content
)
1809 @cli_osm.command(name
='vnfpkg-update', short_help
='updates a VNFD/VNFpkg')
1810 @click.argument('name')
1811 @click.option('--content', default
=None,
1812 help='filename with the VNFD/VNFpkg replacing the current one')
1814 def vnfd_update2(ctx
, name
, content
):
1815 """updates a VNFD/VNFpkg
1817 NAME: VNFD yaml file or VNFpkg tar.gz file
1820 vnfd_update(ctx
, name
, content
)
1823 @cli_osm.command(name
='nfpkg-update', short_help
='updates a NFpkg')
1824 @click.argument('name')
1825 @click.option('--content', default
=None,
1826 help='filename with the NFpkg replacing the current one')
1828 def nfpkg_update(ctx
, name
, content
):
1831 NAME: NF Descriptor yaml file or NFpkg tar.gz file
1834 vnfd_update(ctx
, name
, content
)
1837 def nst_update(ctx
, name
, content
):
1840 check_client_version(ctx
.obj
, ctx
.command
.name
)
1841 ctx
.obj
.nst
.update(name
, content
)
1842 # except ClientException as e:
1847 @cli_osm.command(name
='nst-update', short_help
='updates a Network Slice Template (NST)')
1848 @click.argument('name')
1849 @click.option('--content', default
=None,
1850 help='filename with the NST/NSTpkg replacing the current one')
1852 def nst_update1(ctx
, name
, content
):
1853 """updates a Network Slice Template (NST)
1855 NAME: name or ID of the NSD/NSpkg
1858 nst_update(ctx
, name
, content
)
1861 @cli_osm.command(name
='netslice-template-update', short_help
='updates a Network Slice Template (NST)')
1862 @click.argument('name')
1863 @click.option('--content', default
=None,
1864 help='filename with the NST/NSTpkg replacing the current one')
1866 def nst_update2(ctx
, name
, content
):
1867 """updates a Network Slice Template (NST)
1869 NAME: name or ID of the NSD/NSpkg
1872 nst_update(ctx
, name
, content
)
1875 ####################
1877 ####################
1879 def nsd_delete(ctx
, name
, force
):
1883 ctx
.obj
.nsd
.delete(name
)
1885 check_client_version(ctx
.obj
, '--force')
1886 ctx
.obj
.nsd
.delete(name
, force
)
1887 # except ClientException as e:
1892 @cli_osm.command(name
='nsd-delete', short_help
='deletes a NSD/NSpkg')
1893 @click.argument('name')
1894 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1896 def nsd_delete1(ctx
, name
, force
):
1897 """deletes a NSD/NSpkg
1899 NAME: name or ID of the NSD/NSpkg to be deleted
1902 nsd_delete(ctx
, name
, force
)
1905 @cli_osm.command(name
='nspkg-delete', short_help
='deletes a NSD/NSpkg')
1906 @click.argument('name')
1907 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1909 def nsd_delete2(ctx
, name
, force
):
1910 """deletes a NSD/NSpkg
1912 NAME: name or ID of the NSD/NSpkg to be deleted
1915 nsd_delete(ctx
, name
, force
)
1918 def vnfd_delete(ctx
, name
, force
):
1922 ctx
.obj
.vnfd
.delete(name
)
1924 check_client_version(ctx
.obj
, '--force')
1925 ctx
.obj
.vnfd
.delete(name
, force
)
1926 # except ClientException as e:
1931 @cli_osm.command(name
='vnfd-delete', short_help
='deletes a VNFD/VNFpkg')
1932 @click.argument('name')
1933 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1935 def vnfd_delete1(ctx
, name
, force
):
1936 """deletes a VNFD/VNFpkg
1938 NAME: name or ID of the VNFD/VNFpkg to be deleted
1941 vnfd_delete(ctx
, name
, force
)
1944 @cli_osm.command(name
='vnfpkg-delete', short_help
='deletes a VNFD/VNFpkg')
1945 @click.argument('name')
1946 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1948 def vnfd_delete2(ctx
, name
, force
):
1949 """deletes a VNFD/VNFpkg
1951 NAME: name or ID of the VNFD/VNFpkg to be deleted
1954 vnfd_delete(ctx
, name
, force
)
1957 @cli_osm.command(name
='nfpkg-delete', short_help
='deletes a NFpkg')
1958 @click.argument('name')
1959 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1961 def nfpkg_delete(ctx
, name
, force
):
1964 NAME: name or ID of the NFpkg to be deleted
1967 vnfd_delete(ctx
, name
, force
)
1970 @cli_osm.command(name
='ns-delete', short_help
='deletes a NS instance')
1971 @click.argument('name')
1972 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
1973 @click.option('--wait',
1977 help='do not return the control immediately, but keep it '
1978 'until the operation is completed, or timeout')
1980 def ns_delete(ctx
, name
, force
, wait
):
1981 """deletes a NS instance
1983 NAME: name or ID of the NS instance to be deleted
1988 ctx
.obj
.ns
.delete(name
, wait
=wait
)
1990 check_client_version(ctx
.obj
, '--force')
1991 ctx
.obj
.ns
.delete(name
, force
, wait
=wait
)
1992 # except ClientException as e:
1997 def nst_delete(ctx
, name
, force
):
2000 check_client_version(ctx
.obj
, ctx
.command
.name
)
2001 ctx
.obj
.nst
.delete(name
, force
)
2002 # except ClientException as e:
2007 @cli_osm.command(name
='nst-delete', short_help
='deletes a Network Slice Template (NST)')
2008 @click.argument('name')
2009 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2011 def nst_delete1(ctx
, name
, force
):
2012 """deletes a Network Slice Template (NST)
2014 NAME: name or ID of the NST/NSTpkg to be deleted
2017 nst_delete(ctx
, name
, force
)
2020 @cli_osm.command(name
='netslice-template-delete', short_help
='deletes a Network Slice Template (NST)')
2021 @click.argument('name')
2022 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2024 def nst_delete2(ctx
, name
, force
):
2025 """deletes a Network Slice Template (NST)
2027 NAME: name or ID of the NST/NSTpkg to be deleted
2030 nst_delete(ctx
, name
, force
)
2033 def nsi_delete(ctx
, name
, force
, wait
):
2036 check_client_version(ctx
.obj
, ctx
.command
.name
)
2037 ctx
.obj
.nsi
.delete(name
, force
, wait
=wait
)
2038 # except ClientException as e:
2043 @cli_osm.command(name
='nsi-delete', short_help
='deletes a Network Slice Instance (NSI)')
2044 @click.argument('name')
2045 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2046 @click.option('--wait',
2050 help='do not return the control immediately, but keep it '
2051 'until the operation is completed, or timeout')
2053 def nsi_delete1(ctx
, name
, force
, wait
):
2054 """deletes a Network Slice Instance (NSI)
2056 NAME: name or ID of the Network Slice instance to be deleted
2059 nsi_delete(ctx
, name
, force
, wait
=wait
)
2062 @cli_osm.command(name
='netslice-instance-delete', short_help
='deletes a Network Slice Instance (NSI)')
2063 @click.argument('name')
2064 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2066 def nsi_delete2(ctx
, name
, force
, wait
):
2067 """deletes a Network Slice Instance (NSI)
2069 NAME: name or ID of the Network Slice instance to be deleted
2072 nsi_delete(ctx
, name
, force
, wait
=wait
)
2075 @cli_osm.command(name
='pdu-delete', short_help
='deletes a Physical Deployment Unit (PDU)')
2076 @click.argument('name')
2077 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2079 def pdu_delete(ctx
, name
, force
):
2080 """deletes a Physical Deployment Unit (PDU)
2082 NAME: name or ID of the PDU to be deleted
2086 check_client_version(ctx
.obj
, ctx
.command
.name
)
2087 ctx
.obj
.pdu
.delete(name
, force
)
2088 # except ClientException as e:
2097 @cli_osm.command(name
='vim-create', short_help
='creates a new VIM account')
2098 @click.option('--name',
2100 help='Name to create datacenter')
2101 @click.option('--user',
2103 help='VIM username')
2104 @click.option('--password',
2107 confirmation_prompt
=True,
2108 help='VIM password')
2109 @click.option('--auth_url',
2112 @click.option('--tenant',
2114 help='VIM tenant name')
2115 @click.option('--config',
2117 help='VIM specific config parameters')
2118 @click.option('--account_type',
2119 default
='openstack',
2121 @click.option('--description',
2123 help='human readable description')
2124 @click.option('--sdn_controller', default
=None, help='Name or id of the SDN controller associated to this VIM account')
2125 @click.option('--sdn_port_mapping', default
=None, help="File describing the port mapping between compute nodes' ports and switch ports")
2126 @click.option('--wait',
2130 help='do not return the control immediately, but keep it '
2131 'until the operation is completed, or timeout')
2145 """creates a new VIM account"""
2149 check_client_version(ctx
.obj
, '--sdn_controller')
2150 if sdn_port_mapping
:
2151 check_client_version(ctx
.obj
, '--sdn_port_mapping')
2153 vim
['vim-username'] = user
2154 vim
['vim-password'] = password
2155 vim
['vim-url'] = auth_url
2156 vim
['vim-tenant-name'] = tenant
2157 vim
['vim-type'] = account_type
2158 vim
['description'] = description
2159 vim
['config'] = config
2160 if sdn_controller
or sdn_port_mapping
:
2161 ctx
.obj
.vim
.create(name
, vim
, sdn_controller
, sdn_port_mapping
, wait
=wait
)
2163 ctx
.obj
.vim
.create(name
, vim
, wait
=wait
)
2164 # except ClientException as e:
2169 @cli_osm.command(name
='vim-update', short_help
='updates a VIM account')
2170 @click.argument('name')
2171 @click.option('--newname', help='New name for the VIM account')
2172 @click.option('--user', help='VIM username')
2173 @click.option('--password', help='VIM password')
2174 @click.option('--auth_url', help='VIM url')
2175 @click.option('--tenant', help='VIM tenant name')
2176 @click.option('--config', help='VIM specific config parameters')
2177 @click.option('--account_type', help='VIM type')
2178 @click.option('--description', help='human readable description')
2179 @click.option('--sdn_controller', default
=None, help='Name or id of the SDN controller associated to this VIM account')
2180 @click.option('--sdn_port_mapping', default
=None, help="File describing the port mapping between compute nodes' ports and switch ports")
2181 @click.option('--wait',
2185 help='do not return the control immediately, but keep it '
2186 'until the operation is completed, or timeout')
2201 """updates a VIM account
2203 NAME: name or ID of the VIM account
2207 check_client_version(ctx
.obj
, ctx
.command
.name
)
2209 if newname
: vim
['name'] = newname
2210 if user
: vim
['vim_user'] = user
2211 if password
: vim
['vim_password'] = password
2212 if auth_url
: vim
['vim_url'] = auth_url
2213 if tenant
: vim
['vim-tenant-name'] = tenant
2214 if account_type
: vim
['vim_type'] = account_type
2215 if description
: vim
['description'] = description
2216 if config
: vim
['config'] = config
2217 ctx
.obj
.vim
.update(name
, vim
, sdn_controller
, sdn_port_mapping
, wait
=wait
)
2218 # except ClientException as e:
2223 @cli_osm.command(name
='vim-delete', short_help
='deletes a VIM account')
2224 @click.argument('name')
2225 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2226 @click.option('--wait',
2230 help='do not return the control immediately, but keep it '
2231 'until the operation is completed, or timeout')
2233 def vim_delete(ctx
, name
, force
, wait
):
2234 """deletes a VIM account
2236 NAME: name or ID of the VIM account to be deleted
2241 ctx
.obj
.vim
.delete(name
, wait
=wait
)
2243 check_client_version(ctx
.obj
, '--force')
2244 ctx
.obj
.vim
.delete(name
, force
, wait
=wait
)
2245 # except ClientException as e:
2250 @cli_osm.command(name
='vim-list', short_help
='list all VIM accounts')
2251 #@click.option('--ro_update/--no_ro_update',
2253 # help='update list from RO')
2254 @click.option('--filter', default
=None,
2255 help='restricts the list to the VIM accounts matching the filter')
2257 def vim_list(ctx
, filter):
2258 """list all VIM accounts"""
2261 check_client_version(ctx
.obj
, '--filter')
2263 # check_client_version(ctx.obj, '--ro_update', 'v1')
2264 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
2265 if fullclassname
== 'osmclient.sol005.client.Client':
2266 resp
= ctx
.obj
.vim
.list(filter)
2268 # resp = ctx.obj.vim.list(ro_update)
2269 table
= PrettyTable(['vim name', 'uuid'])
2271 table
.add_row([vim
['name'], vim
['uuid']])
2276 @cli_osm.command(name
='vim-show', short_help
='shows the details of a VIM account')
2277 @click.argument('name')
2279 def vim_show(ctx
, name
):
2280 """shows the details of a VIM account
2282 NAME: name or ID of the VIM account
2286 resp
= ctx
.obj
.vim
.get(name
)
2287 if 'vim_password' in resp
:
2288 resp
['vim_password']='********'
2289 # except ClientException as e:
2293 table
= PrettyTable(['key', 'attribute'])
2294 for k
, v
in list(resp
.items()):
2295 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2),width
=100)])
2300 ####################
2302 ####################
2304 @cli_osm.command(name
='wim-create', short_help
='creates a new WIM account')
2305 @click.option('--name',
2307 help='Name for the WIM account')
2308 @click.option('--user',
2309 help='WIM username')
2310 @click.option('--password',
2311 help='WIM password')
2312 @click.option('--url',
2315 # @click.option('--tenant',
2316 # help='wIM tenant name')
2317 @click.option('--config',
2319 help='WIM specific config parameters')
2320 @click.option('--wim_type',
2322 @click.option('--description',
2324 help='human readable description')
2325 @click.option('--wim_port_mapping', default
=None,
2326 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
2327 "(WAN service endpoint id and info)")
2328 @click.option('--wait',
2332 help='do not return the control immediately, but keep it '
2333 'until the operation is completed, or timeout')
2346 """creates a new WIM account"""
2349 check_client_version(ctx
.obj
, ctx
.command
.name
)
2350 # if sdn_controller:
2351 # check_client_version(ctx.obj, '--sdn_controller')
2352 # if sdn_port_mapping:
2353 # check_client_version(ctx.obj, '--sdn_port_mapping')
2355 if user
: wim
['user'] = user
2356 if password
: wim
['password'] = password
2357 if url
: wim
['wim_url'] = url
2358 # if tenant: wim['tenant'] = tenant
2359 wim
['wim_type'] = wim_type
2360 if description
: wim
['description'] = description
2361 if config
: wim
['config'] = config
2362 ctx
.obj
.wim
.create(name
, wim
, wim_port_mapping
, wait
=wait
)
2363 # except ClientException as e:
2368 @cli_osm.command(name
='wim-update', short_help
='updates a WIM account')
2369 @click.argument('name')
2370 @click.option('--newname', help='New name for the WIM account')
2371 @click.option('--user', help='WIM username')
2372 @click.option('--password', help='WIM password')
2373 @click.option('--url', help='WIM url')
2374 @click.option('--config', help='WIM specific config parameters')
2375 @click.option('--wim_type', help='WIM type')
2376 @click.option('--description', help='human readable description')
2377 @click.option('--wim_port_mapping', default
=None,
2378 help="File describing the port mapping between DC edge (datacenters, switches, ports) and WAN edge "
2379 "(WAN service endpoint id and info)")
2380 @click.option('--wait',
2384 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2397 """updates a WIM account
2399 NAME: name or ID of the WIM account
2403 check_client_version(ctx
.obj
, ctx
.command
.name
)
2405 if newname
: wim
['name'] = newname
2406 if user
: wim
['user'] = user
2407 if password
: wim
['password'] = password
2408 if url
: wim
['url'] = url
2409 # if tenant: wim['tenant'] = tenant
2410 if wim_type
: wim
['wim_type'] = wim_type
2411 if description
: wim
['description'] = description
2412 if config
: wim
['config'] = config
2413 ctx
.obj
.wim
.update(name
, wim
, wim_port_mapping
, wait
=wait
)
2414 # except ClientException as e:
2419 @cli_osm.command(name
='wim-delete', short_help
='deletes a WIM account')
2420 @click.argument('name')
2421 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2422 @click.option('--wait',
2426 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2428 def wim_delete(ctx
, name
, force
, wait
):
2429 """deletes a WIM account
2431 NAME: name or ID of the WIM account to be deleted
2435 check_client_version(ctx
.obj
, ctx
.command
.name
)
2436 ctx
.obj
.wim
.delete(name
, force
, wait
=wait
)
2437 # except ClientException as e:
2442 @cli_osm.command(name
='wim-list', short_help
='list all WIM accounts')
2443 @click.option('--filter', default
=None,
2444 help='restricts the list to the WIM accounts matching the filter')
2446 def wim_list(ctx
, filter):
2447 """list all WIM accounts"""
2450 check_client_version(ctx
.obj
, ctx
.command
.name
)
2451 resp
= ctx
.obj
.wim
.list(filter)
2452 table
= PrettyTable(['wim name', 'uuid'])
2454 table
.add_row([wim
['name'], wim
['uuid']])
2457 # except ClientException as e:
2462 @cli_osm.command(name
='wim-show', short_help
='shows the details of a WIM account')
2463 @click.argument('name')
2465 def wim_show(ctx
, name
):
2466 """shows the details of a WIM account
2468 NAME: name or ID of the WIM account
2472 check_client_version(ctx
.obj
, ctx
.command
.name
)
2473 resp
= ctx
.obj
.wim
.get(name
)
2474 if 'password' in resp
:
2475 resp
['wim_password']='********'
2476 # except ClientException as e:
2480 table
= PrettyTable(['key', 'attribute'])
2481 for k
, v
in list(resp
.items()):
2482 table
.add_row([k
, json
.dumps(v
, indent
=2)])
2487 ####################
2488 # SDN controller operations
2489 ####################
2491 @cli_osm.command(name
='sdnc-create', short_help
='creates a new SDN controller')
2492 @click.option('--name',
2494 help='Name to create sdn controller')
2495 @click.option('--type',
2497 help='SDN controller type')
2498 @click.option('--sdn_controller_version', # hidden=True,
2499 help='Deprecated. Use --config {version: sdn_controller_version}')
2500 @click.option('--url',
2501 help='URL in format http[s]://HOST:IP/')
2502 @click.option('--ip_address', # hidden=True,
2503 help='Deprecated. Use --url')
2504 @click.option('--port', # hidden=True,
2505 help='Deprecated. Use --url')
2506 @click.option('--switch_dpid', # hidden=True,
2507 help='Deprecated. Use --config {dpid: DPID}')
2508 @click.option('--config',
2509 help='Extra information for SDN in yaml format, as {dpid: (Openflow Datapath ID), version: version}')
2510 @click.option('--user',
2511 help='SDN controller username')
2512 @click.option('--password',
2514 confirmation_prompt
=True,
2515 help='SDN controller password')
2516 @click.option('--description', default
=None, help='human readable description')
2517 @click.option('--wait',
2521 help="do not return the control immediately, but keep it until the operation is completed, or timeout")
2523 def sdnc_create(ctx
, **kwargs
):
2524 """creates a new SDN controller"""
2526 sdncontroller
= {x
: kwargs
[x
] for x
in kwargs
if kwargs
[x
] and
2527 x
not in ("wait", "ip_address", "port", "switch_dpid")}
2528 if kwargs
.get("port"):
2529 print("option '--port' is deprecated, use '-url' instead")
2530 sdncontroller
["port"] = int(kwargs
["port"])
2531 if kwargs
.get("ip_address"):
2532 print("option '--ip_address' is deprecated, use '-url' instead")
2533 sdncontroller
["ip"] = kwargs
["ip_address"]
2534 if kwargs
.get("switch_dpid"):
2535 print("option '--switch_dpid' is deprecated, use '---config={dpid: DPID}' instead")
2536 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
2537 if kwargs
.get("sdn_controller_version"):
2538 print("option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
2541 check_client_version(ctx
.obj
, ctx
.command
.name
)
2542 ctx
.obj
.sdnc
.create(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
2543 # except ClientException as e:
2547 @cli_osm.command(name
='sdnc-update', short_help
='updates an SDN controller')
2548 @click.argument('name')
2549 @click.option('--newname', help='New name for the SDN controller')
2550 @click.option('--description', default
=None, help='human readable description')
2551 @click.option('--type', help='SDN controller type')
2552 @click.option('--url', help='URL in format http[s]://HOST:IP/')
2553 @click.option('--config', help='Extra information for SDN in yaml format, as '
2554 '{dpid: (Openflow Datapath ID), version: version}')
2555 @click.option('--user', help='SDN controller username')
2556 @click.option('--password', help='SDN controller password')
2557 @click.option('--ip_address', help='Deprecated. Use --url') # hidden=True
2558 @click.option('--port', help='Deprecated. Use --url') # hidden=True
2559 @click.option('--switch_dpid', help='Deprecated. Use --config {switch_dpid: DPID}') # hidden=True
2560 @click.option('--sdn_controller_version', help='Deprecated. Use --config {version: VERSION}') # hidden=True
2561 @click.option('--wait', required
=False, default
=False, is_flag
=True,
2562 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2564 def sdnc_update(ctx
, **kwargs
):
2565 """updates an SDN controller
2567 NAME: name or ID of the SDN controller
2570 sdncontroller
= {x
: kwargs
[x
] for x
in kwargs
if kwargs
[x
] and
2571 x
not in ("wait", "ip_address", "port", "switch_dpid", "new_name")}
2572 if kwargs
.get("newname"):
2573 sdncontroller
["name"] = kwargs
["newname"]
2574 if kwargs
.get("port"):
2575 print("option '--port' is deprecated, use '-url' instead")
2576 sdncontroller
["port"] = int(kwargs
["port"])
2577 if kwargs
.get("ip_address"):
2578 print("option '--ip_address' is deprecated, use '-url' instead")
2579 sdncontroller
["ip"] = kwargs
["ip_address"]
2580 if kwargs
.get("switch_dpid"):
2581 print("option '--switch_dpid' is deprecated, use '---config={dpid: DPID}' instead")
2582 sdncontroller
["dpid"] = kwargs
["switch_dpid"]
2583 if kwargs
.get("sdn_controller_version"):
2584 print("option '--sdn_controller_version' is deprecated, use '---config={version: SDN_CONTROLLER_VERSION}'"
2588 check_client_version(ctx
.obj
, ctx
.command
.name
)
2589 ctx
.obj
.sdnc
.update(kwargs
["name"], sdncontroller
, wait
=kwargs
["wait"])
2590 # except ClientException as e:
2595 @cli_osm.command(name
='sdnc-delete', short_help
='deletes an SDN controller')
2596 @click.argument('name')
2597 @click.option('--force', is_flag
=True, help='forces the deletion bypassing pre-conditions')
2598 @click.option('--wait', required
=False, default
=False, is_flag
=True,
2599 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2601 def sdnc_delete(ctx
, name
, force
, wait
):
2602 """deletes an SDN controller
2604 NAME: name or ID of the SDN controller to be deleted
2608 check_client_version(ctx
.obj
, ctx
.command
.name
)
2609 ctx
.obj
.sdnc
.delete(name
, force
, wait
=wait
)
2610 # except ClientException as e:
2615 @cli_osm.command(name
='sdnc-list', short_help
='list all SDN controllers')
2616 @click.option('--filter', default
=None,
2617 help="restricts the list to the SDN controllers matching the filter with format: 'k[.k..]=v[&k[.k]=v2]'")
2619 def sdnc_list(ctx
, filter):
2620 """list all SDN controllers"""
2623 check_client_version(ctx
.obj
, ctx
.command
.name
)
2624 resp
= ctx
.obj
.sdnc
.list(filter)
2625 # except ClientException as e:
2628 table
= PrettyTable(['sdnc name', 'id'])
2630 table
.add_row([sdnc
['name'], sdnc
['_id']])
2635 @cli_osm.command(name
='sdnc-show', short_help
='shows the details of an SDN controller')
2636 @click.argument('name')
2638 def sdnc_show(ctx
, name
):
2639 """shows the details of an SDN controller
2641 NAME: name or ID of the SDN controller
2645 check_client_version(ctx
.obj
, ctx
.command
.name
)
2646 resp
= ctx
.obj
.sdnc
.get(name
)
2647 # except ClientException as e:
2651 table
= PrettyTable(['key', 'attribute'])
2652 for k
, v
in list(resp
.items()):
2653 table
.add_row([k
, json
.dumps(v
, indent
=2)])
2658 ###########################
2659 # K8s cluster operations
2660 ###########################
2662 @cli_osm.command(name
='k8scluster-add', short_help
='adds a K8s cluster to OSM')
2663 @click.argument('name')
2664 @click.option('--creds',
2666 help='credentials file, i.e. a valid `.kube/config` file')
2667 @click.option('--version',
2669 help='Kubernetes version')
2670 @click.option('--vim',
2672 help='VIM target, the VIM where the cluster resides')
2673 @click.option('--k8s-nets',
2675 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) ...]}"')
2676 @click.option('--description',
2678 help='human readable description')
2679 @click.option('--namespace',
2680 default
='kube-system',
2681 help='namespace to be used for its operation, defaults to `kube-system`')
2682 @click.option('--cni',
2684 help='list of CNI plugins, in JSON inline format, used in the cluster')
2685 #@click.option('--skip-init',
2687 # help='If set, K8s cluster is assumed to be ready for its use with OSM')
2688 #@click.option('--wait',
2690 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2692 def k8scluster_add(ctx
,
2701 """adds a K8s cluster to OSM
2703 NAME: name of the K8s cluster
2706 check_client_version(ctx
.obj
, ctx
.command
.name
)
2708 cluster
['name'] = name
2709 with
open(creds
, 'r') as cf
:
2710 cluster
['credentials'] = yaml
.safe_load(cf
.read())
2711 cluster
['k8s_version'] = version
2712 cluster
['vim_account'] = vim
2713 cluster
['nets'] = yaml
.safe_load(k8s_nets
)
2714 cluster
['description'] = description
2715 if namespace
: cluster
['namespace'] = namespace
2716 if cni
: cluster
['cni'] = yaml
.safe_load(cni
)
2717 ctx
.obj
.k8scluster
.create(name
, cluster
)
2718 # except ClientException as e:
2723 @cli_osm.command(name
='k8scluster-update', short_help
='updates a K8s cluster')
2724 @click.argument('name')
2725 @click.option('--newname', help='New name for the K8s cluster')
2726 @click.option('--creds', help='credentials file, i.e. a valid `.kube/config` file')
2727 @click.option('--version', help='Kubernetes version')
2728 @click.option('--vim', help='VIM target, the VIM where the cluster resides')
2729 @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) ...]}"')
2730 @click.option('--description', help='human readable description')
2731 @click.option('--namespace', help='namespace to be used for its operation, defaults to `kube-system`')
2732 @click.option('--cni', help='list of CNI plugins, in JSON inline format, used in the cluster')
2734 def k8scluster_update(ctx
,
2744 """updates a K8s cluster
2746 NAME: name or ID of the K8s cluster
2749 check_client_version(ctx
.obj
, ctx
.command
.name
)
2751 if newname
: cluster
['name'] = newname
2753 with
open(creds
, 'r') as cf
:
2754 cluster
['credentials'] = yaml
.safe_load(cf
.read())
2755 if version
: cluster
['k8s_version'] = version
2756 if vim
: cluster
['vim_account'] = vim
2757 if k8s_nets
: cluster
['nets'] = yaml
.safe_load(k8s_nets
)
2758 if description
: cluster
['description'] = description
2759 if namespace
: cluster
['namespace'] = namespace
2760 if cni
: cluster
['cni'] = yaml
.safe_load(cni
)
2761 ctx
.obj
.k8scluster
.update(name
, cluster
)
2762 # except ClientException as e:
2767 @cli_osm.command(name
='k8scluster-delete', short_help
='deletes a K8s cluster')
2768 @click.argument('name')
2769 @click.option('--force', is_flag
=True, help='forces the deletion from the DB (not recommended)')
2770 #@click.option('--wait',
2772 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2774 def k8scluster_delete(ctx
, name
, force
):
2775 """deletes a K8s cluster
2777 NAME: name or ID of the K8s cluster to be deleted
2780 check_client_version(ctx
.obj
, ctx
.command
.name
)
2781 ctx
.obj
.k8scluster
.delete(name
, force
=force
)
2782 # except ClientException as e:
2787 @cli_osm.command(name
='k8scluster-list')
2788 @click.option('--filter', default
=None,
2789 help='restricts the list to the K8s clusters matching the filter')
2790 @click.option('--literal', is_flag
=True,
2791 help='print literally, no pretty table')
2793 def k8scluster_list(ctx
, filter, literal
):
2794 """list all K8s clusters"""
2796 check_client_version(ctx
.obj
, ctx
.command
.name
)
2797 resp
= ctx
.obj
.k8scluster
.list(filter)
2799 print(yaml
.safe_dump(resp
))
2801 table
= PrettyTable(['Name', 'Id', 'Version', 'VIM', 'K8s-nets', 'Operational State', 'Description'])
2802 for cluster
in resp
:
2803 table
.add_row([cluster
['name'], cluster
['_id'], cluster
['k8s_version'], cluster
['vim_account'],
2804 json
.dumps(cluster
['nets']), cluster
["_admin"]["operationalState"],
2805 trunc_text(cluster
.get('description',''),40)])
2808 # except ClientException as e:
2813 @cli_osm.command(name
='k8scluster-show', short_help
='shows the details of a K8s cluster')
2814 @click.argument('name')
2815 @click.option('--literal', is_flag
=True,
2816 help='print literally, no pretty table')
2818 def k8scluster_show(ctx
, name
, literal
):
2819 """shows the details of a K8s cluster
2821 NAME: name or ID of the K8s cluster
2824 resp
= ctx
.obj
.k8scluster
.get(name
)
2826 print(yaml
.safe_dump(resp
))
2828 table
= PrettyTable(['key', 'attribute'])
2829 for k
, v
in list(resp
.items()):
2830 table
.add_row([k
, wrap_text(text
=json
.dumps(v
, indent
=2),width
=100)])
2833 # except ClientException as e:
2839 ###########################
2841 ###########################
2843 @cli_osm.command(name
='repo-add', short_help
='adds a repo to OSM')
2844 @click.argument('name')
2845 @click.argument('uri')
2846 @click.option('--type',
2847 type=click
.Choice(['helm-chart', 'juju-bundle']),
2849 help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
2850 @click.option('--description',
2852 help='human readable description')
2853 #@click.option('--wait',
2855 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2862 """adds a repo to OSM
2864 NAME: name of the repo
2865 URI: URI of the repo
2868 check_client_version(ctx
.obj
, ctx
.command
.name
)
2873 repo
['description'] = description
2874 ctx
.obj
.repo
.create(name
, repo
)
2875 # except ClientException as e:
2880 @cli_osm.command(name
='repo-update', short_help
='updates a repo in OSM')
2881 @click.argument('name')
2882 @click.option('--newname', help='New name for the repo')
2883 @click.option('--uri', help='URI of the repo')
2884 @click.option('--type', type=click
.Choice(['helm-chart', 'juju-bundle']),
2885 help='type of repo (helm-chart for Helm Charts, juju-bundle for Juju Bundles)')
2886 @click.option('--description', help='human readable description')
2887 #@click.option('--wait',
2889 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2891 def repo_update(ctx
,
2897 """updates a repo in OSM
2899 NAME: name of the repo
2902 check_client_version(ctx
.obj
, ctx
.command
.name
)
2904 if newname
: repo
['name'] = newname
2905 if uri
: repo
['uri'] = uri
2906 if type: repo
['type'] = type
2907 if description
: repo
['description'] = description
2908 ctx
.obj
.repo
.update(name
, repo
)
2909 # except ClientException as e:
2914 @cli_osm.command(name
='repo-delete', short_help
='deletes a repo')
2915 @click.argument('name')
2916 @click.option('--force', is_flag
=True, help='forces the deletion from the DB (not recommended)')
2917 #@click.option('--wait',
2919 # help='do not return the control immediately, but keep it until the operation is completed, or timeout')
2921 def repo_delete(ctx
, name
, force
):
2924 NAME: name or ID of the repo to be deleted
2927 check_client_version(ctx
.obj
, ctx
.command
.name
)
2928 ctx
.obj
.repo
.delete(name
, force
=force
)
2929 # except ClientException as e:
2934 @cli_osm.command(name
='repo-list')
2935 @click.option('--filter', default
=None,
2936 help='restricts the list to the repos matching the filter')
2937 @click.option('--literal', is_flag
=True,
2938 help='print literally, no pretty table')
2940 def repo_list(ctx
, filter, literal
):
2941 """list all repos"""
2943 check_client_version(ctx
.obj
, ctx
.command
.name
)
2944 resp
= ctx
.obj
.repo
.list(filter)
2946 print(yaml
.safe_dump(resp
))
2948 table
= PrettyTable(['Name', 'Id', 'Type', 'URI', 'Description'])
2950 #cluster['k8s-nets'] = json.dumps(yaml.safe_load(cluster['k8s-nets']))
2951 table
.add_row([repo
['name'], repo
['_id'], repo
['type'], repo
['url'], trunc_text(repo
.get('description',''),40)])
2954 # except ClientException as e:
2959 @cli_osm.command(name
='repo-show', short_help
='shows the details of a repo')
2960 @click.argument('name')
2961 @click.option('--literal', is_flag
=True,
2962 help='print literally, no pretty table')
2964 def repo_show(ctx
, name
, literal
):
2965 """shows the details of a repo
2967 NAME: name or ID of the repo
2970 resp
= ctx
.obj
.repo
.get(name
)
2972 print(yaml
.safe_dump(resp
))
2974 table
= PrettyTable(['key', 'attribute'])
2975 for k
, v
in list(resp
.items()):
2976 table
.add_row([k
, json
.dumps(v
, indent
=2)])
2979 # except ClientException as e:
2985 ####################
2986 # Project mgmt operations
2987 ####################
2989 @cli_osm.command(name
='project-create', short_help
='creates a new project')
2990 @click.argument('name')
2991 #@click.option('--description',
2992 # default='no description',
2993 # help='human readable description')
2994 @click.option('--domain-name', 'domain_name',
2996 help='assign to a domain')
2998 def project_create(ctx
, name
, domain_name
):
2999 """Creates a new project
3001 NAME: name of the project
3002 DOMAIN_NAME: optional domain name for the project when keystone authentication is used
3006 project
['name'] = name
3008 project
['domain_name'] = domain_name
3010 check_client_version(ctx
.obj
, ctx
.command
.name
)
3011 ctx
.obj
.project
.create(name
, project
)
3012 # except ClientException as e:
3017 @cli_osm.command(name
='project-delete', short_help
='deletes a project')
3018 @click.argument('name')
3019 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3021 def project_delete(ctx
, name
):
3022 """deletes a project
3024 NAME: name or ID of the project to be deleted
3028 check_client_version(ctx
.obj
, ctx
.command
.name
)
3029 ctx
.obj
.project
.delete(name
)
3030 # except ClientException as e:
3035 @cli_osm.command(name
='project-list', short_help
='list all projects')
3036 @click.option('--filter', default
=None,
3037 help='restricts the list to the projects matching the filter')
3039 def project_list(ctx
, filter):
3040 """list all projects"""
3043 check_client_version(ctx
.obj
, ctx
.command
.name
)
3044 resp
= ctx
.obj
.project
.list(filter)
3045 # except ClientException as e:
3048 table
= PrettyTable(['name', 'id'])
3050 table
.add_row([proj
['name'], proj
['_id']])
3055 @cli_osm.command(name
='project-show', short_help
='shows the details of a project')
3056 @click.argument('name')
3058 def project_show(ctx
, name
):
3059 """shows the details of a project
3061 NAME: name or ID of the project
3065 check_client_version(ctx
.obj
, ctx
.command
.name
)
3066 resp
= ctx
.obj
.project
.get(name
)
3067 # except ClientException as e:
3071 table
= PrettyTable(['key', 'attribute'])
3072 for k
, v
in resp
.items():
3073 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3078 @cli_osm.command(name
='project-update', short_help
='updates a project (only the name can be updated)')
3079 @click.argument('project')
3080 @click.option('--name',
3082 help='new name for the project')
3085 def project_update(ctx
, project
, name
):
3087 Update a project name
3090 :param project: id or name of the project to modify
3091 :param name: new name for the project
3095 project_changes
= {}
3096 project_changes
['name'] = name
3099 check_client_version(ctx
.obj
, ctx
.command
.name
)
3100 ctx
.obj
.project
.update(project
, project_changes
)
3101 # except ClientException as e:
3105 ####################
3106 # User mgmt operations
3107 ####################
3109 @cli_osm.command(name
='user-create', short_help
='creates a new user')
3110 @click.argument('username')
3111 @click.option('--password',
3114 confirmation_prompt
=True,
3115 help='user password')
3116 @click.option('--projects',
3117 # prompt="Comma separate list of projects",
3119 callback
=lambda ctx
, param
, value
: ''.join(value
).split(',') if all(len(x
)==1 for x
in value
) else value
,
3120 help='list of project ids that the user belongs to')
3121 @click.option('--project-role-mappings', 'project_role_mappings',
3122 default
=None, multiple
=True,
3123 help='creating user project/role(s) mapping')
3124 @click.option('--domain-name', 'domain_name',
3126 help='assign to a domain')
3128 def user_create(ctx
, username
, password
, projects
, project_role_mappings
, domain_name
):
3129 """Creates a new user
3132 USERNAME: name of the user
3133 PASSWORD: password of the user
3134 PROJECTS: projects assigned to user (internal only)
3135 PROJECT_ROLE_MAPPING: roles in projects assigned to user (keystone)
3136 DOMAIN_NAME: optional domain name for the user when keystone authentication is used
3140 user
['username'] = username
3141 user
['password'] = password
3142 user
['projects'] = projects
3143 user
['project_role_mappings'] = project_role_mappings
3145 user
['domain_name'] = domain_name
3148 check_client_version(ctx
.obj
, ctx
.command
.name
)
3149 ctx
.obj
.user
.create(username
, user
)
3150 # except ClientException as e:
3155 @cli_osm.command(name
='user-update', short_help
='updates user information')
3156 @click.argument('username')
3157 @click.option('--password',
3160 # confirmation_prompt=True,
3161 help='user password')
3162 @click.option('--set-username', 'set_username',
3164 help='change username')
3165 @click.option('--set-project', 'set_project',
3166 default
=None, multiple
=True,
3167 help='create/replace the project,role(s) mapping for this project: \'project,role1,role2,...\'')
3168 @click.option('--remove-project', 'remove_project',
3169 default
=None, multiple
=True,
3170 help='removes project from user: \'project\'')
3171 @click.option('--add-project-role', 'add_project_role',
3172 default
=None, multiple
=True,
3173 help='adds project,role(s) mapping: \'project,role1,role2,...\'')
3174 @click.option('--remove-project-role', 'remove_project_role',
3175 default
=None, multiple
=True,
3176 help='removes project,role(s) mapping: \'project,role1,role2,...\'')
3178 def user_update(ctx
, username
, password
, set_username
, set_project
, remove_project
,
3179 add_project_role
, remove_project_role
):
3180 """Update a user information
3183 USERNAME: name of the user
3184 PASSWORD: new password
3185 SET_USERNAME: new username
3186 SET_PROJECT: creating mappings for project/role(s)
3187 REMOVE_PROJECT: deleting mappings for project/role(s)
3188 ADD_PROJECT_ROLE: adding mappings for project/role(s)
3189 REMOVE_PROJECT_ROLE: removing mappings for project/role(s)
3193 user
['password'] = password
3194 user
['username'] = set_username
3195 user
['set-project'] = set_project
3196 user
['remove-project'] = remove_project
3197 user
['add-project-role'] = add_project_role
3198 user
['remove-project-role'] = remove_project_role
3201 check_client_version(ctx
.obj
, ctx
.command
.name
)
3202 ctx
.obj
.user
.update(username
, user
)
3203 # except ClientException as e:
3208 @cli_osm.command(name
='user-delete', short_help
='deletes a user')
3209 @click.argument('name')
3210 #@click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3212 def user_delete(ctx
, name
):
3216 NAME: name or ID of the user to be deleted
3220 check_client_version(ctx
.obj
, ctx
.command
.name
)
3221 ctx
.obj
.user
.delete(name
)
3222 # except ClientException as e:
3227 @cli_osm.command(name
='user-list', short_help
='list all users')
3228 @click.option('--filter', default
=None,
3229 help='restricts the list to the users matching the filter')
3231 def user_list(ctx
, filter):
3232 """list all users"""
3234 check_client_version(ctx
.obj
, ctx
.command
.name
)
3235 resp
= ctx
.obj
.user
.list(filter)
3236 # except ClientException as e:
3239 table
= PrettyTable(['name', 'id'])
3241 table
.add_row([user
['username'], user
['_id']])
3246 @cli_osm.command(name
='user-show', short_help
='shows the details of a user')
3247 @click.argument('name')
3249 def user_show(ctx
, name
):
3250 """shows the details of a user
3252 NAME: name or ID of the user
3256 check_client_version(ctx
.obj
, ctx
.command
.name
)
3257 resp
= ctx
.obj
.user
.get(name
)
3258 if 'password' in resp
:
3259 resp
['password']='********'
3260 # except ClientException as e:
3264 table
= PrettyTable(['key', 'attribute'])
3265 for k
, v
in resp
.items():
3266 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3271 ####################
3272 # Fault Management operations
3273 ####################
3275 @cli_osm.command(name
='ns-alarm-create')
3276 @click.argument('name')
3277 @click.option('--ns', prompt
=True, help='NS instance id or name')
3278 @click.option('--vnf', prompt
=True,
3279 help='VNF name (VNF member index as declared in the NSD)')
3280 @click.option('--vdu', prompt
=True,
3281 help='VDU name (VDU name as declared in the VNFD)')
3282 @click.option('--metric', prompt
=True,
3283 help='Name of the metric (e.g. cpu_utilization)')
3284 @click.option('--severity', default
='WARNING',
3285 help='severity of the alarm (WARNING, MINOR, MAJOR, CRITICAL, INDETERMINATE)')
3286 @click.option('--threshold_value', prompt
=True,
3287 help='threshold value that, when crossed, an alarm is triggered')
3288 @click.option('--threshold_operator', prompt
=True,
3289 help='threshold operator describing the comparison (GE, LE, GT, LT, EQ)')
3290 @click.option('--statistic', default
='AVERAGE',
3291 help='statistic (AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM)')
3293 def ns_alarm_create(ctx
, name
, ns
, vnf
, vdu
, metric
, severity
,
3294 threshold_value
, threshold_operator
, statistic
):
3295 """creates a new alarm for a NS instance"""
3296 # TODO: Check how to validate threshold_value.
3297 # Should it be an integer (1-100), percentage, or decimal (0.01-1.00)?
3300 ns_instance
= ctx
.obj
.ns
.get(ns
)
3302 alarm
['alarm_name'] = name
3303 alarm
['ns_id'] = ns_instance
['_id']
3304 alarm
['correlation_id'] = ns_instance
['_id']
3305 alarm
['vnf_member_index'] = vnf
3306 alarm
['vdu_name'] = vdu
3307 alarm
['metric_name'] = metric
3308 alarm
['severity'] = severity
3309 alarm
['threshold_value'] = int(threshold_value
)
3310 alarm
['operation'] = threshold_operator
3311 alarm
['statistic'] = statistic
3312 check_client_version(ctx
.obj
, ctx
.command
.name
)
3313 ctx
.obj
.ns
.create_alarm(alarm
)
3314 # except ClientException as e:
3319 #@cli_osm.command(name='ns-alarm-delete')
3320 #@click.argument('name')
3321 #@click.pass_context
3322 #def ns_alarm_delete(ctx, name):
3323 # """deletes an alarm
3325 # NAME: name of the alarm to be deleted
3328 # check_client_version(ctx.obj, ctx.command.name)
3329 # ctx.obj.ns.delete_alarm(name)
3330 # except ClientException as e:
3335 ####################
3336 # Performance Management operations
3337 ####################
3339 @cli_osm.command(name
='ns-metric-export', short_help
='exports a metric to the internal OSM bus, which can be read by other apps')
3340 @click.option('--ns', prompt
=True, help='NS instance id or name')
3341 @click.option('--vnf', prompt
=True,
3342 help='VNF name (VNF member index as declared in the NSD)')
3343 @click.option('--vdu', prompt
=True,
3344 help='VDU name (VDU name as declared in the VNFD)')
3345 @click.option('--metric', prompt
=True,
3346 help='name of the metric (e.g. cpu_utilization)')
3347 #@click.option('--period', default='1w',
3348 # help='metric collection period (e.g. 20s, 30m, 2h, 3d, 1w)')
3349 @click.option('--interval', help='periodic interval (seconds) to export metrics continuously')
3351 def ns_metric_export(ctx
, ns
, vnf
, vdu
, metric
, interval
):
3352 """exports a metric to the internal OSM bus, which can be read by other apps"""
3353 # TODO: Check how to validate interval.
3354 # Should it be an integer (seconds), or should a suffix (s,m,h,d,w) also be permitted?
3357 ns_instance
= ctx
.obj
.ns
.get(ns
)
3359 metric_data
['ns_id'] = ns_instance
['_id']
3360 metric_data
['correlation_id'] = ns_instance
['_id']
3361 metric_data
['vnf_member_index'] = vnf
3362 metric_data
['vdu_name'] = vdu
3363 metric_data
['metric_name'] = metric
3364 metric_data
['collection_unit'] = 'WEEK'
3365 metric_data
['collection_period'] = 1
3366 check_client_version(ctx
.obj
, ctx
.command
.name
)
3368 print('{}'.format(ctx
.obj
.ns
.export_metric(metric_data
)))
3372 print('{} {}'.format(ctx
.obj
.ns
.export_metric(metric_data
),i
))
3373 time
.sleep(int(interval
))
3375 # except ClientException as e:
3380 ####################
3382 ####################
3384 @cli_osm.command(name
='version', short_help
='shows client and server versions')
3386 def get_version(ctx
):
3387 """shows client and server versions"""
3389 check_client_version(ctx
.obj
, "version")
3390 print ("Server version: {}".format(ctx
.obj
.get_version()))
3391 print ("Client version: {}".format(pkg_resources
.get_distribution("osmclient").version
))
3392 # except ClientException as e:
3396 @cli_osm.command(name
='upload-package', short_help
='uploads a VNF package or NS package')
3397 @click.argument('filename')
3398 @click.option('--skip-charm-build', default
=False, is_flag
=True,
3399 help='the charm will not be compiled, it is assumed to already exist')
3401 def upload_package(ctx
, filename
, skip_charm_build
):
3402 """uploads a vnf package or ns package
3404 filename: vnf or ns package folder, or vnf or ns package file (tar.gz)
3408 ctx
.obj
.package
.upload(filename
, skip_charm_build
=skip_charm_build
)
3409 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
3410 if fullclassname
!= 'osmclient.sol005.client.Client':
3411 ctx
.obj
.package
.wait_for_upload(filename
)
3412 # except ClientException as e:
3417 #@cli_osm.command(name='ns-scaling-show')
3418 #@click.argument('ns_name')
3419 #@click.pass_context
3420 #def show_ns_scaling(ctx, ns_name):
3421 # """shows the status of a NS scaling operation
3423 # NS_NAME: name of the NS instance being scaled
3426 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3427 # resp = ctx.obj.ns.list()
3428 # except ClientException as e:
3432 # table = PrettyTable(
3435 # 'operational status',
3440 # if ns_name == ns['name']:
3441 # nsopdata = ctx.obj.ns.get_opdata(ns['id'])
3442 # scaling_records = nsopdata['nsr:nsr']['scaling-group-record']
3443 # for record in scaling_records:
3444 # if 'instance' in record:
3445 # instances = record['instance']
3446 # for inst in instances:
3448 # [record['scaling-group-name-ref'],
3449 # inst['instance-id'],
3450 # inst['op-status'],
3451 # time.strftime('%Y-%m-%d %H:%M:%S',
3453 # inst['create-time'])),
3459 #@cli_osm.command(name='ns-scale')
3460 #@click.argument('ns_name')
3461 #@click.option('--ns_scale_group', prompt=True)
3462 #@click.option('--index', prompt=True)
3463 #@click.option('--wait',
3467 # help='do not return the control immediately, but keep it \
3468 # until the operation is completed, or timeout')
3469 #@click.pass_context
3470 #def ns_scale(ctx, ns_name, ns_scale_group, index, wait):
3473 # NS_NAME: name of the NS instance to be scaled
3476 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3477 # ctx.obj.ns.scale(ns_name, ns_scale_group, index, wait=wait)
3478 # except ClientException as e:
3483 #@cli_osm.command(name='config-agent-list')
3484 #@click.pass_context
3485 #def config_agent_list(ctx):
3486 # """list config agents"""
3488 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3489 # except ClientException as e:
3492 # table = PrettyTable(['name', 'account-type', 'details'])
3493 # for account in ctx.obj.vca.list():
3496 # account['account-type'],
3502 #@cli_osm.command(name='config-agent-delete')
3503 #@click.argument('name')
3504 #@click.pass_context
3505 #def config_agent_delete(ctx, name):
3506 # """deletes a config agent
3508 # NAME: name of the config agent to be deleted
3511 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3512 # ctx.obj.vca.delete(name)
3513 # except ClientException as e:
3518 #@cli_osm.command(name='config-agent-add')
3519 #@click.option('--name',
3521 #@click.option('--account_type',
3523 #@click.option('--server',
3525 #@click.option('--user',
3527 #@click.option('--secret',
3530 # confirmation_prompt=True)
3531 #@click.pass_context
3532 #def config_agent_add(ctx, name, account_type, server, user, secret):
3533 # """adds a config agent"""
3535 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3536 # ctx.obj.vca.create(name, account_type, server, user, secret)
3537 # except ClientException as e:
3542 #@cli_osm.command(name='ro-dump')
3543 #@click.pass_context
3545 # """shows RO agent information"""
3546 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3547 # resp = ctx.obj.vim.get_resource_orchestrator()
3548 # table = PrettyTable(['key', 'attribute'])
3549 # for k, v in list(resp.items()):
3550 # table.add_row([k, json.dumps(v, indent=2)])
3555 #@cli_osm.command(name='vcs-list')
3556 #@click.pass_context
3558 # check_client_version(ctx.obj, ctx.command.name, 'v1')
3559 # resp = ctx.obj.utils.get_vcs_info()
3560 # table = PrettyTable(['component name', 'state'])
3561 # for component in resp:
3562 # table.add_row([component['component_name'], component['state']])
3567 @cli_osm.command(name
='ns-action', short_help
='executes an action/primitive over a NS instance')
3568 @click.argument('ns_name')
3569 @click.option('--vnf_name', default
=None, help='member-vnf-index if the target is a vnf instead of a ns)')
3570 @click.option('--kdu_name', default
=None, help='kdu-name if the target is a kdu)')
3571 @click.option('--vdu_id', default
=None, help='vdu-id if the target is a vdu')
3572 @click.option('--vdu_count', default
=None, help='number of vdu instance of this vdu_id')
3573 @click.option('--action_name', prompt
=True, help='action name')
3574 @click.option('--params', default
=None, help='action params in YAML/JSON inline string')
3575 @click.option('--params_file', default
=None, help='YAML/JSON file with action params')
3576 @click.option('--wait',
3580 help='do not return the control immediately, but keep it until the operation is completed, or timeout')
3592 """executes an action/primitive over a NS instance
3594 NS_NAME: name or ID of the NS instance
3598 check_client_version(ctx
.obj
, ctx
.command
.name
)
3601 op_data
['member_vnf_index'] = vnf_name
3603 op_data
['kdu_name'] = kdu_name
3605 op_data
['vdu_id'] = vdu_id
3607 op_data
['vdu_count_index'] = vdu_count
3608 op_data
['primitive'] = action_name
3610 with
open(params_file
, 'r') as pf
:
3613 op_data
['primitive_params'] = yaml
.safe_load(params
)
3615 op_data
['primitive_params'] = {}
3616 print(ctx
.obj
.ns
.exec_op(ns_name
, op_name
='action', op_data
=op_data
, wait
=wait
))
3618 # except ClientException as e:
3623 @cli_osm.command(name
='vnf-scale', short_help
='executes a VNF scale (adding/removing VDUs)')
3624 @click.argument('ns_name')
3625 @click.argument('vnf_name')
3626 @click.option('--scaling-group', prompt
=True, help="scaling-group-descriptor name to use")
3627 @click.option('--scale-in', default
=False, is_flag
=True, help="performs a scale in operation")
3628 @click.option('--scale-out', default
=False, is_flag
=True, help="performs a scale out operation (by default)")
3637 Executes a VNF scale (adding/removing VDUs)
3640 NS_NAME: name or ID of the NS instance.
3641 VNF_NAME: member-vnf-index in the NS to be scaled.
3645 check_client_version(ctx
.obj
, ctx
.command
.name
)
3646 if not scale_in
and not scale_out
:
3648 ctx
.obj
.ns
.scale_vnf(ns_name
, vnf_name
, scaling_group
, scale_in
, scale_out
)
3649 # except ClientException as e:
3654 ##############################
3655 # Role Management Operations #
3656 ##############################
3658 @cli_osm.command(name
='role-create', short_help
='creates a new role')
3659 @click.argument('name')
3660 @click.option('--permissions',
3662 help='role permissions using a dictionary')
3664 def role_create(ctx
, name
, permissions
):
3669 NAME: Name or ID of the role.
3670 DEFINITION: Definition of grant/denial of access to resources.
3674 check_client_version(ctx
.obj
, ctx
.command
.name
)
3675 ctx
.obj
.role
.create(name
, permissions
)
3676 # except ClientException as e:
3681 @cli_osm.command(name
='role-update', short_help
='updates a role')
3682 @click.argument('name')
3683 @click.option('--set-name',
3685 help='change name of rle')
3686 # @click.option('--permissions',
3688 # help='provide a yaml format dictionary with incremental changes. Values can be bool or None to delete')
3689 @click.option('--add',
3691 help='yaml format dictionary with permission: True/False to access grant/denial')
3692 @click.option('--remove',
3694 help='yaml format list to remove a permission')
3696 def role_update(ctx
, name
, set_name
, add
, remove
):
3701 NAME: Name or ID of the role.
3702 DEFINITION: Definition overwrites the old definition.
3703 ADD: Grant/denial of access to resource to add.
3704 REMOVE: Grant/denial of access to resource to remove.
3708 check_client_version(ctx
.obj
, ctx
.command
.name
)
3709 ctx
.obj
.role
.update(name
, set_name
, None, add
, remove
)
3710 # except ClientException as e:
3715 @cli_osm.command(name
='role-delete', short_help
='deletes a role')
3716 @click.argument('name')
3717 # @click.option('--force', is_flag=True, help='forces the deletion bypassing pre-conditions')
3719 def role_delete(ctx
, name
):
3724 NAME: Name or ID of the role.
3728 check_client_version(ctx
.obj
, ctx
.command
.name
)
3729 ctx
.obj
.role
.delete(name
)
3730 # except ClientException as e:
3735 @cli_osm.command(name
='role-list', short_help
='list all roles')
3736 @click.option('--filter', default
=None,
3737 help='restricts the list to the projects matching the filter')
3739 def role_list(ctx
, filter):
3745 check_client_version(ctx
.obj
, ctx
.command
.name
)
3746 resp
= ctx
.obj
.role
.list(filter)
3747 # except ClientException as e:
3750 table
= PrettyTable(['name', 'id'])
3752 table
.add_row([role
['name'], role
['_id']])
3757 @cli_osm.command(name
='role-show', short_help
='show specific role')
3758 @click.argument('name')
3760 def role_show(ctx
, name
):
3762 Shows the details of a role.
3765 NAME: Name or ID of the role.
3769 check_client_version(ctx
.obj
, ctx
.command
.name
)
3770 resp
= ctx
.obj
.role
.get(name
)
3771 # except ClientException as e:
3775 table
= PrettyTable(['key', 'attribute'])
3776 for k
, v
in resp
.items():
3777 table
.add_row([k
, json
.dumps(v
, indent
=2)])
3782 @cli_osm.command(name
='package-create',
3783 short_help
='Create a package descriptor')
3784 @click.argument('package-type')
3785 @click.argument('package-name')
3786 @click.option('--base-directory',
3788 help=('(NS/VNF/NST) Set the location for package creation. Default: "."'))
3789 @click.option('--image',
3790 default
="image-name",
3791 help='(VNF) Set the name of the vdu image. Default "image-name"')
3792 @click.option('--vdus',
3794 help='(VNF) Set the number of vdus in a VNF. Default 1')
3795 @click.option('--vcpu',
3797 help='(VNF) Set the number of virtual CPUs in a vdu. Default 1')
3798 @click.option('--memory',
3800 help='(VNF) Set the memory size (MB) of the vdu. Default 1024')
3801 @click.option('--storage',
3803 help='(VNF) Set the disk size (GB) of the vdu. Default 10')
3804 @click.option('--interfaces',
3806 help='(VNF) Set the number of additional interfaces apart from the management interface. Default 0')
3807 @click.option('--vendor',
3809 help='(NS/VNF) Set the descriptor vendor. Default "OSM"')
3810 @click.option('--override',
3813 help='(NS/VNF/NST) Flag for overriding the package if exists.')
3814 @click.option('--detailed',
3817 help='(NS/VNF/NST) Flag for generating descriptor .yaml with all possible commented options')
3818 @click.option('--netslice-subnets',
3820 help='(NST) Number of netslice subnets. Default 1')
3821 @click.option('--netslice-vlds',
3823 help='(NST) Number of netslice vlds. Default 1')
3825 def package_create(ctx
,
3841 Creates an OSM NS, VNF, NST package
3844 PACKAGE_TYPE: Package to be created: NS, VNF or NST.
3845 PACKAGE_NAME: Name of the package to create the folder with the content.
3849 check_client_version(ctx
.obj
, ctx
.command
.name
)
3850 print("Creating the {} structure: {}/{}".format(package_type
.upper(), base_directory
, package_name
))
3851 resp
= ctx
.obj
.package_tool
.create(package_type
,
3860 interfaces
=interfaces
,
3863 netslice_subnets
=netslice_subnets
,
3864 netslice_vlds
=netslice_vlds
)
3866 # except ClientException as inst:
3867 # print("ERROR: {}".format(inst))
3870 @cli_osm.command(name
='package-validate',
3871 short_help
='Validate a package descriptor')
3872 @click.argument('base-directory',
3875 @click.option('--recursive/--no-recursive',
3877 help='The activated recursive option will validate the yaml files'
3878 ' within the indicated directory and in its subdirectories')
3880 def package_validate(ctx
,
3884 Validate descriptors given a base directory.
3887 BASE_DIRECTORY: Stub folder for NS, VNF or NST package.
3890 check_client_version(ctx
.obj
, ctx
.command
.name
)
3891 results
= ctx
.obj
.package_tool
.validate(base_directory
, recursive
)
3892 table
= PrettyTable()
3893 table
.field_names
= ["TYPE", "PATH", "VALID", "ERROR"]
3894 # Print the dictionary generated by the validation function
3895 for result
in results
:
3896 table
.add_row([result
["type"], result
["path"], result
["valid"], result
["error"]])
3897 table
.sortby
= "VALID"
3898 table
.align
["PATH"] = "l"
3899 table
.align
["TYPE"] = "l"
3900 table
.align
["ERROR"] = "l"
3902 # except ClientException as inst:
3903 # print("ERROR: {}".format(inst))
3906 @cli_osm.command(name
='package-build',
3907 short_help
='Build the tar.gz of the package')
3908 @click.argument('package-folder')
3909 @click.option('--skip-validation',
3912 help='skip package validation')
3913 @click.option('--skip-charm-build', default
=False, is_flag
=True,
3914 help='the charm will not be compiled, it is assumed to already exist')
3916 def package_build(ctx
,
3921 Build the package NS, VNF given the package_folder.
3924 PACKAGE_FOLDER: Folder of the NS, VNF or NST to be packaged
3927 check_client_version(ctx
.obj
, ctx
.command
.name
)
3928 results
= ctx
.obj
.package_tool
.build(package_folder
,
3929 skip_validation
=skip_validation
,
3930 skip_charm_build
=skip_charm_build
)
3932 # except ClientException as inst:
3933 # print("ERROR: {}".format(inst))
3941 except pycurl
.error
as exc
:
3943 print('Maybe "--hostname" option or OSM_HOSTNAME environment variable needs to be specified')
3944 except ClientException
as exc
:
3945 print("ERROR: {}".format(exc
))
3946 except (FileNotFoundError
, PermissionError
) as exc
:
3947 print("Cannot open file: {}".format(exc
))
3948 except yaml
.YAMLError
as exc
:
3949 print("Invalid YAML format: {}".format(exc
))
3951 # TODO capture other controlled exceptions here
3952 # TODO remove the ClientException captures from all places, unless they do something different
3955 if __name__
== '__main__':