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
.cli_commands
import utils
19 from prettytable
import PrettyTable
22 from datetime
import datetime
25 logger
= logging
.getLogger("osmclient")
28 @click.command(name
="ns-list", short_help
="list all NS instances")
33 help="restricts the list to the NS instances matching the filter.",
38 help="get more details of the NS (project, vim, deployment status, configuration status.",
41 def ns_list(ctx
, filter, long):
42 """list all NS instances
46 --filter filterExpr Restricts the list to the NS instances matching the filter
49 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
50 concatenated using the "&" character:
53 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
54 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
55 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
61 * zero or more occurrences
62 ? zero or one occurrence
63 [] grouping of expressions to be used with ? and *
64 "" quotation marks for marking string constants
68 "AttrName" is the name of one attribute in the data type that defines the representation
69 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
70 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
71 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
72 entries, it means that the operator "op" is applied to the attribute addressed by the last
73 <attrName> entry included in the concatenation. All simple filter expressions are combined
74 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
75 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
76 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
77 prefix". If an attribute referenced in an expression is an array, an object that contains a
78 corresponding array shall be considered to match the expression if any of the elements in the
79 array matches all expressions that have the same attribute prefix.
83 --filter admin-status=ENABLED
84 --filter nsd-ref=<NSD_NAME>
85 --filter nsd.vendor=<VENDOR>
86 --filter nsd.vendor=<VENDOR>&nsd-ref=<NSD_NAME>
87 --filter nsd.constituent-vnfd.vnfd-id-ref=<VNFD_NAME>
90 def summarize_deployment_status(status_dict
):
97 net_list
= status_dict
.get("nets", [])
100 if net
["status"] not in status_nets
:
101 status_nets
[net
["status"]] = 1
103 status_nets
[net
["status"]] += 1
105 for k
, v
in status_nets
.items():
106 message
+= "{}:{},".format(k
, v
)
107 message
+= "TOTAL:{}".format(n_nets
)
108 summary
+= "{}".format(message
)
113 vnf_list
= status_dict
["vnfs"]
115 member_vnf_index
= vnf
["member_vnf_index"]
116 if member_vnf_index
not in status_vnfs
:
117 status_vnfs
[member_vnf_index
] = {}
118 for vm
in vnf
["vms"]:
120 if vm
["status"] not in status_vms
:
121 status_vms
[vm
["status"]] = 1
123 status_vms
[vm
["status"]] += 1
124 if vm
["status"] not in status_vnfs
[member_vnf_index
]:
125 status_vnfs
[member_vnf_index
][vm
["status"]] = 1
127 status_vnfs
[member_vnf_index
][vm
["status"]] += 1
129 for k
, v
in status_vms
.items():
130 message
+= "{}:{},".format(k
, v
)
131 message
+= "TOTAL:{}".format(n_vms
)
132 summary
+= "\n{}".format(message
)
134 for k
, v
in status_vnfs
.items():
136 message
= "\n {} VMs: ".format(k
)
137 for k2
, v2
in v
.items():
138 message
+= "{}:{},".format(k2
, v2
)
140 message
+= "TOTAL:{}".format(total
)
144 def summarize_config_status(ee_list
):
152 if ee
["elementType"] not in status_ee
:
153 status_ee
[ee
["elementType"]] = {}
154 status_ee
[ee
["elementType"]][ee
["status"]] = 1
156 if ee
["status"] in status_ee
[ee
["elementType"]]:
157 status_ee
[ee
["elementType"]][ee
["status"]] += 1
159 status_ee
[ee
["elementType"]][ee
["status"]] = 1
160 for elementType
in ["KDU", "VDU", "PDU", "VNF", "NS"]:
161 if elementType
in status_ee
:
164 for k
, v
in status_ee
[elementType
].items():
165 message
+= "{}:{},".format(k
, v
)
167 message
+= "TOTAL:{}\n".format(total
)
168 summary
+= "{}: {}".format(elementType
, message
)
169 summary
+= "TOTAL Exec. Env.: {}".format(n_ee
)
174 utils
.check_client_version(ctx
.obj
, "--filter")
175 filter = "&".join(filter)
176 resp
= ctx
.obj
.ns
.list(filter)
178 resp
= ctx
.obj
.ns
.list()
191 "configuration status",
194 project_list
= ctx
.obj
.project
.list()
196 vim_list
= ctx
.obj
.vim
.list()
211 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
212 if fullclassname
== "osmclient.sol005.client.Client":
214 logger
.debug("NS info: {}".format(nsr
))
215 nsr_name
= nsr
["name"]
217 date
= datetime
.fromtimestamp(nsr
["create-time"]).strftime(
220 ns_state
= nsr
.get("nsState", nsr
["_admin"]["nsState"])
222 deployment_status
= summarize_deployment_status(
223 nsr
.get("deploymentStatus")
225 config_status
= summarize_config_status(nsr
.get("configurationStatus"))
226 project_id
, project_name
= utils
.get_project(project_list
, nsr
)
227 # project = '{} ({})'.format(project_name, project_id)
228 project
= project_name
229 vim_id
= nsr
.get("datacenter")
230 vim_name
= utils
.get_vim_name(vim_list
, vim_id
)
232 # vim = '{} ({})'.format(vim_name, vim_id)
234 if "currentOperation" in nsr
:
235 current_operation
= "{} ({})".format(
236 nsr
["currentOperation"], nsr
["currentOperationID"]
239 current_operation
= "{} ({})".format(
240 nsr
["_admin"].get("current-operation", "-"),
241 nsr
["_admin"]["nslcmop"],
243 error_details
= "N/A"
246 or ns_state
== "DEGRADED"
247 or ("currentOperation" not in nsr
and nsr
.get("errorDescription"))
249 error_details
= "{}\nDetail: {}".format(
250 nsr
["errorDescription"], nsr
["errorDetail"]
253 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
254 nsr
= nsopdata
["nsr:nsr"]
255 nsr_name
= nsr
["name-ref"]
256 nsr_id
= nsr
["ns-instance-config-ref"]
259 deployment_status
= (
260 nsr
["operational-status"]
261 if "operational-status" in nsr
264 ns_state
= deployment_status
265 config_status
= nsr
.get("config-status", "Not found")
266 current_operation
= "Unknown"
267 error_details
= nsr
.get("detailed-status", "Not found")
268 if config_status
== "config_not_needed":
269 config_status
= "configured (no charms)"
279 utils
.wrap_text(text
=error_details
, width
=40),
294 utils
.wrap_text(text
=error_details
, width
=40),
299 print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
301 'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
305 @click.command(name
="ns-show", short_help
="shows the info of a NS instance")
306 @click.argument("name")
307 @click.option("--literal", is_flag
=True, help="print literally, no pretty table")
311 help="restricts the information to the fields in the filter",
314 def ns_show(ctx
, name
, literal
, filter):
315 """shows the info of a NS instance
317 NAME: name or ID of the NS instance
320 ns
= ctx
.obj
.ns
.get(name
)
323 print(yaml
.safe_dump(ns
, indent
=4, default_flow_style
=False))
326 table
= PrettyTable(["field", "value"])
328 for k
, v
in list(ns
.items()):
329 if not filter or k
in filter:
330 table
.add_row([k
, utils
.wrap_text(text
=json
.dumps(v
, indent
=2), width
=100)])
332 fullclassname
= ctx
.obj
.__module
__ + "." + ctx
.obj
.__class
__.__name
__
333 if fullclassname
!= "osmclient.sol005.client.Client":
334 nsopdata
= ctx
.obj
.ns
.get_opdata(ns
["id"])
335 nsr_optdata
= nsopdata
["nsr:nsr"]
336 for k
, v
in list(nsr_optdata
.items()):
337 if not filter or k
in filter:
338 table
.add_row([k
, utils
.wrap_text(json
.dumps(v
, indent
=2), width
=100)])
343 @click.command(name
="ns-create", short_help
="creates a new Network Service instance")
344 @click.option("--ns_name", prompt
=True, help="name of the NS instance")
345 @click.option("--nsd_name", prompt
=True, help="name of the NS descriptor")
349 help="default VIM account id or name for the deployment",
351 @click.option("--admin_status", default
="ENABLED", help="administration status")
355 help="comma separated list of public key files to inject to vnfs",
357 @click.option("--config", default
=None, help="ns specific yaml configuration")
358 @click.option("--config_file", default
=None, help="ns specific yaml configuration file")
364 help="do not return the control immediately, but keep it "
365 "until the operation is completed, or timeout",
367 @click.option("--timeout", default
=None, help="ns deployment timeout")
381 """creates a new NS instance"""
384 utils
.check_client_version(ctx
.obj
, "--config_file")
386 raise ClientException(
387 '"--config" option is incompatible with "--config_file" option'
389 with
open(config_file
, "r") as cf
:
402 @click.command(name
="ns-delete", short_help
="deletes a NS instance")
403 @click.argument("name")
405 "--force", is_flag
=True, help="forces the deletion bypassing pre-conditions"
410 help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
411 "600, skip_terminate_primitives: True}'",
418 help="do not return the control immediately, but keep it "
419 "until the operation is completed, or timeout",
422 def ns_delete(ctx
, name
, force
, config
, wait
):
423 """deletes a NS instance
425 NAME: name or ID of the NS instance to be deleted
429 ctx
.obj
.ns
.delete(name
, config
=config
, wait
=wait
)
431 utils
.check_client_version(ctx
.obj
, "--force")
432 ctx
.obj
.ns
.delete(name
, force
, config
=config
, wait
=wait
)