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()
214 logger
.debug("NS info: {}".format(nsr
))
215 nsr_name
= nsr
["name"]
217 date
= datetime
.fromtimestamp(nsr
["create-time"]).strftime("%Y-%m-%dT%H:%M:%S")
218 ns_state
= nsr
.get("nsState", nsr
["_admin"]["nsState"])
220 deployment_status
= summarize_deployment_status(nsr
.get("deploymentStatus"))
221 config_status
= summarize_config_status(nsr
.get("configurationStatus"))
222 project_id
, project_name
= utils
.get_project(project_list
, nsr
)
223 # project = '{} ({})'.format(project_name, project_id)
224 project
= project_name
225 vim_id
= nsr
.get("datacenter")
226 vim_name
= utils
.get_vim_name(vim_list
, vim_id
)
228 # vim = '{} ({})'.format(vim_name, vim_id)
230 if "currentOperation" in nsr
:
231 current_operation
= "{} ({})".format(
232 nsr
["currentOperation"], nsr
["currentOperationID"]
235 current_operation
= "{} ({})".format(
236 nsr
["_admin"].get("current-operation", "-"),
237 nsr
["_admin"]["nslcmop"],
239 error_details
= "N/A"
242 or ns_state
== "DEGRADED"
243 or ("currentOperation" not in nsr
and nsr
.get("errorDescription"))
245 error_details
= "{}\nDetail: {}".format(
246 nsr
["errorDescription"], nsr
["errorDetail"]
257 utils
.wrap_text(text
=error_details
, width
=40),
272 utils
.wrap_text(text
=error_details
, width
=40),
275 print_output
.print_output(output
, table
.field_names
, table
._rows
)
276 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
278 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
282 @click.command(name
="ns-show", short_help
="shows the info of a NS instance")
283 @click.argument("name")
284 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
288 help="restricts the information to the fields in the filter",
290 @print_output.output_option
292 def ns_show(ctx
, name
, literal
, filter, output
):
293 """shows the info of a NS instance
295 NAME: name or ID of the NS instance
298 ns
= ctx
.obj
.ns
.get(name
)
301 print(yaml
.safe_dump(ns
, indent
=4, default_flow_style
=False))
304 table
= PrettyTable(["field", "value"])
306 for k
, v
in list(ns
.items()):
307 if not filter or k
in filter:
308 table
.add_row([k
, utils
.wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
310 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
311 nsr_optdata
= nsopdata
["nsr:nsr"]
312 for k
, v
in list(nsr_optdata
.items()):
313 if not filter or k
in filter:
314 table
.add_row([k
, utils
.wrap_text(json
.dumps(v
, indent
=2), width
=100)])
315 print_output
.print_output(output
, table
.field_names
, table
._rows
)
318 @click.command(name
="ns-create", short_help
="creates a new Network Service instance")
319 @click.option("--ns_name", prompt
=True, help="name of the NS instance")
320 @click.option("--nsd_name", prompt
=True, help="name of the NS descriptor")
324 help="default VIM account id or name for the deployment",
326 @click.option("--admin_status", default
="ENABLED", help="administration status")
330 help="comma separated list of public key files to inject to vnfs",
332 @click.option("--config", default
=None, help="ns specific yaml configuration")
333 @click.option("--config_file", default
=None, help="ns specific yaml configuration file")
339 help="do not return the control immediately, but keep it "
340 "until the operation is completed, or timeout",
342 @click.option("--timeout", default
=None, help="ns deployment timeout")
356 """creates a new NS instance"""
359 utils
.check_client_version(ctx
.obj
, "--config_file")
361 raise ClientException(
362 '"--config" option is incompatible with "--config_file" option'
364 with
open(config_file
, "r") as cf
:
377 @click.command(name
="ns-delete", short_help
="deletes a NS instance")
378 @click.argument("name")
380 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
385 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
386 "600, skip_terminate_primitives: True}'",
393 help="do not return the control immediately, but keep it "
394 "until the operation is completed, or timeout",
397 def ns_delete(ctx
, name
, force
, config
, wait
):
398 """deletes a NS instance
400 NAME: name or ID of the NS instance to be deleted
404 ctx
.obj
.ns
.delete(name
, config
=config
, wait
=wait
)
406 utils
.check_client_version(ctx
.obj
, "--force")
407 ctx
.obj
.ns
.delete(name
, force
, config
=config
, wait
=wait
)