2 # -*- coding: utf-8 -*-
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
25 from time
import sleep
26 from random
import randint
28 from sys
import stderr
30 __author__
= "Alfonso Tierno, alfonso.tiernosepulveda@telefonica.com"
31 __date__
= "$2018-03-01$"
33 version_date
= "Oct 2018"
37 print("Usage: ", sys
.argv
[0], "[options]")
38 print(" Performs system tests over running NBI. It can be used for real OSM test using option '--test-osm'")
39 print(" If this is the case env variables 'OSMNBITEST_VIM_NAME' must be supplied to create a VIM if not exist "
40 "where deployment is done")
42 print(" -h|--help: shows this help")
43 print(" --insecure: Allows non trusted https NBI server")
44 print(" --list: list available tests")
45 print(" --manual-check: Deployment tests stop after deployed to allow manual inspection. Only make sense with "
47 print(" -p|--password PASSWORD: NBI access password. 'admin' by default")
48 print(" ---project PROJECT: NBI access project. 'admin' by default")
49 print(" --test TEST[,...]: Execute only a test or a comma separated list of tests")
50 print(" --params key=val: params to the previous test. key can be vnfd-files, nsd-file, ns-name, ns-config")
51 print(" --test-osm: If missing this test is intended for NBI only, no other OSM components are expected. Use "
52 "this flag to test the system. LCM and RO components are expected to be up and running")
53 print(" --timeout TIMEOUT: General NBI timeout, by default {}s".format(timeout
))
54 print(" --timeout-deploy TIMEOUT: Timeout used for getting NS deployed, by default {}s".format(timeout_deploy
))
55 print(" --timeout-configure TIMEOUT: Timeout used for getting NS deployed and configured,"
56 " by default {}s".format(timeout_configure
))
57 print(" -u|--user USERNAME: NBI access username. 'admin' by default")
58 print(" --url URL: complete NBI server URL. 'https//localhost:9999/osm' by default")
59 print(" -v|--verbose print debug information, can be used several times")
60 print(" --no-verbose remove verbosity")
61 print(" --version: prints current version")
62 print("ENV variables used for real deployment tests with option osm-test.")
63 print(" export OSMNBITEST_VIM_NAME=vim-name")
64 print(" export OSMNBITEST_VIM_URL=vim-url")
65 print(" export OSMNBITEST_VIM_TYPE=vim-type")
66 print(" export OSMNBITEST_VIM_TENANT=vim-tenant")
67 print(" export OSMNBITEST_VIM_USER=vim-user")
68 print(" export OSMNBITEST_VIM_PASSWORD=vim-password")
69 print(" export OSMNBITEST_VIM_CONFIG=\"vim-config\"")
70 print(" export OSMNBITEST_NS_NAME=\"vim-config\"")
74 r_header_json
= {"Content-type": "application/json"}
75 headers_json
= {"Content-type": "application/json", "Accept": "application/json"}
76 r_header_yaml
= {"Content-type": "application/yaml"}
77 headers_yaml
= {"Content-type": "application/yaml", "Accept": "application/yaml"}
78 r_header_text
= {"Content-type": "text/plain"}
79 r_header_octect
= {"Content-type": "application/octet-stream"}
80 headers_text
= {"Accept": "text/plain,application/yaml"}
81 r_header_zip
= {"Content-type": "application/zip"}
82 headers_zip
= {"Accept": "application/zip,application/yaml"}
83 headers_zip_yaml
= {"Accept": "application/yaml", "Content-type": "application/zip"}
84 r_headers_yaml_location_vnfd
= {"Location": "/vnfpkgm/v1/vnf_packages_content/", "Content-Type": "application/yaml"}
85 r_headers_yaml_location_nsd
= {"Location": "/nsd/v1/ns_descriptors_content/", "Content-Type": "application/yaml"}
86 r_headers_yaml_location_nst
= {"Location": "/nst/v1/netslice_templates_content", "Content-Type": "application/yaml"}
87 r_headers_yaml_location_nslcmop
= {"Location": "nslcm/v1/ns_lcm_op_occs/", "Content-Type": "application/yaml"}
88 r_headers_yaml_location_nsilcmop
= {"Location": "/osm/nsilcm/v1/nsi_lcm_op_occs/", "Content-Type": "application/yaml"}
90 # test ones authorized
91 test_authorized_list
= (
92 ("AU1", "Invalid vnfd id", "GET", "/vnfpkgm/v1/vnf_packages/non-existing-id",
93 headers_json
, None, 404, r_header_json
, "json"),
94 ("AU2", "Invalid nsd id", "GET", "/nsd/v1/ns_descriptors/non-existing-id",
95 headers_yaml
, None, 404, r_header_yaml
, "yaml"),
96 ("AU3", "Invalid nsd id", "DELETE", "/nsd/v1/ns_descriptors_content/non-existing-id",
97 headers_yaml
, None, 404, r_header_yaml
, "yaml"),
99 timeout
= 120 # general timeout
100 timeout_deploy
= 60*10 # timeout for NS deploying without charms
101 timeout_configure
= 60*20 # timeout for NS deploying and configuring
104 class TestException(Exception):
109 def __init__(self
, url_base
, header_base
=None, verify
=False, user
="admin", password
="admin", project
="admin"):
110 self
.url_base
= url_base
111 if header_base
is None:
112 self
.header_base
= {}
114 self
.header_base
= header_base
.copy()
115 self
.s
= requests
.session()
116 self
.s
.headers
= self
.header_base
120 self
.password
= password
121 self
.project
= project
123 # contains ID of tests obtained from Location response header. "" key contains last obtained id
125 self
.test_name
= None
126 self
.step
= 0 # number of subtest under test
127 self
.passed_tests
= 0
128 self
.failed_tests
= 0
130 def set_test_name(self
, test_name
):
131 self
.test_name
= test_name
135 def set_header(self
, header
):
136 self
.s
.headers
.update(header
)
138 def set_tet_name(self
, test_name
):
139 self
.test_name
= test_name
141 def unset_header(self
, key
):
142 if key
in self
.s
.headers
:
143 del self
.s
.headers
[key
]
145 def test(self
, description
, method
, url
, headers
, payload
, expected_codes
, expected_headers
,
146 expected_payload
, store_file
=None, pooling
=False):
148 Performs an http request and check http code response. Exit if different than allowed. It get the returned id
149 that can be used by following test in the URL with {name} where name is the name of the test
150 :param description: description of the test
151 :param method: HTTP method: GET,PUT,POST,DELETE,...
152 :param url: complete URL or relative URL
153 :param headers: request headers to add to the base headers
154 :param payload: Can be a dict, transformed to json, a text or a file if starts with '@'
155 :param expected_codes: expected response codes, can be int, int tuple or int range
156 :param expected_headers: expected response headers, dict with key values
157 :param expected_payload: expected payload, 0 if empty, 'yaml', 'json', 'text', 'zip', 'octet-stream'
158 :param store_file: filename to store content
159 :param pooling: if True do not count neither log this test. Because a pooling is done with many equal requests
160 :return: requests response
165 self
.s
= requests
.session()
169 elif not url
.startswith("http"):
170 url
= self
.url_base
+ url
172 # replace url <> with the last ID
173 url
= url
.replace("<>", self
.last_id
)
175 if isinstance(payload
, str):
176 if payload
.startswith("@"):
178 file_name
= payload
[1:]
179 if payload
.startswith("@b"):
181 file_name
= payload
[2:]
182 with
open(file_name
, mode
) as f
:
184 elif isinstance(payload
, dict):
185 payload
= json
.dumps(payload
)
188 test_description
= "Test {}{} {} {} {}".format(self
.test_name
, self
.step
, description
, method
, url
)
189 logger
.warning(test_description
)
192 if expected_payload
in ("zip", "octet-string") or store_file
:
197 r
= getattr(self
.s
, method
.lower())(url
, data
=payload
, headers
=headers
, verify
=self
.verify
,
200 except requests
.exceptions
.ConnectionError
as e
:
203 logger
.error("Exception {}. Retrying".format(e
))
206 if expected_payload
in ("zip", "octet-string") or store_file
:
207 logger
.debug("RX {}".format(r
.status_code
))
209 logger
.debug("RX {}: {}".format(r
.status_code
, r
.text
))
213 if isinstance(expected_codes
, int):
214 expected_codes
= (expected_codes
,)
215 if r
.status_code
not in expected_codes
:
217 "Got status {}. Expected {}. {}".format(r
.status_code
, expected_codes
, r
.text
))
220 for header_key
, header_val
in expected_headers
.items():
221 if header_key
.lower() not in r
.headers
:
222 raise TestException("Header {} not present".format(header_key
))
223 if header_val
and header_val
.lower() not in r
.headers
[header_key
]:
224 raise TestException("Header {} does not contain {} but {}".format(header_key
, header_val
,
225 r
.headers
[header_key
]))
227 if expected_payload
is not None:
228 if expected_payload
== 0 and len(r
.content
) > 0:
229 raise TestException("Expected empty payload")
230 elif expected_payload
== "json":
233 except Exception as e
:
234 raise TestException("Expected json response payload, but got Exception {}".format(e
))
235 elif expected_payload
== "yaml":
237 yaml
.safe_load(r
.text
)
238 except Exception as e
:
239 raise TestException("Expected yaml response payload, but got Exception {}".format(e
))
240 elif expected_payload
in ("zip", "octet-string"):
241 if len(r
.content
) == 0:
242 raise TestException("Expected some response payload, but got empty")
244 # tar = tarfile.open(None, 'r:gz', fileobj=r.raw)
245 # for tarinfo in tar:
246 # tarname = tarinfo.name
248 # except Exception as e:
249 # raise TestException("Expected zip response payload, but got Exception {}".format(e))
250 elif expected_payload
== "text":
251 if len(r
.content
) == 0:
252 raise TestException("Expected some response payload, but got empty")
255 with
open(store_file
, 'wb') as fd
:
256 for chunk
in r
.iter_content(chunk_size
=128):
259 location
= r
.headers
.get("Location")
261 _id
= location
[location
.rfind("/") + 1:]
263 self
.last_id
= str(_id
)
265 self
.passed_tests
+= 1
267 except TestException
as e
:
268 self
.failed_tests
+= 1
272 r_status_code
= r
.status_code
274 logger
.error("{} \nRX code{}: {}".format(e
, r_status_code
, r_text
))
279 logger
.error("Cannot open file {}: {}".format(store_file
, e
))
281 logger
.error("Exception: {}".format(e
), exc_info
=True)
282 self
.failed_tests
+= 1
285 except requests
.exceptions
.RequestException
as e
:
286 logger
.error("Exception: {}".format(e
))
288 def get_autorization(self
): # user=None, password=None, project=None):
289 if self
.token
: # and self.user == user and self.password == password and self.project == project:
292 # self.password = password
293 # self.project = project
294 r
= self
.test("Obtain token", "POST", "/admin/v1/tokens", headers_json
,
295 {"username": self
.user
, "password": self
.password
, "project_id": self
.project
},
296 (200, 201), r_header_json
, "json")
300 self
.token
= response
["id"]
301 self
.set_header({"Authorization": "Bearer {}".format(self
.token
)})
303 def remove_authorization(self
):
305 self
.test("Delete token", "DELETE", "/admin/v1/tokens/{}".format(self
.token
), headers_json
,
306 None, (200, 201, 204), None, None)
308 self
.unset_header("Authorization")
310 def get_create_vim(self
, test_osm
):
313 self
.get_autorization()
315 vim_name
= os
.environ
.get("OSMNBITEST_VIM_NAME")
318 "Needed to define OSMNBITEST_VIM_XXX variables to create a real VIM for deployment")
322 r
= self
.test("Get VIM ID", "GET", "/admin/v1/vim_accounts?name={}".format(vim_name
), headers_json
,
323 None, 200, r_header_json
, "json")
328 return vims
[0]["_id"]
331 # check needed environ parameters:
332 if not os
.environ
.get("OSMNBITEST_VIM_URL") or not os
.environ
.get("OSMNBITEST_VIM_TENANT"):
333 raise TestException("Env OSMNBITEST_VIM_URL and OSMNBITEST_VIM_TENANT are needed for create a real VIM"
334 " to deploy on whit the --test-osm option")
335 vim_data
= "{{schema_version: '1.0', name: '{}', vim_type: {}, vim_url: '{}', vim_tenant_name: '{}', "\
336 "vim_user: {}, vim_password: {}".format(vim_name
,
337 os
.environ
.get("OSMNBITEST_VIM_TYPE", "openstack"),
338 os
.environ
.get("OSMNBITEST_VIM_URL"),
339 os
.environ
.get("OSMNBITEST_VIM_TENANT"),
340 os
.environ
.get("OSMNBITEST_VIM_USER"),
341 os
.environ
.get("OSMNBITEST_VIM_PASSWORD"))
342 if os
.environ
.get("OSMNBITEST_VIM_CONFIG"):
343 vim_data
+= " ,config: {}".format(os
.environ
.get("OSMNBITEST_VIM_CONFIG"))
346 vim_data
= "{schema_version: '1.0', name: fakeVim, vim_type: openstack, vim_url: 'http://10.11.12.13/fake'"\
347 ", vim_tenant_name: 'vimtenant', vim_user: vimuser, vim_password: vimpassword}"
348 self
.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_yaml
, vim_data
,
349 (201), {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"}, "yaml")
352 def print_results(self
):
353 print("\n\n\n--------------------------------------------")
354 print("TEST RESULTS: Total: {}, Passed: {}, Failed: {}".format(self
.passed_tests
+ self
.failed_tests
,
355 self
.passed_tests
, self
.failed_tests
))
356 print("--------------------------------------------")
358 def wait_until_delete(self
, url_op
, timeout_delete
):
360 Make a pooling until topic is not present, because of deleted
362 :param timeout_delete:
365 description
= "Wait to topic being deleted"
366 test_description
= "Test {}{} {} {} {}".format(self
.test_name
, self
.step
, description
, "GET", url_op
)
367 logger
.warning(test_description
)
370 wait
= timeout_delete
372 r
= self
.test(description
, "GET", url_op
, headers_yaml
, None, (200, 404), None, r_header_yaml
, "yaml",
376 if r
.status_code
== 404:
377 self
.passed_tests
+= 1
379 elif r
.status_code
== 200:
383 raise TestException("Topic is not deleted after {} seconds".format(timeout_delete
))
384 self
.failed_tests
+= 1
386 def wait_operation_ready(self
, ns_nsi
, opp_id
, timeout
, expected_fail
=False):
388 Wait until nslcmop or nsilcmop finished
389 :param ns_nsi: "ns" o "nsi"
390 :param opp_id: Id o fthe operation
392 :param expected_fail:
393 :return: None. Updates passed/failed_tests
396 url_op
= "/nslcm/v1/ns_lcm_op_occs/{}".format(opp_id
)
398 url_op
= "/nsilcm/v1/nsi_lcm_op_occs/{}".format(opp_id
)
399 description
= "Wait to {} lcm operation complete".format(ns_nsi
)
400 test_description
= "Test {}{} {} {} {}".format(self
.test_name
, self
.step
, description
, "GET", url_op
)
401 logger
.warning(test_description
)
405 r
= self
.test(description
, "GET", url_op
, headers_json
, None,
406 200, r_header_json
, "json", pooling
=True)
410 if "COMPLETED" in nslcmop
["operationState"]:
412 logger
.error("NS terminate has success, expecting failing: {}".format(nslcmop
["detailed-status"]))
413 self
.failed_tests
+= 1
415 self
.passed_tests
+= 1
417 elif "FAILED" in nslcmop
["operationState"]:
418 if not expected_fail
:
419 logger
.error("NS terminate has failed: {}".format(nslcmop
["detailed-status"]))
420 self
.failed_tests
+= 1
422 self
.passed_tests
+= 1
425 print(".", end
="", file=stderr
)
429 self
.failed_tests
+= 1
430 logger
.error("NS instantiate is not terminate after {} seconds".format(timeout
))
432 print("", file=stderr
)
435 class TestNonAuthorized
:
436 description
= "Test invalid URLs. methods and no authorization"
439 def run(engine
, test_osm
, manual_check
, test_params
=None):
440 engine
.set_test_name("NonAuth")
441 engine
.remove_authorization()
442 test_not_authorized_list
= (
443 ("Invalid token", "GET", "/admin/v1/users", headers_json
, None, 401, r_header_json
, "json"),
444 ("Invalid URL", "POST", "/admin/v1/nonexist", headers_yaml
, None, 405, r_header_yaml
, "yaml"),
445 ("Invalid version", "DELETE", "/admin/v2/users", headers_yaml
, None, 405, r_header_yaml
, "yaml"),
447 for t
in test_not_authorized_list
:
451 class TestUsersProjects
:
452 description
= "test project and user creation"
455 def run(engine
, test_osm
, manual_check
, test_params
=None):
456 engine
.set_test_name("UserProject")
457 engine
.get_autorization()
458 engine
.test("Create project non admin", "POST", "/admin/v1/projects", headers_json
, {"name": "P1"},
459 (201, 204), {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
460 engine
.test("Create project admin", "POST", "/admin/v1/projects", headers_json
,
461 {"name": "Padmin", "admin": True}, (201, 204),
462 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
463 engine
.test("Create project bad format", "POST", "/admin/v1/projects", headers_json
, {"name": 1}, (400, 422),
464 r_header_json
, "json")
465 engine
.test("Create user with bad project", "POST", "/admin/v1/users", headers_json
,
466 {"username": "U1", "projects": ["P1", "P2", "Padmin"], "password": "pw1"}, 409,
467 r_header_json
, "json")
468 engine
.test("Create user with bad project and force", "POST", "/admin/v1/users?FORCE=True", headers_json
,
469 {"username": "U1", "projects": ["P1", "P2", "Padmin"], "password": "pw1"}, 201,
470 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
471 engine
.test("Create user 2", "POST", "/admin/v1/users", headers_json
,
472 {"username": "U2", "projects": ["P1"], "password": "pw2"}, 201,
473 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
474 engine
.test("Edit user U1, delete P2 project", "PATCH", "/admin/v1/users/U1", headers_json
,
475 {"projects": {"$'P2'": None}}, 204, None, None)
476 res
= engine
.test("Check user U1, contains the right projects", "GET", "/admin/v1/users/U1",
477 headers_json
, None, 200, None, json
)
481 expected_projects
= ["P1", "Padmin"]
482 if u1
["projects"] != expected_projects
:
483 logger
.error("User content projects '{}' different than expected '{}'. Edition has not done"
484 " properly".format(u1
["projects"], expected_projects
))
485 engine
.failed_tests
+= 1
487 engine
.test("Edit user U1, set Padmin as default project", "PUT", "/admin/v1/users/U1", headers_json
,
488 {"projects": {"$'Padmin'": None, "$+[0]": "Padmin"}}, 204, None, None)
489 res
= engine
.test("Check user U1, contains the right projects", "GET", "/admin/v1/users/U1",
490 headers_json
, None, 200, None, json
)
494 expected_projects
= ["Padmin", "P1"]
495 if u1
["projects"] != expected_projects
:
496 logger
.error("User content projects '{}' different than expected '{}'. Edition has not done"
497 " properly".format(u1
["projects"], expected_projects
))
498 engine
.failed_tests
+= 1
500 engine
.test("Edit user U1, change password", "PATCH", "/admin/v1/users/U1", headers_json
,
501 {"password": "pw1_new"}, 204, None, None)
503 engine
.test("Change to project P1 non existing", "POST", "/admin/v1/tokens/", headers_json
,
504 {"project_id": "P1"}, 401, r_header_json
, "json")
506 res
= engine
.test("Change to user U1 project P1", "POST", "/admin/v1/tokens", headers_json
,
507 {"username": "U1", "password": "pw1_new", "project_id": "P1"}, (200, 201),
508 r_header_json
, "json")
510 response
= res
.json()
511 engine
.set_header({"Authorization": "Bearer {}".format(response
["id"])})
513 engine
.test("Edit user projects non admin", "PUT", "/admin/v1/users/U1", headers_json
,
514 {"projects": {"$'P1'": None}}, 401, r_header_json
, "json")
515 engine
.test("Add new project non admin", "POST", "/admin/v1/projects", headers_json
,
516 {"name": "P2"}, 401, r_header_json
, "json")
517 engine
.test("Add new user non admin", "POST", "/admin/v1/users", headers_json
,
518 {"username": "U3", "projects": ["P1"], "password": "pw3"}, 401,
519 r_header_json
, "json")
521 res
= engine
.test("Change to user U1 project Padmin", "POST", "/admin/v1/tokens", headers_json
,
522 {"project_id": "Padmin"}, (200, 201), r_header_json
, "json")
524 response
= res
.json()
525 engine
.set_header({"Authorization": "Bearer {}".format(response
["id"])})
527 engine
.test("Add new project admin", "POST", "/admin/v1/projects", headers_json
, {"name": "P2"},
528 (201, 204), {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
529 engine
.test("Add new user U3 admin", "POST", "/admin/v1/users",
530 headers_json
, {"username": "U3", "projects": ["P2"], "password": "pw3"}, (201, 204),
531 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
532 engine
.test("Edit user projects admin", "PUT", "/admin/v1/users/U3", headers_json
,
533 {"projects": ["P2"]}, 204, None, None)
535 engine
.test("Delete project P2 conflict", "DELETE", "/admin/v1/projects/P2", headers_json
, None, 409,
536 r_header_json
, "json")
537 engine
.test("Delete project P2 forcing", "DELETE", "/admin/v1/projects/P2?FORCE=True", headers_json
,
538 None, 204, None, None)
540 engine
.test("Delete user U1. Conflict deleting own user", "DELETE", "/admin/v1/users/U1", headers_json
,
541 None, 409, r_header_json
, "json")
542 engine
.test("Delete user U2", "DELETE", "/admin/v1/users/U2", headers_json
, None, 204, None, None)
543 engine
.test("Delete user U3", "DELETE", "/admin/v1/users/U3", headers_json
, None, 204, None, None)
545 engine
.remove_authorization() # To force get authorization
546 engine
.get_autorization()
547 engine
.test("Delete user U1 by Name", "DELETE", "/admin/v1/users/U1", headers_json
, None, 204, None, None)
548 engine
.test("Delete project P1 by Name", "DELETE", "/admin/v1/projects/P1", headers_json
, None, 204, None, None)
549 engine
.test("Delete project Padmin by Name", "DELETE", "/admin/v1/projects/Padmin", headers_json
, None, 204,
552 # BEGIN New Tests - Addressing Projects/Users by Name/ID
553 res
= engine
.test("Create new project P1", "POST", "/admin/v1/projects", headers_json
, {"name": "P1"},
554 201, {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
556 pid1
= res
.json()["id"]
557 # print("# pid =", pid1)
558 res
= engine
.test("Create new project P2", "POST", "/admin/v1/projects", headers_json
, {"name": "P2"},
559 201, {"Location": "/admin/v1/projects/", "Content-Type": "application/json"}, "json")
561 pid2
= res
.json()["id"]
562 # print("# pid =", pid2)
563 res
= engine
.test("Create new user U1", "POST", "/admin/v1/users", headers_json
,
564 {"username": "U1", "projects": ["P1"], "password": "pw1"}, 201,
565 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
567 uid1
= res
.json()["id"]
568 # print("# uid =", uid1)
569 res
= engine
.test("Create new user U2", "POST", "/admin/v1/users", headers_json
,
570 {"username": "U2", "projects": ["P2"], "password": "pw2"}, 201,
571 {"Location": "/admin/v1/users/", "Content-Type": "application/json"}, "json")
573 uid2
= res
.json()["id"]
574 # print("# uid =", uid2)
575 engine
.test("Get Project P1 by Name", "GET", "/admin/v1/projects/P1", headers_json
, None, 200, None, "json")
576 engine
.test("Get Project P1 by ID", "GET", "/admin/v1/projects/"+pid1
, headers_json
, None, 200, None, "json")
577 engine
.test("Get User U1 by Name", "GET", "/admin/v1/users/U1", headers_json
, None, 200, None, "json")
578 engine
.test("Get User U1 by ID", "GET", "/admin/v1/users/"+uid1
, headers_json
, None, 200, None, "json")
579 engine
.test("Rename Project P1 by Name", "PUT", "/admin/v1/projects/P1", headers_json
,
580 {"name": "P3"}, 204, None, None)
581 engine
.test("Rename Project P2 by ID", "PUT", "/admin/v1/projects/"+pid2
, headers_json
,
582 {"name": "P4"}, 204, None, None)
583 engine
.test("Rename User U1 by Name", "PUT", "/admin/v1/users/U1", headers_json
,
584 {"username": "U3"}, 204, None, None)
585 engine
.test("Rename User U2 by ID", "PUT", "/admin/v1/users/"+uid2
, headers_json
,
586 {"username": "U4"}, 204, None, None)
587 engine
.test("Get Project P1 by new Name", "GET", "/admin/v1/projects/P3", headers_json
, None, 200, None, "json")
588 engine
.test("Get User U1 by new Name", "GET", "/admin/v1/users/U3", headers_json
, None, 200, None, "json")
589 engine
.test("Delete User U1 by Name", "DELETE", "/admin/v1/users/U3", headers_json
, None, 204, None, None)
590 engine
.test("Delete User U2 by ID", "DELETE", "/admin/v1/users/"+uid2
, headers_json
, None, 204, None, None)
591 engine
.test("Delete Project P1 by Name", "DELETE", "/admin/v1/projects/P3", headers_json
, None, 204, None,
593 engine
.test("Delete Project P2 by ID", "DELETE", "/admin/v1/projects/"+pid2
, headers_json
, None, 204, None,
595 # END New Tests - Addressing Projects/Users by Name
596 engine
.remove_authorization() # To finish
600 description
= "Creates/edit/delete fake VIMs and SDN controllers"
604 "schema_version": "1.0",
605 "schema_type": "No idea",
607 "description": "Descriptor name",
608 "vim_type": "openstack",
609 "vim_url": "http://localhost:/vim",
610 "vim_tenant_name": "vimTenant",
612 "vim_password": "password",
613 "config": {"config_param": 1}
617 "description": "sdn-description",
618 "dpid": "50:50:52:54:00:94:21:21",
619 "ip": "192.168.15.17",
621 "type": "opendaylight",
626 self
.port_mapping
= [
627 {"compute_node": "compute node 1",
628 "ports": [{"pci": "0000:81:00.0", "switch_port": "port-2/1", "switch_mac": "52:54:00:94:21:21"},
629 {"pci": "0000:81:00.1", "switch_port": "port-2/2", "switch_mac": "52:54:00:94:21:22"}
631 {"compute_node": "compute node 2",
632 "ports": [{"pci": "0000:81:00.0", "switch_port": "port-2/3", "switch_mac": "52:54:00:94:21:23"},
633 {"pci": "0000:81:00.1", "switch_port": "port-2/4", "switch_mac": "52:54:00:94:21:24"}
637 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
639 vim_bad
= self
.vim
.copy()
642 engine
.set_test_name("FakeVim")
643 engine
.get_autorization()
644 engine
.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json
, self
.vim
, (201, 204),
645 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json")
646 vim_id
= engine
.last_id
647 engine
.test("Create VIM without name, bad schema", "POST", "/admin/v1/vim_accounts", headers_json
,
648 vim_bad
, 422, None, headers_json
)
649 engine
.test("Create VIM name repeated", "POST", "/admin/v1/vim_accounts", headers_json
, self
.vim
,
650 409, None, headers_json
)
651 engine
.test("Show VIMs", "GET", "/admin/v1/vim_accounts", headers_yaml
, None, 200, r_header_yaml
,
653 engine
.test("Show VIM", "GET", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_yaml
, None, 200,
654 r_header_yaml
, "yaml")
657 engine
.test("Delete VIM", "DELETE", "/admin/v1/vim_accounts/{}?FORCE=True".format(vim_id
), headers_yaml
,
659 engine
.test("Check VIM is deleted", "GET", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_yaml
, None,
660 404, r_header_yaml
, "yaml")
662 # delete and wait until is really deleted
663 engine
.test("Delete VIM", "DELETE", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_yaml
, None, 202,
665 engine
.wait_until_delete("/admin/v1/vim_accounts/{}".format(vim_id
), timeout
)
668 class TestVIMSDN(TestFakeVim
):
669 description
= "Creates VIM with SDN editing SDN controllers and port_mapping"
672 TestFakeVim
.__init
__(self
)
674 "schema_version": "1.0",
675 "schema_type": "No idea",
677 "description": "Descriptor name",
679 "wim_url": "http://localhost:/wim",
681 "password": "password",
682 "config": {"config_param": 1}
685 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
686 engine
.set_test_name("VimSdn")
687 engine
.get_autorization()
689 engine
.test("Create SDN", "POST", "/admin/v1/sdns", headers_json
, self
.sdn
, (201, 204),
690 {"Location": "/admin/v1/sdns/", "Content-Type": "application/json"}, "json")
691 sdnc_id
= engine
.last_id
694 engine
.test("Edit SDN", "PATCH", "/admin/v1/sdns/{}".format(sdnc_id
), headers_json
, {"name": "new_sdn_name"},
698 self
.vim
["config"]["sdn-controller"] = sdnc_id
699 self
.vim
["config"]["sdn-port-mapping"] = self
.port_mapping
700 engine
.test("Create VIM", "POST", "/admin/v1/vim_accounts", headers_json
, self
.vim
, (200, 204, 201),
701 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"}, "json"),
703 vim_id
= engine
.last_id
704 self
.port_mapping
[0]["compute_node"] = "compute node XX"
705 engine
.test("Edit VIM change port-mapping", "PUT", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_json
,
706 {"config": {"sdn-port-mapping": self
.port_mapping
}}, 204, None, None)
707 engine
.test("Edit VIM remove port-mapping", "PUT", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_json
,
708 {"config": {"sdn-port-mapping": None}}, 204, None, None)
710 engine
.test("Create WIM", "POST", "/admin/v1/wim_accounts", headers_json
, self
.wim
, (200, 204, 201),
711 {"Location": "/admin/v1/wim_accounts/", "Content-Type": "application/json"}, "json"),
712 wim_id
= engine
.last_id
716 engine
.test("Delete VIM remove port-mapping", "DELETE",
717 "/admin/v1/vim_accounts/{}?FORCE=True".format(vim_id
), headers_json
, None, 202, None, 0)
718 engine
.test("Delete SDNC", "DELETE", "/admin/v1/sdns/{}?FORCE=True".format(sdnc_id
), headers_json
, None,
721 engine
.test("Delete WIM", "DELETE",
722 "/admin/v1/wim_accounts/{}?FORCE=True".format(wim_id
), headers_json
, None, 202, None, 0)
723 engine
.test("Check VIM is deleted", "GET", "/admin/v1/vim_accounts/{}".format(vim_id
), headers_yaml
,
724 None, 404, r_header_yaml
, "yaml")
725 engine
.test("Check SDN is deleted", "GET", "/admin/v1/sdns/{}".format(sdnc_id
), headers_yaml
, None,
726 404, r_header_yaml
, "yaml")
727 engine
.test("Check WIM is deleted", "GET", "/admin/v1/wim_accounts/{}".format(wim_id
), headers_yaml
,
728 None, 404, r_header_yaml
, "yaml")
731 input('VIM, SDN, WIM has been deployed. Perform manual check and press enter to resume')
732 # delete and wait until is really deleted
733 engine
.test("Delete VIM remove port-mapping", "DELETE", "/admin/v1/vim_accounts/{}".format(vim_id
),
734 headers_json
, None, (202, 201, 204), None, 0)
735 engine
.test("Delete SDN", "DELETE", "/admin/v1/sdns/{}".format(sdnc_id
), headers_json
, None,
736 (202, 201, 204), None, 0)
737 engine
.test("Delete VIM", "DELETE", "/admin/v1/wim_accounts/{}".format(wim_id
),
738 headers_json
, None, (202, 201, 204), None, 0)
739 engine
.wait_until_delete("/admin/v1/vim_accounts/{}".format(vim_id
), timeout
)
740 engine
.wait_until_delete("/admin/v1/sdns/{}".format(sdnc_id
), timeout
)
741 engine
.wait_until_delete("/admin/v1/wim_accounts/{}".format(wim_id
), timeout
)
745 description
= "Base class for downloading descriptors from ETSI, onboard and deploy in real VIM"
748 self
.test_name
= "DEPLOY"
753 self
.descriptor_url
= "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
754 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
755 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
756 self
.descriptor_edit
= None
757 self
.uses_configuration
= False
764 self
.ns_params
= None
765 self
.vnfr_ip_list
= {}
767 def create_descriptors(self
, engine
):
768 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
769 if not os
.path
.exists(temp_dir
):
770 os
.makedirs(temp_dir
)
771 for vnfd_index
, vnfd_filename
in enumerate(self
.vnfd_filenames
):
772 if "/" in vnfd_filename
:
773 vnfd_filename_path
= vnfd_filename
774 if not os
.path
.exists(vnfd_filename_path
):
775 raise TestException("File '{}' does not exist".format(vnfd_filename_path
))
777 vnfd_filename_path
= temp_dir
+ vnfd_filename
778 if not os
.path
.exists(vnfd_filename_path
):
779 with
open(vnfd_filename_path
, "wb") as file:
780 response
= requests
.get(self
.descriptor_url
+ vnfd_filename
)
781 if response
.status_code
>= 300:
782 raise TestException("Error downloading descriptor from '{}': {}".format(
783 self
.descriptor_url
+ vnfd_filename
, response
.status_code
))
784 file.write(response
.content
)
785 if vnfd_filename_path
.endswith(".yaml"):
786 headers
= headers_yaml
788 headers
= headers_zip_yaml
789 if randint(0, 1) == 0:
790 # vnfd CREATE AND UPLOAD in one step:
791 engine
.test("Onboard VNFD in one step", "POST",
792 "/vnfpkgm/v1/vnf_packages_content" + self
.qforce
, headers
, "@b" + vnfd_filename_path
, 201,
793 r_headers_yaml_location_vnfd
,
795 self
.vnfds_id
.append(engine
.last_id
)
797 # vnfd CREATE AND UPLOAD ZIP
798 engine
.test("Onboard VNFD step 1", "POST", "/vnfpkgm/v1/vnf_packages",
799 headers_json
, None, 201,
800 {"Location": "/vnfpkgm/v1/vnf_packages/", "Content-Type": "application/json"}, "json")
801 self
.vnfds_id
.append(engine
.last_id
)
802 engine
.test("Onboard VNFD step 2 as ZIP", "PUT",
803 "/vnfpkgm/v1/vnf_packages/<>/package_content" + self
.qforce
,
804 headers
, "@b" + vnfd_filename_path
, 204, None, 0)
806 if self
.descriptor_edit
:
807 if "vnfd{}".format(vnfd_index
) in self
.descriptor_edit
:
809 engine
.test("Edit VNFD ", "PATCH",
810 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfds_id
[-1]),
811 headers_yaml
, self
.descriptor_edit
["vnfd{}".format(vnfd_index
)], 204, None, None)
813 if "/" in self
.nsd_filename
:
814 nsd_filename_path
= self
.nsd_filename
815 if not os
.path
.exists(nsd_filename_path
):
816 raise TestException("File '{}' does not exist".format(nsd_filename_path
))
818 nsd_filename_path
= temp_dir
+ self
.nsd_filename
819 if not os
.path
.exists(nsd_filename_path
):
820 with
open(nsd_filename_path
, "wb") as file:
821 response
= requests
.get(self
.descriptor_url
+ self
.nsd_filename
)
822 if response
.status_code
>= 300:
823 raise TestException("Error downloading descriptor from '{}': {}".format(
824 self
.descriptor_url
+ self
.nsd_filename
, response
.status_code
))
825 file.write(response
.content
)
826 if nsd_filename_path
.endswith(".yaml"):
827 headers
= headers_yaml
829 headers
= headers_zip_yaml
831 if randint(0, 1) == 0:
832 # nsd CREATE AND UPLOAD in one step:
833 engine
.test("Onboard NSD in one step", "POST",
834 "/nsd/v1/ns_descriptors_content" + self
.qforce
, headers
, "@b" + nsd_filename_path
, 201,
835 r_headers_yaml_location_nsd
, yaml
)
836 self
.nsd_id
= engine
.last_id
838 # nsd CREATE AND UPLOAD ZIP
839 engine
.test("Onboard NSD step 1", "POST", "/nsd/v1/ns_descriptors",
840 headers_json
, None, 201,
841 {"Location": "/nsd/v1/ns_descriptors/", "Content-Type": "application/json"}, "json")
842 self
.nsd_id
= engine
.last_id
843 engine
.test("Onboard NSD step 2 as ZIP", "PUT",
844 "/nsd/v1/ns_descriptors/<>/nsd_content" + self
.qforce
,
845 headers
, "@b" + nsd_filename_path
, 204, None, 0)
847 if self
.descriptor_edit
and "nsd" in self
.descriptor_edit
:
849 engine
.test("Edit NSD ", "PATCH",
850 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
851 headers_yaml
, self
.descriptor_edit
["nsd"], 204, None, None)
853 def delete_descriptors(self
, engine
):
855 engine
.test("Delete NSSD SOL005", "DELETE",
856 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
857 headers_yaml
, None, 204, None, 0)
858 for vnfd_id
in self
.vnfds_id
:
859 engine
.test("Delete VNFD SOL005", "DELETE",
860 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_id
), headers_yaml
, None, 204, None, 0)
862 def instantiate(self
, engine
, ns_data
):
863 ns_data_text
= yaml
.safe_dump(ns_data
, default_flow_style
=True, width
=256)
864 # create NS Two steps
865 r
= engine
.test("Create NS step 1", "POST", "/nslcm/v1/ns_instances",
866 headers_yaml
, ns_data_text
, 201,
867 {"Location": "nslcm/v1/ns_instances/", "Content-Type": "application/yaml"}, "yaml")
870 self
.ns_id
= engine
.last_id
871 engine
.test("Instantiate NS step 2", "POST",
872 "/nslcm/v1/ns_instances/{}/instantiate".format(self
.ns_id
), headers_yaml
, ns_data_text
,
873 201, r_headers_yaml_location_nslcmop
, "yaml")
874 nslcmop_id
= engine
.last_id
877 # Wait until status is Ok
878 timeout
= timeout_configure
if self
.uses_configuration
else timeout_deploy
879 engine
.wait_operation_ready("ns", nslcmop_id
, timeout
)
881 def terminate(self
, engine
):
884 engine
.test("Terminate NS", "POST", "/nslcm/v1/ns_instances/{}/terminate".format(self
.ns_id
), headers_yaml
,
885 None, 201, r_headers_yaml_location_nslcmop
, "yaml")
886 nslcmop2_id
= engine
.last_id
887 # Wait until status is Ok
888 engine
.wait_operation_ready("ns", nslcmop2_id
, timeout_deploy
)
890 engine
.test("Delete NS", "DELETE", "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), headers_yaml
, None,
893 engine
.test("Delete NS with FORCE", "DELETE", "/nslcm/v1/ns_instances/{}?FORCE=True".format(self
.ns_id
),
894 headers_yaml
, None, 204, None, 0)
896 # check all it is deleted
897 engine
.test("Check NS is deleted", "GET", "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), headers_yaml
, None,
899 r
= engine
.test("Check NSLCMOPs are deleted", "GET",
900 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId={}".format(self
.ns_id
), headers_json
, None,
905 if not isinstance(nslcmops
, list) or nslcmops
:
906 raise TestException("NS {} deleted but with ns_lcm_op_occ active: {}".format(self
.ns_id
, nslcmops
))
908 def test_ns(self
, engine
, test_osm
, commands
=None, users
=None, passwds
=None, keys
=None, timeout
=0):
910 r
= engine
.test("GET VNFR IDs", "GET",
911 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), headers_json
, None,
912 200, r_header_json
, "json")
917 vnfr_list
= ns_data
['constituent-vnfr-ref']
919 _commands
= commands
if commands
is not None else self
.commands
920 _users
= users
if users
is not None else self
.users
921 _passwds
= passwds
if passwds
is not None else self
.passwords
922 _keys
= keys
if keys
is not None else self
.keys
923 _timeout
= timeout
if timeout
!= 0 else self
.timeout
925 # vnfr_list=[d8272263-6bd3-4680-84ca-6a4be23b3f2d, 88b22e2f-994a-4b61-94fd-4a3c90de3dc4]
926 for vnfr_id
in vnfr_list
:
927 r
= engine
.test("Get VNFR to get IP_ADDRESS", "GET",
928 "/nslcm/v1/vnfrs/{}".format(vnfr_id
), headers_json
, None,
929 200, r_header_json
, "json")
934 vnf_index
= str(vnfr_data
["member-vnf-index-ref"])
936 ip_address
= self
.get_vnfr_ip(engine
, vnf_index
)
937 description
= "Exec command='{}' at VNFR={} IP={}".format(_commands
.get(vnf_index
)[0], vnf_index
,
940 test_description
= "{}{} {}".format(engine
.test_name
, engine
.step
, description
)
941 logger
.warning(test_description
)
942 while _timeout
>= time
:
943 result
, message
= self
.do_checks([ip_address
],
944 vnf_index
=vnfr_data
["member-vnf-index-ref"],
945 commands
=_commands
.get(vnf_index
), user
=_users
.get(vnf_index
),
946 passwd
=_passwds
.get(vnf_index
), key
=_keys
.get(vnf_index
))
948 engine
.passed_tests
+= 1
949 logger
.debug(message
)
955 engine
.failed_tests
+= 1
956 logger
.error(message
)
960 engine
.failed_tests
+= 1
961 logger
.error(message
)
963 engine
.failed_tests
+= 1
964 logger
.error("VNFR {} has not mgmt address. Check failed".format(vnf_index
))
966 def do_checks(self
, ip
, vnf_index
, commands
=[], user
=None, passwd
=None, key
=None):
969 from pssh
.clients
import ParallelSSHClient
970 from pssh
.utils
import load_private_key
971 from ssh2
import exceptions
as ssh2Exception
972 except ImportError as e
:
973 logger
.critical("Package <pssh> or/and <urllib3> is not installed. Please add them with 'pip3 install "
974 "parallel-ssh urllib3': {}".format(e
))
975 return -1, "install needed packages 'pip3 install parallel-ssh urllib3'"
976 urllib3
.disable_warnings(urllib3
.exceptions
.InsecureRequestWarning
)
978 p_host
= os
.environ
.get("PROXY_HOST")
979 p_user
= os
.environ
.get("PROXY_USER")
980 p_password
= os
.environ
.get("PROXY_PASSWD")
983 pkey
= load_private_key(key
)
987 client
= ParallelSSHClient(ip
, user
=user
, password
=passwd
, pkey
=pkey
, proxy_host
=p_host
,
988 proxy_user
=p_user
, proxy_password
=p_password
, timeout
=10, num_retries
=0)
990 output
= client
.run_command(cmd
)
992 if output
[ip
[0]].exit_code
:
993 return -1, "VNFR {} command '{}' returns error: '{}'".format(ip
[0], cmd
,
994 "\n".join(output
[ip
[0]].stderr
))
996 return 1, "VNFR {} command '{}' successful".format(ip
[0], cmd
)
997 except (ssh2Exception
.ChannelFailure
, ssh2Exception
.SocketDisconnectError
, ssh2Exception
.SocketTimeout
,
998 ssh2Exception
.SocketRecvError
) as e
:
999 return 0, "Timeout accessing the VNFR {}: {}".format(ip
[0], str(e
))
1000 except Exception as e
:
1001 return -1, "ERROR checking the VNFR {}: {}".format(ip
[0], str(e
))
1003 def additional_operations(self
, engine
, test_osm
, manual_check
):
1006 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
1007 engine
.set_test_name(self
.test_name
)
1008 engine
.get_autorization()
1009 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
1011 if "vnfd-files" in test_params
:
1012 self
.vnfd_filenames
= test_params
["vnfd-files"].split(",")
1013 if "nsd-file" in test_params
:
1014 self
.nsd_filename
= test_params
["nsd-file"]
1015 if test_params
.get("ns-name"):
1016 nsname
= test_params
["ns-name"]
1017 self
.create_descriptors(engine
)
1019 # create real VIM if not exist
1020 self
.vim_id
= engine
.get_create_vim(test_osm
)
1021 ns_data
= {"nsDescription": "default description", "nsName": nsname
, "nsdId": self
.nsd_id
,
1022 "vimAccountId": self
.vim_id
}
1024 ns_data
.update(self
.ns_params
)
1025 if test_params
and test_params
.get("ns-config"):
1026 if isinstance(test_params
["ns-config"], str):
1027 ns_data
.update(yaml
.load(test_params
["ns-config"]))
1029 ns_data
.update(test_params
["ns-config"])
1030 self
.instantiate(engine
, ns_data
)
1033 input('NS has been deployed. Perform manual check and press enter to resume')
1034 if test_osm
and self
.commands
:
1035 self
.test_ns(engine
, test_osm
)
1036 self
.additional_operations(engine
, test_osm
, manual_check
)
1037 self
.terminate(engine
)
1038 self
.delete_descriptors(engine
)
1040 def get_first_ip(self
, ip_string
):
1041 # When using a floating IP, the vnfr_data['ip-address'] contains a semicolon-separated list of IP:s.
1042 first_ip
= ip_string
.split(";")[0] if ip_string
else ""
1045 def get_vnfr_ip(self
, engine
, vnfr_index_wanted
):
1046 # If the IP address list has been obtained before, it has been stored in 'vnfr_ip_list'
1047 ip
= self
.vnfr_ip_list
.get(vnfr_index_wanted
, "")
1049 return self
.get_first_ip(ip
)
1050 r
= engine
.test("Get VNFR to get IP_ADDRESS", "GET",
1051 "/nslcm/v1/vnfrs?member-vnf-index-ref={}&nsr-id-ref={}".format(
1052 vnfr_index_wanted
, self
.ns_id
), headers_json
, None,
1053 200, r_header_json
, "json")
1056 vnfr_data
= r
.json()
1057 if not (vnfr_data
and vnfr_data
[0]):
1059 # Store the IP (or list of IPs) in 'vnfr_ip_list'
1060 ip_list
= vnfr_data
[0].get("ip-address", "")
1062 self
.vnfr_ip_list
[vnfr_index_wanted
] = ip_list
1063 ip
= self
.get_first_ip(ip_list
)
1067 class TestDeployHackfestCirros(TestDeploy
):
1068 description
= "Load and deploy Hackfest cirros_2vnf_ns example"
1072 self
.test_name
= "CIRROS"
1073 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
1074 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
1075 self
.commands
= {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1076 self
.users
= {'1': "cirros", '2': "cirros"}
1077 self
.passwords
= {'1': "cubswin:)", '2': "cubswin:)"}
1079 def terminate(self
, engine
):
1080 # Make a delete in one step, overriding the normal two step of TestDeploy that launched terminate and delete
1082 engine
.test("Terminate and delete NS in one step", "DELETE", "/nslcm/v1/ns_instances_content/{}".
1083 format(self
.ns_id
), headers_yaml
, None, 202, None, "yaml")
1085 engine
.wait_until_delete("/nslcm/v1/ns_instances/{}".format(self
.ns_id
), timeout_deploy
)
1087 engine
.test("Delete NS with FORCE", "DELETE", "/nslcm/v1/ns_instances/{}?FORCE=True".format(self
.ns_id
),
1088 headers_yaml
, None, 204, None, 0)
1090 # check all it is deleted
1091 engine
.test("Check NS is deleted", "GET", "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), headers_yaml
, None,
1093 r
= engine
.test("Check NSLCMOPs are deleted", "GET",
1094 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId={}".format(self
.ns_id
), headers_json
, None,
1099 if not isinstance(nslcmops
, list) or nslcmops
:
1100 raise TestException("NS {} deleted but with ns_lcm_op_occ active: {}".format(self
.ns_id
, nslcmops
))
1103 class TestDeployHackfest1(TestDeploy
):
1104 description
= "Load and deploy Hackfest_1_vnfd example"
1108 self
.test_name
= "HACKFEST1-"
1109 self
.vnfd_filenames
= ("hackfest_1_vnfd.tar.gz",)
1110 self
.nsd_filename
= "hackfest_1_nsd.tar.gz"
1111 # self.commands = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1112 # self.users = {'1': "cirros", '2': "cirros"}
1113 # self.passwords = {'1': "cubswin:)", '2': "cubswin:)"}
1116 class TestDeployHackfestCirrosScaling(TestDeploy
):
1117 description
= "Load and deploy Hackfest cirros_2vnf_ns example with scaling modifications"
1121 self
.test_name
= "CIRROS-SCALE"
1122 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
1123 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
1125 def create_descriptors(self
, engine
):
1126 super().create_descriptors(engine
)
1127 # Modify VNFD to add scaling and count=2
1128 self
.descriptor_edit
= {
1131 "$id: 'cirros_vnfd-VM'": {"count": 2}
1133 "scaling-group-descriptor": [{
1134 "name": "scale_cirros",
1135 "max-instance-count": 2,
1137 "vdu-id-ref": "cirros_vnfd-VM",
1144 def additional_operations(self
, engine
, test_osm
, manual_check
):
1147 # 2 perform scale out twice
1148 payload
= '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
1149 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
1150 for i
in range(0, 2):
1151 engine
.test("Execute scale action over NS", "POST",
1152 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
), headers_yaml
, payload
,
1153 201, r_headers_yaml_location_nslcmop
, "yaml")
1154 nslcmop2_scale_out
= engine
.last_id
1155 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
1157 input('NS scale out done. Check that two more vdus are there')
1158 # TODO check automatic
1160 # 2 perform scale in
1161 payload
= '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
1162 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
1163 for i
in range(0, 2):
1164 engine
.test("Execute scale IN action over NS", "POST",
1165 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
), headers_yaml
, payload
,
1166 201, r_headers_yaml_location_nslcmop
, "yaml")
1167 nslcmop2_scale_in
= engine
.last_id
1168 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
1170 input('NS scale in done. Check that two less vdus are there')
1171 # TODO check automatic
1173 # perform scale in that must fail as reached limit
1174 engine
.test("Execute scale IN out of limit action over NS", "POST",
1175 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
), headers_yaml
, payload
,
1176 201, r_headers_yaml_location_nslcmop
, "yaml")
1177 nslcmop2_scale_in
= engine
.last_id
1178 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
, expected_fail
=True)
1181 class TestDeployIpMac(TestDeploy
):
1182 description
= "Load and deploy descriptor examples setting mac, ip address at descriptor and instantiate params"
1186 self
.test_name
= "SetIpMac"
1187 self
.vnfd_filenames
= ("vnfd_2vdu_set_ip_mac2.yaml", "vnfd_2vdu_set_ip_mac.yaml")
1188 self
.nsd_filename
= "scenario_2vdu_set_ip_mac.yaml"
1189 self
.descriptor_url
= \
1190 "https://osm.etsi.org/gitweb/?p=osm/RO.git;a=blob_plain;f=test/RO_tests/v3_2vdu_set_ip_mac/"
1191 self
.commands
= {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1192 self
.users
= {'1': "osm", '2': "osm"}
1193 self
.passwords
= {'1': "osm4u", '2': "osm4u"}
1196 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
1197 # super().run(engine, test_osm, manual_check, test_params)
1198 # run again setting IPs with instantiate parameters
1199 instantiation_params
= {
1202 "member-vnf-index": "1",
1205 "name": "internal_vld1", # net_internal
1207 "ip-version": "ipv4",
1208 "subnet-address": "10.9.8.0/24",
1209 "dhcp-params": {"count": 100, "start-address": "10.9.8.100"}
1211 "internal-connection-point": [
1214 "ip-address": "10.9.8.2",
1218 "ip-address": "10.9.8.3",
1229 # "name": "iface11",
1230 # "floating-ip-required": True,
1234 "mac-address": "52:33:44:55:66:13"
1243 "ip-address": "10.31.31.22",
1244 "mac-address": "52:33:44:55:66:21"
1253 super().run(engine
, test_osm
, manual_check
, test_params
={"ns-config": instantiation_params
})
1256 class TestDeployHackfest4(TestDeploy
):
1257 description
= "Load and deploy Hackfest 4 example."
1261 self
.test_name
= "HACKFEST4-"
1262 self
.vnfd_filenames
= ("hackfest_4_vnfd.tar.gz",)
1263 self
.nsd_filename
= "hackfest_4_nsd.tar.gz"
1264 self
.uses_configuration
= True
1265 self
.commands
= {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
1266 self
.users
= {'1': "ubuntu", '2': "ubuntu"}
1267 self
.passwords
= {'1': "osm4u", '2': "osm4u"}
1268 # Modify VNFD to add scaling
1269 # self.descriptor_edit = {
1271 # 'vnf-configuration': {
1272 # 'config-primitive': [{
1275 # 'name': 'filename',
1276 # 'data-type': 'STRING',
1277 # 'default-value': '/home/ubuntu/touched'
1281 # 'scaling-group-descriptor': [{
1282 # 'name': 'scale_dataVM',
1283 # 'scaling-policy': [{
1284 # 'threshold-time': 0,
1285 # 'name': 'auto_cpu_util_above_threshold',
1286 # 'scaling-type': 'automatic',
1287 # 'scaling-criteria': [{
1288 # 'name': 'cpu_util_above_threshold',
1289 # 'vnf-monitoring-param-ref': 'all_aaa_cpu_util',
1290 # 'scale-out-relational-operation': 'GE',
1291 # 'scale-in-threshold': 15,
1292 # 'scale-out-threshold': 60,
1293 # 'scale-in-relational-operation': 'LE'
1295 # 'cooldown-time': 60
1297 # 'max-instance-count': 10,
1298 # 'scaling-config-action': [
1299 # {'vnf-config-primitive-name-ref': 'touch',
1300 # 'trigger': 'post-scale-out'},
1301 # {'vnf-config-primitive-name-ref': 'touch',
1302 # 'trigger': 'pre-scale-in'}
1305 # 'vdu-id-ref': 'dataVM',
1313 class TestDeployHackfest3Charmed(TestDeploy
):
1314 description
= "Load and deploy Hackfest 3charmed_ns example"
1318 self
.test_name
= "HACKFEST3-"
1319 self
.vnfd_filenames
= ("hackfest_3charmed_vnfd.tar.gz",)
1320 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
1321 self
.uses_configuration
= True
1322 self
.commands
= {'1': ['ls -lrt /home/ubuntu/first-touch'], '2': ['ls -lrt /home/ubuntu/first-touch']}
1323 self
.users
= {'1': "ubuntu", '2': "ubuntu"}
1324 self
.passwords
= {'1': "osm4u", '2': "osm4u"}
1325 self
.descriptor_edit
= {
1326 "vnfd0": yaml
.full_load(
1329 terminate-config-primitive:
1334 value: '/home/ubuntu/last-touch1'
1339 value: '/home/ubuntu/last-touch3'
1344 value: '/home/ubuntu/last-touch2'
1348 def additional_operations(self
, engine
, test_osm
, manual_check
):
1352 vnfr_index_selected
= "2"
1353 payload
= '{member_vnf_index: "2", primitive: touch, primitive_params: { filename: /home/ubuntu/OSMTESTNBI }}'
1354 engine
.test("Exec service primitive over NS", "POST",
1355 "/nslcm/v1/ns_instances/{}/action".format(self
.ns_id
), headers_yaml
, payload
,
1356 201, r_headers_yaml_location_nslcmop
, "yaml")
1357 nslcmop2_action
= engine
.last_id
1358 # Wait until status is Ok
1359 engine
.wait_operation_ready("ns", nslcmop2_action
, timeout_deploy
)
1360 vnfr_ip
= self
.get_vnfr_ip(engine
, vnfr_index_selected
)
1363 "NS service primitive has been executed."
1364 "Check that file /home/ubuntu/OSMTESTNBI is present at {}".
1367 commands
= {'1': [''], '2': ['ls -lrt /home/ubuntu/OSMTESTNBI', ]}
1368 self
.test_ns(engine
, test_osm
, commands
=commands
)
1370 # # 2 perform scale out
1371 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
1372 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1373 # engine.test("Execute scale action over NS", "POST",
1374 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
1375 # 201, r_headers_yaml_location_nslcmop, "yaml")
1376 # nslcmop2_scale_out = engine.last_id
1377 # engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
1379 # input('NS scale out done. Check that file /home/ubuntu/touched is present and new VM is created')
1380 # # TODO check automatic
1382 # # 2 perform scale in
1383 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
1384 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1385 # engine.test("Execute scale action over NS", "POST",
1386 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
1387 # 201, r_headers_yaml_location_nslcmop, "yaml")
1388 # nslcmop2_scale_in = engine.last_id
1389 # engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
1391 # input('NS scale in done. Check that file /home/ubuntu/touched is updated and new VM is deleted')
1392 # # TODO check automatic
1395 class TestDeployHackfest3Charmed2(TestDeployHackfest3Charmed
):
1396 description
= "Load and deploy Hackfest 3charmed_ns example modified version of descriptors to have dots in " \
1397 "ids and member-vnf-index."
1401 self
.test_name
= "HACKFEST3v2-"
1402 self
.qforce
= "?FORCE=True"
1403 self
.descriptor_edit
= {
1407 "interface": {"$[0]": {"external-connection-point-ref": "pdu-mgmt"}}
1411 "vnf-configuration": None,
1412 "connection-point": {
1416 "short-name": "pdu-mgmt"
1420 "mgmt-interface": {"cp": "pdu-mgmt"},
1421 "description": "A vnf single vdu to be used as PDU",
1425 "id": "pdu_internal",
1426 "name": "pdu_internal",
1427 "internal-connection-point": {"$[1]": None},
1428 "short-name": "pdu_internal",
1434 # Modify NSD accordingly
1436 "constituent-vnfd": {
1437 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
1440 "description": "A nsd to deploy the vnf to act as as PDU",
1442 "name": "nsd-as-pdu",
1443 "short-name": "nsd-as-pdu",
1448 "short-name": "mgmt_pdu",
1449 "vnfd-connection-point-ref": {
1451 "vnfd-connection-point-ref": "pdu-mgmt",
1452 "vnfd-id-ref": "vdu-as-pdu",
1464 class TestDeployHackfest3Charmed3(TestDeployHackfest3Charmed
):
1465 description
= "Load and deploy Hackfest 3charmed_ns example modified version to test scaling and NS parameters"
1469 self
.test_name
= "HACKFEST3v3-"
1470 self
.commands
= {'1': ['ls -lrt /home/ubuntu/first-touch-1'], '2': ['ls -lrt /home/ubuntu/first-touch-2']}
1471 self
.descriptor_edit
= {
1474 scaling-group-descriptor:
1475 - name: "scale_dataVM"
1476 max-instance-count: 10
1478 - name: "auto_cpu_util_above_threshold"
1479 scaling-type: "automatic"
1483 - name: "cpu_util_above_threshold"
1484 scale-in-threshold: 15
1485 scale-in-relational-operation: "LE"
1486 scale-out-threshold: 60
1487 scale-out-relational-operation: "GE"
1488 vnf-monitoring-param-ref: "monitor1"
1490 - vdu-id-ref: dataVM
1492 scaling-config-action:
1493 - trigger: post-scale-out
1494 vnf-config-primitive-name-ref: touch
1495 - trigger: pre-scale-in
1496 vnf-config-primitive-name-ref: touch
1500 - id: "dataVM_cpu_util"
1501 nfvi-metric: "cpu_utilization"
1506 aggregation-type: AVERAGE
1507 vdu-monitoring-param:
1509 vdu-monitoring-param-ref: "dataVM_cpu_util"
1511 initial-config-primitive:
1515 value: "<touch-filename>" # default-value: /home/ubuntu/first-touch
1520 default-value: "<touch-filename2>"
1524 "additionalParamsForVnf": [
1525 {"member-vnf-index": "1", "additionalParams": {"touch-filename": "/home/ubuntu/first-touch-1",
1526 "touch-filename2": "/home/ubuntu/second-touch-1"}},
1527 {"member-vnf-index": "2", "additionalParams": {"touch-filename": "/home/ubuntu/first-touch-2",
1528 "touch-filename2": "/home/ubuntu/second-touch-2"}},
1532 def additional_operations(self
, engine
, test_osm
, manual_check
):
1533 super().additional_operations(engine
, test_osm
, manual_check
)
1537 # 2 perform scale out
1538 payload
= '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
1539 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1540 engine
.test("Execute scale action over NS", "POST",
1541 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
), headers_yaml
, payload
,
1542 201, r_headers_yaml_location_nslcmop
, "yaml")
1543 nslcmop2_scale_out
= engine
.last_id
1544 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
1546 input('NS scale out done. Check that file /home/ubuntu/second-touch-1 is present and new VM is created')
1548 commands
= {'1': ['ls -lrt /home/ubuntu/second-touch-1', ]}
1549 self
.test_ns(engine
, test_osm
, commands
=commands
)
1550 # TODO check automatic connection to scaled VM
1552 # 2 perform scale in
1553 payload
= '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
1554 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
1555 engine
.test("Execute scale action over NS", "POST",
1556 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
), headers_yaml
, payload
,
1557 201, r_headers_yaml_location_nslcmop
, "yaml")
1558 nslcmop2_scale_in
= engine
.last_id
1559 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
1561 input('NS scale in done. Check that file /home/ubuntu/second-touch-1 is updated and new VM is deleted')
1562 # TODO check automatic
1565 class TestDeploySimpleCharm(TestDeploy
):
1566 description
= "Deploy hackfest-4 hackfest_simplecharm example"
1570 self
.test_name
= "HACKFEST-SIMPLE"
1571 self
.descriptor_url
= "https://osm-download.etsi.org/ftp/osm-4.0-four/4th-hackfest/packages/"
1572 self
.vnfd_filenames
= ("hackfest_simplecharm_vnf.tar.gz",)
1573 self
.nsd_filename
= "hackfest_simplecharm_ns.tar.gz"
1574 self
.uses_configuration
= True
1575 self
.commands
= {'1': [''], '2': ['ls -lrt /home/ubuntu/first-touch', ]}
1576 self
.users
= {'1': "ubuntu", '2': "ubuntu"}
1577 self
.passwords
= {'1': "osm4u", '2': "osm4u"}
1580 class TestDeploySimpleCharm2(TestDeploySimpleCharm
):
1581 description
= "Deploy hackfest-4 hackfest_simplecharm example changing naming to contain dots on ids and " \
1586 self
.test_name
= "HACKFEST-SIMPLE2-"
1587 self
.qforce
= "?FORCE=True"
1588 self
.descriptor_edit
= {
1590 "id": "hackfest.simplecharm.vnf"
1594 "id": "hackfest.simplecharm.ns",
1595 "constituent-vnfd": {
1596 "$[0]": {"vnfd-id-ref": "hackfest.simplecharm.vnf", "member-vnf-index": "$1"},
1597 "$[1]": {"vnfd-id-ref": "hackfest.simplecharm.vnf", "member-vnf-index": "$2"},
1601 "vnfd-connection-point-ref": {"$[0]": {"member-vnf-index-ref": "$1",
1602 "vnfd-id-ref": "hackfest.simplecharm.vnf"},
1603 "$[1]": {"member-vnf-index-ref": "$2",
1604 "vnfd-id-ref": "hackfest.simplecharm.vnf"}},
1607 "vnfd-connection-point-ref": {"$[0]": {"member-vnf-index-ref": "$1",
1608 "vnfd-id-ref": "hackfest.simplecharm.vnf"},
1609 "$[1]": {"member-vnf-index-ref": "$2",
1610 "vnfd-id-ref": "hackfest.simplecharm.vnf"}},
1617 class TestDeploySingleVdu(TestDeployHackfest3Charmed
):
1618 description
= "Generate a single VDU base on editing Hackfest3Charmed descriptors and deploy"
1622 self
.test_name
= "SingleVDU"
1623 self
.qforce
= "?FORCE=True"
1624 self
.descriptor_edit
= {
1625 # Modify VNFD to remove one VDU
1629 "interface": {"$[0]": {"external-connection-point-ref": "pdu-mgmt"}}
1633 "vnf-configuration": None,
1634 "connection-point": {
1638 "short-name": "pdu-mgmt"
1642 "mgmt-interface": {"cp": "pdu-mgmt"},
1643 "description": "A vnf single vdu to be used as PDU",
1647 "id": "pdu_internal",
1648 "name": "pdu_internal",
1649 "internal-connection-point": {"$[1]": None},
1650 "short-name": "pdu_internal",
1656 # Modify NSD accordingly
1658 "constituent-vnfd": {
1659 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
1662 "description": "A nsd to deploy the vnf to act as as PDU",
1664 "name": "nsd-as-pdu",
1665 "short-name": "nsd-as-pdu",
1670 "short-name": "mgmt_pdu",
1671 "vnfd-connection-point-ref": {
1673 "vnfd-connection-point-ref": "pdu-mgmt",
1674 "vnfd-id-ref": "vdu-as-pdu",
1686 class TestDeployHnfd(TestDeployHackfest3Charmed
):
1687 description
= "Generate a HNFD base on editing Hackfest3Charmed descriptors and deploy"
1691 self
.test_name
= "HNFD"
1692 self
.pduDeploy
= TestDeploySingleVdu()
1693 self
.pdu_interface_0
= {}
1694 self
.pdu_interface_1
= {}
1697 # self.vnf_to_pdu = """
1700 # pdu-type: PDU-TYPE-1
1705 # name: pdu-iface-internal
1707 # description: HFND, one PDU + One VDU
1713 self
.pdu_descriptor
= {
1715 "type": "PDU-TYPE-1",
1716 "vim_accounts": "to-override",
1719 "name": "mgmt-iface",
1722 "ip-address": "to override",
1723 "mac-address": "mac_address",
1724 "vim-network-name": "mgmt",
1727 "name": "pdu-iface-internal",
1730 "ip-address": "to override",
1731 "mac-address": "mac_address",
1732 "vim-network-name": "pdu_internal", # OSMNBITEST-PDU-pdu_internal
1736 self
.vnfd_filenames
= ("hackfest_3charmed_vnfd.tar.gz", "hackfest_3charmed_vnfd.tar.gz")
1738 self
.descriptor_edit
= {
1742 "short-name": "hfn1",
1745 "pdu-type": "PDU-TYPE-1",
1747 "$[0]": {"name": "mgmt-iface"},
1748 "$[1]": {"name": "pdu-iface-internal"},
1754 "constituent-vnfd": {
1755 "$[1]": {"vnfd-id-ref": "hfnd1"}
1758 "$[0]": {"vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}},
1759 "$[1]": {"vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}}
1764 def create_descriptors(self
, engine
):
1765 super().create_descriptors(engine
)
1768 self
.pdu_descriptor
["interfaces"][0].update(self
.pdu_interface_0
)
1769 self
.pdu_descriptor
["interfaces"][1].update(self
.pdu_interface_1
)
1770 self
.pdu_descriptor
["vim_accounts"] = [self
.vim_id
]
1771 # TODO get vim-network-name from vnfr.vld.name
1772 self
.pdu_descriptor
["interfaces"][1]["vim-network-name"] = "{}-{}-{}".format(
1773 os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST"),
1774 "PDU", self
.pdu_descriptor
["interfaces"][1]["vim-network-name"])
1775 engine
.test("Onboard PDU descriptor", "POST", "/pdu/v1/pdu_descriptors",
1776 {"Location": "/pdu/v1/pdu_descriptors/", "Content-Type": "application/yaml"}, self
.pdu_descriptor
,
1777 201, r_header_yaml
, "yaml")
1778 self
.pdu_id
= engine
.last_id
1780 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
1781 engine
.get_autorization()
1782 engine
.set_test_name(self
.test_name
)
1783 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
1785 # create real VIM if not exist
1786 self
.vim_id
= engine
.get_create_vim(test_osm
)
1788 self
.pduDeploy
.create_descriptors(engine
)
1789 self
.pduDeploy
.instantiate(engine
, {"nsDescription": "to be used as PDU", "nsName": nsname
+ "-PDU",
1790 "nsdId": self
.pduDeploy
.nsd_id
, "vimAccountId": self
.vim_id
})
1792 input('VNF to be used as PDU has been deployed. Perform manual check and press enter to resume')
1794 self
.pduDeploy
.test_ns(engine
, test_osm
)
1797 r
= engine
.test("Get VNFR to obtain IP_ADDRESS", "GET",
1798 "/nslcm/v1/vnfrs?nsr-id-ref={}".format(self
.pduDeploy
.ns_id
), headers_json
, None,
1799 200, r_header_json
, "json")
1802 vnfr_data
= r
.json()
1805 self
.pdu_interface_0
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][0].get("ip-address")
1806 self
.pdu_interface_1
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][1].get("ip-address")
1807 self
.pdu_interface_0
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][0].get("mac-address")
1808 self
.pdu_interface_1
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][1].get("mac-address")
1809 if not self
.pdu_interface_0
["ip-address"]:
1810 raise TestException("Vnfr has not managment ip address")
1812 self
.pdu_interface_0
["ip-address"] = "192.168.10.10"
1813 self
.pdu_interface_1
["ip-address"] = "192.168.11.10"
1814 self
.pdu_interface_0
["mac-address"] = "52:33:44:55:66:13"
1815 self
.pdu_interface_1
["mac-address"] = "52:33:44:55:66:14"
1817 self
.create_descriptors(engine
)
1819 ns_data
= {"nsDescription": "default description", "nsName": nsname
, "nsdId": self
.nsd_id
,
1820 "vimAccountId": self
.vim_id
}
1821 if test_params
and test_params
.get("ns-config"):
1822 if isinstance(test_params
["ns-config"], str):
1823 ns_data
.update(yaml
.load(test_params
["ns-config"]))
1825 ns_data
.update(test_params
["ns-config"])
1827 self
.instantiate(engine
, ns_data
)
1829 input('NS has been deployed. Perform manual check and press enter to resume')
1831 self
.test_ns(engine
, test_osm
)
1832 self
.additional_operations(engine
, test_osm
, manual_check
)
1833 self
.terminate(engine
)
1834 self
.pduDeploy
.terminate(engine
)
1835 self
.delete_descriptors(engine
)
1836 self
.pduDeploy
.delete_descriptors(engine
)
1838 def delete_descriptors(self
, engine
):
1839 super().delete_descriptors(engine
)
1841 engine
.test("Delete PDU SOL005", "DELETE",
1842 "/pdu/v1/pdu_descriptors/{}".format(self
.pdu_id
),
1843 headers_yaml
, None, 204, None, 0)
1846 class TestDescriptors
:
1847 description
= "Test VNFD, NSD, PDU descriptors CRUD and dependencies"
1850 self
.vnfd_filename
= "hackfest_3charmed_vnfd.tar.gz"
1851 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
1852 self
.descriptor_url
= "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
1855 self
.vnfd_empty
= """vnfd:vnfd-catalog:
1861 self
.vnfd_prova
= """vnfd:vnfd-catalog:
1873 - external-connection-point-ref: cp_0h8m
1881 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
1882 engine
.set_test_name("Descriptors")
1883 engine
.get_autorization()
1884 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
1885 if not os
.path
.exists(temp_dir
):
1886 os
.makedirs(temp_dir
)
1889 for filename
in (self
.vnfd_filename
, self
.nsd_filename
):
1890 filename_path
= temp_dir
+ filename
1891 if not os
.path
.exists(filename_path
):
1892 with
open(filename_path
, "wb") as file:
1893 response
= requests
.get(self
.descriptor_url
+ filename
)
1894 if response
.status_code
>= 300:
1895 raise TestException("Error downloading descriptor from '{}': {}".format(
1896 self
.descriptor_url
+ filename
, response
.status_code
))
1897 file.write(response
.content
)
1899 vnfd_filename_path
= temp_dir
+ self
.vnfd_filename
1900 nsd_filename_path
= temp_dir
+ self
.nsd_filename
1902 engine
.test("Onboard empty VNFD in one step", "POST", "/vnfpkgm/v1/vnf_packages_content", headers_yaml
,
1903 self
.vnfd_empty
, 201, r_headers_yaml_location_vnfd
, "yaml")
1904 self
.vnfd_id
= engine
.last_id
1907 engine
.test("Upload invalid VNFD ", "PUT", "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
1908 headers_yaml
, self
.vnfd_prova
, 422, r_header_yaml
, "yaml")
1910 engine
.test("Upload VNFD {}".format(self
.vnfd_filename
), "PUT",
1911 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
), headers_zip_yaml
,
1912 "@b" + vnfd_filename_path
, 204, None, 0)
1914 queries
= ["mgmt-interface.cp=mgmt", "vdu.0.interface.0.external-connection-point-ref=mgmt",
1915 "vdu.0.interface.1.internal-connection-point-ref=internal",
1916 "internal-vld.0.internal-connection-point.0.id-ref=internal",
1917 # Detection of duplicated VLD names in VNF Descriptors
1918 # URL: internal-vld=[
1919 # {id: internal1, name: internal, type:ELAN,
1920 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]},
1921 # {id: internal2, name: internal, type:ELAN,
1922 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]}
1924 "internal-vld=%5B%7Bid%3A%20internal1%2C%20name%3A%20internal%2C%20type%3A%20ELAN%2C%20"
1925 "internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7Bid-ref%3A%20"
1926 "dataVM-internal%7D%5D%7D%2C%20%7Bid%3A%20internal2%2C%20name%3A%20internal%2C%20type%3A%20"
1927 "ELAN%2C%20internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7B"
1928 "id-ref%3A%20dataVM-internal%7D%5D%7D%5D"
1930 for query
in queries
:
1931 engine
.test("Upload invalid VNFD ", "PUT",
1932 "/vnfpkgm/v1/vnf_packages/{}/package_content?{}".format(self
.vnfd_id
, query
),
1933 headers_zip_yaml
, "@b" + vnfd_filename_path
, 422, r_header_yaml
, "yaml")
1936 engine
.test("Upload invalid VNFD ", "PUT", "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
1937 headers_yaml
, self
.vnfd_prova
, 422, r_header_yaml
, "yaml")
1939 # get vnfd descriptor
1940 engine
.test("Get VNFD descriptor", "GET", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
1941 headers_yaml
, None, 200, r_header_yaml
, "yaml")
1943 # get vnfd file descriptor
1944 engine
.test("Get VNFD file descriptor", "GET", "/vnfpkgm/v1/vnf_packages/{}/vnfd".format(self
.vnfd_id
),
1945 headers_text
, None, 200, r_header_text
, "text", temp_dir
+"vnfd-yaml")
1946 # TODO compare files: diff vnfd-yaml hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml
1948 # get vnfd zip file package
1949 engine
.test("Get VNFD zip package", "GET",
1950 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
), headers_zip
, None, 200,
1951 r_header_zip
, "zip", temp_dir
+"vnfd-zip")
1952 # TODO compare files: diff vnfd-zip hackfest_3charmed_vnfd.tar.gz
1955 engine
.test("Get VNFD artifact package", "GET",
1956 "/vnfpkgm/v1/vnf_packages/{}/artifacts/icons/osm.png".format(self
.vnfd_id
), headers_zip
, None, 200,
1957 r_header_octect
, "octet-string", temp_dir
+"vnfd-icon")
1958 # TODO compare files: diff vnfd-icon hackfest_3charmed_vnfd/icons/osm.png
1960 # nsd CREATE AND UPLOAD in one step:
1961 engine
.test("Onboard NSD in one step", "POST", "/nsd/v1/ns_descriptors_content", headers_zip_yaml
,
1962 "@b" + nsd_filename_path
, 201, r_headers_yaml_location_nsd
, "yaml")
1963 self
.nsd_id
= engine
.last_id
1965 queries
= ["vld.0.vnfd-connection-point-ref.0.vnfd-id-ref=hf"]
1966 for query
in queries
:
1967 engine
.test("Upload invalid NSD ", "PUT",
1968 "/nsd/v1/ns_descriptors/{}/nsd_content?{}".format(self
.nsd_id
, query
),
1969 headers_zip_yaml
, "@b" + nsd_filename_path
, 422, r_header_yaml
, "yaml")
1971 # get nsd descriptor
1972 engine
.test("Get NSD descriptor", "GET", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
), headers_yaml
,
1973 None, 200, r_header_yaml
, "yaml")
1975 # get nsd file descriptor
1976 engine
.test("Get NSD file descriptor", "GET", "/nsd/v1/ns_descriptors/{}/nsd".format(self
.nsd_id
), headers_text
,
1977 None, 200, r_header_text
, "text", temp_dir
+"nsd-yaml")
1978 # TODO compare files: diff nsd-yaml hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml
1980 # get nsd zip file package
1981 engine
.test("Get NSD zip package", "GET", "/nsd/v1/ns_descriptors/{}/nsd_content".format(self
.nsd_id
),
1982 headers_zip
, None, 200, r_header_zip
, "zip", temp_dir
+"nsd-zip")
1983 # TODO compare files: diff nsd-zip hackfest_3charmed_nsd.tar.gz
1986 engine
.test("Get NSD artifact package", "GET",
1987 "/nsd/v1/ns_descriptors/{}/artifacts/icons/osm.png".format(self
.nsd_id
), headers_zip
, None, 200,
1988 r_header_octect
, "octet-string", temp_dir
+"nsd-icon")
1989 # TODO compare files: diff nsd-icon hackfest_3charmed_nsd/icons/osm.png
1992 test_rest
.test("Delete VNFD conflict", "DELETE", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
1993 headers_yaml
, None, 409, None, None)
1995 test_rest
.test("Delete VNFD force", "DELETE", "/vnfpkgm/v1/vnf_packages/{}?FORCE=TRUE".format(self
.vnfd_id
),
1996 headers_yaml
, None, 204, None, 0)
1999 test_rest
.test("Delete NSD", "DELETE", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
), headers_yaml
, None, 204,
2003 class TestNetSliceTemplates
:
2004 description
= "Upload a NST to OSM"
2007 self
.vnfd_filename
= ("@./slice_shared/vnfd/slice_shared_vnfd.yaml")
2008 self
.vnfd_filename_middle
= ("@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml")
2009 self
.nsd_filename
= ("@./slice_shared/nsd/slice_shared_nsd.yaml")
2010 self
.nsd_filename_middle
= ("@./slice_shared/nsd/slice_shared_middle_nsd.yaml")
2011 self
.nst_filenames
= ("@./slice_shared/slice_shared_nstd.yaml")
2013 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2015 engine
.set_test_name("NST step ")
2016 engine
.get_autorization()
2017 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
2018 if not os
.path
.exists(temp_dir
):
2019 os
.makedirs(temp_dir
)
2022 engine
.test("Onboard edge VNFD", "POST", "/vnfpkgm/v1/vnf_packages_content", headers_yaml
,
2023 self
.vnfd_filename
, 201, r_headers_yaml_location_vnfd
, "yaml")
2024 self
.vnfd_edge_id
= engine
.last_id
2026 engine
.test("Onboard middle VNFD", "POST", "/vnfpkgm/v1/vnf_packages_content", headers_yaml
,
2027 self
.vnfd_filename_middle
, 201, r_headers_yaml_location_vnfd
, "yaml")
2028 self
.vnfd_middle_id
= engine
.last_id
2031 engine
.test("Onboard NSD edge", "POST", "/nsd/v1/ns_descriptors_content", headers_yaml
,
2032 self
.nsd_filename
, 201, r_headers_yaml_location_nsd
, "yaml")
2033 self
.nsd_edge_id
= engine
.last_id
2035 engine
.test("Onboard NSD middle", "POST", "/nsd/v1/ns_descriptors_content", headers_yaml
,
2036 self
.nsd_filename_middle
, 201, r_headers_yaml_location_nsd
, "yaml")
2037 self
.nsd_middle_id
= engine
.last_id
2040 engine
.test("Onboard NST", "POST", "/nst/v1/netslice_templates_content", headers_yaml
, self
.nst_filenames
,
2041 201, r_headers_yaml_location_nst
, "yaml")
2042 nst_id
= engine
.last_id
2044 # nstd SHOW OSM format
2045 engine
.test("Show NSTD OSM format", "GET", "/nst/v1/netslice_templates/{}".format(nst_id
), headers_json
, None,
2046 200, r_header_json
, "json")
2049 engine
.test("Delete NSTD", "DELETE", "/nst/v1/netslice_templates/{}".format(nst_id
), headers_json
, None,
2053 test_rest
.test("Delete NSD middle", "DELETE", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
2054 headers_json
, None, 204, None, 0)
2056 test_rest
.test("Delete NSD edge", "DELETE", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
), headers_json
,
2060 test_rest
.test("Delete VNFD edge", "DELETE", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
2061 headers_yaml
, None, 204, None, 0)
2063 test_rest
.test("Delete VNFD middle", "DELETE", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
2064 headers_yaml
, None, 204, None, 0)
2067 class TestNetSliceInstances
:
2070 1. Populate databases with VNFD, NSD, NST with the following scenario
2071 +-----------------management-----------------+
2073 +--+---+ +----+----+ +---+--+
2075 | edge +---data1----+ middle +---data2-----+ edge |
2077 +------+ +---------+ +------+
2080 3. Instantiate NSI-1
2082 5. Instantiate NSI-2
2083 Manual check - Are 2 slices instantiated correctly?
2084 NSI-1 3 nss (2 nss-edges + 1 nss-middle)
2085 NSI-2 2 nss (2 nss-edge sharing nss-middle)
2088 Manual check - Is slice NSI-1 deleted correctly?
2089 NSI-2 with 2 nss-edge + 1 nss-middle (The one from NSI-1)
2091 9. Instantiate NSI-3
2092 Manual check - Is slice NSI-3 instantiated correctly?
2093 NSI-3 reuse nss-middle. NSI-3 only create 2 nss-edge
2098 Manual check - All cleaned correctly?
2099 NSI-2 and NSI-3 were terminated and deleted
2100 14. Cleanup database
2103 description
= "Upload a NST to OSM"
2107 self
.vnfd_filename
= ("@./slice_shared/vnfd/slice_shared_vnfd.yaml")
2108 self
.vnfd_filename_middle
= ("@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml")
2109 self
.nsd_filename
= ("@./slice_shared/nsd/slice_shared_nsd.yaml")
2110 self
.nsd_filename_middle
= ("@./slice_shared/nsd/slice_shared_middle_nsd.yaml")
2111 self
.nst_filenames
= ("@./slice_shared/slice_shared_nstd.yaml")
2113 def create_slice(self
, engine
, nsi_data
, name
):
2114 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
2115 r
= engine
.test(name
, "POST", "/nsilcm/v1/netslice_instances",
2116 headers_yaml
, ns_data_text
, 201,
2117 {"Location": "nsilcm/v1/netslice_instances/", "Content-Type": "application/yaml"}, "yaml")
2120 def instantiate_slice(self
, engine
, nsi_data
, nsi_id
, name
):
2121 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
2122 engine
.test(name
, "POST",
2123 "/nsilcm/v1/netslice_instances/{}/instantiate".format(nsi_id
), headers_yaml
, ns_data_text
,
2124 201, r_headers_yaml_location_nsilcmop
, "yaml")
2126 def terminate_slice(self
, engine
, nsi_id
, name
):
2127 engine
.test(name
, "POST", "/nsilcm/v1/netslice_instances/{}/terminate".format(nsi_id
),
2128 headers_yaml
, None, 201, r_headers_yaml_location_nsilcmop
, "yaml")
2130 def delete_slice(self
, engine
, nsi_id
, name
):
2131 engine
.test(name
, "DELETE", "/nsilcm/v1/netslice_instances/{}".format(nsi_id
), headers_yaml
, None,
2134 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2136 engine
.set_test_name("NSI")
2137 engine
.get_autorization()
2140 engine
.test("Onboard edge VNFD", "POST", "/vnfpkgm/v1/vnf_packages_content", headers_yaml
,
2141 self
.vnfd_filename
, 201, r_headers_yaml_location_vnfd
, "yaml")
2142 self
.vnfd_edge_id
= engine
.last_id
2144 engine
.test("Onboard middle VNFD", "POST", "/vnfpkgm/v1/vnf_packages_content", headers_yaml
,
2145 self
.vnfd_filename_middle
, 201, r_headers_yaml_location_vnfd
, "yaml")
2146 self
.vnfd_middle_id
= engine
.last_id
2149 engine
.test("Onboard NSD edge", "POST", "/nsd/v1/ns_descriptors_content", headers_yaml
,
2150 self
.nsd_filename
, 201, r_headers_yaml_location_nsd
, "yaml")
2151 self
.nsd_edge_id
= engine
.last_id
2153 engine
.test("Onboard NSD middle", "POST", "/nsd/v1/ns_descriptors_content", headers_yaml
,
2154 self
.nsd_filename_middle
, 201, r_headers_yaml_location_nsd
, "yaml")
2155 self
.nsd_middle_id
= engine
.last_id
2158 engine
.test("Onboard NST", "POST", "/nst/v1/netslice_templates_content", headers_yaml
, self
.nst_filenames
,
2159 201, r_headers_yaml_location_nst
, "yaml")
2160 nst_id
= engine
.last_id
2162 self
.vim_id
= engine
.get_create_vim(test_osm
)
2165 ns_data
= {'nsiName': 'Deploy-NSI-1', 'vimAccountId': self
.vim_id
, 'nstId': nst_id
, 'nsiDescription': 'default'}
2166 r
= self
.create_slice(engine
, ns_data
, "Create NSI-1 step 1")
2169 self
.nsi_id1
= engine
.last_id
2172 self
.instantiate_slice(engine
, ns_data
, self
.nsi_id1
, "Instantiate NSI-1 step 2")
2173 nsilcmop_id1
= engine
.last_id
2176 engine
.wait_operation_ready("nsi", nsilcmop_id1
, timeout_deploy
)
2179 ns_data
= {'nsiName': 'Deploy-NSI-2', 'vimAccountId': self
.vim_id
, 'nstId': nst_id
, 'nsiDescription': 'default'}
2180 r
= self
.create_slice(engine
, ns_data
, "Create NSI-2 step 1")
2183 self
.nsi_id2
= engine
.last_id
2186 self
.instantiate_slice(engine
, ns_data
, self
.nsi_id2
, "Instantiate NSI-2 step 2")
2187 nsilcmop_id2
= engine
.last_id
2190 engine
.wait_operation_ready("nsi", nsilcmop_id2
, timeout_deploy
)
2193 input('NSI-1 AND NSI-2 has been deployed. Perform manual check and press enter to resume')
2196 self
.terminate_slice(engine
, self
.nsi_id1
, "Terminate NSI-1")
2197 nsilcmop1_id
= engine
.last_id
2199 # Wait terminate NSI-1
2200 engine
.wait_operation_ready("nsi", nsilcmop1_id
, timeout_deploy
)
2203 self
.delete_slice(engine
, self
.nsi_id1
, "Delete NS")
2206 input('NSI-1 has been deleted. Perform manual check and press enter to resume')
2209 ns_data
= {'nsiName': 'Deploy-NSI-3', 'vimAccountId': self
.vim_id
, 'nstId': nst_id
, 'nsiDescription': 'default'}
2210 r
= self
.create_slice(engine
, ns_data
, "Create NSI-3 step 1")
2214 self
.nsi_id3
= engine
.last_id
2217 self
.instantiate_slice(engine
, ns_data
, self
.nsi_id3
, "Instantiate NSI-3 step 2")
2218 nsilcmop_id3
= engine
.last_id
2220 # Wait Instantiate NSI-3
2221 engine
.wait_operation_ready("nsi", nsilcmop_id3
, timeout_deploy
)
2224 input('NSI-3 has been deployed. Perform manual check and press enter to resume')
2227 self
.terminate_slice(engine
, self
.nsi_id2
, "Terminate NSI-2")
2228 nsilcmop2_id
= engine
.last_id
2230 # Wait terminate NSI-2
2231 engine
.wait_operation_ready("nsi", nsilcmop2_id
, timeout_deploy
)
2234 self
.delete_slice(engine
, self
.nsi_id2
, "DELETE NSI-2")
2237 self
. terminate_slice(engine
, self
.nsi_id3
, "Terminate NSI-3")
2238 nsilcmop3_id
= engine
.last_id
2240 # Wait terminate NSI-3
2241 engine
.wait_operation_ready("nsi", nsilcmop3_id
, timeout_deploy
)
2244 self
.delete_slice(engine
, self
.nsi_id3
, "DELETE NSI-3")
2247 input('NSI-2 and NSI-3 has been deleted. Perform manual check and press enter to resume')
2250 engine
.test("Delete NSTD", "DELETE", "/nst/v1/netslice_templates/{}".format(nst_id
), headers_json
, None,
2254 test_rest
.test("Delete NSD middle", "DELETE", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
2255 headers_json
, None, 204, None, 0)
2257 test_rest
.test("Delete NSD edge", "DELETE", "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
), headers_json
,
2261 test_rest
.test("Delete VNFD edge", "DELETE", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
2262 headers_yaml
, None, 204, None, 0)
2264 test_rest
.test("Delete VNFD middle", "DELETE", "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
2265 headers_yaml
, None, 204, None, 0)
2268 if __name__
== "__main__":
2272 # Disable warnings from self-signed certificates.
2273 requests
.packages
.urllib3
.disable_warnings()
2275 logging
.basicConfig(format
="%(levelname)s %(message)s", level
=logging
.ERROR
)
2276 logger
= logging
.getLogger('NBI')
2277 # load parameters and configuration
2278 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hvu:p:",
2279 ["url=", "user=", "password=", "help", "version", "verbose", "no-verbose",
2280 "project=", "insecure", "timeout", "timeout-deploy", "timeout-configure",
2281 "test=", "list", "test-osm", "manual-check", "params=", 'fail-fast'])
2282 url
= "https://localhost:9999/osm"
2283 user
= password
= project
= "admin"
2285 manual_check
= False
2290 "NonAuthorized": TestNonAuthorized
,
2291 "FakeVIM": TestFakeVim
,
2292 "TestUsersProjects": TestUsersProjects
,
2293 "VIM-SDN": TestVIMSDN
,
2294 "Deploy-Custom": TestDeploy
,
2295 "Deploy-Hackfest-Cirros": TestDeployHackfestCirros
,
2296 "Deploy-Hackfest-Cirros-Scaling": TestDeployHackfestCirrosScaling
,
2297 "Deploy-Hackfest-3Charmed": TestDeployHackfest3Charmed
,
2298 "Deploy-Hackfest-3Charmed2": TestDeployHackfest3Charmed2
,
2299 "Deploy-Hackfest-3Charmed3": TestDeployHackfest3Charmed3
,
2300 "Deploy-Hackfest-4": TestDeployHackfest4
,
2301 "Deploy-CirrosMacIp": TestDeployIpMac
,
2302 "TestDescriptors": TestDescriptors
,
2303 "TestDeployHackfest1": TestDeployHackfest1
,
2304 # "Deploy-MultiVIM": TestDeployMultiVIM,
2305 "DeploySingleVdu": TestDeploySingleVdu
,
2306 "DeployHnfd": TestDeployHnfd
,
2307 "Upload-Slice-Template": TestNetSliceTemplates
,
2308 "Deploy-Slice-Instance": TestNetSliceInstances
,
2309 "TestDeploySimpleCharm": TestDeploySimpleCharm
,
2310 "TestDeploySimpleCharm2": TestDeploySimpleCharm2
,
2316 # print("parameter:", o, a)
2317 if o
== "--version":
2318 print("test version " + __version__
+ ' ' + version_date
)
2321 for test
, test_class
in sorted(test_classes
.items()):
2322 print("{:32} {}".format(test
+ ":", test_class
.description
))
2324 elif o
in ("-v", "--verbose"):
2326 elif o
== "no-verbose":
2328 elif o
in ("-h", "--help"):
2331 elif o
== "--test-osm":
2333 elif o
== "--manual-check":
2337 elif o
in ("-u", "--user"):
2339 elif o
in ("-p", "--password"):
2341 elif o
== "--project":
2343 elif o
== "--fail-fast":
2346 # print("asdfadf", o, a, a.split(","))
2347 for _test
in a
.split(","):
2348 if _test
not in test_classes
:
2349 print("Invalid test name '{}'. Use option '--list' to show available tests".format(_test
),
2352 test_to_do
.append(_test
)
2353 elif o
== "--params":
2354 param_key
, _
, param_value
= a
.partition("=")
2355 text_index
= len(test_to_do
)
2356 if text_index
not in test_params
:
2357 test_params
[text_index
] = {}
2358 test_params
[text_index
][param_key
] = param_value
2359 elif o
== "--insecure":
2361 elif o
== "--timeout":
2363 elif o
== "--timeout-deploy":
2364 timeout_deploy
= int(a
)
2365 elif o
== "--timeout-configure":
2366 timeout_configure
= int(a
)
2368 assert False, "Unhandled option"
2370 logger
.setLevel(logging
.WARNING
)
2372 logger
.setLevel(logging
.DEBUG
)
2374 logger
.setLevel(logging
.ERROR
)
2376 test_rest
= TestRest(url
, user
=user
, password
=password
, project
=project
)
2377 # print("tests to do:", test_to_do)
2380 for test
in test_to_do
:
2381 if fail_fast
and test_rest
.failed_tests
:
2384 test_class
= test_classes
[test
]
2385 test_class().run(test_rest
, test_osm
, manual_check
, test_params
.get(text_index
))
2387 for test
, test_class
in sorted(test_classes
.items()):
2388 if fail_fast
and test_rest
.failed_tests
:
2390 test_class().run(test_rest
, test_osm
, manual_check
, test_params
.get(0))
2391 test_rest
.print_results()
2392 exit(1 if test_rest
.failed_tests
else 0)
2394 except TestException
as e
:
2395 logger
.error(test
+ "Test {} Exception: {}".format(test
, str(e
)))
2397 except getopt
.GetoptError
as e
:
2399 print(e
, file=sys
.stderr
)
2401 except Exception as e
:
2402 logger
.critical(test
+ " Exception: " + str(e
), exc_info
=True)