Code Coverage

Cobertura Coverage Report > osmclient.cli_commands >

ns.py

Trend

File Coverage summary

NameClassesLinesConditionals
ns.py
100%
1/1
23%
42/180
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
ns.py
23%
42/180
N/A

Source

osmclient/cli_commands/ns.py
1 # Copyright ETSI Contributors and Others.
2 # All Rights Reserved.
3 #
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
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
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
14 #    under the License.
15
16 1 import click
17 1 from osmclient.common.exceptions import ClientException
18 1 from osmclient.common import print_output
19 1 from osmclient.cli_commands import utils
20 1 from prettytable import PrettyTable
21 1 import yaml
22 1 import json
23 1 from datetime import datetime
24 1 import logging
25
26 1 logger = logging.getLogger("osmclient")
27
28
29 1 @click.command(name="ns-list", short_help="list all NS instances")
30 1 @click.option(
31     "--filter",
32     default=None,
33     multiple=True,
34     help="restricts the list to the NS instances matching the filter.",
35 )
36 1 @click.option(
37     "--long",
38     is_flag=True,
39     help="get more details of the NS (project, vim, deployment status, configuration status.",
40 )
41 1 @print_output.output_option
42 1 @click.pass_context
43 1 def ns_list(ctx, filter, long, output):
44     """list all NS instances
45
46     \b
47     Options:
48       --filter filterExpr    Restricts the list to the NS instances matching the filter
49
50     \b
51     filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
52     concatenated using the "&" character:
53
54       \b
55       filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
56       simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
57       op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
58       attrName := string
59       value := scalar value
60
61     \b
62     where:
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
67       <> name separator
68
69     \b
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.
82
83     \b
84     Filter examples:
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>
90     """
91
92 0     def summarize_deployment_status(status_dict):
93         # Nets
94 0         summary = ""
95 0         if not status_dict:
96 0             return summary
97 0         n_nets = 0
98 0         status_nets = {}
99 0         net_list = status_dict.get("nets", [])
100 0         for net in net_list:
101 0             n_nets += 1
102 0             if net["status"] not in status_nets:
103 0                 status_nets[net["status"]] = 1
104             else:
105 0                 status_nets[net["status"]] += 1
106 0         message = "Nets: "
107 0         for k, v in status_nets.items():
108 0             message += "{}:{},".format(k, v)
109 0         message += "TOTAL:{}".format(n_nets)
110 0         summary += "{}".format(message)
111         # VMs and VNFs
112 0         n_vms = 0
113 0         status_vms = {}
114 0         status_vnfs = {}
115 0         vnf_list = status_dict["vnfs"]
116 0         for vnf in vnf_list:
117 0             member_vnf_index = vnf["member_vnf_index"]
118 0             if member_vnf_index not in status_vnfs:
119 0                 status_vnfs[member_vnf_index] = {}
120 0             for vm in vnf["vms"]:
121 0                 n_vms += 1
122 0                 if vm["status"] not in status_vms:
123 0                     status_vms[vm["status"]] = 1
124                 else:
125 0                     status_vms[vm["status"]] += 1
126 0                 if vm["status"] not in status_vnfs[member_vnf_index]:
127 0                     status_vnfs[member_vnf_index][vm["status"]] = 1
128                 else:
129 0                     status_vnfs[member_vnf_index][vm["status"]] += 1
130 0         message = "VMs: "
131 0         for k, v in status_vms.items():
132 0             message += "{}:{},".format(k, v)
133 0         message += "TOTAL:{}".format(n_vms)
134 0         summary += "\n{}".format(message)
135 0         summary += "\nNFs:"
136 0         for k, v in status_vnfs.items():
137 0             total = 0
138 0             message = "\n  {} VMs: ".format(k)
139 0             for k2, v2 in v.items():
140 0                 message += "{}:{},".format(k2, v2)
141 0                 total += v2
142 0             message += "TOTAL:{}".format(total)
143 0         summary += message
144 0         return summary
145
146 0     def summarize_config_status(ee_list):
147 0         summary = ""
148 0         if not ee_list:
149 0             return summary
150 0         n_ee = 0
151 0         status_ee = {}
152 0         for ee in ee_list:
153 0             n_ee += 1
154 0             if ee["elementType"] not in status_ee:
155 0                 status_ee[ee["elementType"]] = {}
156 0                 status_ee[ee["elementType"]][ee["status"]] = 1
157 0                 continue
158 0             if ee["status"] in status_ee[ee["elementType"]]:
159 0                 status_ee[ee["elementType"]][ee["status"]] += 1
160             else:
161 0                 status_ee[ee["elementType"]][ee["status"]] = 1
162 0         for elementType in ["KDU", "VDU", "PDU", "VNF", "NS"]:
163 0             if elementType in status_ee:
164 0                 message = ""
165 0                 total = 0
166 0                 for k, v in status_ee[elementType].items():
167 0                     message += "{}:{},".format(k, v)
168 0                     total += v
169 0                 message += "TOTAL:{}\n".format(total)
170 0                 summary += "{}: {}".format(elementType, message)
171 0         summary += "TOTAL Exec. Env.: {}".format(n_ee)
172 0         return summary
173
174 0     logger.debug("")
175 0     if filter:
176 0         utils.check_client_version(ctx.obj, "--filter")
177 0         filter = "&".join(filter)
178 0         resp = ctx.obj.ns.list(filter)
179     else:
180 0         resp = ctx.obj.ns.list()
181 0     if long:
182 0         table = PrettyTable(
183             [
184                 "ns instance name",
185                 "id",
186                 "date",
187                 "ns state",
188                 "current operation",
189                 "error details",
190                 "project",
191                 "vim (inst param)",
192                 "deployment status",
193                 "configuration status",
194             ]
195         )
196 0         project_list = ctx.obj.project.list()
197 0         try:
198 0             vim_list = ctx.obj.vim.list()
199 0         except Exception:
200 0             vim_list = []
201     else:
202 0         table = PrettyTable(
203             [
204                 "ns instance name",
205                 "id",
206                 "date",
207                 "ns state",
208                 "current operation",
209                 "error details",
210             ]
211         )
212 0     for ns in resp:
213 0         nsr = ns
214 0         logger.debug("NS info: {}".format(nsr))
215 0         nsr_name = nsr["name"]
216 0         nsr_id = nsr["_id"]
217 0         date = datetime.fromtimestamp(nsr["create-time"]).strftime("%Y-%m-%dT%H:%M:%S")
218 0         ns_state = nsr.get("nsState", nsr["_admin"]["nsState"])
219 0         if long:
220 0             deployment_status = summarize_deployment_status(nsr.get("deploymentStatus"))
221 0             config_status = summarize_config_status(nsr.get("configurationStatus"))
222 0             project_id, project_name = utils.get_project(project_list, nsr)
223             # project = '{} ({})'.format(project_name, project_id)
224 0             project = project_name
225 0             vim_id = nsr.get("datacenter")
226 0             vim_name = utils.get_vim_name(vim_list, vim_id)
227
228             # vim = '{} ({})'.format(vim_name, vim_id)
229 0             vim = vim_name
230 0         if "currentOperation" in nsr:
231 0             current_operation = "{} ({})".format(
232                 nsr["currentOperation"], nsr["currentOperationID"]
233             )
234         else:
235 0             current_operation = "{} ({})".format(
236                 nsr["_admin"].get("current-operation", "-"),
237                 nsr["_admin"]["nslcmop"],
238             )
239 0         error_details = "N/A"
240 0         if (
241             ns_state == "BROKEN"
242             or ns_state == "DEGRADED"
243             or ("currentOperation" not in nsr and nsr.get("errorDescription"))
244         ):
245 0             error_details = "{}\nDetail: {}".format(
246                 nsr["errorDescription"], nsr["errorDetail"]
247             )
248
249 0         if long:
250 0             table.add_row(
251                 [
252                     nsr_name,
253                     nsr_id,
254                     date,
255                     ns_state,
256                     current_operation,
257                     utils.wrap_text(text=error_details, width=40),
258                     project,
259                     vim,
260                     deployment_status,
261                     config_status,
262                 ]
263             )
264         else:
265 0             table.add_row(
266                 [
267                     nsr_name,
268                     nsr_id,
269                     date,
270                     ns_state,
271                     current_operation,
272                     utils.wrap_text(text=error_details, width=40),
273                 ]
274             )
275 0     print_output.print_output(output, table.field_names, table._rows)
276 0     print('To get the history of all operations over a NS, run "osm ns-op-list NS_ID"')
277 0     print(
278         'For more details on the current operation, run "osm ns-op-show OPERATION_ID"'
279     )
280
281
282 1 @click.command(name="ns-show", short_help="shows the info of a NS instance")
283 1 @click.argument("name")
284 1 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
285 1 @click.option(
286     "--filter",
287     multiple=True,
288     help="restricts the information to the fields in the filter",
289 )
290 1 @print_output.output_option
291 1 @click.pass_context
292 1 def ns_show(ctx, name, literal, filter, output):
293     """shows the info of a NS instance
294
295     NAME: name or ID of the NS instance
296     """
297 0     logger.debug("")
298 0     ns = ctx.obj.ns.get(name)
299
300 0     if literal:
301 0         print(yaml.safe_dump(ns, indent=4, default_flow_style=False))
302 0         return
303
304 0     table = PrettyTable(["field", "value"])
305
306 0     for k, v in list(ns.items()):
307 0         if not filter or k in filter:
308 0             table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)])
309
310 0     print_output.print_output(output, table.field_names, table._rows)
311
312
313 1 @click.command(name="ns-create", short_help="creates a new Network Service instance")
314 1 @click.option("--ns_name", prompt=True, help="name of the NS instance")
315 1 @click.option("--nsd_name", prompt=True, help="name of the NS descriptor")
316 1 @click.option(
317     "--vim_account",
318     prompt=True,
319     help="default VIM account id or name for the deployment",
320 )
321 1 @click.option("--admin_status", default="ENABLED", help="administration status")
322 1 @click.option(
323     "--ssh_keys",
324     default=None,
325     help="comma separated list of public key files to inject to vnfs",
326 )
327 1 @click.option("--config", default=None, help="ns specific yaml configuration")
328 1 @click.option("--config_file", default=None, help="ns specific yaml configuration file")
329 1 @click.option(
330     "--wait",
331     required=False,
332     default=False,
333     is_flag=True,
334     help="do not return the control immediately, but keep it "
335     "until the operation is completed, or timeout",
336 )
337 1 @click.option("--timeout", default=None, help="ns deployment timeout")
338 1 @click.pass_context
339 1 def ns_create(
340     ctx,
341     nsd_name,
342     ns_name,
343     vim_account,
344     admin_status,
345     ssh_keys,
346     config,
347     config_file,
348     wait,
349     timeout,
350 ):
351     """creates a new NS instance"""
352 0     logger.debug("")
353 0     if config_file:
354 0         utils.check_client_version(ctx.obj, "--config_file")
355 0         if config:
356 0             raise ClientException(
357                 '"--config" option is incompatible with "--config_file" option'
358             )
359 0         with open(config_file, "r") as cf:
360 0             config = cf.read()
361 0     ctx.obj.ns.create(
362         nsd_name,
363         ns_name,
364         config=config,
365         ssh_keys=ssh_keys,
366         account=vim_account,
367         wait=wait,
368         timeout=timeout,
369     )
370
371
372 1 @click.command(name="ns-delete", short_help="deletes a NS instance")
373 1 @click.argument("name")
374 1 @click.option(
375     "--force", is_flag=True, help="forces the deletion bypassing pre-conditions"
376 )
377 1 @click.option(
378     "--config",
379     default=None,
380     help="specific yaml configuration for the termination, e.g. '{autoremove: False, timeout_ns_terminate: "
381     "600, skip_terminate_primitives: True}'",
382 )
383 1 @click.option(
384     "--wait",
385     required=False,
386     default=False,
387     is_flag=True,
388     help="do not return the control immediately, but keep it "
389     "until the operation is completed, or timeout",
390 )
391 1 @click.pass_context
392 1 def ns_delete(ctx, name, force, config, wait):
393     """deletes a NS instance
394
395     NAME: name or ID of the NS instance to be deleted
396     """
397 0     logger.debug("")
398 0     if not force:
399 0         ctx.obj.ns.delete(name, config=config, wait=wait)
400     else:
401 0         utils.check_client_version(ctx.obj, "--force")
402 0         ctx.obj.ns.delete(name, force, config=config, wait=wait)