New global option to adapt output format
[osm/osmclient.git] / osmclient / cli_commands / vnf.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 import click
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
21 import yaml
22 import json
23 import time
24 from datetime import datetime
25 import logging
26
27 logger = logging.getLogger("osmclient")
28
29
30 def vnf_list(ctx, ns, filter, long, o):
31 logger.debug("")
32 if ns or filter:
33 if ns:
34 utils.check_client_version(ctx.obj, "--ns")
35 if filter:
36 filter = "&".join(filter)
37 utils.check_client_version(ctx.obj, "--filter")
38 resp = ctx.obj.vnf.list(ns, filter)
39 else:
40 resp = ctx.obj.vnf.list()
41 fullclassname = ctx.obj.__module__ + "." + ctx.obj.__class__.__name__
42 if fullclassname == "osmclient.sol005.client.Client":
43 field_names = [
44 "vnf id",
45 "name",
46 "ns id",
47 "vnf member index",
48 "vnfd name",
49 "vim account id",
50 "ip address",
51 ]
52 if long:
53 field_names = [
54 "vnf id",
55 "name",
56 "ns id",
57 "vnf member index",
58 "vnfd name",
59 "vim account id",
60 "ip address",
61 "date",
62 "last update",
63 ]
64 table = PrettyTable(field_names)
65 for vnfr in resp:
66 name = vnfr["name"] if "name" in vnfr else "-"
67 new_row = [
68 vnfr["_id"],
69 name,
70 vnfr["nsr-id-ref"],
71 vnfr["member-vnf-index-ref"],
72 vnfr["vnfd-ref"],
73 vnfr["vim-account-id"],
74 vnfr["ip-address"],
75 ]
76 if long:
77 date = datetime.fromtimestamp(vnfr["_admin"]["created"]).strftime(
78 "%Y-%m-%dT%H:%M:%S"
79 )
80 last_update = datetime.fromtimestamp(
81 vnfr["_admin"]["modified"]
82 ).strftime("%Y-%m-%dT%H:%M:%S")
83 new_row.extend([date, last_update])
84 table.add_row(new_row)
85 else:
86 table = PrettyTable(["vnf name", "id", "operational status", "config status"])
87 for vnfr in resp:
88 if "mgmt-interface" not in vnfr:
89 vnfr["mgmt-interface"] = {}
90 vnfr["mgmt-interface"]["ip-address"] = None
91 table.add_row(
92 [
93 vnfr["name"],
94 vnfr["id"],
95 vnfr["operational-status"],
96 vnfr["config-status"],
97 ]
98 )
99 table.align = "l"
100 # print(table)
101 print_output.print_output(o, table.field_names, table._rows)
102
103
104 @click.command(name="vnf-list", short_help="list all NF instances")
105 @click.option(
106 "--ns", default=None, help="NS instance id or name to restrict the NF list"
107 )
108 @click.option(
109 "--filter",
110 default=None,
111 multiple=True,
112 help="restricts the list to the NF instances matching the filter.",
113 )
114 @click.option("--long", is_flag=True, help="get more details")
115 @click.option(
116 "-o",
117 default="table",
118 is_eager=True,
119 callback=print_output.validate_command_output,
120 help="adapt the output as table, yaml, csv, json, jsonpath",
121 )
122 @click.pass_context
123 def vnf_list1(ctx, ns, filter, long, o):
124 """list all NF instances"""
125 logger.debug("")
126 vnf_list(ctx, ns, filter, long, o)
127
128
129 @click.command(name="nf-list", short_help="list all NF instances")
130 @click.option(
131 "--ns", default=None, help="NS instance id or name to restrict the NF list"
132 )
133 @click.option(
134 "--filter",
135 default=None,
136 multiple=True,
137 help="restricts the list to the NF instances matching the filter.",
138 )
139 @click.option("--long", is_flag=True, help="get more details")
140 @click.option(
141 "-o",
142 default="table",
143 # is_eager=True,
144 # callback=print_output.validate_command_output,
145 help="adapt the output as table, yaml, csv, json, jsonpath",
146 )
147 @click.pass_context
148 def nf_list(ctx, ns, filter, long, o):
149 """list all NF instances
150
151 \b
152 Options:
153 --ns TEXT NS instance id or name to restrict the VNF list
154 --filter filterExpr Restricts the list to the VNF instances matching the filter
155
156 \b
157 filterExpr consists of one or more strings formatted according to "simpleFilterExpr",
158 concatenated using the "&" character:
159
160 \b
161 filterExpr := <simpleFilterExpr>["&"<simpleFilterExpr>]*
162 simpleFilterExpr := <attrName>["."<attrName>]*["."<op>]"="<value>[","<value>]*
163 op := "eq" | "neq" | "gt" | "lt" | "gte" | "lte" | "cont" | "ncont"
164 attrName := string
165 value := scalar value
166
167 \b
168 where:
169 * zero or more occurrences
170 ? zero or one occurrence
171 [] grouping of expressions to be used with ? and *
172 "" quotation marks for marking string constants
173 <> name separator
174
175 \b
176 "AttrName" is the name of one attribute in the data type that defines the representation
177 of the resource. The dot (".") character in "simpleFilterExpr" allows concatenation of
178 <attrName> entries to filter by attributes deeper in the hierarchy of a structured document.
179 "Op" stands for the comparison operator. If the expression has concatenated <attrName>
180 entries, it means that the operator "op" is applied to the attribute addressed by the last
181 <attrName> entry included in the concatenation. All simple filter expressions are combined
182 by the "AND" logical operator. In a concatenation of <attrName> entries in a <simpleFilterExpr>,
183 the rightmost "attrName" entry in a "simpleFilterExpr" is called "leaf attribute". The
184 concatenation of all "attrName" entries except the leaf attribute is called the "attribute
185 prefix". If an attribute referenced in an expression is an array, an object that contains a
186 corresponding array shall be considered to match the expression if any of the elements in the
187 array matches all expressions that have the same attribute prefix.
188
189 \b
190 Filter examples:
191 --filter vim-account-id=<VIM_ACCOUNT_ID>
192 --filter vnfd-ref=<VNFD_NAME>
193 --filter vdur.ip-address=<IP_ADDRESS>
194 --filter vnfd-ref=<VNFD_NAME>,vdur.ip-address=<IP_ADDRESS>
195 """
196 logger.debug("")
197 vnf_list(ctx, ns, filter, long, o)
198
199
200 @click.command(name="vnf-show", short_help="shows the info of a VNF instance")
201 @click.argument("name")
202 @click.option("--literal", is_flag=True, help="print literally, no pretty table")
203 @click.option(
204 "--filter",
205 multiple=True,
206 help="restricts the information to the fields in the filter",
207 )
208 @click.option("--kdu", default=None, help="KDU name (whose status will be shown)")
209 @click.option(
210 "-o",
211 default="table",
212 is_eager=True,
213 callback=print_output.validate_command_output,
214 help="adapt the output as table, yaml, csv, json, jsonpath",
215 )
216 @click.pass_context
217 def vnf_show(ctx, name, literal, filter, kdu, o):
218 """shows the info of a VNF instance
219
220 NAME: name or ID of the VNF instance
221 """
222
223 def print_kdu_status(op_info_status):
224 """print KDU status properly formatted"""
225 try:
226 op_status = yaml.safe_load(op_info_status)
227 if (
228 "namespace" in op_status
229 and "info" in op_status
230 and "last_deployed" in op_status["info"]
231 and "status" in op_status["info"]
232 and "code" in op_status["info"]["status"]
233 and "resources" in op_status["info"]["status"]
234 and "seconds" in op_status["info"]["last_deployed"]
235 ):
236 last_deployed_time = datetime.fromtimestamp(
237 op_status["info"]["last_deployed"]["seconds"]
238 ).strftime("%a %b %d %I:%M:%S %Y")
239 print("LAST DEPLOYED: {}".format(last_deployed_time))
240 print("NAMESPACE: {}".format(op_status["namespace"]))
241 status_code = "UNKNOWN"
242 if op_status["info"]["status"]["code"] == 1:
243 status_code = "DEPLOYED"
244 print("STATUS: {}".format(status_code))
245 print()
246 print("RESOURCES:")
247 print(op_status["info"]["status"]["resources"])
248 if "notes" in op_status["info"]["status"]:
249 print("NOTES:")
250 print(op_status["info"]["status"]["notes"])
251 else:
252 print(op_info_status)
253 except Exception:
254 print(op_info_status)
255
256 logger.debug("")
257 if kdu:
258 if literal:
259 raise ClientException(
260 '"--literal" option is incompatible with "--kdu" option'
261 )
262 if filter:
263 raise ClientException(
264 '"--filter" option is incompatible with "--kdu" option'
265 )
266
267 utils.check_client_version(ctx.obj, ctx.command.name)
268 resp = ctx.obj.vnf.get(name)
269
270 if kdu:
271 ns_id = resp["nsr-id-ref"]
272 op_data = {}
273 op_data["member_vnf_index"] = resp["member-vnf-index-ref"]
274 op_data["kdu_name"] = kdu
275 op_data["primitive"] = "status"
276 op_data["primitive_params"] = {}
277 op_id = ctx.obj.ns.exec_op(ns_id, op_name="action", op_data=op_data, wait=False)
278 t = 0
279 while t < 30:
280 op_info = ctx.obj.ns.get_op(op_id)
281 if op_info["operationState"] == "COMPLETED":
282 print_kdu_status(op_info["detailed-status"])
283 return
284 time.sleep(5)
285 t += 5
286 print("Could not determine KDU status")
287 return
288
289 if literal:
290 print(yaml.safe_dump(resp, indent=4, default_flow_style=False))
291 return
292
293 table = PrettyTable(["field", "value"])
294 for k, v in list(resp.items()):
295 if not filter or k in filter:
296 table.add_row([k, utils.wrap_text(text=json.dumps(v, indent=2), width=100)])
297 table.align = "l"
298 # print(table)
299 print_output.print_output(o, table.field_names, table._rows)