Code Coverage

Cobertura Coverage Report > osmclient.sol005 >

vnfd.py

Trend

Classes0%
 
Lines0%
 
Conditionals100%
 

File Coverage summary

NameClassesLinesConditionals
vnfd.py
0%
0/1
0%
0/194
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
vnfd.py
0%
0/194
N/A

Source

osmclient/sol005/vnfd.py
1 # Copyright 2018 Telefonica
2 #
3 # All Rights Reserved.
4 #
5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
6 #    not use this file except in compliance with the License. You may obtain
7 #    a copy of the License at
8 #
9 #         http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #    Unless required by applicable law or agreed to in writing, software
12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 #    License for the specific language governing permissions and limitations
15 #    under the License.
16
17 0 """
18 OSM vnfd API handling
19 """
20
21 0 from osmclient.common.exceptions import NotFound
22 0 from osmclient.common.exceptions import ClientException
23 0 from osmclient.common import utils
24 0 import json
25 0 import yaml
26 0 import magic
27 0 from os.path import basename
28 0 import logging
29 0 import os.path
30 0 from urllib.parse import quote
31 0 import tarfile
32 0 from osm_im.validation import Validation as validation_im
33
34
35 0 class Vnfd(object):
36 0     def __init__(self, http=None, client=None):
37 0         self._http = http
38 0         self._client = client
39 0         self._logger = logging.getLogger("osmclient")
40 0         self._apiName = "/vnfpkgm"
41 0         self._apiVersion = "/v1"
42 0         self._apiResource = "/vnf_packages"
43 0         self._apiBase = "{}{}{}".format(
44             self._apiName, self._apiVersion, self._apiResource
45         )
46
47 0     def list(self, filter=None):
48 0         self._logger.debug("")
49 0         self._client.get_token()
50 0         filter_string = ""
51 0         if filter:
52 0             filter_string = "?{}".format(filter)
53 0         _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string))
54
55 0         if resp:
56 0             return json.loads(resp)
57 0         return list()
58
59 0     def get(self, name):
60 0         self._logger.debug("")
61 0         self._client.get_token()
62 0         if utils.validate_uuid4(name):
63 0             for vnfd in self.list():
64 0                 if name == vnfd["_id"]:
65 0                     return vnfd
66         else:
67 0             for vnfd in self.list():
68 0                 if "product-name" in vnfd and name == vnfd["product-name"]:
69 0                     return vnfd
70 0                 elif "name" in vnfd and name == vnfd["name"]:
71 0                     return vnfd
72 0         raise NotFound("vnfd {} not found".format(name))
73
74 0     def get_individual(self, name):
75 0         self._logger.debug("")
76 0         vnfd = self.get(name)
77         # It is redundant, since the previous one already gets the whole vnfpkginfo
78         # The only difference is that a different primitive is exercised
79 0         try:
80 0             _, resp = self._http.get2_cmd("{}/{}".format(self._apiBase, vnfd["_id"]))
81 0             if resp:
82 0                 return json.loads(resp)
83 0         except NotFound:
84 0             raise NotFound("vnfd '{}' not found".format(name))
85 0         raise NotFound("vnfd '{}' not found".format(name))
86
87 0     def get_thing(self, name, thing, filename):
88 0         self._logger.debug("")
89 0         vnfd = self.get(name)
90 0         headers = self._client._headers
91 0         headers["Accept"] = "application/binary"
92 0         http_code, resp = self._http.get2_cmd(
93             "{}/{}/{}".format(self._apiBase, vnfd["_id"], thing)
94         )
95
96 0         if resp:
97 0             return json.loads(resp)
98
99 0     def get_descriptor(self, name, filename):
100 0         self._logger.debug("")
101 0         self.get_thing(name, "vnfd", filename)
102
103 0     def get_package(self, name, filename):
104 0         self._logger.debug("")
105 0         self.get_thing(name, "package_content", filename)
106
107 0     def get_artifact(self, name, artifact, filename):
108 0         self._logger.debug("")
109 0         self.get_thing(name, "artifacts/{}".format(artifact), filename)
110
111 0     def delete(self, name, force=False):
112 0         self._logger.debug("")
113 0         self._client.get_token()
114 0         vnfd = self.get(name)
115 0         querystring = ""
116 0         if force:
117 0             querystring = "?FORCE=True"
118 0         http_code, resp = self._http.delete_cmd(
119             "{}/{}{}".format(self._apiBase, vnfd["_id"], querystring)
120         )
121
122 0         if http_code == 202:
123 0             print("Deletion in progress")
124 0         elif http_code == 204:
125 0             print("Deleted")
126         else:
127 0             msg = resp or ""
128 0             raise ClientException("failed to delete vnfd {} - {}".format(name, msg))
129
130 0     def create(
131         self,
132         filename,
133         overwrite=None,
134         update_endpoint=None,
135         skip_charm_build=False,
136         override_epa=False,
137         override_nonepa=False,
138         override_paravirt=False,
139     ):
140 0         self._logger.debug("")
141 0         if os.path.isdir(filename):
142 0             filename = filename.rstrip("/")
143 0             filename = self._client.package_tool.build(
144                 filename, skip_validation=False, skip_charm_build=skip_charm_build
145             )
146
147 0             print("Uploading package {}".format(filename))
148 0             self.create(
149                 filename,
150                 overwrite=overwrite,
151                 update_endpoint=update_endpoint,
152                 override_epa=override_epa,
153                 override_nonepa=override_nonepa,
154                 override_paravirt=override_paravirt,
155             )
156         else:
157 0             self._client.get_token()
158 0             mime_type = magic.from_file(filename, mime=True)
159 0             if mime_type is None:
160 0                 raise ClientException(
161                     "Unexpected MIME type for file {}: MIME type {}".format(
162                         filename, mime_type
163                     )
164                 )
165 0             headers = self._client._headers
166 0             headers["Content-Filename"] = basename(filename)
167 0             if mime_type in ["application/yaml", "text/plain", "application/json"]:
168 0                 headers["Content-Type"] = "text/plain"
169 0             elif mime_type in ["application/gzip", "application/x-gzip"]:
170 0                 headers["Content-Type"] = "application/gzip"
171             else:
172 0                 raise ClientException(
173                     "Unexpected MIME type for file {}: MIME type {}".format(
174                         filename, mime_type
175                     )
176                 )
177
178 0             special_override_string = ""
179 0             if override_epa or override_nonepa or override_paravirt:
180                 # If override for EPA, non-EPA or paravirt is required, get the descriptor data
181 0                 descriptor_data = None
182 0                 if mime_type in ["application/yaml", "text/plain", "application/json"]:
183 0                     with open(filename) as df:
184 0                         descriptor_data = df.read()
185 0                 elif mime_type in ["application/gzip", "application/x-gzip"]:
186 0                     tar_object = tarfile.open(filename, "r:gz")
187 0                     descriptor_list = []
188 0                     for member in tar_object:
189 0                         if member.isreg():
190 0                             if "/" not in os.path.dirname(
191                                 member.name
192                             ) and member.name.endswith(".yaml"):
193 0                                 descriptor_list.append(member.name)
194 0                     if len(descriptor_list) > 1:
195 0                         raise ClientException(
196                             "Found more than one potential descriptor in the tar.gz file"
197                         )
198 0                     elif len(descriptor_list) == 0:
199 0                         raise ClientException(
200                             "No descriptor was found in the tar.gz file"
201                         )
202 0                     with tar_object.extractfile(descriptor_list[0]) as df:
203 0                         descriptor_data = df.read()
204 0                     tar_object.close()
205 0                 if not descriptor_data:
206 0                     raise ClientException("Descriptor could not be read")
207 0                 desc_type, vnfd = validation_im().yaml_validation(descriptor_data)
208 0                 validation_im().pyangbind_validation(desc_type, vnfd)
209
210 0                 vnfd = yaml.safe_load(descriptor_data)
211 0                 vcd_list = []
212 0                 vdu_list = []
213 0                 for k in vnfd:
214                     # Get only the first descriptor in case there are many in the yaml file
215                     # k can be vnfd or  etsi-nfv-vnfd:vnfd. This check is skipped
216 0                     first_vnfd = vnfd.get(k, {})
217 0                     vcd_list = first_vnfd.get("virtual-compute-desc", [])
218 0                     vdu_list = first_vnfd.get("vdu", [])
219 0                     break
220
221 0                 for vcd_number, vcd in enumerate(vcd_list):
222 0                     if override_epa:
223 0                         virtual_memory = vcd["virtual-memory"]
224 0                         virtual_memory["mempage-size"] = "LARGE"
225 0                         virtual_memory["numa-enabled"] = True
226 0                         virtual_memory["numa-node-policy"] = {
227                             "node-cnt": 1,
228                             "mem-policy": "STRICT",
229                         }
230 0                         virtual_cpu = vcd["virtual-cpu"]
231 0                         virtual_cpu["pinning"] = {
232                             "policy": "static",
233                             "thread-policy": "PREFER",
234                         }
235
236 0                         cpu_override_string = (
237                             "virtual-compute-desc.{}.virtual-cpu={};".format(
238                                 vcd_number, quote(yaml.safe_dump(virtual_cpu))
239                             )
240                         )
241 0                         memory_override_string = (
242                             "virtual-compute-desc.{}.virtual-memory={};".format(
243                                 vcd_number, quote(yaml.safe_dump(virtual_memory))
244                             )
245                         )
246 0                         special_override_string = "{}{}{}".format(
247                             special_override_string,
248                             cpu_override_string,
249                             memory_override_string,
250                         )
251
252 0                     headers["Query-String-Format"] = "yaml"
253 0                     if override_nonepa:
254 0                         virtual_memory = vcd["virtual-memory"]
255 0                         virtual_memory["mempage-size"] = ""
256 0                         virtual_memory["numa-enabled"] = ""
257 0                         virtual_memory["numa-node-policy"] = {}
258 0                         virtual_cpu = vcd["virtual-cpu"]
259 0                         virtual_cpu["pinning"] = {}
260
261 0                         cpu_override_string = (
262                             "virtual-compute-desc.{}.virtual-cpu={};".format(
263                                 vcd_number, quote(yaml.safe_dump(virtual_cpu))
264                             )
265                         )
266 0                         memory_override_string = (
267                             "virtual-compute-desc.{}.virtual-memory={};".format(
268                                 vcd_number, quote(yaml.safe_dump(virtual_memory))
269                             )
270                         )
271 0                         special_override_string = "{}{}{}".format(
272                             special_override_string,
273                             cpu_override_string,
274                             memory_override_string,
275                         )
276
277 0                 if override_paravirt:
278 0                     for vdu_number, vdu in enumerate(vdu_list):
279 0                         for cpd_number, cpd in enumerate(vdu["int-cpd"]):
280 0                             for vnir_number, vnir in enumerate(
281                                 cpd["virtual-network-interface-requirement"]
282                             ):
283 0                                 special_override_string = (
284                                     "{}vdu.{}.int-cpd.{}.virtual-network-interface-"
285                                     "requirement.{}.virtual-interface.type="
286                                     "PARAVIRT;".format(
287                                         special_override_string,
288                                         vdu_number,
289                                         cpd_number,
290                                         vnir_number,
291                                     )
292                                 )
293
294 0                 special_override_string = special_override_string.rstrip(";")
295
296 0             headers["Content-File-MD5"] = utils.md5(filename)
297 0             http_header = [
298                 "{}: {}".format(key, val) for (key, val) in list(headers.items())
299             ]
300
301 0             self._http.set_http_header(http_header)
302 0             if update_endpoint:
303 0                 http_code, resp = self._http.put_cmd(
304                     endpoint=update_endpoint, filename=filename
305                 )
306             else:
307 0                 ow_string = ""
308 0                 if special_override_string:
309 0                     if overwrite:
310 0                         overwrite = "{};{}".format(overwrite, special_override_string)
311                     else:
312 0                         overwrite = special_override_string
313
314 0                 if overwrite:
315 0                     ow_string = "?{}".format(overwrite)
316 0                 self._apiResource = "/vnf_packages_content"
317 0                 self._apiBase = "{}{}{}".format(
318                     self._apiName, self._apiVersion, self._apiResource
319                 )
320 0                 endpoint = "{}{}".format(self._apiBase, ow_string)
321 0                 http_code, resp = self._http.post_cmd(
322                     endpoint=endpoint, filename=filename
323                 )
324
325 0             if http_code in (200, 201, 202):
326 0                 if resp:
327 0                     resp = json.loads(resp)
328 0                 if not resp or "id" not in resp:
329 0                     raise ClientException(
330                         "unexpected response from server: {}".format(resp)
331                     )
332 0                 print(resp["id"])
333 0             elif http_code == 204:
334 0                 print("Updated")
335
336 0     def update(self, name, filename):
337 0         self._logger.debug("")
338 0         self._client.get_token()
339 0         vnfd = self.get(name)
340 0         endpoint = "{}/{}/package_content".format(self._apiBase, vnfd["_id"])
341 0         self.create(filename=filename, update_endpoint=endpoint)