blob: 0c08c22dadf80398ab30df953e106f1c1fdc4c0d [file] [log] [blame]
tiernof27c79b2018-03-12 17:08:42 +01001#! /usr/bin/python3
2# -*- coding: utf-8 -*-
3
4import getopt
5import sys
6import requests
tiernof27c79b2018-03-12 17:08:42 +01007import json
8import logging
9import yaml
tierno2236d202018-05-16 19:05:16 +020010# import json
tiernoc32ba4a2018-05-24 18:06:41 +020011# import tarfile
12from time import sleep
13import os
tiernof27c79b2018-03-12 17:08:42 +010014
15__author__ = "Alfonso Tierno, alfonso.tiernosepulveda@telefonica.com"
16__date__ = "$2018-03-01$"
gcalvino337ec512018-07-30 10:30:13 +020017__version__ = "0.3"
18version_date = "Oct 2018"
tiernof27c79b2018-03-12 17:08:42 +010019
20
21def usage():
22 print("Usage: ", sys.argv[0], "[options]")
tiernoc32ba4a2018-05-24 18:06:41 +020023 print(" Performs system tests over running NBI. It can be used for real OSM test using option '--test-osm'")
24 print(" If this is the case env variables 'OSMNBITEST_VIM_NAME' must be suplied to create a VIM if not exist "
25 "where deployment is done")
26 print("OPTIONS")
tiernof27c79b2018-03-12 17:08:42 +010027 print(" -h|--help: shows this help")
tiernoc32ba4a2018-05-24 18:06:41 +020028 print(" --insecure: Allows non trusted https NBI server")
29 print(" --list: list available tests")
30 print(" --manual-check: Deployment tests stop after deployed to allow manual inspection. Only make sense with "
31 "'--test-osm'")
32 print(" -p|--password PASSWORD: NBI access password. 'admin' by default")
33 print(" ---project PROJECT: NBI access project. 'admin' by default")
34 print(" --test TEST[,...]: Execute only a test or a comma separated list of tests")
35 print(" --params key=val: params to the previous test. key can be vnfd-files, nsd-file, ns-name, ns-config")
36 print(" --test-osm: If missing this test is intended for NBI only, no other OSM components are expected. Use "
37 "this flag to test the system. LCM and RO components are expected to be up and running")
38 print(" --timeout TIMEOUT: General NBI timeout, by default {}s".format(timeout))
39 print(" --timeout-deploy TIMEOUT: Timeout used for getting NS deployed, by default {}s".format(timeout_deploy))
40 print(" --timeout-configure TIMEOUT: Timeout used for getting NS deployed and configured,"
41 " by default {}s".format(timeout_configure))
42 print(" -u|--user USERNAME: NBI access username. 'admin' by default")
43 print(" --url URL: complete NBI server URL. 'https//localhost:9999/osm' by default")
tiernof27c79b2018-03-12 17:08:42 +010044 print(" -v|--verbose print debug information, can be used several times")
tiernoc32ba4a2018-05-24 18:06:41 +020045 print(" --no-verbose remove verbosity")
46 print(" --version: prints current version")
47 print("ENV variables used for real deployment tests with option osm-test.")
48 print(" export OSMNBITEST_VIM_NAME=vim-name")
49 print(" export OSMNBITEST_VIM_URL=vim-url")
50 print(" export OSMNBITEST_VIM_TYPE=vim-type")
51 print(" export OSMNBITEST_VIM_TENANT=vim-tenant")
52 print(" export OSMNBITEST_VIM_USER=vim-user")
53 print(" export OSMNBITEST_VIM_PASSWORD=vim-password")
54 print(" export OSMNBITEST_VIM_CONFIG=\"vim-config\"")
55 print(" export OSMNBITEST_NS_NAME=\"vim-config\"")
tiernof27c79b2018-03-12 17:08:42 +010056 return
57
58
59r_header_json = {"Content-type": "application/json"}
60headers_json = {
61 "Content-type": "application/json",
62 "Accept": "application/json",
63}
64r_header_yaml = {"Content-type": "application/yaml"}
65headers_yaml = {
66 "Content-type": "application/yaml",
67 "Accept": "application/yaml",
68}
69r_header_text = {"Content-type": "text/plain"}
70r_header_octect = {"Content-type": "application/octet-stream"}
71headers_text = {
72 "Accept": "text/plain",
73}
74r_header_zip = {"Content-type": "application/zip"}
75headers_zip = {
76 "Accept": "application/zip",
77}
tiernoc32ba4a2018-05-24 18:06:41 +020078headers_zip_yaml = {
79 "Accept": "application/yaml", "Content-type": "application/zip"
80}
81
tiernof27c79b2018-03-12 17:08:42 +010082
83# test ones authorized
84test_authorized_list = (
tierno2236d202018-05-16 19:05:16 +020085 ("AU1", "Invalid vnfd id", "GET", "/vnfpkgm/v1/vnf_packages/non-existing-id",
86 headers_json, None, 404, r_header_json, "json"),
87 ("AU2", "Invalid nsd id", "GET", "/nsd/v1/ns_descriptors/non-existing-id",
88 headers_yaml, None, 404, r_header_yaml, "yaml"),
89 ("AU3", "Invalid nsd id", "DELETE", "/nsd/v1/ns_descriptors_content/non-existing-id",
90 headers_yaml, None, 404, r_header_yaml, "yaml"),
tierno0f98af52018-03-19 10:28:22 +010091)
tiernoc32ba4a2018-05-24 18:06:41 +020092timeout = 120 # general timeout
93timeout_deploy = 60*10 # timeout for NS deploying without charms
94timeout_configure = 60*20 # timeout for NS deploying and configuring
tiernof27c79b2018-03-12 17:08:42 +010095
tierno2236d202018-05-16 19:05:16 +020096
tiernof27c79b2018-03-12 17:08:42 +010097class TestException(Exception):
98 pass
99
100
101class TestRest:
tiernoc32ba4a2018-05-24 18:06:41 +0200102 def __init__(self, url_base, header_base=None, verify=False, user="admin", password="admin", project="admin"):
tiernof27c79b2018-03-12 17:08:42 +0100103 self.url_base = url_base
tiernoc32ba4a2018-05-24 18:06:41 +0200104 if header_base is None:
105 self.header_base = {}
106 else:
107 self.header_base = header_base.copy()
tiernof27c79b2018-03-12 17:08:42 +0100108 self.s = requests.session()
tiernoc32ba4a2018-05-24 18:06:41 +0200109 self.s.headers = self.header_base
tiernof27c79b2018-03-12 17:08:42 +0100110 self.verify = verify
tiernoc32ba4a2018-05-24 18:06:41 +0200111 self.token = False
112 self.user = user
113 self.password = password
114 self.project = project
115 self.vim_id = None
tierno0f98af52018-03-19 10:28:22 +0100116 # contains ID of tests obtained from Location response header. "" key contains last obtained id
117 self.test_ids = {}
tiernoc32ba4a2018-05-24 18:06:41 +0200118 self.old_test_description = ""
tiernof27c79b2018-03-12 17:08:42 +0100119
120 def set_header(self, header):
121 self.s.headers.update(header)
122
tiernocd54a4a2018-09-12 16:40:35 +0200123 def unset_header(self, key):
124 if key in self.s.headers:
125 del self.s.headers[key]
126
tierno2236d202018-05-16 19:05:16 +0200127 def test(self, name, description, method, url, headers, payload, expected_codes, expected_headers,
tierno49e42062018-10-24 12:50:53 +0200128 expected_payload, store_file=None):
tiernof27c79b2018-03-12 17:08:42 +0100129 """
tierno0f98af52018-03-19 10:28:22 +0100130 Performs an http request and check http code response. Exit if different than allowed. It get the returned id
131 that can be used by following test in the URL with {name} where name is the name of the test
132 :param name: short name of the test
133 :param description: description of the test
tiernof27c79b2018-03-12 17:08:42 +0100134 :param method: HTTP method: GET,PUT,POST,DELETE,...
135 :param url: complete URL or relative URL
136 :param headers: request headers to add to the base headers
137 :param payload: Can be a dict, transformed to json, a text or a file if starts with '@'
138 :param expected_codes: expected response codes, can be int, int tuple or int range
139 :param expected_headers: expected response headers, dict with key values
tierno49e42062018-10-24 12:50:53 +0200140 :param expected_payload: expected payload, 0 if empty, 'yaml', 'json', 'text', 'zip', 'octet-stream'
141 :param store_file: filename to store content
tierno0f98af52018-03-19 10:28:22 +0100142 :return: requests response
tiernof27c79b2018-03-12 17:08:42 +0100143 """
tiernoc32ba4a2018-05-24 18:06:41 +0200144 r = None
tiernof27c79b2018-03-12 17:08:42 +0100145 try:
146 if not self.s:
147 self.s = requests.session()
tierno0f98af52018-03-19 10:28:22 +0100148 # URL
tiernof27c79b2018-03-12 17:08:42 +0100149 if not url:
150 url = self.url_base
151 elif not url.startswith("http"):
152 url = self.url_base + url
tierno0f98af52018-03-19 10:28:22 +0100153
tiernoc32ba4a2018-05-24 18:06:41 +0200154 var_start = url.find("<") + 1
tierno0f98af52018-03-19 10:28:22 +0100155 while var_start:
tiernoc32ba4a2018-05-24 18:06:41 +0200156 var_end = url.find(">", var_start)
tierno0f98af52018-03-19 10:28:22 +0100157 if var_end == -1:
158 break
159 var_name = url[var_start:var_end]
160 if var_name in self.test_ids:
161 url = url[:var_start-1] + self.test_ids[var_name] + url[var_end+1:]
162 var_start += len(self.test_ids[var_name])
tiernoc32ba4a2018-05-24 18:06:41 +0200163 var_start = url.find("<", var_start) + 1
tiernof27c79b2018-03-12 17:08:42 +0100164 if payload:
165 if isinstance(payload, str):
166 if payload.startswith("@"):
167 mode = "r"
168 file_name = payload[1:]
169 if payload.startswith("@b"):
170 mode = "rb"
171 file_name = payload[2:]
172 with open(file_name, mode) as f:
173 payload = f.read()
174 elif isinstance(payload, dict):
175 payload = json.dumps(payload)
tierno2236d202018-05-16 19:05:16 +0200176
tiernoc32ba4a2018-05-24 18:06:41 +0200177 test_description = "Test {} {} {} {}".format(name, description, method, url)
178 if self.old_test_description != test_description:
179 self.old_test_description = test_description
180 logger.warning(test_description)
tiernof27c79b2018-03-12 17:08:42 +0100181 stream = False
tierno49e42062018-10-24 12:50:53 +0200182 if expected_payload in ("zip", "octet-string") or store_file:
183 stream = True
tiernof27c79b2018-03-12 17:08:42 +0100184 r = getattr(self.s, method.lower())(url, data=payload, headers=headers, verify=self.verify, stream=stream)
tierno49e42062018-10-24 12:50:53 +0200185 if expected_payload in ("zip", "octet-string") or store_file:
186 logger.debug("RX {}".format(r.status_code))
187 else:
188 logger.debug("RX {}: {}".format(r.status_code, r.text))
tiernof27c79b2018-03-12 17:08:42 +0100189
190 # check response
191 if expected_codes:
192 if isinstance(expected_codes, int):
193 expected_codes = (expected_codes,)
194 if r.status_code not in expected_codes:
195 raise TestException(
196 "Got status {}. Expected {}. {}".format(r.status_code, expected_codes, r.text))
197
198 if expected_headers:
199 for header_key, header_val in expected_headers.items():
200 if header_key.lower() not in r.headers:
201 raise TestException("Header {} not present".format(header_key))
202 if header_val and header_val.lower() not in r.headers[header_key]:
203 raise TestException("Header {} does not contain {} but {}".format(header_key, header_val,
204 r.headers[header_key]))
205
206 if expected_payload is not None:
207 if expected_payload == 0 and len(r.content) > 0:
208 raise TestException("Expected empty payload")
209 elif expected_payload == "json":
210 try:
211 r.json()
212 except Exception as e:
213 raise TestException("Expected json response payload, but got Exception {}".format(e))
214 elif expected_payload == "yaml":
215 try:
216 yaml.safe_load(r.text)
217 except Exception as e:
218 raise TestException("Expected yaml response payload, but got Exception {}".format(e))
tierno49e42062018-10-24 12:50:53 +0200219 elif expected_payload in ("zip", "octet-string"):
tiernof27c79b2018-03-12 17:08:42 +0100220 if len(r.content) == 0:
221 raise TestException("Expected some response payload, but got empty")
222 # try:
223 # tar = tarfile.open(None, 'r:gz', fileobj=r.raw)
224 # for tarinfo in tar:
225 # tarname = tarinfo.name
226 # print(tarname)
227 # except Exception as e:
228 # raise TestException("Expected zip response payload, but got Exception {}".format(e))
229 elif expected_payload == "text":
230 if len(r.content) == 0:
231 raise TestException("Expected some response payload, but got empty")
tierno2236d202018-05-16 19:05:16 +0200232 # r.text
tierno49e42062018-10-24 12:50:53 +0200233 if store_file:
234 with open(store_file, 'wb') as fd:
235 for chunk in r.iter_content(chunk_size=128):
236 fd.write(chunk)
237
tierno0f98af52018-03-19 10:28:22 +0100238 location = r.headers.get("Location")
239 if location:
240 _id = location[location.rfind("/") + 1:]
241 if _id:
242 self.test_ids[name] = str(_id)
243 self.test_ids[""] = str(_id) # last id
tiernof27c79b2018-03-12 17:08:42 +0100244 return r
245 except TestException as e:
tiernoc32ba4a2018-05-24 18:06:41 +0200246 r_status_code = None
247 r_text = None
248 if r:
249 r_status_code = r.status_code
250 r_text = r.text
251 logger.error("{} \nRX code{}: {}".format(e, r_status_code, r_text))
tiernof27c79b2018-03-12 17:08:42 +0100252 exit(1)
253 except IOError as e:
254 logger.error("Cannot open file {}".format(e))
255 exit(1)
256
tiernoc32ba4a2018-05-24 18:06:41 +0200257 def get_autorization(self): # user=None, password=None, project=None):
258 if self.token: # and self.user == user and self.password == password and self.project == project:
259 return
260 # self.user = user
261 # self.password = password
262 # self.project = project
263 r = self.test("TOKEN", "Obtain token", "POST", "/admin/v1/tokens", headers_json,
264 {"username": self.user, "password": self.password, "project_id": self.project},
tiernocd54a4a2018-09-12 16:40:35 +0200265 (200, 201), r_header_json, "json")
tiernoc32ba4a2018-05-24 18:06:41 +0200266 response = r.json()
267 self.token = response["id"]
268 self.set_header({"Authorization": "Bearer {}".format(self.token)})
269
tiernocd54a4a2018-09-12 16:40:35 +0200270 def remove_authorization(self):
271 if self.token:
272 self.test("TOKEN_DEL", "Delete token", "DELETE", "/admin/v1/tokens/{}".format(self.token), headers_json,
273 None, (200, 201, 204), None, None)
274 self.token = None
275 self.unset_header("Authorization")
276
tiernoc32ba4a2018-05-24 18:06:41 +0200277 def get_create_vim(self, test_osm):
278 if self.vim_id:
279 return self.vim_id
280 self.get_autorization()
281 if test_osm:
282 vim_name = os.environ.get("OSMNBITEST_VIM_NAME")
283 if not vim_name:
284 raise TestException(
285 "Needed to define OSMNBITEST_VIM_XXX variables to create a real VIM for deployment")
286 else:
287 vim_name = "fakeVim"
288 # Get VIM
289 r = self.test("_VIMGET1", "Get VIM ID", "GET", "/admin/v1/vim_accounts?name={}".format(vim_name), headers_json,
290 None, 200, r_header_json, "json")
291 vims = r.json()
292 if vims:
293 return vims[0]["_id"]
294 # Add VIM
295 if test_osm:
296 # check needed environ parameters:
297 if not os.environ.get("OSMNBITEST_VIM_URL") or not os.environ.get("OSMNBITEST_VIM_TENANT"):
298 raise TestException("Env OSMNBITEST_VIM_URL and OSMNBITEST_VIM_TENANT are needed for create a real VIM"
299 " to deploy on whit the --test-osm option")
300 vim_data = "{{schema_version: '1.0', name: '{}', vim_type: {}, vim_url: '{}', vim_tenant_name: '{}', "\
301 "vim_user: {}, vim_password: {}".format(vim_name,
302 os.environ.get("OSMNBITEST_VIM_TYPE", "openstack"),
303 os.environ.get("OSMNBITEST_VIM_URL"),
304 os.environ.get("OSMNBITEST_VIM_TENANT"),
305 os.environ.get("OSMNBITEST_VIM_USER"),
306 os.environ.get("OSMNBITEST_VIM_PASSWORD"))
307 if os.environ.get("OSMNBITEST_VIM_CONFIG"):
308 vim_data += " ,config: {}".format(os.environ.get("OSMNBITEST_VIM_CONFIG"))
309 vim_data += "}"
310 else:
311 vim_data = "{schema_version: '1.0', name: fakeVim, vim_type: openstack, vim_url: 'http://10.11.12.13/fake'"\
312 ", vim_tenant_name: 'vimtenant', vim_user: vimuser, vim_password: vimpassword}"
313 r = self.test("_VIMGET2", "Create VIM", "POST", "/admin/v1/vim_accounts", headers_yaml, vim_data,
314 (201), {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"}, "yaml")
315 location = r.headers.get("Location")
316 return location[location.rfind("/") + 1:]
317
318
319class TestNonAuthorized:
320 description = "test invalid URLs. methods and no authorization"
321
322 @staticmethod
tiernocd54a4a2018-09-12 16:40:35 +0200323 def run(engine, test_osm, manual_check, test_params=None):
324 engine.remove_authorization()
tiernoc32ba4a2018-05-24 18:06:41 +0200325 test_not_authorized_list = (
326 ("NA1", "Invalid token", "GET", "/admin/v1/users", headers_json, None, 401, r_header_json, "json"),
327 ("NA2", "Invalid URL", "POST", "/admin/v1/nonexist", headers_yaml, None, 405, r_header_yaml, "yaml"),
328 ("NA3", "Invalid version", "DELETE", "/admin/v2/users", headers_yaml, None, 405, r_header_yaml, "yaml"),
329 )
330 for t in test_not_authorized_list:
331 engine.test(*t)
332
333
tiernocd54a4a2018-09-12 16:40:35 +0200334class TestUsersProjects:
335 description = "test project and user creation"
336
337 @staticmethod
338 def run(engine, test_osm, manual_check, test_params=None):
339 engine.get_autorization()
340 engine.test("PU1", "Create project non admin", "POST", "/admin/v1/projects", headers_json, {"name": "P1"},
341 (201, 204), {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
342 engine.test("PU2", "Create project admin", "POST", "/admin/v1/projects", headers_json,
343 {"name": "Padmin", "admin": True}, (201, 204),
344 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
345 engine.test("PU3", "Create project bad format", "POST", "/admin/v1/projects", headers_json, {"name": 1}, 422,
346 r_header_json, "json")
347 engine.test("PU4", "Create user with bad project", "POST", "/admin/v1/users", headers_json,
348 {"username": "U1", "projects": ["P1", "P2", "Padmin"], "password": "pw1"}, 409,
349 r_header_json, "json")
350 engine.test("PU5", "Create user with bad project and force", "POST", "/admin/v1/users?FORCE=True", headers_json,
351 {"username": "U1", "projects": ["P1", "P2", "Padmin"], "password": "pw1"}, 201,
352 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
353 engine.test("PU6", "Create user 2", "POST", "/admin/v1/users", headers_json,
354 {"username": "U2", "projects": ["P1"], "password": "pw2"}, 201,
355 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
356
357 engine.test("PU7", "Edit user U1, delete P2 project", "PATCH", "/admin/v1/users/U1", headers_json,
358 {"projects": {"$'P2'": None}}, 204, None, None)
359 res = engine.test("PU1", "Check user U1, contains the right projects", "GET", "/admin/v1/users/U1",
360 headers_json, None, 200, None, json)
361 u1 = res.json()
362 # print(u1)
363 expected_projects = ["P1", "Padmin"]
364 if u1["projects"] != expected_projects:
365 raise TestException("User content projects '{}' different than expected '{}'. Edition has not done"
366 " properly".format(u1["projects"], expected_projects))
367
368 engine.test("PU8", "Edit user U1, set Padmin as default project", "PUT", "/admin/v1/users/U1", headers_json,
369 {"projects": {"$'Padmin'": None, "$+[0]": "Padmin"}}, 204, None, None)
370 res = engine.test("PU1", "Check user U1, contains the right projects", "GET", "/admin/v1/users/U1",
371 headers_json, None, 200, None, json)
372 u1 = res.json()
373 # print(u1)
374 expected_projects = ["Padmin", "P1"]
375 if u1["projects"] != expected_projects:
376 raise TestException("User content projects '{}' different than expected '{}'. Edition has not done"
377 " properly".format(u1["projects"], expected_projects))
378
379 engine.test("PU9", "Edit user U1, change password", "PATCH", "/admin/v1/users/U1", headers_json,
380 {"password": "pw1_new"}, 204, None, None)
381
382 engine.test("PU10", "Change to project P1 non existing", "POST", "/admin/v1/tokens/", headers_json,
383 {"project_id": "P1"}, 401, r_header_json, "json")
384
385 res = engine.test("PU1", "Change to user U1 project P1", "POST", "/admin/v1/tokens", headers_json,
386 {"username": "U1", "password": "pw1_new", "project_id": "P1"}, (200, 201),
387 r_header_json, "json")
388 response = res.json()
389 engine.set_header({"Authorization": "Bearer {}".format(response["id"])})
390
391 engine.test("PU11", "Edit user projects non admin", "PUT", "/admin/v1/users/U1", headers_json,
392 {"projects": {"$'P1'": None}}, 401, r_header_json, "json")
393 engine.test("PU12", "Add new project non admin", "POST", "/admin/v1/projects", headers_json,
394 {"name": "P2"}, 401, r_header_json, "json")
395 engine.test("PU13", "Add new user non admin", "POST", "/admin/v1/users", headers_json,
396 {"username": "U3", "projects": ["P1"], "password": "pw3"}, 401,
397 r_header_json, "json")
398
399 res = engine.test("PU14", "Change to user U1 project Padmin", "POST", "/admin/v1/tokens", headers_json,
400 {"project_id": "Padmin"}, (200, 201), r_header_json, "json")
401 response = res.json()
402 engine.set_header({"Authorization": "Bearer {}".format(response["id"])})
403
404 engine.test("PU15", "Add new project admin", "POST", "/admin/v1/projects", headers_json, {"name": "P2"},
405 (201, 204), {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
406 engine.test("PU16", "Add new user U3 admin", "POST", "/admin/v1/users",
407 headers_json, {"username": "U3", "projects": ["P2"], "password": "pw3"}, (201, 204),
408 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
409 engine.test("PU17", "Edit user projects admin", "PUT", "/admin/v1/users/U3", headers_json,
410 {"projects": ["P2"]}, 204, None, None)
411
412 engine.test("PU18", "Delete project P2 conflict", "DELETE", "/admin/v1/projects/P2", headers_json, None, 409,
413 r_header_json, "json")
414 engine.test("PU19", "Delete project P2 forcing", "DELETE", "/admin/v1/projects/P2?FORCE=True", headers_json,
415 None, 204, None, None)
416
417 engine.test("PU20", "Delete user U1. Conflict deleting own user", "DELETE", "/admin/v1/users/U1", headers_json,
418 None, 409, r_header_json, "json")
419 engine.test("PU21", "Delete user U2", "DELETE", "/admin/v1/users/U2", headers_json, None, 204, None, None)
420 engine.test("PU22", "Delete user U3", "DELETE", "/admin/v1/users/U3", headers_json, None, 204, None, None)
421 # change to admin
422 engine.remove_authorization() # To force get authorization
423 engine.get_autorization()
424 engine.test("PU23", "Delete user U1", "DELETE", "/admin/v1/users/U1", headers_json, None, 204, None, None)
425 engine.test("PU24", "Delete project P1", "DELETE", "/admin/v1/projects/P1", headers_json, None, 204, None, None)
426 engine.test("PU25", "Delete project Padmin", "DELETE", "/admin/v1/projects/Padmin", headers_json, None, 204,
427 None, None)
428
429
tiernoc32ba4a2018-05-24 18:06:41 +0200430class TestFakeVim:
431 description = "Creates/edit/delete fake VIMs and SDN controllers"
432
433 def __init__(self):
434 self.vim = {
435 "schema_version": "1.0",
436 "schema_type": "No idea",
437 "name": "myVim",
438 "description": "Descriptor name",
439 "vim_type": "openstack",
440 "vim_url": "http://localhost:/vim",
441 "vim_tenant_name": "vimTenant",
442 "vim_user": "user",
443 "vim_password": "password",
444 "config": {"config_param": 1}
445 }
446 self.sdn = {
447 "name": "sdn-name",
448 "description": "sdn-description",
449 "dpid": "50:50:52:54:00:94:21:21",
450 "ip": "192.168.15.17",
451 "port": 8080,
452 "type": "opendaylight",
453 "version": "3.5.6",
454 "user": "user",
455 "password": "passwd"
456 }
457 self.port_mapping = [
458 {"compute_node": "compute node 1",
459 "ports": [{"pci": "0000:81:00.0", "switch_port": "port-2/1", "switch_mac": "52:54:00:94:21:21"},
460 {"pci": "0000:81:00.1", "switch_port": "port-2/2", "switch_mac": "52:54:00:94:21:22"}
461 ]},
462 {"compute_node": "compute node 2",
463 "ports": [{"pci": "0000:81:00.0", "switch_port": "port-2/3", "switch_mac": "52:54:00:94:21:23"},
464 {"pci": "0000:81:00.1", "switch_port": "port-2/4", "switch_mac": "52:54:00:94:21:24"}
465 ]}
466 ]
467
tiernocd54a4a2018-09-12 16:40:35 +0200468 def run(self, engine, test_osm, manual_check, test_params=None):
tiernoc32ba4a2018-05-24 18:06:41 +0200469
470 vim_bad = self.vim.copy()
471 vim_bad.pop("name")
472
473 engine.get_autorization()
474 engine.test("FVIM1", "Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (201, 204),
475 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json")
476 engine.test("FVIM2", "Create VIM without name, bad schema", "POST", "/admin/v1/vim_accounts", headers_json,
477 vim_bad, 422, None, headers_json)
478 engine.test("FVIM3", "Create VIM name repeated", "POST", "/admin/v1/vim_accounts", headers_json, self.vim,
479 409, None, headers_json)
480 engine.test("FVIM4", "Show VIMs", "GET", "/admin/v1/vim_accounts", headers_yaml, None, 200, r_header_yaml,
481 "yaml")
482 engine.test("FVIM5", "Show VIM", "GET", "/admin/v1/vim_accounts/<FVIM1>", headers_yaml, None, 200,
483 r_header_yaml, "yaml")
484 if not test_osm:
485 # delete with FORCE
486 engine.test("FVIM6", "Delete VIM", "DELETE", "/admin/v1/vim_accounts/<FVIM1>?FORCE=True", headers_yaml,
487 None, 202, None, 0)
488 engine.test("FVIM7", "Check VIM is deleted", "GET", "/admin/v1/vim_accounts/<FVIM1>", headers_yaml, None,
489 404, r_header_yaml, "yaml")
490 else:
491 # delete and wait until is really deleted
492 engine.test("FVIM6", "Delete VIM", "DELETE", "/admin/v1/vim_accounts/<FVIM1>", headers_yaml, None, 202,
493 None, 0)
494 wait = timeout
495 while wait >= 0:
496 r = engine.test("FVIM7", "Check VIM is deleted", "GET", "/admin/v1/vim_accounts/<FVIM1>", headers_yaml,
497 None, None, r_header_yaml, "yaml")
498 if r.status_code == 404:
499 break
500 elif r.status_code == 200:
501 wait -= 5
502 sleep(5)
503 else:
504 raise TestException("Vim created at 'FVIM1' is not delete after {} seconds".format(timeout))
505
506
507class TestVIMSDN(TestFakeVim):
508 description = "Creates VIM with SDN editing SDN controllers and port_mapping"
509
510 def __init__(self):
511 TestFakeVim.__init__(self)
512
tiernocd54a4a2018-09-12 16:40:35 +0200513 def run(self, engine, test_osm, manual_check, test_params=None):
tiernoc32ba4a2018-05-24 18:06:41 +0200514 engine.get_autorization()
515 # Added SDN
tiernocd54a4a2018-09-12 16:40:35 +0200516 engine.test("VIMSDN1", "Create SDN", "POST", "/admin/v1/sdns", headers_json, self.sdn, (201, 204),
tiernoc32ba4a2018-05-24 18:06:41 +0200517 {"Location": "/admin/v1/sdns/", "Content-Type": "application/json"}, "json")
tiernocd54a4a2018-09-12 16:40:35 +0200518 # sleep(5)
tiernoc32ba4a2018-05-24 18:06:41 +0200519 # Edit SDN
tiernocd54a4a2018-09-12 16:40:35 +0200520 engine.test("VIMSDN2", "Edit SDN", "PATCH", "/admin/v1/sdns/<VIMSDN1>", headers_json, {"name": "new_sdn_name"},
521 204, None, None)
522 # sleep(5)
tiernoc32ba4a2018-05-24 18:06:41 +0200523 # VIM with SDN
tiernocd54a4a2018-09-12 16:40:35 +0200524 self.vim["config"]["sdn-controller"] = engine.test_ids["VIMSDN1"]
tiernoc32ba4a2018-05-24 18:06:41 +0200525 self.vim["config"]["sdn-port-mapping"] = self.port_mapping
tiernocd54a4a2018-09-12 16:40:35 +0200526 engine.test("VIMSDN3", "Create VIM", "POST", "/admin/v1/vim_accounts", headers_json, self.vim, (200, 204, 201),
tiernoc32ba4a2018-05-24 18:06:41 +0200527 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json"),
528
529 self.port_mapping[0]["compute_node"] = "compute node XX"
tiernocd54a4a2018-09-12 16:40:35 +0200530 engine.test("VIMSDN4", "Edit VIM change port-mapping", "PUT", "/admin/v1/vim_accounts/<VIMSDN3>", headers_json,
531 {"config": {"sdn-port-mapping": self.port_mapping}}, 204, None, None)
532 engine.test("VIMSDN5", "Edit VIM remove port-mapping", "PUT", "/admin/v1/vim_accounts/<VIMSDN3>", headers_json,
533 {"config": {"sdn-port-mapping": None}}, 204, None, None)
534
535 if not test_osm:
536 # delete with FORCE
537 engine.test("VIMSDN6", "Delete VIM remove port-mapping", "DELETE",
538 "/admin/v1/vim_accounts/<VIMSDN3>?FORCE=True", headers_json, None, 202, None, 0)
539 engine.test("VIMSDN7", "Delete SDNC", "DELETE", "/admin/v1/sdns/<VIMSDN1>?FORCE=True", headers_json, None,
540 202, None, 0)
541
542 engine.test("VIMSDN8", "Check VIM is deleted", "GET", "/admin/v1/vim_accounts/<VIMSDN3>", headers_yaml,
543 None, 404, r_header_yaml, "yaml")
544 engine.test("VIMSDN9", "Check SDN is deleted", "GET", "/admin/v1/sdns/<VIMSDN1>", headers_yaml, None,
545 404, r_header_yaml, "yaml")
546 else:
547 # delete and wait until is really deleted
548 engine.test("VIMSDN6", "Delete VIM remove port-mapping", "DELETE", "/admin/v1/vim_accounts/<VIMSDN3>",
549 headers_json, None, (202, 201, 204), None, 0)
550 engine.test("VIMSDN7", "Delete SDN", "DELETE", "/admin/v1/sdns/<VIMSDN1>", headers_json, None,
551 (202, 201, 204), None, 0)
552 wait = timeout
553 while wait >= 0:
554 r = engine.test("VIMSDN8", "Check VIM is deleted", "GET", "/admin/v1/vim_accounts/<VIMSDN3>",
555 headers_yaml, None, None, r_header_yaml, "yaml")
556 if r.status_code == 404:
557 break
558 elif r.status_code == 200:
559 wait -= 5
560 sleep(5)
561 else:
562 raise TestException("Vim created at 'VIMSDN3' is not delete after {} seconds".format(timeout))
563 while wait >= 0:
564 r = engine.test("VIMSDN9", "Check SDNC is deleted", "GET", "/admin/v1/sdns/<VIMSDN1>",
565 headers_yaml, None, None, r_header_yaml, "yaml")
566 if r.status_code == 404:
567 break
568 elif r.status_code == 200:
569 wait -= 5
570 sleep(5)
571 else:
572 raise TestException("SDNC created at 'VIMSDN1' is not delete after {} seconds".format(timeout))
tiernoc32ba4a2018-05-24 18:06:41 +0200573
574
575class TestDeploy:
576 description = "Base class for downloading descriptors from ETSI, onboard and deploy in real VIM"
577
578 def __init__(self):
579 self.step = 0
580 self.nsd_id = None
581 self.vim_id = None
582 self.nsd_test = None
583 self.ns_test = None
gcalvino337ec512018-07-30 10:30:13 +0200584 self.ns_id = None
tiernoc32ba4a2018-05-24 18:06:41 +0200585 self.vnfds_test = []
tiernocc103432018-10-19 14:10:35 +0200586 self.vnfds_id = []
tiernoc32ba4a2018-05-24 18:06:41 +0200587 self.descriptor_url = "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
588 self.vnfd_filenames = ("cirros_vnf.tar.gz",)
589 self.nsd_filename = "cirros_2vnf_ns.tar.gz"
590 self.uses_configuration = False
gcalvino337ec512018-07-30 10:30:13 +0200591 self.uss = {}
592 self.passwds = {}
593 self.cmds = {}
594 self.keys = {}
595 self.timeout = 120
596 self.passed_tests = 0
597 self.total_tests = 0
tiernoc32ba4a2018-05-24 18:06:41 +0200598
599 def create_descriptors(self, engine):
gcalvino337ec512018-07-30 10:30:13 +0200600 temp_dir = os.path.dirname(os.path.abspath(__file__)) + "/temp/"
tiernoc32ba4a2018-05-24 18:06:41 +0200601 if not os.path.exists(temp_dir):
602 os.makedirs(temp_dir)
603 for vnfd_filename in self.vnfd_filenames:
604 if "/" in vnfd_filename:
605 vnfd_filename_path = vnfd_filename
606 if not os.path.exists(vnfd_filename_path):
607 raise TestException("File '{}' does not exist".format(vnfd_filename_path))
608 else:
609 vnfd_filename_path = temp_dir + vnfd_filename
610 if not os.path.exists(vnfd_filename_path):
611 with open(vnfd_filename_path, "wb") as file:
612 response = requests.get(self.descriptor_url + vnfd_filename)
613 if response.status_code >= 300:
614 raise TestException("Error downloading descriptor from '{}': {}".format(
615 self.descriptor_url + vnfd_filename, response.status_code))
616 file.write(response.content)
617 if vnfd_filename_path.endswith(".yaml"):
618 headers = headers_yaml
619 else:
620 headers = headers_zip_yaml
621 if self.step % 2 == 0:
622 # vnfd CREATE AND UPLOAD in one step:
tiernocc103432018-10-19 14:10:35 +0200623 test_name = "DEPLOY{}".format(self.step)
624 engine.test(test_name, "Onboard VNFD in one step", "POST",
tiernoc32ba4a2018-05-24 18:06:41 +0200625 "/vnfpkgm/v1/vnf_packages_content", headers, "@b" + vnfd_filename_path, 201,
626 {"Location": "/vnfpkgm/v1/vnf_packages_content/", "Content-Type": "application/yaml"}, yaml)
tiernocc103432018-10-19 14:10:35 +0200627 self.vnfds_test.append(test_name)
628 self.vnfds_id.append(engine.test_ids[test_name])
tiernoc32ba4a2018-05-24 18:06:41 +0200629 self.step += 1
630 else:
631 # vnfd CREATE AND UPLOAD ZIP
tiernocc103432018-10-19 14:10:35 +0200632 test_name = "DEPLOY{}".format(self.step)
633 engine.test(test_name, "Onboard VNFD step 1", "POST", "/vnfpkgm/v1/vnf_packages",
tiernoc32ba4a2018-05-24 18:06:41 +0200634 headers_json, None, 201,
635 {"Location": "/vnfpkgm/v1/vnf_packages/", "Content-Type": "application/json"}, "json")
tiernocc103432018-10-19 14:10:35 +0200636 self.vnfds_test.append(test_name)
637 self.vnfds_id.append(engine.test_ids[test_name])
tiernoc32ba4a2018-05-24 18:06:41 +0200638 self.step += 1
639 # location = r.headers["Location"]
640 # vnfd_id = location[location.rfind("/")+1:]
641 engine.test("DEPLOY{}".format(self.step), "Onboard VNFD step 2 as ZIP", "PUT",
642 "/vnfpkgm/v1/vnf_packages/<>/package_content",
643 headers, "@b" + vnfd_filename_path, 204, None, 0)
644 self.step += 2
645
646 if "/" in self.nsd_filename:
647 nsd_filename_path = self.nsd_filename
648 if not os.path.exists(nsd_filename_path):
649 raise TestException("File '{}' does not exist".format(nsd_filename_path))
650 else:
651 nsd_filename_path = temp_dir + self.nsd_filename
652 if not os.path.exists(nsd_filename_path):
653 with open(nsd_filename_path, "wb") as file:
654 response = requests.get(self.descriptor_url + self.nsd_filename)
655 if response.status_code >= 300:
656 raise TestException("Error downloading descriptor from '{}': {}".format(
657 self.descriptor_url + self.nsd_filename, response.status_code))
658 file.write(response.content)
659 if nsd_filename_path.endswith(".yaml"):
660 headers = headers_yaml
661 else:
662 headers = headers_zip_yaml
663
664 self.nsd_test = "DEPLOY" + str(self.step)
665 if self.step % 2 == 0:
666 # nsd CREATE AND UPLOAD in one step:
667 engine.test("DEPLOY{}".format(self.step), "Onboard NSD in one step", "POST",
668 "/nsd/v1/ns_descriptors_content", headers, "@b" + nsd_filename_path, 201,
669 {"Location": "/nsd/v1/ns_descriptors_content/", "Content-Type": "application/yaml"}, yaml)
670 self.step += 1
671 else:
672 # nsd CREATE AND UPLOAD ZIP
673 engine.test("DEPLOY{}".format(self.step), "Onboard NSD step 1", "POST", "/nsd/v1/ns_descriptors",
674 headers_json, None, 201,
675 {"Location": "/nsd/v1/ns_descriptors/", "Content-Type": "application/json"}, "json")
676 self.step += 1
677 # location = r.headers["Location"]
678 # vnfd_id = location[location.rfind("/")+1:]
679 engine.test("DEPLOY{}".format(self.step), "Onboard NSD step 2 as ZIP", "PUT",
680 "/nsd/v1/ns_descriptors/<>/nsd_content",
681 headers, "@b" + nsd_filename_path, 204, None, 0)
682 self.step += 2
683 self.nsd_id = engine.test_ids[self.nsd_test]
684
685 def delete_descriptors(self, engine):
686 # delete descriptors
687 engine.test("DEPLOY{}".format(self.step), "Delete NSSD SOL005", "DELETE",
688 "/nsd/v1/ns_descriptors/<{}>".format(self.nsd_test),
689 headers_yaml, None, 204, None, 0)
690 self.step += 1
691 for vnfd_test in self.vnfds_test:
692 engine.test("DEPLOY{}".format(self.step), "Delete VNFD SOL005", "DELETE",
693 "/vnfpkgm/v1/vnf_packages/<{}>".format(vnfd_test), headers_yaml, None, 204, None, 0)
694 self.step += 1
695
696 def instantiate(self, engine, ns_data):
697 ns_data_text = yaml.safe_dump(ns_data, default_flow_style=True, width=256)
698 # create NS Two steps
699 r = engine.test("DEPLOY{}".format(self.step), "Create NS step 1", "POST", "/nslcm/v1/ns_instances",
700 headers_yaml, ns_data_text, 201,
701 {"Location": "nslcm/v1/ns_instances/", "Content-Type": "application/yaml"}, "yaml")
702 self.ns_test = "DEPLOY{}".format(self.step)
gcalvino337ec512018-07-30 10:30:13 +0200703 self.ns_id = engine.test_ids[self.ns_test]
tiernoc32ba4a2018-05-24 18:06:41 +0200704 engine.test_ids[self.ns_test]
705 self.step += 1
706 r = engine.test("DEPLOY{}".format(self.step), "Instantiate NS step 2", "POST",
707 "/nslcm/v1/ns_instances/<{}>/instantiate".format(self.ns_test), headers_yaml, ns_data_text,
708 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
709 nslcmop_test = "DEPLOY{}".format(self.step)
710 self.step += 1
711
712 if test_osm:
713 # Wait until status is Ok
714 wait = timeout_configure if self.uses_configuration else timeout_deploy
715 while wait >= 0:
716 r = engine.test("DEPLOY{}".format(self.step), "Wait until NS is deployed and configured", "GET",
717 "/nslcm/v1/ns_lcm_op_occs/<{}>".format(nslcmop_test), headers_json, None,
718 200, r_header_json, "json")
719 nslcmop = r.json()
720 if "COMPLETED" in nslcmop["operationState"]:
721 break
722 elif "FAILED" in nslcmop["operationState"]:
723 raise TestException("NS instantiate has failed: {}".format(nslcmop["detailed-status"]))
724 wait -= 5
725 sleep(5)
726 else:
727 raise TestException("NS instantiate is not done after {} seconds".format(timeout_deploy))
728 self.step += 1
729
tiernocc103432018-10-19 14:10:35 +0200730 def _wait_nslcmop_ready(self, engine, nslcmop_test, timeout_deploy, expected_fail=False):
tiernoc32ba4a2018-05-24 18:06:41 +0200731 wait = timeout
732 while wait >= 0:
733 r = engine.test("DEPLOY{}".format(self.step), "Wait to ns lcm operation complete", "GET",
734 "/nslcm/v1/ns_lcm_op_occs/<{}>".format(nslcmop_test), headers_json, None,
735 200, r_header_json, "json")
736 nslcmop = r.json()
737 if "COMPLETED" in nslcmop["operationState"]:
tiernocc103432018-10-19 14:10:35 +0200738 if expected_fail:
739 raise TestException("NS terminate has success, expecting failing: {}".format(
740 nslcmop["detailed-status"]))
tiernoc32ba4a2018-05-24 18:06:41 +0200741 break
742 elif "FAILED" in nslcmop["operationState"]:
tiernocc103432018-10-19 14:10:35 +0200743 if not expected_fail:
744 raise TestException("NS terminate has failed: {}".format(nslcmop["detailed-status"]))
745 break
tiernoc32ba4a2018-05-24 18:06:41 +0200746 wait -= 5
747 sleep(5)
748 else:
749 raise TestException("NS instantiate is not terminate after {} seconds".format(timeout))
750
751 def terminate(self, engine):
752 # remove deployment
753 if test_osm:
754 r = engine.test("DEPLOY{}".format(self.step), "Terminate NS", "POST",
755 "/nslcm/v1/ns_instances/<{}>/terminate".format(self.ns_test), headers_yaml, None,
756 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
757 nslcmop2_test = "DEPLOY{}".format(self.step)
758 self.step += 1
759 # Wait until status is Ok
760 self._wait_nslcmop_ready(engine, nslcmop2_test, timeout_deploy)
761
762 r = engine.test("DEPLOY{}".format(self.step), "Delete NS", "DELETE",
763 "/nslcm/v1/ns_instances/<{}>".format(self.ns_test), headers_yaml, None,
764 204, None, 0)
765 self.step += 1
766 else:
767 r = engine.test("DEPLOY{}".format(self.step), "Delete NS with FORCE", "DELETE",
768 "/nslcm/v1/ns_instances/<{}>?FORCE=True".format(self.ns_test), headers_yaml, None,
769 204, None, 0)
770 self.step += 1
771
772 # check all it is deleted
773 r = engine.test("DEPLOY{}".format(self.step), "Check NS is deleted", "GET",
774 "/nslcm/v1/ns_instances/<{}>".format(self.ns_test), headers_yaml, None,
775 404, None, "yaml")
776 self.step += 1
777 r = engine.test("DEPLOY{}".format(self.step), "Check NSLCMOPs are deleted", "GET",
778 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId=<{}>".format(self.ns_test), headers_json, None,
779 200, None, "json")
780 nslcmops = r.json()
781 if not isinstance(nslcmops, list) or nslcmops:
782 raise TestException("NS {} deleted but with ns_lcm_op_occ active: {}".format(self.ns_test, nslcmops))
783
gcalvino337ec512018-07-30 10:30:13 +0200784 def test_ns(self, engine, test_osm, commands=None, users=None, passwds=None, keys=None, timeout=0):
785
786 n = 0
787 r = engine.test("TEST_NS{}".format(n), "GET VNFR_IDs", "GET",
788 "/nslcm/v1/ns_instances/{}".format(self.ns_id), headers_json, None,
789 200, r_header_json, "json")
790 n += 1
791 ns_data = r.json()
792
793 vnfr_list = ns_data['constituent-vnfr-ref']
794 time = 0
795
796 for vnfr_id in vnfr_list:
797 self.total_tests += 1
798 r = engine.test("TEST_NS{}".format(n), "GET IP_ADDRESS OF VNFR", "GET",
799 "/nslcm/v1/vnfrs/{}".format(vnfr_id), headers_json, None,
800 200, r_header_json, "json")
801 n += 1
802 vnfr_data = r.json()
803
804 if vnfr_data.get("ip-address"):
805 name = "TEST_NS{}".format(n)
806 description = "Run tests in VNFR with IP {}".format(vnfr_data['ip-address'])
807 n += 1
808 test_description = "Test {} {}".format(name, description)
809 logger.warning(test_description)
810 vnf_index = str(vnfr_data["member-vnf-index-ref"])
811 while timeout >= time:
812 result, message = self.do_checks([vnfr_data["ip-address"]],
813 vnf_index=vnfr_data["member-vnf-index-ref"],
814 commands=commands.get(vnf_index), user=users.get(vnf_index),
815 passwd=passwds.get(vnf_index), key=keys.get(vnf_index))
816 if result == 1:
817 logger.warning(message)
818 break
819 elif result == 0:
820 time += 20
821 sleep(20)
822 elif result == -1:
823 logger.critical(message)
824 break
825 else:
826 time -= 20
827 logger.critical(message)
828 else:
829 logger.critical("VNFR {} has not mgmt address. Check failed".format(vnfr_id))
830
831 def do_checks(self, ip, vnf_index, commands=[], user=None, passwd=None, key=None):
832 try:
833 import urllib3
834 from pssh.clients import ParallelSSHClient
835 from pssh.utils import load_private_key
836 from ssh2 import exceptions as ssh2Exception
837 except ImportError as e:
838 logger.critical("package <pssh> or/and <urllib3> is not installed. Please add it with 'pip3 install "
839 "parallel-ssh' and/or 'pip3 install urllib3': {}".format(e))
840 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
841 try:
842 p_host = os.environ.get("PROXY_HOST")
843 p_user = os.environ.get("PROXY_USER")
844 p_password = os.environ.get("PROXY_PASSWD")
845
846 if key:
847 pkey = load_private_key(key)
848 else:
849 pkey = None
850
851 client = ParallelSSHClient(ip, user=user, password=passwd, pkey=pkey, proxy_host=p_host,
852 proxy_user=p_user, proxy_password=p_password, timeout=10, num_retries=0)
853 for cmd in commands:
854 output = client.run_command(cmd)
855 client.join(output)
856 if output[ip[0]].exit_code:
857 return -1, " VNFR {} could not be checked: {}".format(ip[0], output[ip[0]].stderr)
858 else:
859 self.passed_tests += 1
860 return 1, " Test successful"
861 except (ssh2Exception.ChannelFailure, ssh2Exception.SocketDisconnectError, ssh2Exception.SocketTimeout,
862 ssh2Exception.SocketRecvError) as e:
863 return 0, "Timeout accessing the VNFR {}: {}".format(ip[0], str(e))
864 except Exception as e:
865 return -1, "ERROR checking the VNFR {}: {}".format(ip[0], str(e))
tiernoc32ba4a2018-05-24 18:06:41 +0200866
867 def aditional_operations(self, engine, test_osm, manual_check):
868 pass
869
870 def run(self, engine, test_osm, manual_check, test_params=None):
871 engine.get_autorization()
872 nsname = os.environ.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
873 if test_params:
874 if "vnfd-files" in test_params:
875 self.vnfd_filenames = test_params["vnfd-files"].split(",")
876 if "nsd-file" in test_params:
877 self.nsd_filename = test_params["nsd-file"]
878 if test_params.get("ns-name"):
879 nsname = test_params["ns-name"]
880 self.create_descriptors(engine)
881
882 # create real VIM if not exist
883 self.vim_id = engine.get_create_vim(test_osm)
884 ns_data = {"nsDescription": "default description", "nsName": nsname, "nsdId": self.nsd_id,
885 "vimAccountId": self.vim_id}
886 if test_params and test_params.get("ns-config"):
887 if isinstance(test_params["ns-config"], str):
888 ns_data.update(yaml.load(test_params["ns-config"]))
889 else:
890 ns_data.update(test_params["ns-config"])
891 self.instantiate(engine, ns_data)
892
893 if manual_check:
894 input('NS has been deployed. Perform manual check and press enter to resume')
895 else:
gcalvino337ec512018-07-30 10:30:13 +0200896 self.test_ns(engine, test_osm, self.cmds, self.uss, self.pss, self.keys, self.timeout)
tiernoc32ba4a2018-05-24 18:06:41 +0200897 self.aditional_operations(engine, test_osm, manual_check)
898 self.terminate(engine)
899 self.delete_descriptors(engine)
gcalvino337ec512018-07-30 10:30:13 +0200900 self.print_results()
901
902 def print_results(self):
903 print("\n\n\n--------------------------------------------")
904 print("TEST RESULTS:\n PASSED TESTS: {} - TOTAL TESTS: {}".format(self.total_tests, self.passed_tests))
905 print("--------------------------------------------")
tiernoc32ba4a2018-05-24 18:06:41 +0200906
907
908class TestDeployHackfestCirros(TestDeploy):
909 description = "Load and deploy Hackfest cirros_2vnf_ns example"
910
911 def __init__(self):
912 super().__init__()
913 self.vnfd_filenames = ("cirros_vnf.tar.gz",)
914 self.nsd_filename = "cirros_2vnf_ns.tar.gz"
gcalvino337ec512018-07-30 10:30:13 +0200915 self.cmds = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
916 self.uss = {'1': "cirros", '2': "cirros"}
917 self.pss = {'1': "cubswin:)", '2': "cubswin:)"}
tiernoc32ba4a2018-05-24 18:06:41 +0200918
919
tiernocc103432018-10-19 14:10:35 +0200920class TestDeployHackfest1(TestDeploy):
921 description = "Load and deploy Hackfest_1_vnfd example"
922
923 def __init__(self):
924 super().__init__()
925 self.vnfd_filenames = ("hackfest_1_vnfd.tar.gz",)
926 self.nsd_filename = "hackfest_1_nsd.tar.gz"
927 # self.cmds = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
928 # self.uss = {'1': "cirros", '2': "cirros"}
929 # self.pss = {'1': "cubswin:)", '2': "cubswin:)"}
930
931
932class TestDeployHackfestCirrosScaling(TestDeploy):
933 description = "Load and deploy Hackfest cirros_2vnf_ns example with scaling modifications"
934
935 def __init__(self):
936 super().__init__()
937 self.vnfd_filenames = ("cirros_vnf.tar.gz",)
938 self.nsd_filename = "cirros_2vnf_ns.tar.gz"
939
940 def create_descriptors(self, engine):
941 super().create_descriptors(engine)
942 # Modify VNFD to add scaling and count=2
943 payload = """
944 vdu:
945 "$id: 'cirros_vnfd-VM'":
946 count: 2
947 scaling-group-descriptor:
948 - name: "scale_cirros"
949 max-instance-count: 2
950 vdu:
951 - vdu-id-ref: cirros_vnfd-VM
952 count: 2
953 """
954 engine.test("DEPLOY{}".format(self.step), "Edit VNFD ", "PATCH",
955 "/vnfpkgm/v1/vnf_packages/{}".format(self.vnfds_id[0]),
956 headers_yaml, payload, 204, None, None)
957 self.step += 1
958
959 def aditional_operations(self, engine, test_osm, manual_check):
960 if not test_osm:
961 return
962 # 2 perform scale out twice
963 payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
964 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
965 for i in range(0, 2):
966 engine.test("DEPLOY{}".format(self.step), "Execute scale action over NS", "POST",
967 "/nslcm/v1/ns_instances/<{}>/scale".format(self.ns_test), headers_yaml, payload,
968 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
969 nslcmop2_scale_out = "DEPLOY{}".format(self.step)
970 self._wait_nslcmop_ready(engine, nslcmop2_scale_out, timeout_deploy)
971 if manual_check:
972 input('NS scale out done. Check that two more vdus are there')
973 # TODO check automatic
974
975 # 2 perform scale in
976 payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
977 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
978 for i in range(0, 2):
979 engine.test("DEPLOY{}".format(self.step), "Execute scale IN action over NS", "POST",
980 "/nslcm/v1/ns_instances/<{}>/scale".format(self.ns_test), headers_yaml, payload,
981 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
982 nslcmop2_scale_in = "DEPLOY{}".format(self.step)
983 self._wait_nslcmop_ready(engine, nslcmop2_scale_in, timeout_deploy)
984 if manual_check:
985 input('NS scale in done. Check that two less vdus are there')
986 # TODO check automatic
987
988 # perform scale in that must fail as reached limit
989 engine.test("DEPLOY{}".format(self.step), "Execute scale IN out of limit action over NS", "POST",
990 "/nslcm/v1/ns_instances/<{}>/scale".format(self.ns_test), headers_yaml, payload,
991 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
992 nslcmop2_scale_in = "DEPLOY{}".format(self.step)
993 self._wait_nslcmop_ready(engine, nslcmop2_scale_in, timeout_deploy, expected_fail=True)
994
995
tiernoc32ba4a2018-05-24 18:06:41 +0200996class TestDeployIpMac(TestDeploy):
997 description = "Load and deploy descriptor examples setting mac, ip address at descriptor and instantiate params"
998
999 def __init__(self):
1000 super().__init__()
1001 self.vnfd_filenames = ("vnfd_2vdu_set_ip_mac2.yaml", "vnfd_2vdu_set_ip_mac.yaml")
1002 self.nsd_filename = "scenario_2vdu_set_ip_mac.yaml"
1003 self.descriptor_url = \
1004 "https://osm.etsi.org/gitweb/?p=osm/RO.git;a=blob_plain;f=test/RO_tests/v3_2vdu_set_ip_mac/"
gcalvino337ec512018-07-30 10:30:13 +02001005 self.cmds = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1006 self.uss = {'1': "osm", '2': "osm"}
1007 self.pss = {'1': "osm4u", '2': "osm4u"}
1008 self.timeout = 360
tiernoc32ba4a2018-05-24 18:06:41 +02001009
1010 def run(self, engine, test_osm, manual_check, test_params=None):
1011 # super().run(engine, test_osm, manual_check, test_params)
1012 # run again setting IPs with instantiate parameters
1013 instantiation_params = {
1014 "vnf": [
1015 {
1016 "member-vnf-index": "1",
1017 "internal-vld": [
1018 {
1019 "name": "internal_vld1", # net_internal
1020 "ip-profile": {
1021 "ip-version": "ipv4",
1022 "subnet-address": "10.9.8.0/24",
1023 "dhcp-params": {"count": 100, "start-address": "10.9.8.100"}
1024 },
1025 "internal-connection-point": [
1026 {
1027 "id-ref": "eth2",
1028 "ip-address": "10.9.8.2",
1029 },
1030 {
1031 "id-ref": "eth3",
1032 "ip-address": "10.9.8.3",
1033 }
1034 ]
1035 },
1036 ],
1037
1038 "vdu": [
1039 {
1040 "id": "VM1",
1041 "interface": [
tierno7ce1db92018-07-25 12:50:52 +02001042 # {
1043 # "name": "iface11",
1044 # "floating-ip-required": True,
1045 # },
tiernoc32ba4a2018-05-24 18:06:41 +02001046 {
1047 "name": "iface13",
1048 "mac-address": "52:33:44:55:66:13"
1049 },
1050 ],
1051 },
1052 {
1053 "id": "VM2",
1054 "interface": [
1055 {
1056 "name": "iface21",
gcalvino337ec512018-07-30 10:30:13 +02001057 "ip-address": "10.31.31.22",
tiernoc32ba4a2018-05-24 18:06:41 +02001058 "mac-address": "52:33:44:55:66:21"
1059 },
1060 ],
1061 },
1062 ]
1063 },
1064 ]
1065 }
gcalvino337ec512018-07-30 10:30:13 +02001066
tiernoc32ba4a2018-05-24 18:06:41 +02001067 super().run(engine, test_osm, manual_check, test_params={"ns-config": instantiation_params})
1068
1069
1070class TestDeployHackfest4(TestDeploy):
1071 description = "Load and deploy Hackfest 4 example."
1072
1073 def __init__(self):
1074 super().__init__()
1075 self.vnfd_filenames = ("hackfest_4_vnfd.tar.gz",)
1076 self.nsd_filename = "hackfest_4_nsd.tar.gz"
1077 self.uses_configuration = True
gcalvino337ec512018-07-30 10:30:13 +02001078 self.cmds = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1079 self.uss = {'1': "ubuntu", '2': "ubuntu"}
1080 self.pss = {'1': "osm4u", '2': "osm4u"}
tiernoc32ba4a2018-05-24 18:06:41 +02001081
1082 def create_descriptors(self, engine):
1083 super().create_descriptors(engine)
1084 # Modify VNFD to add scaling
1085 payload = """
1086 scaling-group-descriptor:
1087 - name: "scale_dataVM"
1088 max-instance-count: 10
1089 scaling-policy:
1090 - name: "auto_cpu_util_above_threshold"
1091 scaling-type: "automatic"
1092 threshold-time: 0
1093 cooldown-time: 60
1094 scaling-criteria:
1095 - name: "cpu_util_above_threshold"
1096 scale-in-threshold: 15
1097 scale-in-relational-operation: "LE"
1098 scale-out-threshold: 60
1099 scale-out-relational-operation: "GE"
1100 vnf-monitoring-param-ref: "all_aaa_cpu_util"
1101 vdu:
1102 - vdu-id-ref: dataVM
1103 count: 1
1104 scaling-config-action:
1105 - trigger: post-scale-out
1106 vnf-config-primitive-name-ref: touch
1107 - trigger: pre-scale-in
1108 vnf-config-primitive-name-ref: touch
1109 vnf-configuration:
1110 config-primitive:
1111 - name: touch
1112 parameter:
1113 - name: filename
1114 data-type: STRING
1115 default-value: '/home/ubuntu/touched'
1116 """
1117 engine.test("DEPLOY{}".format(self.step), "Edit VNFD ", "PATCH",
tiernocd54a4a2018-09-12 16:40:35 +02001118 "/vnfpkgm/v1/vnf_packages/<{}>".format(self.vnfds_test[0]), headers_yaml, payload, 204, None, None)
tiernoc32ba4a2018-05-24 18:06:41 +02001119 self.step += 1
1120
tiernoc32ba4a2018-05-24 18:06:41 +02001121
1122class TestDeployHackfest3Charmed(TestDeploy):
1123 description = "Load and deploy Hackfest 3charmed_ns example. Modifies it for adding scaling and performs " \
1124 "primitive actions and scaling"
1125
1126 def __init__(self):
1127 super().__init__()
1128 self.vnfd_filenames = ("hackfest_3charmed_vnfd.tar.gz",)
1129 self.nsd_filename = "hackfest_3charmed_nsd.tar.gz"
1130 self.uses_configuration = True
gcalvino337ec512018-07-30 10:30:13 +02001131 self.cmds = {'1': [''], '2': ['ls -lrt /home/ubuntu/first-touch', ]}
1132 self.uss = {'1': "ubuntu", '2': "ubuntu"}
1133 self.pss = {'1': "osm4u", '2': "osm4u"}
tiernoc32ba4a2018-05-24 18:06:41 +02001134
1135 # def create_descriptors(self, engine):
1136 # super().create_descriptors(engine)
1137 # # Modify VNFD to add scaling
1138 # payload = """
1139 # scaling-group-descriptor:
1140 # - name: "scale_dataVM"
1141 # max-instance-count: 10
1142 # scaling-policy:
1143 # - name: "auto_cpu_util_above_threshold"
1144 # scaling-type: "automatic"
1145 # threshold-time: 0
1146 # cooldown-time: 60
1147 # scaling-criteria:
1148 # - name: "cpu_util_above_threshold"
1149 # scale-in-threshold: 15
1150 # scale-in-relational-operation: "LE"
1151 # scale-out-threshold: 60
1152 # scale-out-relational-operation: "GE"
1153 # vnf-monitoring-param-ref: "all_aaa_cpu_util"
1154 # vdu:
1155 # - vdu-id-ref: dataVM
1156 # count: 1
1157 # scaling-config-action:
1158 # - trigger: post-scale-out
1159 # vnf-config-primitive-name-ref: touch
1160 # - trigger: pre-scale-in
1161 # vnf-config-primitive-name-ref: touch
1162 # vnf-configuration:
1163 # config-primitive:
1164 # - name: touch
1165 # parameter:
1166 # - name: filename
1167 # data-type: STRING
1168 # default-value: '/home/ubuntu/touched'
1169 # """
1170 # engine.test("DEPLOY{}".format(self.step), "Edit VNFD ", "PATCH",
1171 # "/vnfpkgm/v1/vnf_packages/<{}>".format(self.vnfds_test[0]),
1172 # headers_yaml, payload, 200,
1173 # r_header_yaml, yaml)
1174 # self.vnfds_test.append("DEPLOY" + str(self.step))
1175 # self.step += 1
1176
1177 def aditional_operations(self, engine, test_osm, manual_check):
1178 if not test_osm:
1179 return
1180 # 1 perform action
1181 payload = '{member_vnf_index: "2", primitive: touch, primitive_params: { filename: /home/ubuntu/OSMTESTNBI }}'
1182 engine.test("DEPLOY{}".format(self.step), "Executer service primitive over NS", "POST",
1183 "/nslcm/v1/ns_instances/<{}>/action".format(self.ns_test), headers_yaml, payload,
1184 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
1185 nslcmop2_action = "DEPLOY{}".format(self.step)
1186 self.step += 1
1187 # Wait until status is Ok
1188 self._wait_nslcmop_ready(engine, nslcmop2_action, timeout_deploy)
1189 if manual_check:
1190 input('NS service primitive has been executed. Check that file /home/ubuntu/OSMTESTNBI is present at '
1191 'TODO_PUT_IP')
gcalvino337ec512018-07-30 10:30:13 +02001192 else:
1193 cmds = {'1': [''], '2': ['ls -lrt /home/ubuntu/OSMTESTNBI', ]}
1194 uss = {'1': "ubuntu", '2': "ubuntu"}
1195 pss = {'1': "osm4u", '2': "osm4u"}
1196 self.test_ns(engine, test_osm, cmds, uss, pss, self.keys, self.timeout)
tiernoc32ba4a2018-05-24 18:06:41 +02001197
1198 # # 2 perform scale out
1199 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
1200 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1201 # engine.test("DEPLOY{}".format(self.step), "Execute scale action over NS", "POST",
1202 # "/nslcm/v1/ns_instances/<{}>/scale".format(self.ns_test), headers_yaml, payload,
1203 # 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
1204 # nslcmop2_scale_out = "DEPLOY{}".format(self.step)
1205 # self._wait_nslcmop_ready(engine, nslcmop2_scale_out, timeout_deploy)
1206 # if manual_check:
1207 # input('NS scale out done. Check that file /home/ubuntu/touched is present and new VM is created')
1208 # # TODO check automatic
1209 #
1210 # # 2 perform scale in
1211 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
1212 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1213 # engine.test("DEPLOY{}".format(self.step), "Execute scale action over NS", "POST",
1214 # "/nslcm/v1/ns_instances/<{}>/scale".format(self.ns_test), headers_yaml, payload,
1215 # 201, {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}, "yaml")
1216 # nslcmop2_scale_in = "DEPLOY{}".format(self.step)
1217 # self._wait_nslcmop_ready(engine, nslcmop2_scale_in, timeout_deploy)
1218 # if manual_check:
1219 # input('NS scale in done. Check that file /home/ubuntu/touched is updated and new VM is deleted')
1220 # # TODO check automatic
1221
tiernof27c79b2018-03-12 17:08:42 +01001222
tierno49e42062018-10-24 12:50:53 +02001223class TestDescriptors:
1224 description = "Test VNFD, NSD, PDU descriptors CRUD and dependencies"
1225
1226 def __init__(self):
1227 self.step = 0
1228 self.vnfd_filename = "hackfest_3charmed_vnfd.tar.gz"
1229 self.nsd_filename = "hackfest_3charmed_nsd.tar.gz"
1230 self.descriptor_url = "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
1231 self.vnfd_id = None
1232 self.nsd_id = None
1233
1234 def run(self, engine, test_osm, manual_check, test_params=None):
1235 engine.get_autorization()
1236 temp_dir = os.path.dirname(os.path.abspath(__file__)) + "/temp/"
1237 if not os.path.exists(temp_dir):
1238 os.makedirs(temp_dir)
1239
1240 # download files
1241 for filename in (self.vnfd_filename, self.nsd_filename):
1242 filename_path = temp_dir + filename
1243 if not os.path.exists(filename_path):
1244 with open(filename_path, "wb") as file:
1245 response = requests.get(self.descriptor_url + filename)
1246 if response.status_code >= 300:
1247 raise TestException("Error downloading descriptor from '{}': {}".format(
1248 self.descriptor_url + filename, response.status_code))
1249 file.write(response.content)
1250
1251 vnfd_filename_path = temp_dir + self.vnfd_filename
1252 nsd_filename_path = temp_dir + self.nsd_filename
1253
1254 # vnfd CREATE AND UPLOAD in one step:
1255 test_name = "DESCRIPTOR{}".format(self.step)
1256 engine.test(test_name, "Onboard VNFD in one step", "POST",
1257 "/vnfpkgm/v1/vnf_packages_content", headers_zip_yaml, "@b" + vnfd_filename_path, 201,
1258 {"Location": "/vnfpkgm/v1/vnf_packages_content/", "Content-Type": "application/yaml"}, "yaml")
1259 self.vnfd_id = engine.test_ids[test_name]
1260 self.step += 1
1261
1262 # get vnfd descriptor
1263 engine.test("DESCRIPTOR" + str(self.step), "Get VNFD descriptor", "GET",
1264 "/vnfpkgm/v1/vnf_packages/{}".format(self.vnfd_id), headers_yaml, None, 200, r_header_yaml, "yaml")
1265 self.step += 1
1266
1267 # get vnfd file descriptor
1268 engine.test("DESCRIPTOR" + str(self.step), "Get VNFD file descriptor", "GET",
1269 "/vnfpkgm/v1/vnf_packages/{}/vnfd".format(self.vnfd_id), headers_text, None, 200,
1270 r_header_text, "text", temp_dir+"vnfd-yaml")
1271 self.step += 1
1272 # TODO compare files: diff vnfd-yaml hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml
1273
1274 # get vnfd zip file package
1275 engine.test("DESCRIPTOR" + str(self.step), "Get VNFD zip package", "GET",
1276 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self.vnfd_id), headers_zip, None, 200,
1277 r_header_zip, "zip", temp_dir+"vnfd-zip")
1278 self.step += 1
1279 # TODO compare files: diff vnfd-zip hackfest_3charmed_vnfd.tar.gz
1280
1281 # get vnfd artifact
1282 engine.test("DESCRIPTOR" + str(self.step), "Get VNFD artifact package", "GET",
1283 "/vnfpkgm/v1/vnf_packages/{}/artifacts/icons/osm.png".format(self.vnfd_id), headers_zip, None, 200,
1284 r_header_octect, "octet-string", temp_dir+"vnfd-icon")
1285 self.step += 1
1286 # TODO compare files: diff vnfd-icon hackfest_3charmed_vnfd/icons/osm.png
1287
1288 # nsd CREATE AND UPLOAD in one step:
1289 test_name = "DESCRIPTOR{}".format(self.step)
1290 engine.test(test_name, "Onboard NSD in one step", "POST",
1291 "/nsd/v1/ns_descriptors_content", headers_zip_yaml, "@b" + nsd_filename_path, 201,
1292 {"Location": "/nsd/v1/ns_descriptors_content/", "Content-Type": "application/yaml"}, "yaml")
1293 self.nsd_id = engine.test_ids[test_name]
1294 self.step += 1
1295
1296 # get nsd descriptor
1297 engine.test("DESCRIPTOR" + str(self.step), "Get NSD descriptor", "GET",
1298 "/nsd/v1/ns_descriptors/{}".format(self.nsd_id), headers_yaml, None, 200, r_header_yaml, "yaml")
1299 self.step += 1
1300
1301 # get nsd file descriptor
1302 engine.test("DESCRIPTOR" + str(self.step), "Get NSD file descriptor", "GET",
1303 "/nsd/v1/ns_descriptors/{}/nsd".format(self.nsd_id), headers_text, None, 200,
1304 r_header_text, "text", temp_dir+"nsd-yaml")
1305 self.step += 1
1306 # TODO compare files: diff nsd-yaml hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml
1307
1308 # get nsd zip file package
1309 engine.test("DESCRIPTOR" + str(self.step), "Get NSD zip package", "GET",
1310 "/nsd/v1/ns_descriptors/{}/nsd_content".format(self.nsd_id), headers_zip, None, 200,
1311 r_header_zip, "zip", temp_dir+"nsd-zip")
1312 self.step += 1
1313 # TODO compare files: diff nsd-zip hackfest_3charmed_nsd.tar.gz
1314
1315 # get nsd artifact
1316 engine.test("DESCRIPTOR" + str(self.step), "Get NSD artifact package", "GET",
1317 "/nsd/v1/ns_descriptors/{}/artifacts/icons/osm.png".format(self.nsd_id), headers_zip, None, 200,
1318 r_header_octect, "octet-string", temp_dir+"nsd-icon")
1319 self.step += 1
1320 # TODO compare files: diff nsd-icon hackfest_3charmed_nsd/icons/osm.png
1321
1322 # vnfd DELETE
1323 test_rest.test("DESCRIPTOR" + str(self.step), "Delete VNFD conflict", "DELETE",
1324 "/vnfpkgm/v1/vnf_packages/{}".format(self.vnfd_id), headers_yaml, None, 409, None, None)
1325 self.step += 1
1326
1327 test_rest.test("DESCRIPTOR" + str(self.step), "Delete VNFD force", "DELETE",
1328 "/vnfpkgm/v1/vnf_packages/{}?FORCE=TRUE".format(self.vnfd_id), headers_yaml, None, 204, None, 0)
1329 self.step += 1
1330
1331 # nsd DELETE
1332 test_rest.test("DESCRIPTOR" + str(self.step), "Delete NSD", "DELETE",
1333 "/nsd/v1/ns_descriptors/{}".format(self.nsd_id), headers_yaml, None, 204, None, 0)
1334 self.step += 1
1335
1336
tiernof27c79b2018-03-12 17:08:42 +01001337if __name__ == "__main__":
1338 global logger
1339 test = ""
tierno0f98af52018-03-19 10:28:22 +01001340
1341 # Disable warnings from self-signed certificates.
1342 requests.packages.urllib3.disable_warnings()
tiernof27c79b2018-03-12 17:08:42 +01001343 try:
1344 logging.basicConfig(format="%(levelname)s %(message)s", level=logging.ERROR)
1345 logger = logging.getLogger('NBI')
1346 # load parameters and configuration
1347 opts, args = getopt.getopt(sys.argv[1:], "hvu:p:",
tiernoc32ba4a2018-05-24 18:06:41 +02001348 ["url=", "user=", "password=", "help", "version", "verbose", "no-verbose",
1349 "project=", "insecure", "timeout", "timeout-deploy", "timeout-configure",
1350 "test=", "list", "test-osm", "manual-check", "params="])
tiernof27c79b2018-03-12 17:08:42 +01001351 url = "https://localhost:9999/osm"
1352 user = password = project = "admin"
tiernoc32ba4a2018-05-24 18:06:41 +02001353 test_osm = False
1354 manual_check = False
tiernof27c79b2018-03-12 17:08:42 +01001355 verbose = 0
1356 verify = True
tiernoc32ba4a2018-05-24 18:06:41 +02001357 test_classes = {
1358 "NonAuthorized": TestNonAuthorized,
1359 "FakeVIM": TestFakeVim,
tiernocd54a4a2018-09-12 16:40:35 +02001360 "TestUsersProjects": TestUsersProjects,
tiernoc32ba4a2018-05-24 18:06:41 +02001361 "VIM-SDN": TestVIMSDN,
1362 "Deploy-Custom": TestDeploy,
1363 "Deploy-Hackfest-Cirros": TestDeployHackfestCirros,
tiernocc103432018-10-19 14:10:35 +02001364 "Deploy-Hackfest-Cirros-Scaling": TestDeployHackfestCirrosScaling,
tiernoc32ba4a2018-05-24 18:06:41 +02001365 "Deploy-Hackfest-3Charmed": TestDeployHackfest3Charmed,
1366 "Deploy-Hackfest-4": TestDeployHackfest4,
1367 "Deploy-CirrosMacIp": TestDeployIpMac,
tierno49e42062018-10-24 12:50:53 +02001368 "TestDescriptors": TestDescriptors,
tiernocc103432018-10-19 14:10:35 +02001369 "TestDeployHackfest1": TestDeployHackfest1,
gcalvino337ec512018-07-30 10:30:13 +02001370 # "Deploy-MultiVIM": TestDeployMultiVIM,
tiernoc32ba4a2018-05-24 18:06:41 +02001371 }
1372 test_to_do = []
1373 test_params = {}
tiernof27c79b2018-03-12 17:08:42 +01001374
1375 for o, a in opts:
tiernoc32ba4a2018-05-24 18:06:41 +02001376 # print("parameter:", o, a)
tiernof27c79b2018-03-12 17:08:42 +01001377 if o == "--version":
tierno2236d202018-05-16 19:05:16 +02001378 print("test version " + __version__ + ' ' + version_date)
tiernoc32ba4a2018-05-24 18:06:41 +02001379 exit()
1380 elif o == "--list":
1381 for test, test_class in test_classes.items():
1382 print("{:20} {}".format(test + ":", test_class.description))
1383 exit()
tiernof27c79b2018-03-12 17:08:42 +01001384 elif o in ("-v", "--verbose"):
1385 verbose += 1
tierno2236d202018-05-16 19:05:16 +02001386 elif o == "no-verbose":
tiernof27c79b2018-03-12 17:08:42 +01001387 verbose = -1
1388 elif o in ("-h", "--help"):
1389 usage()
1390 sys.exit()
tiernoc32ba4a2018-05-24 18:06:41 +02001391 elif o == "--test-osm":
1392 test_osm = True
1393 elif o == "--manual-check":
1394 manual_check = True
tierno2236d202018-05-16 19:05:16 +02001395 elif o == "--url":
tiernof27c79b2018-03-12 17:08:42 +01001396 url = a
1397 elif o in ("-u", "--user"):
1398 user = a
1399 elif o in ("-p", "--password"):
1400 password = a
tierno2236d202018-05-16 19:05:16 +02001401 elif o == "--project":
tiernof27c79b2018-03-12 17:08:42 +01001402 project = a
tiernoc32ba4a2018-05-24 18:06:41 +02001403 elif o == "--test":
1404 # print("asdfadf", o, a, a.split(","))
1405 for _test in a.split(","):
1406 if _test not in test_classes:
1407 print("Invalid test name '{}'. Use option '--list' to show available tests".format(_test),
1408 file=sys.stderr)
1409 exit(1)
1410 test_to_do.append(_test)
1411 elif o == "--params":
1412 param_key, _, param_value = a.partition("=")
1413 text_index = len(test_to_do)
1414 if text_index not in test_params:
1415 test_params[text_index] = {}
1416 test_params[text_index][param_key] = param_value
tierno2236d202018-05-16 19:05:16 +02001417 elif o == "--insecure":
tiernof27c79b2018-03-12 17:08:42 +01001418 verify = False
tiernoc32ba4a2018-05-24 18:06:41 +02001419 elif o == "--timeout":
1420 timeout = int(a)
1421 elif o == "--timeout-deploy":
1422 timeout_deploy = int(a)
1423 elif o == "--timeout-configure":
1424 timeout_configure = int(a)
tiernof27c79b2018-03-12 17:08:42 +01001425 else:
1426 assert False, "Unhandled option"
1427 if verbose == 0:
1428 logger.setLevel(logging.WARNING)
1429 elif verbose > 1:
1430 logger.setLevel(logging.DEBUG)
1431 else:
1432 logger.setLevel(logging.ERROR)
1433
tiernoc32ba4a2018-05-24 18:06:41 +02001434 test_rest = TestRest(url, user=user, password=password, project=project)
1435 # print("tests to do:", test_to_do)
1436 if test_to_do:
1437 text_index = 0
1438 for test in test_to_do:
1439 text_index += 1
1440 test_class = test_classes[test]
1441 test_class().run(test_rest, test_osm, manual_check, test_params.get(text_index))
1442 else:
1443 for test, test_class in test_classes.items():
1444 test_class().run(test_rest, test_osm, manual_check, test_params.get(0))
1445 exit(0)
tiernof27c79b2018-03-12 17:08:42 +01001446
1447 # get token
tiernof27c79b2018-03-12 17:08:42 +01001448 print("PASS")
1449
tiernoc32ba4a2018-05-24 18:06:41 +02001450 except TestException as e:
1451 logger.error(test + "Test {} Exception: {}".format(test, str(e)))
1452 exit(1)
1453 except getopt.GetoptError as e:
1454 logger.error(e)
1455 print(e, file=sys.stderr)
1456 exit(1)
tiernof27c79b2018-03-12 17:08:42 +01001457 except Exception as e:
tiernoc32ba4a2018-05-24 18:06:41 +02001458 logger.critical(test + " Exception: " + str(e), exc_info=True)