1 # Copyright ETSI Contributors and Others.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
17 from osmclient
.common
.exceptions
import ClientException
18 from osmclient
.common
import print_output
19 from osmclient
.cli_commands
import utils
20 from prettytable
import PrettyTable
23 from datetime
import datetime
26 logger
= logging
.getLogger("osmclient")
29 @click.command(name
="ns-list", short_help
="list all NS instances")
34 help="restricts the list to the NS instances matching the filter.",
39 help="get more details of the NS (project, vim, deployment status, configuration status.",
41 @print_output.output_option
43 def ns_list(ctx
, filter, long, output
):
44 """list all NS instances
48 --filter filterExpr Restricts the list to the NS instances matching the filter
51 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
52 concatenated using the "&" character:
55 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
56 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
57 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
63 * zero or more occurrences
64 ? zero or one occurrence
65 [] grouping of expressions to be used with ? and *
66 "" quotation marks for marking string constants
70 "AttrName" is the name of one attribute in the data type that defines the representation
71 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
72 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
73 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
74 entries, it means that the operator "op" is applied to the attribute addressed by the last
75 <attrName> entry included in the concatenation. All simple filter expressions are combined
76 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
77 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
78 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
79 prefix". If an attribute referenced in an expression is an array, an object that contains a
80 corresponding array shall be considered to match the expression if any of the elements in the
81 array matches all expressions that have the same attribute prefix.
85 --filter admin-status=ENABLED
86 --filter nsd-ref=<NSD_NAME>
87 --filter nsd.vendor=<VENDOR>
88 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
89 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
92 def summarize_deployment_status(status_dict
):
99 net_list
= status_dict
.get("nets", [])
102 if net
["status"] not in status_nets
:
103 status_nets
[net
["status"]] = 1
105 status_nets
[net
["status"]] += 1
107 for k
, v
in status_nets
.items():
108 message
+= "{}:{},".format(k
, v
)
109 message
+= "TOTAL:{}".format(n_nets
)
110 summary
+= "{}".format(message
)
115 vnf_list
= status_dict
["vnfs"]
117 member_vnf_index
= vnf
["member_vnf_index"]
118 if member_vnf_index
not in status_vnfs
:
119 status_vnfs
[member_vnf_index
] = {}
120 for vm
in vnf
["vms"]:
122 if vm
["status"] not in status_vms
:
123 status_vms
[vm
["status"]] = 1
125 status_vms
[vm
["status"]] += 1
126 if vm
["status"] not in status_vnfs
[member_vnf_index
]:
127 status_vnfs
[member_vnf_index
][vm
["status"]] = 1
129 status_vnfs
[member_vnf_index
][vm
["status"]] += 1
131 for k
, v
in status_vms
.items():
132 message
+= "{}:{},".format(k
, v
)
133 message
+= "TOTAL:{}".format(n_vms
)
134 summary
+= "\n{}".format(message
)
136 for k
, v
in status_vnfs
.items():
138 message
= "\n {} VMs: ".format(k
)
139 for k2
, v2
in v
.items():
140 message
+= "{}:{},".format(k2
, v2
)
142 message
+= "TOTAL:{}".format(total
)
146 def summarize_config_status(ee_list
):
154 if ee
["elementType"] not in status_ee
:
155 status_ee
[ee
["elementType"]] = {}
156 status_ee
[ee
["elementType"]][ee
["status"]] = 1
158 if ee
["status"] in status_ee
[ee
["elementType"]]:
159 status_ee
[ee
["elementType"]][ee
["status"]] += 1
161 status_ee
[ee
["elementType"]][ee
["status"]] = 1
162 for elementType
in ["KDU", "VDU", "PDU", "VNF", "NS"]:
163 if elementType
in status_ee
:
166 for k
, v
in status_ee
[elementType
].items():
167 message
+= "{}:{},".format(k
, v
)
169 message
+= "TOTAL:{}\n".format(total
)
170 summary
+= "{}: {}".format(elementType
, message
)
171 summary
+= "TOTAL Exec. Env.: {}".format(n_ee
)
176 utils
.check_client_version(ctx
.obj
, "--filter")
177 filter = "&".join(filter)
178 resp
= ctx
.obj
.ns
.list(filter)
180 resp
= ctx
.obj
.ns
.list()
193 "configuration status",
196 project_list
= ctx
.obj
.project
.list()
198 vim_list
= ctx
.obj
.vim
.list()
213 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
214 if fullclassname
== "osmclient.sol005.client.Client":
216 logger
.debug("NS info: {}".format(nsr
))
217 nsr_name
= nsr
["name"]
219 date
= datetime
.fromtimestamp(nsr
["create-time"]).strftime(
222 ns_state
= nsr
.get("nsState", nsr
["_admin"]["nsState"])
224 deployment_status
= summarize_deployment_status(
225 nsr
.get("deploymentStatus")
227 config_status
= summarize_config_status(nsr
.get("configurationStatus"))
228 project_id
, project_name
= utils
.get_project(project_list
, nsr
)
229 # project = '{} ({})'.format(project_name, project_id)
230 project
= project_name
231 vim_id
= nsr
.get("datacenter")
232 vim_name
= utils
.get_vim_name(vim_list
, vim_id
)
234 # vim = '{} ({})'.format(vim_name, vim_id)
236 if "currentOperation" in nsr
:
237 current_operation
= "{} ({})".format(
238 nsr
["currentOperation"], nsr
["currentOperationID"]
241 current_operation
= "{} ({})".format(
242 nsr
["_admin"].get("current-operation", "-"),
243 nsr
["_admin"]["nslcmop"],
245 error_details
= "N/A"
248 or ns_state
== "DEGRADED"
249 or ("currentOperation" not in nsr
and nsr
.get("errorDescription"))
251 error_details
= "{}\nDetail: {}".format(
252 nsr
["errorDescription"], nsr
["errorDetail"]
255 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
256 nsr
= nsopdata
["nsr:nsr"]
257 nsr_name
= nsr
["name-ref"]
258 nsr_id
= nsr
["ns-instance-config-ref"]
261 deployment_status
= (
262 nsr
["operational-status"]
263 if "operational-status" in nsr
266 ns_state
= deployment_status
267 config_status
= nsr
.get("config-status", "Not found")
268 current_operation
= "Unknown"
269 error_details
= nsr
.get("detailed-status", "Not found")
270 if config_status
== "config_not_needed":
271 config_status
= "configured (no charms)"
281 utils
.wrap_text(text
=error_details
, width
=40),
296 utils
.wrap_text(text
=error_details
, width
=40),
299 print_output
.print_output(output
, table
.field_names
, table
._rows
)
300 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
302 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
306 @click.command(name
="ns-show", short_help
="shows the info of a NS instance")
307 @click.argument("name")
308 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
312 help="restricts the information to the fields in the filter",
314 @print_output.output_option
316 def ns_show(ctx
, name
, literal
, filter, output
):
317 """shows the info of a NS instance
319 NAME: name or ID of the NS instance
322 ns
= ctx
.obj
.ns
.get(name
)
325 print(yaml
.safe_dump(ns
, indent
=4, default_flow_style
=False))
328 table
= PrettyTable(["field", "value"])
330 for k
, v
in list(ns
.items()):
331 if not filter or k
in filter:
332 table
.add_row([k
, utils
.wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
334 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
335 if fullclassname
!= "osmclient.sol005.client.Client":
336 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
337 nsr_optdata
= nsopdata
["nsr:nsr"]
338 for k
, v
in list(nsr_optdata
.items()):
339 if not filter or k
in filter:
340 table
.add_row([k
, utils
.wrap_text(json
.dumps(v
, indent
=2), width
=100)])
341 print_output
.print_output(output
, table
.field_names
, table
._rows
)
344 @click.command(name
="ns-create", short_help
="creates a new Network Service instance")
345 @click.option("--ns_name", prompt
=True, help="name of the NS instance")
346 @click.option("--nsd_name", prompt
=True, help="name of the NS descriptor")
350 help="default VIM account id or name for the deployment",
352 @click.option("--admin_status", default
="ENABLED", help="administration status")
356 help="comma separated list of public key files to inject to vnfs",
358 @click.option("--config", default
=None, help="ns specific yaml configuration")
359 @click.option("--config_file", default
=None, help="ns specific yaml configuration file")
365 help="do not return the control immediately, but keep it "
366 "until the operation is completed, or timeout",
368 @click.option("--timeout", default
=None, help="ns deployment timeout")
382 """creates a new NS instance"""
385 utils
.check_client_version(ctx
.obj
, "--config_file")
387 raise ClientException(
388 '"--config" option is incompatible with "--config_file" option'
390 with
open(config_file
, "r") as cf
:
403 @click.command(name
="ns-delete", short_help
="deletes a NS instance")
404 @click.argument("name")
406 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
411 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
412 "600, skip_terminate_primitives: True}'",
419 help="do not return the control immediately, but keep it "
420 "until the operation is completed, or timeout",
423 def ns_delete(ctx
, name
, force
, config
, wait
):
424 """deletes a NS instance
426 NAME: name or ID of the NS instance to be deleted
430 ctx
.obj
.ns
.delete(name
, config
=config
, wait
=wait
)
432 utils
.check_client_version(ctx
.obj
, "--force")
433 ctx
.obj
.ns
.delete(name
, force
, config
=config
, wait
=wait
)