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
37 0     def __init__(self, http=None, client=None):
38 0         self._http = http
39 0         self._client = client
40 0         self._logger = logging.getLogger('osmclient')
41 0         self._apiName = '/vnfpkgm'
42 0         self._apiVersion = '/v1'
43 0         self._apiResource = '/vnf_packages'
44 0         self._apiBase = '{}{}{}'.format(self._apiName,
45                                         self._apiVersion, self._apiResource)
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('{}/{}/{}'.format(self._apiBase, vnfd['_id'], thing))
93
94 0         if resp:
95 0             return json.loads(resp)
96
97 0     def get_descriptor(self, name, filename):
98 0         self._logger.debug("")
99 0         self.get_thing(name, 'vnfd', filename)
100
101 0     def get_package(self, name, filename):
102 0         self._logger.debug("")
103 0         self.get_thing(name, 'package_content', filename)
104
105 0     def get_artifact(self, name, artifact, filename):
106 0         self._logger.debug("")
107 0         self.get_thing(name, 'artifacts/{}'.format(artifact), filename)
108
109 0     def delete(self, name, force=False):
110 0         self._logger.debug("")
111 0         self._client.get_token()
112 0         vnfd = self.get(name)
113 0         querystring = ''
114 0         if force:
115 0             querystring = '?FORCE=True'
116 0         http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
117                                                                  vnfd['_id'], querystring))
118
119 0         if http_code == 202:
120 0             print('Deletion in progress')
121 0         elif http_code == 204:
122 0             print('Deleted')
123         else:
124 0             msg = resp or ""
125 0             raise ClientException("failed to delete vnfd {} - {}".format(name, msg))
126
127 0     def create(self, filename, overwrite=None, update_endpoint=None, skip_charm_build=False,
128                override_epa=False, override_nonepa=False, override_paravirt=False):
129 0         self._logger.debug("")
130 0         if os.path.isdir(filename):
131 0             filename = filename.rstrip('/')
132 0             filename = self._client.package_tool.build(filename, skip_validation=False,
133                                                        skip_charm_build=skip_charm_build)
134
135 0             print('Uploading package {}'.format(filename))
136 0             self.create(filename, overwrite=overwrite, update_endpoint=update_endpoint,
137                         override_epa=override_epa, override_nonepa=override_nonepa,
138                         override_paravirt=override_paravirt)
139         else:
140 0             self._client.get_token()
141 0             mime_type = magic.from_file(filename, mime=True)
142 0             if mime_type is None:
143 0                 raise ClientException(
144                     "Unexpected MIME type for file {}: MIME type {}".format(
145                         filename, mime_type)
146                 )
147 0             headers = self._client._headers
148 0             headers['Content-Filename'] = basename(filename)
149 0             if mime_type in ['application/yaml', 'text/plain', 'application/json']:
150 0                 headers['Content-Type'] = 'text/plain'
151 0             elif mime_type in ['application/gzip', 'application/x-gzip']:
152 0                 headers['Content-Type'] = 'application/gzip'
153             else:
154 0                 raise ClientException(
155                     "Unexpected MIME type for file {}: MIME type {}".format(
156                         filename, mime_type)
157                 )
158
159 0             special_override_string = ''
160 0             if override_epa or override_nonepa or override_paravirt:
161                 # If override for EPA, non-EPA or paravirt is required, get the descriptor data
162 0                 descriptor_data = None
163 0                 if mime_type in ['application/yaml', 'text/plain', 'application/json']:
164 0                     with open(filename) as df:
165 0                         descriptor_data = df.read()
166 0                 elif mime_type in ['application/gzip', 'application/x-gzip']:
167 0                     tar_object = tarfile.open(filename, "r:gz")
168 0                     descriptor_list = []
169 0                     for member in tar_object:
170 0                         if member.isreg():
171 0                             if '/' not in os.path.dirname(member.name) and member.name.endswith('.yaml'):
172 0                                 descriptor_list.append(member.name)
173 0                     if len(descriptor_list) > 1:
174 0                         raise ClientException('Found more than one potential descriptor in the tar.gz file')
175 0                     elif len(descriptor_list) == 0:
176 0                         raise ClientException('No descriptor was found in the tar.gz file')
177 0                     with tar_object.extractfile(descriptor_list[0]) as df:
178 0                         descriptor_data = df.read()
179 0                     tar_object.close()
180 0                 if not descriptor_data:
181 0                     raise ClientException('Descriptor could not be read')
182 0                 desc_type, vnfd = validation_im().yaml_validation(descriptor_data)
183 0                 validation_im().pyangbind_validation(desc_type, vnfd)
184
185 0                 vnfd = yaml.safe_load(descriptor_data)
186 0                 vcd_list = []
187 0                 vdu_list = []
188 0                 for k in vnfd:
189                     # Get only the first descriptor in case there are many in the yaml file
190                     # k can be vnfd or  etsi-nfv-vnfd:vnfd. This check is skipped
191 0                     first_vnfd = vnfd.get(k, {})
192 0                     vcd_list = first_vnfd.get('virtual-compute-desc', [])
193 0                     vdu_list = first_vnfd.get('vdu', [])
194 0                     break
195
196 0                 for vcd_number, vcd in enumerate(vcd_list):
197 0                     if override_epa:
198 0                         virtual_memory = vcd["virtual-memory"]
199 0                         virtual_memory["mempage-size"] = "LARGE"
200 0                         virtual_memory["numa-enabled"] = True
201 0                         virtual_memory["numa-node-policy"] = {
202                             "node-cnt": 1,
203                             "mem-policy": "STRICT"
204                         }
205 0                         virtual_cpu = vcd["virtual-cpu"]
206 0                         virtual_cpu["pinning"] = {
207                             "policy": "static",
208                             "thread-policy": "PREFER"
209                         }
210
211 0                         cpu_override_string = "virtual-compute-desc.{}.virtual-cpu={};"\
212                                                  .format(vcd_number, quote(yaml.safe_dump(virtual_cpu)))
213 0                         memory_override_string = "virtual-compute-desc.{}.virtual-memory={};"\
214                                               .format(vcd_number, quote(yaml.safe_dump(virtual_memory)))
215 0                         special_override_string = "{}{}{}".format(special_override_string,
216                                                                   cpu_override_string, memory_override_string)
217
218 0                     headers['Query-String-Format'] = 'yaml'
219 0                     if override_nonepa:
220 0                         virtual_memory = vcd["virtual-memory"]
221 0                         virtual_memory["mempage-size"] = ""
222 0                         virtual_memory["numa-enabled"] = ""
223 0                         virtual_memory["numa-node-policy"] = {}
224 0                         virtual_cpu = vcd["virtual-cpu"]
225 0                         virtual_cpu["pinning"] = {}
226
227 0                         cpu_override_string = "virtual-compute-desc.{}.virtual-cpu={};"\
228                                                  .format(vcd_number, quote(yaml.safe_dump(virtual_cpu)))
229 0                         memory_override_string = "virtual-compute-desc.{}.virtual-memory={};"\
230                                               .format(vcd_number, quote(yaml.safe_dump(virtual_memory)))
231 0                         special_override_string = "{}{}{}".format(special_override_string,
232                                                                   cpu_override_string, memory_override_string)
233
234 0                 if override_paravirt:
235 0                     for vdu_number, vdu in enumerate(vdu_list):
236 0                         for cpd_number, cpd in enumerate(vdu["int-cpd"]):
237 0                             for vnir_number, vnir in enumerate(cpd['virtual-network-interface-requirement']):
238 0                                 special_override_string = "{}vdu.{}.int-cpd.{}.virtual-network-interface-" \
239                                                           "requirement.{}.virtual-interface.type=PARAVIRT;"\
240                                     .format(special_override_string, vdu_number, cpd_number, vnir_number)
241
242 0                 special_override_string = special_override_string.rstrip(";")
243
244 0             headers["Content-File-MD5"] = utils.md5(filename)
245 0             http_header = ['{}: {}'.format(key, val)
246                            for (key, val) in list(headers.items())]
247
248 0             self._http.set_http_header(http_header)
249 0             if update_endpoint:
250 0                 http_code, resp = self._http.put_cmd(endpoint=update_endpoint, filename=filename)
251             else:
252 0                 ow_string = ''
253 0                 if special_override_string:
254 0                     if overwrite:
255 0                         overwrite = "{};{}".format(overwrite, special_override_string)
256                     else:
257 0                         overwrite = special_override_string
258
259 0                 if overwrite:
260 0                     ow_string = '?{}'.format(overwrite)
261 0                 self._apiResource = '/vnf_packages_content'
262 0                 self._apiBase = '{}{}{}'.format(self._apiName,
263                                                 self._apiVersion, self._apiResource)
264 0                 endpoint = '{}{}'.format(self._apiBase, ow_string)
265 0                 http_code, resp = self._http.post_cmd(endpoint=endpoint, filename=filename)
266
267 0             if http_code in (200, 201, 202):
268 0                 if resp:
269 0                     resp = json.loads(resp)
270 0                 if not resp or 'id' not in resp:
271 0                     raise ClientException('unexpected response from server: {}'.format(resp))
272 0                 print(resp['id'])
273 0             elif http_code == 204:
274 0                 print('Updated')
275
276 0     def update(self, name, filename):
277 0         self._logger.debug("")
278 0         self._client.get_token()
279 0         vnfd = self.get(name)
280 0         endpoint = '{}/{}/package_content'.format(self._apiBase, vnfd['_id'])
281 0         self.create(filename=filename, update_endpoint=endpoint)