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.
26 from time
import sleep
27 from random
import randint
29 from sys
import stderr
30 from uuid
import uuid4
33 __author__
= "Alfonso Tierno, alfonso.tiernosepulveda@telefonica.com"
34 __date__
= "$2018-03-01$"
36 version_date
= "Oct 2018"
40 print("Usage: ", sys
.argv
[0], "[options]")
42 " Performs system tests over running NBI. It can be used for real OSM test using option '--test-osm'"
45 " If this is the case env variables 'OSMNBITEST_VIM_NAME' must be supplied to create a VIM if not exist "
46 "where deployment is done"
49 print(" -h|--help: shows this help")
50 print(" --insecure: Allows non trusted https NBI server")
51 print(" --list: list available tests")
53 " --manual-check: Deployment tests stop after deployed to allow manual inspection. Only make sense with "
56 print(" -p|--password PASSWORD: NBI access password. 'admin' by default")
57 print(" ---project PROJECT: NBI access project. 'admin' by default")
59 " --test TEST[,...]: Execute only a test or a comma separated list of tests"
62 " --params key=val: params to the previous test. key can be vnfd-files, nsd-file, ns-name, ns-config"
65 " --test-osm: If missing this test is intended for NBI only, no other OSM components are expected. Use "
66 "this flag to test the system. LCM and RO components are expected to be up and running"
69 " --timeout TIMEOUT: General NBI timeout, by default {}s".format(timeout
)
72 " --timeout-deploy TIMEOUT: Timeout used for getting NS deployed, by default {}s".format(
77 " --timeout-configure TIMEOUT: Timeout used for getting NS deployed and configured,"
78 " by default {}s".format(timeout_configure
)
80 print(" -u|--user USERNAME: NBI access username. 'admin' by default")
82 " --url URL: complete NBI server URL. 'https//localhost:9999/osm' by default"
84 print(" -v|--verbose print debug information, can be used several times")
85 print(" --no-verbose remove verbosity")
86 print(" --version: prints current version")
87 print("ENV variables used for real deployment tests with option osm-test.")
88 print(" export OSMNBITEST_VIM_NAME=vim-name")
89 print(" export OSMNBITEST_VIM_URL=vim-url")
90 print(" export OSMNBITEST_VIM_TYPE=vim-type")
91 print(" export OSMNBITEST_VIM_TENANT=vim-tenant")
92 print(" export OSMNBITEST_VIM_USER=vim-user")
93 print(" export OSMNBITEST_VIM_PASSWORD=vim-password")
94 print(' export OSMNBITEST_VIM_CONFIG="vim-config"')
95 print(' export OSMNBITEST_NS_NAME="vim-config"')
99 r_header_json
= {"Content-type": "application/json"}
100 headers_json
= {"Content-type": "application/json", "Accept": "application/json"}
101 r_header_yaml
= {"Content-type": "application/yaml"}
102 headers_yaml
= {"Content-type": "application/yaml", "Accept": "application/yaml"}
103 r_header_text
= {"Content-type": "text/plain"}
104 r_header_octect
= {"Content-type": "application/octet-stream"}
105 headers_text
= {"Accept": "text/plain,application/yaml"}
106 r_header_zip
= {"Content-type": "application/zip"}
107 headers_zip
= {"Accept": "application/zip,application/yaml"}
108 headers_zip_yaml
= {"Accept": "application/yaml", "Content-type": "application/zip"}
109 headers_zip_json
= {"Accept": "application/json", "Content-type": "application/zip"}
110 headers_txt_json
= {"Accept": "application/json", "Content-type": "text/plain"}
111 r_headers_yaml_location_vnfd
= {
112 "Location": "/vnfpkgm/v1/vnf_packages_content/",
113 "Content-Type": "application/yaml",
115 r_headers_yaml_location_nsd
= {
116 "Location": "/nsd/v1/ns_descriptors_content/",
117 "Content-Type": "application/yaml",
119 r_headers_yaml_location_nst
= {
120 "Location": "/nst/v1/netslice_templates_content",
121 "Content-Type": "application/yaml",
123 r_headers_yaml_location_nslcmop
= {
124 "Location": "nslcm/v1/ns_lcm_op_occs/",
125 "Content-Type": "application/yaml",
127 r_headers_yaml_location_nsilcmop
= {
128 "Location": "/osm/nsilcm/v1/nsi_lcm_op_occs/",
129 "Content-Type": "application/yaml",
132 # test ones authorized
133 test_authorized_list
= (
138 "/vnfpkgm/v1/vnf_packages/non-existing-id",
149 "/nsd/v1/ns_descriptors/non-existing-id",
160 "/nsd/v1/ns_descriptors_content/non-existing-id",
168 timeout
= 120 # general timeout
169 timeout_deploy
= 60 * 10 # timeout for NS deploying without charms
170 timeout_configure
= 60 * 20 # timeout for NS deploying and configuring
173 class TestException(Exception):
187 self
.url_base
= url_base
188 if header_base
is None:
189 self
.header_base
= {}
191 self
.header_base
= header_base
.copy()
192 self
.s
= requests
.session()
193 self
.s
.headers
= self
.header_base
197 self
.password
= password
198 self
.project
= project
200 # contains ID of tests obtained from Location response header. "" key contains last obtained id
202 self
.test_name
= None
203 self
.step
= 0 # number of subtest under test
204 self
.passed_tests
= 0
205 self
.failed_tests
= 0
207 def set_test_name(self
, test_name
):
208 self
.test_name
= test_name
212 def set_header(self
, header
):
213 self
.s
.headers
.update(header
)
215 def set_tet_name(self
, test_name
):
216 self
.test_name
= test_name
218 def unset_header(self
, key
):
219 if key
in self
.s
.headers
:
220 del self
.s
.headers
[key
]
236 Performs an http request and check http code response. Exit if different than allowed. It get the returned id
237 that can be used by following test in the URL with {name} where name is the name of the test
238 :param description: description of the test
239 :param method: HTTP method: GET,PUT,POST,DELETE,...
240 :param url: complete URL or relative URL
241 :param headers: request headers to add to the base headers
242 :param payload: Can be a dict, transformed to json, a text or a file if starts with '@'
243 :param expected_codes: expected response codes, can be int, int tuple or int range
244 :param expected_headers: expected response headers, dict with key values
245 :param expected_payload: expected payload, 0 if empty, 'yaml', 'json', 'text', 'zip', 'octet-stream'
246 :param store_file: filename to store content
247 :param pooling: if True do not count neither log this test. Because a pooling is done with many equal requests
248 :return: requests response
253 self
.s
= requests
.session()
257 elif not url
.startswith("http"):
258 url
= self
.url_base
+ url
260 # replace url <> with the last ID
261 url
= url
.replace("<>", self
.last_id
)
263 if isinstance(payload
, str):
264 if payload
.startswith("@"):
266 file_name
= payload
[1:]
267 if payload
.startswith("@b"):
269 file_name
= payload
[2:]
270 with
open(file_name
, mode
) as f
:
272 elif isinstance(payload
, dict):
273 payload
= json
.dumps(payload
)
276 test_description
= "Test {}{} {} {} {}".format(
277 self
.test_name
, self
.step
, description
, method
, url
279 logger
.warning(test_description
)
282 if expected_payload
in ("zip", "octet-string") or store_file
:
287 r
= getattr(self
.s
, method
.lower())(
295 except requests
.exceptions
.ConnectionError
as e
:
298 logger
.error("Exception {}. Retrying".format(e
))
301 if expected_payload
in ("zip", "octet-string") or store_file
:
302 logger
.debug("RX {}".format(r
.status_code
))
304 logger
.debug("RX {}: {}".format(r
.status_code
, r
.text
))
308 if isinstance(expected_codes
, int):
309 expected_codes
= (expected_codes
,)
310 if r
.status_code
not in expected_codes
:
312 "Got status {}. Expected {}. {}".format(
313 r
.status_code
, expected_codes
, r
.text
318 for header_key
, header_val
in expected_headers
.items():
319 if header_key
.lower() not in r
.headers
:
320 raise TestException("Header {} not present".format(header_key
))
321 if header_val
and header_val
.lower() not in r
.headers
[header_key
]:
323 "Header {} does not contain {} but {}".format(
324 header_key
, header_val
, r
.headers
[header_key
]
328 if expected_payload
is not None:
329 if expected_payload
== 0 and len(r
.content
) > 0:
330 raise TestException("Expected empty payload")
331 elif expected_payload
== "json":
334 except Exception as e
:
336 "Expected json response payload, but got Exception {}".format(
340 elif expected_payload
== "yaml":
342 yaml
.safe_load(r
.text
)
343 except Exception as e
:
345 "Expected yaml response payload, but got Exception {}".format(
349 elif expected_payload
in ("zip", "octet-string"):
350 if len(r
.content
) == 0:
352 "Expected some response payload, but got empty"
355 # tar = tarfile.open(None, 'r:gz', fileobj=r.raw)
356 # for tarinfo in tar:
357 # tarname = tarinfo.name
359 # except Exception as e:
360 # raise TestException("Expected zip response payload, but got Exception {}".format(e))
361 elif expected_payload
== "text":
362 if len(r
.content
) == 0:
364 "Expected some response payload, but got empty"
368 with
open(store_file
, "wb") as fd
:
369 for chunk
in r
.iter_content(chunk_size
=128):
372 location
= r
.headers
.get("Location")
374 _id
= location
[location
.rfind("/") + 1:]
376 self
.last_id
= str(_id
)
378 self
.passed_tests
+= 1
380 except TestException
as e
:
381 self
.failed_tests
+= 1
385 r_status_code
= r
.status_code
387 logger
.error("{} \nRX code{}: {}".format(e
, r_status_code
, r_text
))
392 logger
.error("Cannot open file {}: {}".format(store_file
, e
))
394 logger
.error("Exception: {}".format(e
), exc_info
=True)
395 self
.failed_tests
+= 1
398 except requests
.exceptions
.RequestException
as e
:
399 logger
.error("Exception: {}".format(e
))
401 def get_autorization(self
): # user=None, password=None, project=None):
404 ): # and self.user == user and self.password == password and self.project == project:
407 # self.password = password
408 # self.project = project
415 "username": self
.user
,
416 "password": self
.password
,
417 "project_id": self
.project
,
426 self
.token
= response
["id"]
427 self
.set_header({"Authorization": "Bearer {}".format(self
.token
)})
429 def remove_authorization(self
):
434 "/admin/v1/tokens/{}".format(self
.token
),
442 self
.unset_header("Authorization")
444 def get_create_vim(self
, test_osm
):
447 self
.get_autorization()
449 vim_name
= os
.environ
.get("OSMNBITEST_VIM_NAME")
452 "Needed to define OSMNBITEST_VIM_XXX variables to create a real VIM for deployment"
460 "/admin/v1/vim_accounts?name={}".format(vim_name
),
471 return vims
[0]["_id"]
474 # check needed environ parameters:
475 if not os
.environ
.get("OSMNBITEST_VIM_URL") or not os
.environ
.get(
476 "OSMNBITEST_VIM_TENANT"
479 "Env OSMNBITEST_VIM_URL and OSMNBITEST_VIM_TENANT are needed for create a real VIM"
480 " to deploy on whit the --test-osm option"
483 "{{schema_version: '1.0', name: '{}', vim_type: {}, vim_url: '{}',"
484 "vim_tenant_name: '{}', " "vim_user: {}, vim_password: {}"
487 os
.environ
.get("OSMNBITEST_VIM_TYPE", "openstack"),
488 os
.environ
.get("OSMNBITEST_VIM_URL"),
489 os
.environ
.get("OSMNBITEST_VIM_TENANT"),
490 os
.environ
.get("OSMNBITEST_VIM_USER"),
491 os
.environ
.get("OSMNBITEST_VIM_PASSWORD"),
493 if os
.environ
.get("OSMNBITEST_VIM_CONFIG"):
494 vim_data
+= " ,config: {}".format(
495 os
.environ
.get("OSMNBITEST_VIM_CONFIG")
500 "{schema_version: '1.0', name: fakeVim, vim_type: openstack, vim_url: 'http://10.11.12.13/fake'"
501 ", vim_tenant_name: 'vimtenant', vim_user: vimuser, vim_password: vimpassword}"
506 "/admin/v1/vim_accounts",
510 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"},
515 def print_results(self
):
516 print("\n\n\n--------------------------------------------")
518 "TEST RESULTS: Total: {}, Passed: {}, Failed: {}".format(
519 self
.passed_tests
+ self
.failed_tests
,
524 print("--------------------------------------------")
526 def wait_until_delete(self
, url_op
, timeout_delete
):
528 Make a pooling until topic is not present, because of deleted
530 :param timeout_delete:
533 description
= "Wait to topic being deleted"
534 test_description
= "Test {}{} {} {} {}".format(
535 self
.test_name
, self
.step
, description
, "GET", url_op
537 logger
.warning(test_description
)
540 wait
= timeout_delete
556 if r
.status_code
== 404:
557 self
.passed_tests
+= 1
559 elif r
.status_code
== 200:
564 "Topic is not deleted after {} seconds".format(timeout_delete
)
566 self
.failed_tests
+= 1
568 def wait_operation_ready(self
, ns_nsi
, opp_id
, timeout
, expected_fail
=False):
570 Wait until nslcmop or nsilcmop finished
571 :param ns_nsi: "ns" o "nsi"
572 :param opp_id: Id o fthe operation
574 :param expected_fail:
575 :return: None. Updates passed/failed_tests
578 url_op
= "/nslcm/v1/ns_lcm_op_occs/{}".format(opp_id
)
580 url_op
= "/nsilcm/v1/nsi_lcm_op_occs/{}".format(opp_id
)
581 description
= "Wait to {} lcm operation complete".format(ns_nsi
)
582 test_description
= "Test {}{} {} {} {}".format(
583 self
.test_name
, self
.step
, description
, "GET", url_op
585 logger
.warning(test_description
)
603 if "COMPLETED" in nslcmop
["operationState"]:
606 "NS terminate has success, expecting failing: {}".format(
607 nslcmop
["detailed-status"]
610 self
.failed_tests
+= 1
612 self
.passed_tests
+= 1
614 elif "FAILED" in nslcmop
["operationState"]:
615 if not expected_fail
:
617 "NS terminate has failed: {}".format(nslcmop
["detailed-status"])
619 self
.failed_tests
+= 1
621 self
.passed_tests
+= 1
624 print(".", end
="", file=stderr
)
628 self
.failed_tests
+= 1
630 "NS instantiate is not terminate after {} seconds".format(timeout
)
633 print("", file=stderr
)
636 class TestNonAuthorized
:
637 description
= "Test invalid URLs. methods and no authorization"
640 def run(engine
, test_osm
, manual_check
, test_params
=None):
641 engine
.set_test_name("NonAuth")
642 engine
.remove_authorization()
643 test_not_authorized_list
= (
657 "/admin/v1/nonexist",
675 for t
in test_not_authorized_list
:
679 class TestUsersProjects
:
680 description
= "test project and user creation"
683 def run(engine
, test_osm
, manual_check
, test_params
=None):
684 engine
.set_test_name("UserProject")
685 # backend = test_params.get("backend") if test_params else None # UNUSED
690 u1
= u2
= u3
= u4
= None
692 engine
.get_autorization()
695 "Create project non admin 1",
697 "/admin/v1/projects",
701 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
704 p1
= engine
.last_id
if res
else None
707 "Create project admin",
709 "/admin/v1/projects",
711 {"name": "Padmin", "admin": True},
713 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
716 padmin
= engine
.last_id
if res
else None
719 "Create project bad format",
721 "/admin/v1/projects",
728 pbad
= engine
.last_id
if res
else None
731 "Get project admin role",
733 "/admin/v1/roles?name=project_admin",
737 {"Content-Type": "application/json"},
740 rpa
= res
.json()[0]["_id"] if res
else None
742 "Get project user role",
744 "/admin/v1/roles?name=project_user",
748 {"Content-Type": "application/json"},
751 rpu
= res
.json()[0]["_id"] if res
else None
753 "Get system admin role",
755 "/admin/v1/roles?name=system_admin",
759 {"Content-Type": "application/json"},
762 rsa
= res
.json()[0]["_id"] if res
else None
764 data
= {"username": "U1", "password": "pw1"}
766 data
["project_role_mappings"] = [
767 {"project": p1
, "role": rpa
},
768 {"project": p2
, "role": rpa
},
769 {"project": padmin
, "role": rpu
},
772 xhd
= {"Location": "/admin/v1/users/", "Content-Type": "application/json"}
774 "Create user with bad project and force",
776 "/admin/v1/users?FORCE=True",
786 # User is created sometimes even though an exception is raised
790 "/admin/v1/users?username=U1",
794 {"Content-Type": "application/json"},
797 u1
= res
.json()[0]["_id"] if res
else None
799 data
= {"username": "U2", "password": "pw2"}
800 data
["project_role_mappings"] = [
801 {"project": p1
, "role": rpa
},
802 {"project": padmin
, "role": rsa
},
811 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
814 u2
= engine
.last_id
if res
else None
817 ftt
= "project_role_mappings"
818 xpr
= [{"project": p1
, "role": rpa
}, {"project": padmin
, "role": rpu
}]
821 "Edit user U1, delete P2 project",
823 "/admin/v1/users/" + u1
,
831 "Check user U1, contains the right projects",
833 "/admin/v1/users/" + u1
,
842 xpr
[0]["project_name"] = "P1"
843 xpr
[0]["role_name"] = "project_admin"
844 xpr
[1]["project_name"] = "Padmin"
845 xpr
[1]["role_name"] = "project_user"
851 if pr
not in rj
[ftt
]:
855 "User {} '{}' are different than expected '{}'. Edition was not done properly".format(
859 engine
.failed_tests
+= 1
861 p2
= None # To prevent deletion attempts
863 # Add a test of 'default project' for Keystone?
867 "Edit user U2, change password",
869 "/admin/v1/users/" + u2
,
871 {"password": "pw2_new"},
879 "Change to project P1 non existing",
891 "Change to user U2 project P1",
895 {"username": "U2", "password": "pw2_new", "project_id": "P1"},
902 engine
.set_header({"Authorization": "Bearer {}".format(rj
["id"])})
905 "Edit user projects non admin",
907 "/admin/v1/users/U1",
909 {"remove_project_role_mappings": [{"project": "P1", "role": None}]},
916 "Add new project non admin",
918 "/admin/v1/projects",
925 if res
is None or res
.status_code
== 201:
926 # The project has been created even though it shouldn't
930 "/admin/v1/projects/P2",
937 p2
= res
.json()["_id"] if res
else None
940 data
= {"username": "U3", "password": "pw3"}
941 data
["project_role_mappings"] = [{"project": p1
, "role": rpu
}]
943 "Add new user non admin",
952 if res
is None or res
.status_code
== 201:
953 # The user has been created even though it shouldn't
957 "/admin/v1/users/U3",
964 u3
= res
.json()["_id"] if res
else None
970 "Change to user U2 project Padmin",
975 "project_id": "Padmin"
976 }, # Caused a Keystone authentication error
977 # {"username": "U2", "password": "pw2_new", "project_id": "Padmin"},
985 {"Authorization": "Bearer {}".format(rj
["id"])}
989 "Add new project admin",
991 "/admin/v1/projects",
996 "Location": "/admin/v1/projects/",
997 "Content-Type": "application/json",
1001 p3
= engine
.last_id
if res
else None
1004 data
= {"username": "U4", "password": "pw4"}
1005 data
["project_role_mappings"] = [
1006 {"project": p1
, "role": rpa
}
1009 "Add new user admin",
1016 "Location": "/admin/v1/users/",
1017 "Content-Type": "application/json",
1021 u4
= engine
.last_id
if res
else None
1027 "project_role_mappings": [{"project": p3
, "role": rpa
}]
1030 "Edit user projects admin",
1032 "/admin/v1/users/U4",
1039 # Project is deleted even though it shouldn't - PROVISIONAL?
1041 "Delete project P3 conflict",
1043 "/admin/v1/projects/" + p3
,
1050 if res
and res
.status_code
in (200, 204):
1054 "Delete project P3 forcing",
1056 "/admin/v1/projects/" + p3
+ "?FORCE=True",
1063 if res
and res
.status_code
in (200, 204):
1068 "Delete user U2. Conflict deleting own user",
1070 "/admin/v1/users/" + u2
,
1077 if res
is None or res
.status_code
in (200, 204):
1083 "/admin/v1/users/" + u4
,
1090 if res
and res
.status_code
in (200, 204):
1094 "Delete project P3",
1096 "/admin/v1/projects/" + p3
,
1103 if res
and res
.status_code
in (200, 204):
1110 "/admin/v1/users/" + u3
,
1121 engine
.remove_authorization() # To force get authorization
1122 engine
.get_autorization()
1127 "/admin/v1/users/" + u1
,
1138 "/admin/v1/users/" + u2
,
1149 "/admin/v1/users/" + u3
,
1160 "/admin/v1/users/" + u4
,
1169 "Delete project P1",
1171 "/admin/v1/projects/" + p1
,
1180 "Delete project P2",
1182 "/admin/v1/projects/" + p2
,
1191 "Delete project P3",
1193 "/admin/v1/projects/" + p3
,
1202 "Delete project Padmin",
1204 "/admin/v1/projects/" + padmin
,
1213 "Delete bad project",
1215 "/admin/v1/projects/" + pbad
,
1223 # BEGIN New Tests - Addressing Projects/Users by Name/ID
1227 "Create new project P1",
1229 "/admin/v1/projects",
1233 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1237 pid1
= res
.json()["id"]
1238 # print("# pid =", pid1)
1240 "Create new project P2",
1242 "/admin/v1/projects",
1246 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1250 pid2
= res
.json()["id"]
1251 # print("# pid =", pid2)
1252 data
= {"username": "U1", "password": "pw1"}
1253 data
["project_role_mappings"] = [{"project": pid1
, "role": rpu
}]
1255 "Create new user U1",
1261 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1265 uid1
= res
.json()["id"]
1266 # print("# uid =", uid1)
1267 data
= {"username": "U2", "password": "pw2"}
1268 data
["project_role_mappings"] = [{"project": pid2
, "role": rpu
}]
1270 "Create new user U2",
1276 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1280 uid2
= res
.json()["id"]
1281 # print("# uid =", uid2)
1284 "Get Project P1 by Name",
1286 "/admin/v1/projects/P1",
1294 "Get Project P1 by ID",
1296 "/admin/v1/projects/" + pid1
,
1305 "Get User U1 by Name",
1307 "/admin/v1/users/U1",
1315 "Get User U1 by ID",
1317 "/admin/v1/users/" + uid1
,
1326 "Rename Project P1 by Name",
1328 "/admin/v1/projects/P1",
1337 "Get Project P1 by new Name",
1339 "/admin/v1/projects/P3",
1348 "Rename Project P2 by ID",
1350 "/admin/v1/projects/" + pid2
,
1359 "Get Project P2 by new Name",
1361 "/admin/v1/projects/P4",
1371 "Rename User U1 by Name",
1373 "/admin/v1/users/U1",
1382 "Get User U1 by new Name",
1384 "/admin/v1/users/U3",
1394 "Rename User U2 by ID",
1396 "/admin/v1/users/" + uid2
,
1405 "Get User U2 by new Name",
1407 "/admin/v1/users/U4",
1416 "Delete User U1 by Name",
1418 "/admin/v1/users/U3",
1430 "Delete User U2 by ID",
1432 "/admin/v1/users/" + uid2
,
1444 "Delete Project P1 by Name",
1446 "/admin/v1/projects/P3",
1458 "Delete Project P2 by ID",
1460 "/admin/v1/projects/" + pid2
,
1470 # END New Tests - Addressing Projects/Users by Name
1475 "Delete Project P1",
1477 "/admin/v1/projects/" + pid1
,
1486 "Delete Project P2",
1488 "/admin/v1/projects/" + pid2
,
1499 "/admin/v1/users/" + uid1
,
1510 "/admin/v1/users/" + uid2
,
1518 engine
.remove_authorization() # To finish
1521 class TestProjectsDescriptors
:
1522 description
= "test descriptors visibility among projects"
1525 def run(engine
, test_osm
, manual_check
, test_params
=None):
1527 engine
.set_test_name("ProjectDescriptors")
1528 engine
.get_autorization()
1530 project_admin_id
= None
1532 "Get my project Padmin",
1534 "/admin/v1/projects/{}".format(engine
.project
),
1542 response
= res
.json()
1543 project_admin_id
= response
["_id"]
1545 "Create project Padmin",
1547 "/admin/v1/projects",
1549 {"name": "Padmin", "admin": True},
1551 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1555 "Create project P2",
1557 "/admin/v1/projects",
1561 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1565 "Create project P3",
1567 "/admin/v1/projects",
1571 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1583 "project_role_mappings": [
1584 {"project": "Padmin", "role": "system_admin"},
1585 {"project": "P2", "role": "project_admin"},
1586 {"project": "P3", "role": "project_admin"},
1590 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1597 "/vnfpkgm/v1/vnf_packages_content?id=id1",
1599 TestDescriptors
.vnfd_empty
,
1601 r_headers_yaml_location_vnfd
,
1604 vnfd_ids
.append(engine
.last_id
)
1606 "Onboard VNFD id2 PUBLIC",
1608 "/vnfpkgm/v1/vnf_packages_content?id=id2&PUBLIC=TRUE",
1610 TestDescriptors
.vnfd_empty
,
1612 r_headers_yaml_location_vnfd
,
1615 vnfd_ids
.append(engine
.last_id
)
1619 "/vnfpkgm/v1/vnf_packages_content?id=id3&PUBLIC=FALSE",
1621 TestDescriptors
.vnfd_empty
,
1623 r_headers_yaml_location_vnfd
,
1626 vnfd_ids
.append(engine
.last_id
)
1629 "Get VNFD descriptors",
1631 "/vnfpkgm/v1/vnf_packages?id=id1,id2,id3",
1638 response
= res
.json()
1639 if len(response
) != 3:
1641 "Only 3 vnfds should be present for project admin. {} listed".format(
1645 engine
.failed_tests
+= 1
1647 # Change to other project Padmin
1649 "Change to user U1 project Padmin",
1653 {"username": "U1", "password": "pw1", "project_id": "Padmin"},
1659 response
= res
.json()
1660 engine
.set_header({"Authorization": "Bearer {}".format(response
["id"])})
1664 "List VNFD descriptors for Padmin",
1666 "/vnfpkgm/v1/vnf_packages",
1673 response
= res
.json()
1674 if len(response
) != 0:
1676 "Only 0 vnfds should be present for project Padmin. {} listed".format(
1680 engine
.failed_tests
+= 1
1684 "List VNFD public descriptors",
1686 "/vnfpkgm/v1/vnf_packages?PUBLIC=True",
1693 response
= res
.json()
1694 if len(response
) != 1:
1696 "Only 1 vnfds should be present for project Padmin. {} listed".format(
1700 engine
.failed_tests
+= 1
1702 # list vnfds belonging to project "admin"
1704 "List VNFD of admin project",
1706 "/vnfpkgm/v1/vnf_packages?ADMIN={}".format(project_admin_id
),
1714 response
= res
.json()
1715 if len(response
) != 3:
1717 "Only 3 vnfds should be present for project Padmin. {} listed".format(
1721 engine
.failed_tests
+= 1
1725 "Get VNFD public descriptors",
1727 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1734 # Edit not owned vnfd
1738 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[0]),
1748 "Add VNFD id2 to my catalog",
1750 "/vnfpkgm/v1/vnf_packages/{}?SET_PROJECT".format(vnfd_ids
[1]),
1762 "/vnfpkgm/v1/vnf_packages_content?id=id4",
1764 TestDescriptors
.vnfd_empty
,
1766 r_headers_yaml_location_vnfd
,
1769 vnfd_ids
.append(engine
.last_id
)
1773 "List VNFD public descriptors",
1775 "/vnfpkgm/v1/vnf_packages",
1782 response
= res
.json()
1783 if len(response
) != 2:
1785 "Only 2 vnfds should be present for project Padmin. {} listed".format(
1789 engine
.failed_tests
+= 1
1793 "VNFDs have been omboarded. Perform manual check and press enter to resume"
1799 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1807 # change to admin project
1808 engine
.remove_authorization() # To force get authorization
1809 engine
.get_autorization()
1813 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[0]),
1823 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1833 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[2]),
1843 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[3]),
1853 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[3]),
1862 "Get VNFD deleted id1",
1864 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[0]),
1872 "Get VNFD deleted id2",
1874 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[1]),
1882 "Get VNFD deleted id3",
1884 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[2]),
1892 "Get VNFD deleted id4",
1894 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[3]),
1905 "/admin/v1/users/U1",
1913 "Delete project Padmin",
1915 "/admin/v1/projects/Padmin",
1923 "Delete project P2",
1925 "/admin/v1/projects/P2",
1933 "Delete project P3",
1935 "/admin/v1/projects/P3",
1945 description
= "Creates/edit/delete fake VIMs and SDN controllers"
1949 "schema_version": "1.0",
1950 "schema_type": "No idea",
1952 "description": "Descriptor name",
1953 "vim_type": "openstack",
1954 "vim_url": "http://localhost:/vim",
1955 "vim_tenant_name": "vimTenant",
1957 "vim_password": "password",
1958 "config": {"config_param": 1},
1962 "description": "sdn-description",
1963 "dpid": "50:50:52:54:00:94:21:21",
1964 "ip": "192.168.15.17",
1966 "type": "opendaylight",
1969 "password": "passwd",
1971 self
.port_mapping
= [
1973 "compute_node": "compute node 1",
1976 "pci": "0000:81:00.0",
1977 "switch_port": "port-2/1",
1978 "switch_mac": "52:54:00:94:21:21",
1981 "pci": "0000:81:00.1",
1982 "switch_port": "port-2/2",
1983 "switch_mac": "52:54:00:94:21:22",
1988 "compute_node": "compute node 2",
1991 "pci": "0000:81:00.0",
1992 "switch_port": "port-2/3",
1993 "switch_mac": "52:54:00:94:21:23",
1996 "pci": "0000:81:00.1",
1997 "switch_port": "port-2/4",
1998 "switch_mac": "52:54:00:94:21:24",
2004 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2006 vim_bad
= self
.vim
.copy()
2009 engine
.set_test_name("FakeVim")
2010 engine
.get_autorization()
2014 "/admin/v1/vim_accounts",
2018 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"},
2021 vim_id
= engine
.last_id
2023 "Create VIM without name, bad schema",
2025 "/admin/v1/vim_accounts",
2033 "Create VIM name repeated",
2035 "/admin/v1/vim_accounts",
2045 "/admin/v1/vim_accounts",
2055 "/admin/v1/vim_accounts/{}".format(vim_id
),
2067 "/admin/v1/vim_accounts/{}?FORCE=True".format(vim_id
),
2075 "Check VIM is deleted",
2077 "/admin/v1/vim_accounts/{}".format(vim_id
),
2085 # delete and wait until is really deleted
2089 "/admin/v1/vim_accounts/{}".format(vim_id
),
2096 engine
.wait_until_delete(
2097 "/admin/v1/vim_accounts/{}".format(vim_id
), timeout
2101 class TestVIMSDN(TestFakeVim
):
2102 description
= "Creates VIM with SDN editing SDN controllers and port_mapping"
2105 TestFakeVim
.__init
__(self
)
2107 "schema_version": "1.0",
2108 "schema_type": "No idea",
2110 "description": "Descriptor name",
2112 "wim_url": "http://localhost:/wim",
2114 "password": "password",
2115 "config": {"config_param": 1},
2118 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2119 engine
.set_test_name("VimSdn")
2120 engine
.get_autorization()
2129 {"Location": "/admin/v1/sdns/", "Content-Type": "application/json"},
2132 sdnc_id
= engine
.last_id
2138 "/admin/v1/sdns/{}".format(sdnc_id
),
2140 {"name": "new_sdn_name"},
2147 self
.vim
["config"]["sdn-controller"] = sdnc_id
2148 self
.vim
["config"]["sdn-port-mapping"] = self
.port_mapping
2152 "/admin/v1/vim_accounts",
2156 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/json"},
2160 vim_id
= engine
.last_id
2161 self
.port_mapping
[0]["compute_node"] = "compute node XX"
2163 "Edit VIM change port-mapping",
2165 "/admin/v1/vim_accounts/{}".format(vim_id
),
2167 {"config": {"sdn-port-mapping": self
.port_mapping
}},
2173 "Edit VIM remove port-mapping",
2175 "/admin/v1/vim_accounts/{}".format(vim_id
),
2177 {"config": {"sdn-port-mapping": None}},
2186 "/admin/v1/wim_accounts",
2190 {"Location": "/admin/v1/wim_accounts/", "Content-Type": "application/json"},
2193 wim_id
= engine
.last_id
2198 "Delete VIM remove port-mapping",
2200 "/admin/v1/vim_accounts/{}?FORCE=True".format(vim_id
),
2210 "/admin/v1/sdns/{}?FORCE=True".format(sdnc_id
),
2221 "/admin/v1/wim_accounts/{}?FORCE=True".format(wim_id
),
2229 "Check VIM is deleted",
2231 "/admin/v1/vim_accounts/{}".format(vim_id
),
2239 "Check SDN is deleted",
2241 "/admin/v1/sdns/{}".format(sdnc_id
),
2249 "Check WIM is deleted",
2251 "/admin/v1/wim_accounts/{}".format(wim_id
),
2261 "VIM, SDN, WIM has been deployed. Perform manual check and press enter to resume"
2263 # delete and wait until is really deleted
2265 "Delete VIM remove port-mapping",
2267 "/admin/v1/vim_accounts/{}".format(vim_id
),
2277 "/admin/v1/sdns/{}".format(sdnc_id
),
2287 "/admin/v1/wim_accounts/{}".format(wim_id
),
2294 engine
.wait_until_delete(
2295 "/admin/v1/vim_accounts/{}".format(vim_id
), timeout
2297 engine
.wait_until_delete("/admin/v1/sdns/{}".format(sdnc_id
), timeout
)
2298 engine
.wait_until_delete(
2299 "/admin/v1/wim_accounts/{}".format(wim_id
), timeout
2304 description
= "Base class for downloading descriptors from ETSI, onboard and deploy in real VIM"
2307 self
.test_name
= "DEPLOY"
2312 self
.descriptor_url
= (
2313 "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
2315 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
2316 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
2317 self
.descriptor_edit
= None
2318 self
.uses_configuration
= False
2325 self
.ns_params
= None
2326 self
.vnfr_ip_list
= {}
2328 def create_descriptors(self
, engine
):
2329 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
2330 if not os
.path
.exists(temp_dir
):
2331 os
.makedirs(temp_dir
)
2332 for vnfd_index
, vnfd_filename
in enumerate(self
.vnfd_filenames
):
2333 if "/" in vnfd_filename
:
2334 vnfd_filename_path
= vnfd_filename
2335 if not os
.path
.exists(vnfd_filename_path
):
2336 raise TestException(
2337 "File '{}' does not exist".format(vnfd_filename_path
)
2340 vnfd_filename_path
= temp_dir
+ vnfd_filename
2341 if not os
.path
.exists(vnfd_filename_path
):
2342 with
open(vnfd_filename_path
, "wb") as file:
2343 response
= requests
.get(self
.descriptor_url
+ vnfd_filename
)
2344 if response
.status_code
>= 300:
2345 raise TestException(
2346 "Error downloading descriptor from '{}': {}".format(
2347 self
.descriptor_url
+ vnfd_filename
,
2348 response
.status_code
,
2351 file.write(response
.content
)
2352 if vnfd_filename_path
.endswith(".yaml"):
2353 headers
= headers_yaml
2355 headers
= headers_zip_yaml
2356 if randint(0, 1) == 0:
2357 # vnfd CREATE AND UPLOAD in one step:
2359 "Onboard VNFD in one step",
2361 "/vnfpkgm/v1/vnf_packages_content" + self
.qforce
,
2363 "@b" + vnfd_filename_path
,
2365 r_headers_yaml_location_vnfd
,
2368 self
.vnfds_id
.append(engine
.last_id
)
2370 # vnfd CREATE AND UPLOAD ZIP
2372 "Onboard VNFD step 1",
2374 "/vnfpkgm/v1/vnf_packages",
2379 "Location": "/vnfpkgm/v1/vnf_packages/",
2380 "Content-Type": "application/json",
2384 self
.vnfds_id
.append(engine
.last_id
)
2386 "Onboard VNFD step 2 as ZIP",
2388 "/vnfpkgm/v1/vnf_packages/<>/package_content" + self
.qforce
,
2390 "@b" + vnfd_filename_path
,
2396 if self
.descriptor_edit
:
2397 if "vnfd{}".format(vnfd_index
) in self
.descriptor_edit
:
2402 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfds_id
[-1]),
2404 self
.descriptor_edit
["vnfd{}".format(vnfd_index
)],
2410 if "/" in self
.nsd_filename
:
2411 nsd_filename_path
= self
.nsd_filename
2412 if not os
.path
.exists(nsd_filename_path
):
2413 raise TestException(
2414 "File '{}' does not exist".format(nsd_filename_path
)
2417 nsd_filename_path
= temp_dir
+ self
.nsd_filename
2418 if not os
.path
.exists(nsd_filename_path
):
2419 with
open(nsd_filename_path
, "wb") as file:
2420 response
= requests
.get(self
.descriptor_url
+ self
.nsd_filename
)
2421 if response
.status_code
>= 300:
2422 raise TestException(
2423 "Error downloading descriptor from '{}': {}".format(
2424 self
.descriptor_url
+ self
.nsd_filename
,
2425 response
.status_code
,
2428 file.write(response
.content
)
2429 if nsd_filename_path
.endswith(".yaml"):
2430 headers
= headers_yaml
2432 headers
= headers_zip_yaml
2434 if randint(0, 1) == 0:
2435 # nsd CREATE AND UPLOAD in one step:
2437 "Onboard NSD in one step",
2439 "/nsd/v1/ns_descriptors_content" + self
.qforce
,
2441 "@b" + nsd_filename_path
,
2443 r_headers_yaml_location_nsd
,
2446 self
.nsd_id
= engine
.last_id
2448 # nsd CREATE AND UPLOAD ZIP
2450 "Onboard NSD step 1",
2452 "/nsd/v1/ns_descriptors",
2457 "Location": "/nsd/v1/ns_descriptors/",
2458 "Content-Type": "application/json",
2462 self
.nsd_id
= engine
.last_id
2464 "Onboard NSD step 2 as ZIP",
2466 "/nsd/v1/ns_descriptors/<>/nsd_content" + self
.qforce
,
2468 "@b" + nsd_filename_path
,
2474 if self
.descriptor_edit
and "nsd" in self
.descriptor_edit
:
2479 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
2481 self
.descriptor_edit
["nsd"],
2487 def delete_descriptors(self
, engine
):
2488 # delete descriptors
2490 "Delete NSSD SOL005",
2492 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
2499 for vnfd_id
in self
.vnfds_id
:
2501 "Delete VNFD SOL005",
2503 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_id
),
2511 def instantiate(self
, engine
, ns_data
):
2512 ns_data_text
= yaml
.safe_dump(ns_data
, default_flow_style
=True, width
=256)
2513 # create NS Two steps
2517 "/nslcm/v1/ns_instances",
2521 {"Location": "nslcm/v1/ns_instances/", "Content-Type": "application/yaml"},
2526 self
.ns_id
= engine
.last_id
2528 "Instantiate NS step 2",
2530 "/nslcm/v1/ns_instances/{}/instantiate".format(self
.ns_id
),
2534 r_headers_yaml_location_nslcmop
,
2537 nslcmop_id
= engine
.last_id
2540 # Wait until status is Ok
2541 timeout
= timeout_configure
if self
.uses_configuration
else timeout_deploy
2542 engine
.wait_operation_ready("ns", nslcmop_id
, timeout
)
2544 def terminate(self
, engine
):
2550 "/nslcm/v1/ns_instances/{}/terminate".format(self
.ns_id
),
2554 r_headers_yaml_location_nslcmop
,
2557 nslcmop2_id
= engine
.last_id
2558 # Wait until status is Ok
2559 engine
.wait_operation_ready("ns", nslcmop2_id
, timeout_deploy
)
2564 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2573 "Delete NS with FORCE",
2575 "/nslcm/v1/ns_instances/{}?FORCE=True".format(self
.ns_id
),
2583 # check all it is deleted
2585 "Check NS is deleted",
2587 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2595 "Check NSLCMOPs are deleted",
2597 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId={}".format(self
.ns_id
),
2607 if not isinstance(nslcmops
, list) or nslcmops
:
2608 raise TestException(
2609 "NS {} deleted but with ns_lcm_op_occ active: {}".format(
2610 self
.ns_id
, nslcmops
2628 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2639 vnfr_list
= ns_data
["constituent-vnfr-ref"]
2641 _commands
= commands
if commands
is not None else self
.commands
2642 _users
= users
if users
is not None else self
.users
2643 _passwds
= passwds
if passwds
is not None else self
.passwords
2644 _keys
= keys
if keys
is not None else self
.keys
2645 _timeout
= timeout
if timeout
!= 0 else self
.timeout
2647 # vnfr_list=[d8272263-6bd3-4680-84ca-6a4be23b3f2d, 88b22e2f-994a-4b61-94fd-4a3c90de3dc4]
2648 for vnfr_id
in vnfr_list
:
2650 "Get VNFR to get IP_ADDRESS",
2652 "/nslcm/v1/vnfrs/{}".format(vnfr_id
),
2661 vnfr_data
= r
.json()
2663 vnf_index
= str(vnfr_data
["member-vnf-index-ref"])
2665 ip_address
= self
.get_vnfr_ip(engine
, vnf_index
)
2666 description
= "Exec command='{}' at VNFR={} IP={}".format(
2667 _commands
.get(vnf_index
)[0], vnf_index
, ip_address
2670 test_description
= "{}{} {}".format(
2671 engine
.test_name
, engine
.step
, description
2673 logger
.warning(test_description
)
2674 while _timeout
>= time
:
2675 result
, message
= self
.do_checks(
2677 vnf_index
=vnfr_data
["member-vnf-index-ref"],
2678 commands
=_commands
.get(vnf_index
),
2679 user
=_users
.get(vnf_index
),
2680 passwd
=_passwds
.get(vnf_index
),
2681 key
=_keys
.get(vnf_index
),
2684 engine
.passed_tests
+= 1
2685 logger
.debug(message
)
2691 engine
.failed_tests
+= 1
2692 logger
.error(message
)
2696 engine
.failed_tests
+= 1
2697 logger
.error(message
)
2699 engine
.failed_tests
+= 1
2701 "VNFR {} has not mgmt address. Check failed".format(vnf_index
)
2704 def do_checks(self
, ip
, vnf_index
, commands
=[], user
=None, passwd
=None, key
=None):
2707 from pssh
.clients
import ParallelSSHClient
2708 from pssh
.utils
import load_private_key
2709 from ssh2
import exceptions
as ssh2Exception
2710 except ImportError as e
:
2712 "Package <pssh> or/and <urllib3> is not installed. Please add them with 'pip3 install "
2713 "parallel-ssh urllib3': {}".format(e
)
2715 return -1, "install needed packages 'pip3 install parallel-ssh urllib3'"
2716 urllib3
.disable_warnings(urllib3
.exceptions
.InsecureRequestWarning
)
2718 p_host
= os
.environ
.get("PROXY_HOST")
2719 p_user
= os
.environ
.get("PROXY_USER")
2720 p_password
= os
.environ
.get("PROXY_PASSWD")
2723 pkey
= load_private_key(key
)
2727 client
= ParallelSSHClient(
2734 proxy_password
=p_password
,
2738 for cmd
in commands
:
2739 output
= client
.run_command(cmd
)
2741 if output
[ip
[0]].exit_code
:
2742 return -1, "VNFR {} command '{}' returns error: '{}'".format(
2743 ip
[0], cmd
, "\n".join(output
[ip
[0]].stderr
)
2746 return 1, "VNFR {} command '{}' successful".format(ip
[0], cmd
)
2748 ssh2Exception
.ChannelFailure
,
2749 ssh2Exception
.SocketDisconnectError
,
2750 ssh2Exception
.SocketTimeout
,
2751 ssh2Exception
.SocketRecvError
,
2753 return 0, "Timeout accessing the VNFR {}: {}".format(ip
[0], str(e
))
2754 except Exception as e
:
2755 return -1, "ERROR checking the VNFR {}: {}".format(ip
[0], str(e
))
2757 def additional_operations(self
, engine
, test_osm
, manual_check
):
2760 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2761 engine
.set_test_name(self
.test_name
)
2762 engine
.get_autorization()
2763 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
2765 if "vnfd-files" in test_params
:
2766 self
.vnfd_filenames
= test_params
["vnfd-files"].split(",")
2767 if "nsd-file" in test_params
:
2768 self
.nsd_filename
= test_params
["nsd-file"]
2769 if test_params
.get("ns-name"):
2770 nsname
= test_params
["ns-name"]
2771 self
.create_descriptors(engine
)
2773 # create real VIM if not exist
2774 self
.vim_id
= engine
.get_create_vim(test_osm
)
2776 "nsDescription": "default description",
2778 "nsdId": self
.nsd_id
,
2779 "vimAccountId": self
.vim_id
,
2782 ns_data
.update(self
.ns_params
)
2783 if test_params
and test_params
.get("ns-config"):
2784 if isinstance(test_params
["ns-config"], str):
2785 ns_data
.update(yaml
.load(test_params
["ns-config"]), Loader
=yaml
.Loader
)
2787 ns_data
.update(test_params
["ns-config"])
2788 self
.instantiate(engine
, ns_data
)
2792 "NS has been deployed. Perform manual check and press enter to resume"
2794 if test_osm
and self
.commands
:
2795 self
.test_ns(engine
, test_osm
)
2796 self
.additional_operations(engine
, test_osm
, manual_check
)
2797 self
.terminate(engine
)
2798 self
.delete_descriptors(engine
)
2800 def get_first_ip(self
, ip_string
):
2801 # When using a floating IP, the vnfr_data['ip-address'] contains a semicolon-separated list of IP:s.
2802 first_ip
= ip_string
.split(";")[0] if ip_string
else ""
2805 def get_vnfr_ip(self
, engine
, vnfr_index_wanted
):
2806 # If the IP address list has been obtained before, it has been stored in 'vnfr_ip_list'
2807 ip
= self
.vnfr_ip_list
.get(vnfr_index_wanted
, "")
2809 return self
.get_first_ip(ip
)
2811 "Get VNFR to get IP_ADDRESS",
2813 "/nslcm/v1/vnfrs?member-vnf-index-ref={}&nsr-id-ref={}".format(
2814 vnfr_index_wanted
, self
.ns_id
2824 vnfr_data
= r
.json()
2825 if not (vnfr_data
and vnfr_data
[0]):
2827 # Store the IP (or list of IPs) in 'vnfr_ip_list'
2828 ip_list
= vnfr_data
[0].get("ip-address", "")
2830 self
.vnfr_ip_list
[vnfr_index_wanted
] = ip_list
2831 ip
= self
.get_first_ip(ip_list
)
2835 class TestDeployHackfestCirros(TestDeploy
):
2836 description
= "Load and deploy Hackfest cirros_2vnf_ns example"
2840 self
.test_name
= "CIRROS"
2841 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
2842 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
2851 self
.users
= {"1": "cirros", "2": "cirros"}
2852 self
.passwords
= {"1": "cubswin:)", "2": "cubswin:)"}
2854 def terminate(self
, engine
):
2855 # Make a delete in one step, overriding the normal two step of TestDeploy that launched terminate and delete
2858 "Terminate and delete NS in one step",
2860 "/nslcm/v1/ns_instances_content/{}".format(self
.ns_id
),
2868 engine
.wait_until_delete(
2869 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), timeout_deploy
2873 "Delete NS with FORCE",
2875 "/nslcm/v1/ns_instances/{}?FORCE=True".format(self
.ns_id
),
2883 # check all it is deleted
2885 "Check NS is deleted",
2887 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2895 "Check NSLCMOPs are deleted",
2897 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId={}".format(self
.ns_id
),
2907 if not isinstance(nslcmops
, list) or nslcmops
:
2908 raise TestException(
2909 "NS {} deleted but with ns_lcm_op_occ active: {}".format(
2910 self
.ns_id
, nslcmops
2915 class TestDeployHackfest1(TestDeploy
):
2916 description
= "Load and deploy Hackfest_1_vnfd example"
2920 self
.test_name
= "HACKFEST1-"
2921 self
.vnfd_filenames
= ("hackfest_1_vnfd.tar.gz",)
2922 self
.nsd_filename
= "hackfest_1_nsd.tar.gz"
2923 # self.commands = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
2924 # self.users = {'1': "cirros", '2': "cirros"}
2925 # self.passwords = {'1': "cubswin:)", '2': "cubswin:)"}
2928 class TestDeployHackfestCirrosScaling(TestDeploy
):
2930 "Load and deploy Hackfest cirros_2vnf_ns example with scaling modifications"
2935 self
.test_name
= "CIRROS-SCALE"
2936 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
2937 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
2938 # Modify VNFD to add scaling and count=2
2939 self
.descriptor_edit
= {
2941 "vdu": {"$id: 'cirros_vnfd-VM'": {"count": 2}},
2942 "scaling-group-descriptor": [
2944 "name": "scale_cirros",
2945 "max-instance-count": 2,
2946 "vdu": [{"vdu-id-ref": "cirros_vnfd-VM", "count": 2}],
2952 def additional_operations(self
, engine
, test_osm
, manual_check
):
2955 # 2 perform scale out twice
2957 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: "
2958 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
2960 for i
in range(0, 2):
2962 "Execute scale action over NS",
2964 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
2968 r_headers_yaml_location_nslcmop
,
2971 nslcmop2_scale_out
= engine
.last_id
2972 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
2974 input("NS scale out done. Check that two more vdus are there")
2975 # TODO check automatic
2977 # 2 perform scale in
2979 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: "
2980 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
2982 for i
in range(0, 2):
2984 "Execute scale IN action over NS",
2986 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
2990 r_headers_yaml_location_nslcmop
,
2993 nslcmop2_scale_in
= engine
.last_id
2994 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
2996 input("NS scale in done. Check that two less vdus are there")
2997 # TODO check automatic
2999 # perform scale in that must fail as reached limit
3001 "Execute scale IN out of limit action over NS",
3003 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3007 r_headers_yaml_location_nslcmop
,
3010 nslcmop2_scale_in
= engine
.last_id
3011 engine
.wait_operation_ready(
3012 "ns", nslcmop2_scale_in
, timeout_deploy
, expected_fail
=True
3016 class TestDeployIpMac(TestDeploy
):
3017 description
= "Load and deploy descriptor examples setting mac, ip address at descriptor and instantiate params"
3021 self
.test_name
= "SetIpMac"
3022 self
.vnfd_filenames
= (
3023 "vnfd_2vdu_set_ip_mac2.yaml",
3024 "vnfd_2vdu_set_ip_mac.yaml",
3026 self
.nsd_filename
= "scenario_2vdu_set_ip_mac.yaml"
3027 self
.descriptor_url
= (
3028 "https://osm.etsi.org/gitweb/?p=osm/RO.git;a=blob_plain;f=test/RO_tests/v3_2vdu_set_ip_mac/"
3038 self
.users
= {"1": "osm", "2": "osm"}
3039 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3042 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3043 # super().run(engine, test_osm, manual_check, test_params)
3044 # run again setting IPs with instantiate parameters
3045 instantiation_params
= {
3048 "member-vnf-index": "1",
3051 "name": "internal_vld1", # net_internal
3053 "ip-version": "ipv4",
3054 "subnet-address": "10.9.8.0/24",
3057 "start-address": "10.9.8.100",
3060 "internal-connection-point": [
3063 "ip-address": "10.9.8.2",
3067 "ip-address": "10.9.8.3",
3077 # "name": "iface11",
3078 # "floating-ip-required": True,
3080 {"name": "iface13", "mac-address": "52:33:44:55:66:13"},
3088 "ip-address": "10.31.31.22",
3089 "mac-address": "52:33:44:55:66:21",
3102 test_params
={"ns-config": instantiation_params
},
3106 class TestDeployHackfest4(TestDeploy
):
3107 description
= "Load and deploy Hackfest 4 example."
3111 self
.test_name
= "HACKFEST4-"
3112 self
.vnfd_filenames
= ("hackfest_4_vnfd.tar.gz",)
3113 self
.nsd_filename
= "hackfest_4_nsd.tar.gz"
3114 self
.uses_configuration
= True
3123 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3124 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3125 # Modify VNFD to add scaling
3126 # self.descriptor_edit = {
3128 # 'vnf-configuration': {
3129 # 'config-primitive': [{
3132 # 'name': 'filename',
3133 # 'data-type': 'STRING',
3134 # 'default-value': '/home/ubuntu/touched'
3138 # 'scaling-group-descriptor': [{
3139 # 'name': 'scale_dataVM',
3140 # 'scaling-policy': [{
3141 # 'threshold-time': 0,
3142 # 'name': 'auto_cpu_util_above_threshold',
3143 # 'scaling-type': 'automatic',
3144 # 'scaling-criteria': [{
3145 # 'name': 'cpu_util_above_threshold',
3146 # 'vnf-monitoring-param-ref': 'all_aaa_cpu_util',
3147 # 'scale-out-relational-operation': 'GE',
3148 # 'scale-in-threshold': 15,
3149 # 'scale-out-threshold': 60,
3150 # 'scale-in-relational-operation': 'LE'
3152 # 'cooldown-time': 60
3154 # 'max-instance-count': 10,
3155 # 'scaling-config-action': [
3156 # {'vnf-config-primitive-name-ref': 'touch',
3157 # 'trigger': 'post-scale-out'},
3158 # {'vnf-config-primitive-name-ref': 'touch',
3159 # 'trigger': 'pre-scale-in'}
3162 # 'vdu-id-ref': 'dataVM',
3170 class TestDeployHackfest3Charmed(TestDeploy
):
3171 description
= "Load and deploy Hackfest 3charmed_ns example"
3175 self
.test_name
= "HACKFEST3-"
3176 self
.vnfd_filenames
= ("hackfest_3charmed_vnfd.tar.gz",)
3177 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
3178 self
.uses_configuration
= True
3180 "1": ["ls -lrt /home/ubuntu/first-touch"],
3181 "2": ["ls -lrt /home/ubuntu/first-touch"],
3183 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3184 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3185 self
.descriptor_edit
= {
3186 "vnfd0": yaml
.safe_load(
3189 terminate-config-primitive:
3194 value: '/home/ubuntu/last-touch1'
3199 value: '/home/ubuntu/last-touch3'
3204 value: '/home/ubuntu/last-touch2'
3209 def additional_operations(self
, engine
, test_osm
, manual_check
):
3213 vnfr_index_selected
= "2"
3214 payload
= '{member_vnf_index: "2", primitive: touch, primitive_params: { filename: /home/ubuntu/OSMTESTNBI }}'
3216 "Exec service primitive over NS",
3218 "/nslcm/v1/ns_instances/{}/action".format(self
.ns_id
),
3222 r_headers_yaml_location_nslcmop
,
3225 nslcmop2_action
= engine
.last_id
3226 # Wait until status is Ok
3227 engine
.wait_operation_ready("ns", nslcmop2_action
, timeout_deploy
)
3228 vnfr_ip
= self
.get_vnfr_ip(engine
, vnfr_index_selected
)
3231 "NS service primitive has been executed."
3232 "Check that file /home/ubuntu/OSMTESTNBI is present at {}".format(
3240 "ls -lrt /home/ubuntu/OSMTESTNBI",
3243 self
.test_ns(engine
, test_osm
, commands
=commands
)
3245 # # 2 perform scale out
3246 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
3247 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3248 # engine.test("Execute scale action over NS", "POST",
3249 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
3250 # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
3251 # nslcmop2_scale_out = engine.last_id
3252 # engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
3254 # input('NS scale out done. Check that file /home/ubuntu/touched is present and new VM is created')
3255 # # TODO check automatic
3257 # # 2 perform scale in
3258 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
3259 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3260 # engine.test("Execute scale action over NS", "POST",
3261 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
3262 # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
3263 # nslcmop2_scale_in = engine.last_id
3264 # engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
3266 # input('NS scale in done. Check that file /home/ubuntu/touched is updated and new VM is deleted')
3267 # # TODO check automatic
3270 class TestDeployHackfest3Charmed2(TestDeployHackfest3Charmed
):
3272 "Load and deploy Hackfest 3charmed_ns example modified version of descriptors to have dots in "
3273 "ids and member-vnf-index."
3278 self
.test_name
= "HACKFEST3v2-"
3279 self
.qforce
= "?FORCE=True"
3280 self
.descriptor_edit
= {
3285 "$[0]": {"external-connection-point-ref": "pdu-mgmt"}
3290 "vnf-configuration": None,
3291 "connection-point": {
3295 "short-name": "pdu-mgmt",
3299 "mgmt-interface": {"cp": "pdu-mgmt"},
3300 "description": "A vnf single vdu to be used as PDU",
3304 "id": "pdu_internal",
3305 "name": "pdu_internal",
3306 "internal-connection-point": {"$[1]": None},
3307 "short-name": "pdu_internal",
3312 # Modify NSD accordingly
3314 "constituent-vnfd": {
3315 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
3318 "description": "A nsd to deploy the vnf to act as as PDU",
3320 "name": "nsd-as-pdu",
3321 "short-name": "nsd-as-pdu",
3326 "short-name": "mgmt_pdu",
3327 "vnfd-connection-point-ref": {
3329 "vnfd-connection-point-ref": "pdu-mgmt",
3330 "vnfd-id-ref": "vdu-as-pdu",
3342 class TestDeployHackfest3Charmed3(TestDeployHackfest3Charmed
):
3343 description
= "Load and deploy Hackfest 3charmed_ns example modified version to test scaling and NS parameters"
3347 self
.test_name
= "HACKFEST3v3-"
3349 "1": ["ls -lrt /home/ubuntu/first-touch-1"],
3350 "2": ["ls -lrt /home/ubuntu/first-touch-2"],
3352 self
.descriptor_edit
= {
3355 scaling-group-descriptor:
3356 - name: "scale_dataVM"
3357 max-instance-count: 10
3359 - name: "auto_cpu_util_above_threshold"
3360 scaling-type: "automatic"
3364 - name: "cpu_util_above_threshold"
3365 scale-in-threshold: 15
3366 scale-in-relational-operation: "LE"
3367 scale-out-threshold: 60
3368 scale-out-relational-operation: "GE"
3369 vnf-monitoring-param-ref: "monitor1"
3371 - vdu-id-ref: dataVM
3373 scaling-config-action:
3374 - trigger: post-scale-out
3375 vnf-config-primitive-name-ref: touch
3376 - trigger: pre-scale-in
3377 vnf-config-primitive-name-ref: touch
3381 - id: "dataVM_cpu_util"
3382 nfvi-metric: "cpu_utilization"
3387 aggregation-type: AVERAGE
3388 vdu-monitoring-param:
3390 vdu-monitoring-param-ref: "dataVM_cpu_util"
3392 initial-config-primitive:
3396 value: "<touch_filename>" # default-value: /home/ubuntu/first-touch
3401 default-value: "<touch_filename2>"
3407 "additionalParamsForVnf": [
3409 "member-vnf-index": "1",
3410 "additionalParams": {
3411 "touch_filename": "/home/ubuntu/first-touch-1",
3412 "touch_filename2": "/home/ubuntu/second-touch-1",
3416 "member-vnf-index": "2",
3417 "additionalParams": {
3418 "touch_filename": "/home/ubuntu/first-touch-2",
3419 "touch_filename2": "/home/ubuntu/second-touch-2",
3425 def additional_operations(self
, engine
, test_osm
, manual_check
):
3426 super().additional_operations(engine
, test_osm
, manual_check
)
3430 # 2 perform scale out
3432 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: "
3433 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3436 "Execute scale action over NS",
3438 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3442 r_headers_yaml_location_nslcmop
,
3445 nslcmop2_scale_out
= engine
.last_id
3446 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
3449 "NS scale out done. Check that file /home/ubuntu/second-touch-1 is present and new VM is created"
3454 "ls -lrt /home/ubuntu/second-touch-1",
3457 self
.test_ns(engine
, test_osm
, commands
=commands
)
3458 # TODO check automatic connection to scaled VM
3460 # 2 perform scale in
3462 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: "
3463 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3466 "Execute scale action over NS",
3468 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3472 r_headers_yaml_location_nslcmop
,
3475 nslcmop2_scale_in
= engine
.last_id
3476 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
3479 "NS scale in done. Check that file /home/ubuntu/second-touch-1 is updated and new VM is deleted"
3481 # TODO check automatic
3484 class TestDeploySimpleCharm(TestDeploy
):
3485 description
= "Deploy hackfest-4 hackfest_simplecharm example"
3489 self
.test_name
= "HACKFEST-SIMPLE"
3490 self
.descriptor_url
= (
3491 "https://osm-download.etsi.org/ftp/osm-4.0-four/4th-hackfest/packages/"
3493 self
.vnfd_filenames
= ("hackfest_simplecharm_vnf.tar.gz",)
3494 self
.nsd_filename
= "hackfest_simplecharm_ns.tar.gz"
3495 self
.uses_configuration
= True
3499 "ls -lrt /home/ubuntu/first-touch",
3502 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3503 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3506 class TestDeploySimpleCharm2(TestDeploySimpleCharm
):
3508 "Deploy hackfest-4 hackfest_simplecharm example changing naming to contain dots on ids and "
3514 self
.test_name
= "HACKFEST-SIMPLE2-"
3515 self
.qforce
= "?FORCE=True"
3516 self
.descriptor_edit
= {
3517 "vnfd0": {"id": "hackfest.simplecharm.vnf"},
3519 "id": "hackfest.simplecharm.ns",
3520 "constituent-vnfd": {
3522 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3523 "member-vnf-index": "$1",
3526 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3527 "member-vnf-index": "$2",
3532 "vnfd-connection-point-ref": {
3534 "member-vnf-index-ref": "$1",
3535 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3538 "member-vnf-index-ref": "$2",
3539 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3544 "vnfd-connection-point-ref": {
3546 "member-vnf-index-ref": "$1",
3547 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3550 "member-vnf-index-ref": "$2",
3551 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3560 class TestDeploySingleVdu(TestDeployHackfest3Charmed
):
3562 "Generate a single VDU base on editing Hackfest3Charmed descriptors and deploy"
3567 self
.test_name
= "SingleVDU"
3568 self
.qforce
= "?FORCE=True"
3569 self
.descriptor_edit
= {
3570 # Modify VNFD to remove one VDU
3575 "$[0]": {"external-connection-point-ref": "pdu-mgmt"}
3580 "vnf-configuration": None,
3581 "connection-point": {
3585 "short-name": "pdu-mgmt",
3589 "mgmt-interface": {"cp": "pdu-mgmt"},
3590 "description": "A vnf single vdu to be used as PDU",
3594 "id": "pdu_internal",
3595 "name": "pdu_internal",
3596 "internal-connection-point": {"$[1]": None},
3597 "short-name": "pdu_internal",
3602 # Modify NSD accordingly
3604 "constituent-vnfd": {
3605 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
3608 "description": "A nsd to deploy the vnf to act as as PDU",
3610 "name": "nsd-as-pdu",
3611 "short-name": "nsd-as-pdu",
3616 "short-name": "mgmt_pdu",
3617 "vnfd-connection-point-ref": {
3619 "vnfd-connection-point-ref": "pdu-mgmt",
3620 "vnfd-id-ref": "vdu-as-pdu",
3632 class TestDeployHnfd(TestDeployHackfest3Charmed
):
3634 "Generate a HNFD base on editing Hackfest3Charmed descriptors and deploy"
3639 self
.test_name
= "HNFD"
3640 self
.pduDeploy
= TestDeploySingleVdu()
3641 self
.pdu_interface_0
= {}
3642 self
.pdu_interface_1
= {}
3645 # self.vnf_to_pdu = """
3648 # pdu-type: PDU-TYPE-1
3653 # name: pdu-iface-internal
3655 # description: HFND, one PDU + One VDU
3661 self
.pdu_descriptor
= {
3663 "type": "PDU-TYPE-1",
3664 "vim_accounts": "to-override",
3667 "name": "mgmt-iface",
3670 "ip-address": "to override",
3671 "mac-address": "mac_address",
3672 "vim-network-name": "mgmt",
3675 "name": "pdu-iface-internal",
3678 "ip-address": "to override",
3679 "mac-address": "mac_address",
3680 "vim-network-name": "pdu_internal", # OSMNBITEST-PDU-pdu_internal
3684 self
.vnfd_filenames
= (
3685 "hackfest_3charmed_vnfd.tar.gz",
3686 "hackfest_3charmed_vnfd.tar.gz",
3689 self
.descriptor_edit
= {
3693 "short-name": "hfn1",
3696 "pdu-type": "PDU-TYPE-1",
3698 "$[0]": {"name": "mgmt-iface"},
3699 "$[1]": {"name": "pdu-iface-internal"},
3705 "constituent-vnfd": {"$[1]": {"vnfd-id-ref": "hfnd1"}},
3708 "vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}
3711 "vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}
3717 def create_descriptors(self
, engine
):
3718 super().create_descriptors(engine
)
3721 self
.pdu_descriptor
["interfaces"][0].update(self
.pdu_interface_0
)
3722 self
.pdu_descriptor
["interfaces"][1].update(self
.pdu_interface_1
)
3723 self
.pdu_descriptor
["vim_accounts"] = [self
.vim_id
]
3724 # TODO get vim-network-name from vnfr.vld.name
3725 self
.pdu_descriptor
["interfaces"][1]["vim-network-name"] = "{}-{}-{}".format(
3726 os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST"),
3728 self
.pdu_descriptor
["interfaces"][1]["vim-network-name"],
3731 "Onboard PDU descriptor",
3733 "/pdu/v1/pdu_descriptors",
3735 "Location": "/pdu/v1/pdu_descriptors/",
3736 "Content-Type": "application/yaml",
3738 self
.pdu_descriptor
,
3743 self
.pdu_id
= engine
.last_id
3745 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3746 engine
.get_autorization()
3747 engine
.set_test_name(self
.test_name
)
3748 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
3750 # create real VIM if not exist
3751 self
.vim_id
= engine
.get_create_vim(test_osm
)
3753 self
.pduDeploy
.create_descriptors(engine
)
3754 self
.pduDeploy
.instantiate(
3757 "nsDescription": "to be used as PDU",
3758 "nsName": nsname
+ "-PDU",
3759 "nsdId": self
.pduDeploy
.nsd_id
,
3760 "vimAccountId": self
.vim_id
,
3765 "VNF to be used as PDU has been deployed. Perform manual check and press enter to resume"
3768 self
.pduDeploy
.test_ns(engine
, test_osm
)
3772 "Get VNFR to obtain IP_ADDRESS",
3774 "/nslcm/v1/vnfrs?nsr-id-ref={}".format(self
.pduDeploy
.ns_id
),
3783 vnfr_data
= r
.json()
3786 self
.pdu_interface_0
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3789 self
.pdu_interface_1
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3792 self
.pdu_interface_0
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3794 ].get("mac-address")
3795 self
.pdu_interface_1
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3797 ].get("mac-address")
3798 if not self
.pdu_interface_0
["ip-address"]:
3799 raise TestException("Vnfr has not managment ip address")
3801 self
.pdu_interface_0
["ip-address"] = "192.168.10.10"
3802 self
.pdu_interface_1
["ip-address"] = "192.168.11.10"
3803 self
.pdu_interface_0
["mac-address"] = "52:33:44:55:66:13"
3804 self
.pdu_interface_1
["mac-address"] = "52:33:44:55:66:14"
3806 self
.create_descriptors(engine
)
3809 "nsDescription": "default description",
3811 "nsdId": self
.nsd_id
,
3812 "vimAccountId": self
.vim_id
,
3814 if test_params
and test_params
.get("ns-config"):
3815 if isinstance(test_params
["ns-config"], str):
3816 ns_data
.update(yaml
.load(test_params
["ns-config"]), Loader
=yaml
.Loader
)
3818 ns_data
.update(test_params
["ns-config"])
3820 self
.instantiate(engine
, ns_data
)
3823 "NS has been deployed. Perform manual check and press enter to resume"
3826 self
.test_ns(engine
, test_osm
)
3827 self
.additional_operations(engine
, test_osm
, manual_check
)
3828 self
.terminate(engine
)
3829 self
.pduDeploy
.terminate(engine
)
3830 self
.delete_descriptors(engine
)
3831 self
.pduDeploy
.delete_descriptors(engine
)
3833 def delete_descriptors(self
, engine
):
3834 super().delete_descriptors(engine
)
3837 "Delete PDU SOL005",
3839 "/pdu/v1/pdu_descriptors/{}".format(self
.pdu_id
),
3848 class TestDescriptors
:
3849 description
= "Test VNFD, NSD, PDU descriptors CRUD and dependencies"
3850 vnfd_empty
= """vnfd:vnfd-catalog:
3856 vnfd_prova
= """vnfd:vnfd-catalog:
3868 - external-connection-point-ref: cp_0h8m
3877 self
.vnfd_filename
= "hackfest_3charmed_vnfd.tar.gz"
3878 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
3879 self
.descriptor_url
= (
3880 "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
3885 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3886 engine
.set_test_name("Descriptors")
3887 engine
.get_autorization()
3888 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
3889 if not os
.path
.exists(temp_dir
):
3890 os
.makedirs(temp_dir
)
3893 for filename
in (self
.vnfd_filename
, self
.nsd_filename
):
3894 filename_path
= temp_dir
+ filename
3895 if not os
.path
.exists(filename_path
):
3896 with
open(filename_path
, "wb") as file:
3897 response
= requests
.get(self
.descriptor_url
+ filename
)
3898 if response
.status_code
>= 300:
3899 raise TestException(
3900 "Error downloading descriptor from '{}': {}".format(
3901 self
.descriptor_url
+ filename
, response
.status_code
3904 file.write(response
.content
)
3906 vnfd_filename_path
= temp_dir
+ self
.vnfd_filename
3907 nsd_filename_path
= temp_dir
+ self
.nsd_filename
3910 "Onboard empty VNFD in one step",
3912 "/vnfpkgm/v1/vnf_packages_content",
3916 r_headers_yaml_location_vnfd
,
3919 self
.vnfd_id
= engine
.last_id
3923 "Upload invalid VNFD ",
3925 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3934 "Upload VNFD {}".format(self
.vnfd_filename
),
3936 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3938 "@b" + vnfd_filename_path
,
3945 "mgmt-interface.cp=mgmt",
3946 "vdu.0.interface.0.external-connection-point-ref=mgmt",
3947 "vdu.0.interface.1.internal-connection-point-ref=internal",
3948 "internal-vld.0.internal-connection-point.0.id-ref=internal",
3949 # Detection of duplicated VLD names in VNF Descriptors
3950 # URL: internal-vld=[
3951 # {id: internal1, name: internal, type:ELAN,
3952 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]},
3953 # {id: internal2, name: internal, type:ELAN,
3954 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]}
3956 "internal-vld=%5B%7Bid%3A%20internal1%2C%20name%3A%20internal%2C%20type%3A%20ELAN%2C%20"
3957 "internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7Bid-ref%3A%20"
3958 "dataVM-internal%7D%5D%7D%2C%20%7Bid%3A%20internal2%2C%20name%3A%20internal%2C%20type%3A%20"
3959 "ELAN%2C%20internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7B"
3960 "id-ref%3A%20dataVM-internal%7D%5D%7D%5D",
3962 for query
in queries
:
3964 "Upload invalid VNFD ",
3966 "/vnfpkgm/v1/vnf_packages/{}/package_content?{}".format(
3970 "@b" + vnfd_filename_path
,
3978 "Upload invalid VNFD ",
3980 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3988 # get vnfd descriptor
3990 "Get VNFD descriptor",
3992 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
4000 # get vnfd file descriptor
4002 "Get VNFD file descriptor",
4004 "/vnfpkgm/v1/vnf_packages/{}/vnfd".format(self
.vnfd_id
),
4010 temp_dir
+ "vnfd-yaml",
4012 # TODO compare files: diff vnfd-yaml hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml
4014 # get vnfd zip file package
4016 "Get VNFD zip package",
4018 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
4024 temp_dir
+ "vnfd-zip",
4026 # TODO compare files: diff vnfd-zip hackfest_3charmed_vnfd.tar.gz
4030 "Get VNFD artifact package",
4032 "/vnfpkgm/v1/vnf_packages/{}/artifacts/icons/osm.png".format(self
.vnfd_id
),
4038 temp_dir
+ "vnfd-icon",
4040 # TODO compare files: diff vnfd-icon hackfest_3charmed_vnfd/icons/osm.png
4042 # nsd CREATE AND UPLOAD in one step:
4044 "Onboard NSD in one step",
4046 "/nsd/v1/ns_descriptors_content",
4048 "@b" + nsd_filename_path
,
4050 r_headers_yaml_location_nsd
,
4053 self
.nsd_id
= engine
.last_id
4055 queries
= ["vld.0.vnfd-connection-point-ref.0.vnfd-id-ref=hf"]
4056 for query
in queries
:
4058 "Upload invalid NSD ",
4060 "/nsd/v1/ns_descriptors/{}/nsd_content?{}".format(self
.nsd_id
, query
),
4062 "@b" + nsd_filename_path
,
4068 # get nsd descriptor
4070 "Get NSD descriptor",
4072 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
4080 # get nsd file descriptor
4082 "Get NSD file descriptor",
4084 "/nsd/v1/ns_descriptors/{}/nsd".format(self
.nsd_id
),
4090 temp_dir
+ "nsd-yaml",
4092 # TODO compare files: diff nsd-yaml hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml
4094 # get nsd zip file package
4096 "Get NSD zip package",
4098 "/nsd/v1/ns_descriptors/{}/nsd_content".format(self
.nsd_id
),
4104 temp_dir
+ "nsd-zip",
4106 # TODO compare files: diff nsd-zip hackfest_3charmed_nsd.tar.gz
4110 "Get NSD artifact package",
4112 "/nsd/v1/ns_descriptors/{}/artifacts/icons/osm.png".format(self
.nsd_id
),
4118 temp_dir
+ "nsd-icon",
4120 # TODO compare files: diff nsd-icon hackfest_3charmed_nsd/icons/osm.png
4124 "Delete VNFD conflict",
4126 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
4135 "Delete VNFD force",
4137 "/vnfpkgm/v1/vnf_packages/{}?FORCE=TRUE".format(self
.vnfd_id
),
4149 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
4158 class TestNetSliceTemplates
:
4159 description
= "Upload a NST to OSM"
4162 self
.vnfd_filename
= "@./slice_shared/vnfd/slice_shared_vnfd.yaml"
4163 self
.vnfd_filename_middle
= "@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml"
4164 self
.nsd_filename
= "@./slice_shared/nsd/slice_shared_nsd.yaml"
4165 self
.nsd_filename_middle
= "@./slice_shared/nsd/slice_shared_middle_nsd.yaml"
4166 self
.nst_filenames
= "@./slice_shared/slice_shared_nstd.yaml"
4168 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
4170 engine
.set_test_name("NST step ")
4171 engine
.get_autorization()
4172 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
4173 if not os
.path
.exists(temp_dir
):
4174 os
.makedirs(temp_dir
)
4178 "Onboard edge VNFD",
4180 "/vnfpkgm/v1/vnf_packages_content",
4184 r_headers_yaml_location_vnfd
,
4187 self
.vnfd_edge_id
= engine
.last_id
4190 "Onboard middle VNFD",
4192 "/vnfpkgm/v1/vnf_packages_content",
4194 self
.vnfd_filename_middle
,
4196 r_headers_yaml_location_vnfd
,
4199 self
.vnfd_middle_id
= engine
.last_id
4205 "/nsd/v1/ns_descriptors_content",
4209 r_headers_yaml_location_nsd
,
4212 self
.nsd_edge_id
= engine
.last_id
4215 "Onboard NSD middle",
4217 "/nsd/v1/ns_descriptors_content",
4219 self
.nsd_filename_middle
,
4221 r_headers_yaml_location_nsd
,
4224 self
.nsd_middle_id
= engine
.last_id
4230 "/nst/v1/netslice_templates_content",
4234 r_headers_yaml_location_nst
,
4237 nst_id
= engine
.last_id
4239 # nstd SHOW OSM format
4241 "Show NSTD OSM format",
4243 "/nst/v1/netslice_templates/{}".format(nst_id
),
4255 "/nst/v1/netslice_templates/{}".format(nst_id
),
4265 "Delete NSD middle",
4267 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
4278 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
),
4290 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
4299 "Delete VNFD middle",
4301 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
4310 class TestNetSliceInstances
:
4313 1. Populate databases with VNFD, NSD, NST with the following scenario
4314 +-----------------management-----------------+
4316 +--+---+ +----+----+ +---+--+
4318 | edge +---data1----+ middle +---data2-----+ edge |
4320 +------+ +---------+ +------+
4323 3. Instantiate NSI-1
4325 5. Instantiate NSI-2
4326 Manual check - Are 2 slices instantiated correctly?
4327 NSI-1 3 nss (2 nss-edges + 1 nss-middle)
4328 NSI-2 2 nss (2 nss-edge sharing nss-middle)
4331 Manual check - Is slice NSI-1 deleted correctly?
4332 NSI-2 with 2 nss-edge + 1 nss-middle (The one from NSI-1)
4334 9. Instantiate NSI-3
4335 Manual check - Is slice NSI-3 instantiated correctly?
4336 NSI-3 reuse nss-middle. NSI-3 only create 2 nss-edge
4341 Manual check - All cleaned correctly?
4342 NSI-2 and NSI-3 were terminated and deleted
4343 14. Cleanup database
4346 description
= "Upload a NST to OSM"
4350 self
.vnfd_filename
= "@./slice_shared/vnfd/slice_shared_vnfd.yaml"
4351 self
.vnfd_filename_middle
= "@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml"
4352 self
.nsd_filename
= "@./slice_shared/nsd/slice_shared_nsd.yaml"
4353 self
.nsd_filename_middle
= "@./slice_shared/nsd/slice_shared_middle_nsd.yaml"
4354 self
.nst_filenames
= "@./slice_shared/slice_shared_nstd.yaml"
4356 def create_slice(self
, engine
, nsi_data
, name
):
4357 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
4361 "/nsilcm/v1/netslice_instances",
4366 "Location": "nsilcm/v1/netslice_instances/",
4367 "Content-Type": "application/yaml",
4373 def instantiate_slice(self
, engine
, nsi_data
, nsi_id
, name
):
4374 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
4378 "/nsilcm/v1/netslice_instances/{}/instantiate".format(nsi_id
),
4382 r_headers_yaml_location_nsilcmop
,
4386 def terminate_slice(self
, engine
, nsi_id
, name
):
4390 "/nsilcm/v1/netslice_instances/{}/terminate".format(nsi_id
),
4394 r_headers_yaml_location_nsilcmop
,
4398 def delete_slice(self
, engine
, nsi_id
, name
):
4402 "/nsilcm/v1/netslice_instances/{}".format(nsi_id
),
4410 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
4412 engine
.set_test_name("NSI")
4413 engine
.get_autorization()
4417 "Onboard edge VNFD",
4419 "/vnfpkgm/v1/vnf_packages_content",
4423 r_headers_yaml_location_vnfd
,
4426 self
.vnfd_edge_id
= engine
.last_id
4429 "Onboard middle VNFD",
4431 "/vnfpkgm/v1/vnf_packages_content",
4433 self
.vnfd_filename_middle
,
4435 r_headers_yaml_location_vnfd
,
4438 self
.vnfd_middle_id
= engine
.last_id
4444 "/nsd/v1/ns_descriptors_content",
4448 r_headers_yaml_location_nsd
,
4451 self
.nsd_edge_id
= engine
.last_id
4454 "Onboard NSD middle",
4456 "/nsd/v1/ns_descriptors_content",
4458 self
.nsd_filename_middle
,
4460 r_headers_yaml_location_nsd
,
4463 self
.nsd_middle_id
= engine
.last_id
4469 "/nst/v1/netslice_templates_content",
4473 r_headers_yaml_location_nst
,
4476 nst_id
= engine
.last_id
4478 self
.vim_id
= engine
.get_create_vim(test_osm
)
4482 "nsiName": "Deploy-NSI-1",
4483 "vimAccountId": self
.vim_id
,
4485 "nsiDescription": "default",
4487 r
= self
.create_slice(engine
, ns_data
, "Create NSI-1 step 1")
4490 self
.nsi_id1
= engine
.last_id
4493 self
.instantiate_slice(
4494 engine
, ns_data
, self
.nsi_id1
, "Instantiate NSI-1 step 2"
4496 nsilcmop_id1
= engine
.last_id
4500 engine
.wait_operation_ready("nsi", nsilcmop_id1
, timeout_deploy
)
4504 "nsiName": "Deploy-NSI-2",
4505 "vimAccountId": self
.vim_id
,
4507 "nsiDescription": "default",
4509 r
= self
.create_slice(engine
, ns_data
, "Create NSI-2 step 1")
4512 self
.nsi_id2
= engine
.last_id
4515 self
.instantiate_slice(
4516 engine
, ns_data
, self
.nsi_id2
, "Instantiate NSI-2 step 2"
4518 nsilcmop_id2
= engine
.last_id
4522 engine
.wait_operation_ready("nsi", nsilcmop_id2
, timeout_deploy
)
4526 "NSI-1 AND NSI-2 has been deployed. Perform manual check and press enter to resume"
4531 self
.terminate_slice(engine
, self
.nsi_id1
, "Terminate NSI-1")
4532 nsilcmop1_id
= engine
.last_id
4534 # Wait terminate NSI-1
4535 engine
.wait_operation_ready("nsi", nsilcmop1_id
, timeout_deploy
)
4538 self
.delete_slice(engine
, self
.nsi_id1
, "Delete NS")
4542 "NSI-1 has been deleted. Perform manual check and press enter to resume"
4547 "nsiName": "Deploy-NSI-3",
4548 "vimAccountId": self
.vim_id
,
4550 "nsiDescription": "default",
4552 r
= self
.create_slice(engine
, ns_data
, "Create NSI-3 step 1")
4556 self
.nsi_id3
= engine
.last_id
4559 self
.instantiate_slice(
4560 engine
, ns_data
, self
.nsi_id3
, "Instantiate NSI-3 step 2"
4562 nsilcmop_id3
= engine
.last_id
4564 # Wait Instantiate NSI-3
4566 engine
.wait_operation_ready("nsi", nsilcmop_id3
, timeout_deploy
)
4570 "NSI-3 has been deployed. Perform manual check and press enter to resume"
4575 self
.terminate_slice(engine
, self
.nsi_id2
, "Terminate NSI-2")
4576 nsilcmop2_id
= engine
.last_id
4578 # Wait terminate NSI-2
4579 engine
.wait_operation_ready("nsi", nsilcmop2_id
, timeout_deploy
)
4582 self
.delete_slice(engine
, self
.nsi_id2
, "DELETE NSI-2")
4586 self
.terminate_slice(engine
, self
.nsi_id3
, "Terminate NSI-3")
4587 nsilcmop3_id
= engine
.last_id
4589 # Wait terminate NSI-3
4590 engine
.wait_operation_ready("nsi", nsilcmop3_id
, timeout_deploy
)
4593 self
.delete_slice(engine
, self
.nsi_id3
, "DELETE NSI-3")
4597 "NSI-2 and NSI-3 has been deleted. Perform manual check and press enter to resume"
4604 "/nst/v1/netslice_templates/{}".format(nst_id
),
4614 "Delete NSD middle",
4616 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
4627 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
),
4639 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
4648 "Delete VNFD middle",
4650 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
4659 class TestAuthentication
:
4660 description
= "Test Authentication"
4663 def run(engine
, test_osm
, manual_check
, test_params
=None):
4664 engine
.set_test_name("Authentication")
4665 # backend = test_params.get("backend") if test_params else None # UNUSED
4667 admin_project_id
= test_project_id
= None
4668 project_admin_role_id
= project_user_role_id
= None
4669 test_user_id
= empty_user_id
= None
4670 default_role_id
= empty_role_id
= token_role_id
= None
4672 engine
.get_autorization()
4682 {"Content-Type": "application/json"},
4688 "/admin/v1/projects",
4692 {"Content-Type": "application/json"},
4702 {"Content-Type": "application/json"},
4712 {"Content-Type": "application/json"},
4716 "Get admin project",
4718 "/admin/v1/projects?name=admin",
4722 {"Content-Type": "application/json"},
4725 admin_project_id
= res
.json()[0]["_id"] if res
else None
4727 "Get project admin role",
4729 "/admin/v1/roles?name=project_admin",
4733 {"Content-Type": "application/json"},
4736 project_admin_role_id
= res
.json()[0]["_id"] if res
else None
4738 "Get project user role",
4740 "/admin/v1/roles?name=project_user",
4744 {"Content-Type": "application/json"},
4747 project_user_role_id
= res
.json()[0]["_id"] if res
else None
4751 "Create test project",
4753 "/admin/v1/projects",
4757 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
4760 test_project_id
= engine
.last_id
if res
else None
4762 "Create role without permissions",
4768 {"Content-Type": "application/json"},
4771 empty_role_id
= engine
.last_id
if res
else None
4773 "Create role with default permissions",
4777 {"name": "default", "permissions": {"default": True}},
4779 {"Location": "/admin/v1/roles/", "Content-Type": "application/json"},
4782 default_role_id
= engine
.last_id
if res
else None
4784 "Create role with token permissions",
4790 "permissions": {"tokens": True},
4791 }, # is default required ?
4793 {"Location": "/admin/v1/roles/", "Content-Type": "application/json"},
4796 token_role_id
= engine
.last_id
if res
else None
4797 pr
= "project-role mappings"
4799 "Create user without " + pr
,
4803 {"username": "empty", "password": "empty"},
4805 {"Content-Type": "application/json"},
4808 empty_user_id
= engine
.last_id
if res
else None
4812 and project_admin_role_id
4813 and project_user_role_id
4815 data
= {"username": "test", "password": "test"}
4816 data
["project_role_mappings"] = [
4817 {"project": test_project_id
, "role": project_admin_role_id
},
4818 {"project": admin_project_id
, "role": project_user_role_id
},
4821 "Create user with " + pr
,
4827 {"Content-Type": "application/json"},
4830 test_user_id
= engine
.last_id
if res
else None
4835 "Modify test user's password",
4837 "/admin/v1/users/" + test_user_id
,
4839 {"password": "password"},
4846 and admin_project_id
4848 and project_admin_role_id
4849 and project_user_role_id
4852 "project_role_mappings": [
4853 {"project": test_project_id
, "role": project_admin_role_id
},
4854 {"project": admin_project_id
, "role": project_user_role_id
},
4858 "Modify empty user's " + pr
,
4860 "/admin/v1/users/" + empty_user_id
,
4871 "Delete empty user",
4873 "/admin/v1/users/" + empty_user_id
,
4884 "/admin/v1/users/" + test_user_id
,
4893 "Delete empty role",
4895 "/admin/v1/roles/" + empty_role_id
,
4904 "Delete default role",
4906 "/admin/v1/roles/" + default_role_id
,
4915 "Delete token role",
4917 "/admin/v1/roles/" + token_role_id
,
4926 "Delete test project",
4928 "/admin/v1/projects/" + test_project_id
,
4938 engine
.remove_authorization() # To finish
4941 class TestNbiQuotas
:
4942 description
= "Test NBI Quotas"
4945 def run(engine
, test_osm
, manual_check
, test_params
=None):
4946 engine
.set_test_name("NBI-Quotas_")
4947 # backend = test_params.get("backend") if test_params else None # UNUSED
4949 test_username
= "test-nbi-quotas"
4950 test_password
= "test-nbi-quotas"
4951 test_project
= "test-nbi-quotas"
4953 test_vim
= "test-nbi-quotas"
4954 test_wim
= "test-nbi-quotas"
4955 test_sdn
= "test-nbi-quotas"
4958 test_project_id
= None
4970 # Save admin access data
4971 admin_username
= engine
.user
4972 admin_password
= engine
.password
4973 admin_project
= engine
.project
4976 engine
.get_autorization()
4977 admin_token
= engine
.last_id
4979 # Check that test project,user do not exist
4981 "Check that test project doesn't exist",
4983 "/admin/v1/projects/" + test_project
,
4991 "Check that test user doesn't exist",
4993 "/admin/v1/users/" + test_username
,
5000 if None in [res1
, res2
]:
5001 engine
.remove_authorization()
5002 logger
.error("Test project and/or user already exist")
5005 # Create test project&user
5007 "Create test project",
5009 "/admin/v1/projects",
5012 "name": test_username
,
5029 test_project_id
= engine
.last_id
if res
else None
5036 "username": test_username
,
5037 "password": test_password
,
5038 "project_role_mappings": [
5039 {"project": test_project
, "role": "project_admin"}
5046 test_user_id
= engine
.last_id
if res
else None
5048 if test_project_id
and test_user_id
:
5052 engine
.user
= test_username
5053 engine
.password
= test_password
5054 engine
.project
= test_project
5055 engine
.get_autorization()
5056 user_token
= engine
.last_id
5062 "/admin/v1/vim_accounts",
5066 "vim_type": "openvim",
5067 "vim_user": test_username
,
5068 "vim_password": test_password
,
5069 "vim_tenant_name": test_project
,
5070 "vim_url": "https://0.0.0.0:0/v0.0",
5076 test_vim_ids
+= [engine
.last_id
if res
else None]
5079 "Try to create second test VIM",
5081 "/admin/v1/vim_accounts",
5084 "name": test_vim
+ "_2",
5085 "vim_type": "openvim",
5086 "vim_user": test_username
,
5087 "vim_password": test_password
,
5088 "vim_tenant_name": test_project
,
5089 "vim_url": "https://0.0.0.0:0/v0.0",
5095 test_vim_ids
+= [engine
.last_id
if res
is None else None]
5098 "Try to create second test VIM with FORCE",
5100 "/admin/v1/vim_accounts?FORCE",
5103 "name": test_vim
+ "_3",
5104 "vim_type": "openvim",
5105 "vim_user": test_username
,
5106 "vim_password": test_password
,
5107 "vim_tenant_name": test_project
,
5108 "vim_url": "https://0.0.0.0:0/v0.0",
5114 test_vim_ids
+= [engine
.last_id
if res
else None]
5118 # Download descriptor files (if required)
5119 test_dir
= "/tmp/" + test_username
+ "/"
5120 test_url
= "https://osm-download.etsi.org/ftp/osm-6.0-six/7th-hackfest/packages/"
5122 "slice_hackfest_vnfd.tar.gz",
5123 "slice_hackfest_middle_vnfd.tar.gz",
5126 "slice_hackfest_nsd.tar.gz",
5127 "slice_hackfest_middle_nsd.tar.gz",
5129 nst_filenames
= ["slice_hackfest_nstd.yaml"]
5130 pdu_filenames
= ["PDU_router.yaml"]
5132 vnfd_filenames
+ nsd_filenames
+ nst_filenames
+ pdu_filenames
5134 if not os
.path
.exists(test_dir
):
5135 os
.makedirs(test_dir
)
5136 for filename
in desc_filenames
:
5137 if not os
.path
.exists(test_dir
+ filename
):
5138 res
= requests
.get(test_url
+ filename
)
5139 if res
.status_code
< 300:
5140 with
open(test_dir
+ filename
, "wb") as file:
5141 file.write(res
.content
)
5143 if all([os
.path
.exists(test_dir
+ p
) for p
in desc_filenames
]):
5147 "Create test VNFD #1",
5149 "/vnfpkgm/v1/vnf_packages_content",
5151 "@b" + test_dir
+ vnfd_filenames
[0],
5156 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5158 "Create test VNFD #2",
5160 "/vnfpkgm/v1/vnf_packages_content",
5162 "@b" + test_dir
+ vnfd_filenames
[1],
5167 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5169 "Try to create extra test VNFD",
5171 "/vnfpkgm/v1/vnf_packages_content",
5173 "@b" + test_dir
+ vnfd_filenames
[0],
5178 test_vnfd_ids
+= [engine
.last_id
if res
is None else None]
5180 "Try to create extra test VNFD with FORCE",
5182 "/vnfpkgm/v1/vnf_packages_content?FORCE",
5184 "@b" + test_dir
+ vnfd_filenames
[0],
5189 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5191 # Remove extra VNFDs to prevent further errors
5193 if test_vnfd_ids
[i
]:
5195 "Delete test VNFD #" + str(i
),
5197 "/vnfpkgm/v1/vnf_packages_content/"
5207 test_vnfd_ids
[i
] = None
5209 if test_vnfd_ids
[0] and test_vnfd_ids
[1]:
5213 "Create test NSD #1",
5215 "/nsd/v1/ns_descriptors_content",
5217 "@b" + test_dir
+ nsd_filenames
[0],
5222 test_nsd_ids
+= [engine
.last_id
if res
else None]
5224 "Create test NSD #2",
5226 "/nsd/v1/ns_descriptors_content",
5228 "@b" + test_dir
+ nsd_filenames
[1],
5233 test_nsd_ids
+= [engine
.last_id
if res
else None]
5235 "Try to create extra test NSD",
5237 "/nsd/v1/ns_descriptors_content",
5239 "@b" + test_dir
+ nsd_filenames
[0],
5244 test_nsd_ids
+= [engine
.last_id
if res
is None else None]
5246 "Try to create extra test NSD with FORCE",
5248 "/nsd/v1/ns_descriptors_content?FORCE",
5250 "@b" + test_dir
+ nsd_filenames
[0],
5255 test_nsd_ids
+= [engine
.last_id
if res
else None]
5257 # Remove extra NSDs to prevent further errors
5261 "Delete test NSD #" + str(i
),
5263 "/nsd/v1/ns_descriptors_content/"
5273 test_nsd_ids
[i
] = None
5275 if test_nsd_ids
[0] and test_nsd_ids
[1]:
5279 "Create test NSR #1",
5281 "/nslcm/v1/ns_instances_content",
5284 "nsName": test_username
+ "_1",
5285 "nsdId": test_nsd_ids
[0],
5286 "vimAccountId": test_vim_ids
[0],
5292 test_nsr_ids
+= [engine
.last_id
if res
else None]
5294 "Create test NSR #2",
5296 "/nslcm/v1/ns_instances_content",
5299 "nsName": test_username
+ "_2",
5300 "nsdId": test_nsd_ids
[1],
5301 "vimAccountId": test_vim_ids
[0],
5307 test_nsr_ids
+= [engine
.last_id
if res
else None]
5309 "Try to create extra test NSR",
5311 "/nslcm/v1/ns_instances_content",
5314 "nsName": test_username
+ "_3",
5315 "nsdId": test_nsd_ids
[0],
5316 "vimAccountId": test_vim_ids
[0],
5322 test_nsr_ids
+= [engine
.last_id
if res
is None else None]
5324 "Try to create test NSR with FORCE",
5326 "/nslcm/v1/ns_instances_content?FORCE",
5329 "nsName": test_username
+ "_4",
5330 "nsdId": test_nsd_ids
[0],
5331 "vimAccountId": test_vim_ids
[0],
5337 test_nsr_ids
+= [engine
.last_id
if res
else None]
5343 "/nst/v1/netslice_templates_content",
5345 "@b" + test_dir
+ nst_filenames
[0],
5350 test_nst_ids
+= [engine
.last_id
if res
else None]
5352 "Try to create extra test NST",
5354 "/nst/v1/netslice_templates_content",
5356 "@b" + test_dir
+ nst_filenames
[0],
5361 test_nst_ids
+= [engine
.last_id
if res
is None else None]
5363 "Try to create extra test NST with FORCE",
5365 "/nst/v1/netslice_templates_content?FORCE",
5367 "@b" + test_dir
+ nst_filenames
[0],
5372 test_nst_ids
+= [engine
.last_id
if res
else None]
5377 {"Authorization": "Bearer {}".format(admin_token
)}
5382 "/admin/v1/projects/" + test_project_id
,
5384 {"quotas": {"nsrs": None}},
5390 {"Authorization": "Bearer {}".format(user_token
)}
5397 "/nsilcm/v1/netslice_instances_content",
5400 "nsiName": test_username
,
5401 "nstId": test_nst_ids
[0],
5402 "vimAccountId": test_vim_ids
[0],
5408 test_nsi_ids
+= [engine
.last_id
if res
else None]
5410 "Try to create extra test NSI",
5412 "/nsilcm/v1/netslice_instances_content",
5415 "nsiName": test_username
,
5416 "nstId": test_nst_ids
[0],
5417 "vimAccountId": test_vim_ids
[0],
5424 engine
.last_id
if res
is None else None
5427 "Try to create extra test NSI with FORCE",
5429 "/nsilcm/v1/netslice_instances_content?FORCE",
5432 "nsiName": test_username
,
5433 "nstId": test_nst_ids
[0],
5434 "vimAccountId": test_vim_ids
[0],
5440 test_nsi_ids
+= [engine
.last_id
if res
else None]
5443 with
open(test_dir
+ pdu_filenames
[0], "rb") as file:
5445 r
"ip-address: *\[[^\]]*\]",
5446 "ip-address: '0.0.0.0'",
5447 file.read().decode("utf-8"),
5449 with
open(test_dir
+ pdu_filenames
[0], "wb") as file:
5450 file.write(pdu_text
.encode("utf-8"))
5454 "/pdu/v1/pdu_descriptors",
5456 "@b" + test_dir
+ pdu_filenames
[0],
5461 test_pdu_ids
+= [engine
.last_id
if res
else None]
5463 "Try to create extra test PDU",
5465 "/pdu/v1/pdu_descriptors",
5467 "@b" + test_dir
+ pdu_filenames
[0],
5472 test_pdu_ids
+= [engine
.last_id
if res
is None else None]
5474 "Try to create extra test PDU with FORCE",
5476 "/pdu/v1/pdu_descriptors?FORCE",
5478 "@b" + test_dir
+ pdu_filenames
[0],
5483 test_pdu_ids
+= [engine
.last_id
if res
else None]
5486 for i
, id in enumerate(test_nsi_ids
):
5489 "Delete test NSI #" + str(i
),
5491 "/nsilcm/v1/netslice_instances_content/"
5500 for i
, id in enumerate(test_nsr_ids
):
5503 "Delete test NSR #" + str(i
),
5505 "/nslcm/v1/ns_instances_content/" + id + "?FORCE",
5512 for i
, id in enumerate(test_nst_ids
):
5515 "Delete test NST #" + str(i
),
5517 "/nst/v1/netslice_templates_content/" + id + "?FORCE",
5524 for i
, id in enumerate(test_nsd_ids
):
5527 "Delete test NSD #" + str(i
),
5529 "/nsd/v1/ns_descriptors_content/" + id + "?FORCE",
5536 for i
, id in enumerate(test_vnfd_ids
):
5539 "Delete test VNFD #" + str(i
),
5541 "/vnfpkgm/v1/vnf_packages_content/" + id + "?FORCE",
5548 for i
, id in enumerate(test_pdu_ids
):
5551 "Delete test PDU #" + str(i
),
5553 "/pdu/v1/pdu_descriptors/" + id + "?FORCE",
5561 # END Test NBI Quotas
5567 "/admin/v1/wim_accounts",
5572 "wim_url": "https://0.0.0.0:0/v0.0",
5578 test_wim_ids
+= [engine
.last_id
if res
else None]
5580 "Try to create second test WIM",
5582 "/admin/v1/wim_accounts",
5585 "name": test_wim
+ "_2",
5587 "wim_url": "https://0.0.0.0:0/v0.0",
5593 test_wim_ids
+= [engine
.last_id
if res
is None else None]
5595 "Try to create second test WIM with FORCE",
5597 "/admin/v1/wim_accounts?FORCE",
5600 "name": test_wim
+ "_3",
5602 "wim_url": "https://0.0.0.0:0/v0.0",
5608 test_wim_ids
+= [engine
.last_id
if res
else None]
5621 "dpid": "00:00:00:00:00:00:00:00",
5627 test_sdn_ids
+= [engine
.last_id
if res
else None]
5629 "Try to create second test SDN",
5634 "name": test_sdn
+ "_2",
5638 "dpid": "00:00:00:00:00:00:00:00",
5644 test_sdn_ids
+= [engine
.last_id
if res
is None else None]
5646 "Try to create second test SDN with FORCE",
5648 "/admin/v1/sdns?FORCE",
5651 "name": test_sdn
+ "_3",
5655 "dpid": "00:00:00:00:00:00:00:00",
5661 test_sdn_ids
+= [engine
.last_id
if res
else None]
5664 for i
, id in enumerate(test_vim_ids
):
5667 "Delete test VIM #" + str(i
),
5669 "/admin/v1/vim_accounts/" + id + "?FORCE",
5676 for i
, id in enumerate(test_wim_ids
):
5679 "Delete test WIM #" + str(i
),
5681 "/admin/v1/wim_accounts/" + id + "?FORCE",
5688 for i
, id in enumerate(test_sdn_ids
):
5691 "Delete test SDN #" + str(i
),
5693 "/admin/v1/sdns/" + id + "?FORCE",
5701 # Release user access
5702 engine
.remove_authorization()
5705 engine
.user
= admin_username
5706 engine
.password
= admin_password
5707 engine
.project
= admin_project
5708 engine
.get_autorization()
5713 "/admin/v1/users/" + test_user_id
+ "?FORCE",
5722 "Delete test project",
5724 "/admin/v1/projects/" + test_project_id
+ "?FORCE",
5731 engine
.remove_authorization()
5733 # END class TestNbiQuotas
5736 if __name__
== "__main__":
5740 # Disable warnings from self-signed certificates.
5741 requests
.packages
.urllib3
.disable_warnings()
5743 logging
.basicConfig(format
="%(levelname)s %(message)s", level
=logging
.ERROR
)
5744 logger
= logging
.getLogger("NBI")
5745 # load parameters and configuration
5746 opts
, args
= getopt
.getopt(
5761 "timeout-configure",
5770 url
= "https://localhost:9999/osm"
5771 user
= password
= project
= "admin"
5773 manual_check
= False
5778 "NonAuthorized": TestNonAuthorized
,
5779 "FakeVIM": TestFakeVim
,
5780 "Users-Projects": TestUsersProjects
,
5781 "Projects-Descriptors": TestProjectsDescriptors
,
5782 "VIM-SDN": TestVIMSDN
,
5783 "Deploy-Custom": TestDeploy
,
5784 "Deploy-Hackfest-Cirros": TestDeployHackfestCirros
,
5785 "Deploy-Hackfest-Cirros-Scaling": TestDeployHackfestCirrosScaling
,
5786 "Deploy-Hackfest-3Charmed": TestDeployHackfest3Charmed
,
5787 "Deploy-Hackfest-3Charmed2": TestDeployHackfest3Charmed2
,
5788 "Deploy-Hackfest-3Charmed3": TestDeployHackfest3Charmed3
,
5789 "Deploy-Hackfest-4": TestDeployHackfest4
,
5790 "Deploy-CirrosMacIp": TestDeployIpMac
,
5791 "Descriptors": TestDescriptors
,
5792 "Deploy-Hackfest1": TestDeployHackfest1
,
5793 # "Deploy-MultiVIM": TestDeployMultiVIM,
5794 "Deploy-SingleVdu": TestDeploySingleVdu
,
5795 "Deploy-Hnfd": TestDeployHnfd
,
5796 "Upload-Slice-Template": TestNetSliceTemplates
,
5797 "Deploy-Slice-Instance": TestNetSliceInstances
,
5798 "Deploy-SimpleCharm": TestDeploySimpleCharm
,
5799 "Deploy-SimpleCharm2": TestDeploySimpleCharm2
,
5800 "Authentication": TestAuthentication
,
5801 "NBI-Quotas": TestNbiQuotas
,
5807 # print("parameter:", o, a)
5808 if o
== "--version":
5809 print("test version " + __version__
+ " " + version_date
)
5812 for test
, test_class
in sorted(test_classes
.items()):
5813 print("{:32} {}".format(test
+ ":", test_class
.description
))
5815 elif o
in ("-v", "--verbose"):
5817 elif o
== "no-verbose":
5819 elif o
in ("-h", "--help"):
5822 elif o
== "--test-osm":
5824 elif o
== "--manual-check":
5828 elif o
in ("-u", "--user"):
5830 elif o
in ("-p", "--password"):
5832 elif o
== "--project":
5834 elif o
== "--fail-fast":
5837 for _test
in a
.split(","):
5838 if _test
not in test_classes
:
5840 "Invalid test name '{}'. Use option '--list' to show available tests".format(
5846 test_to_do
.append(_test
)
5847 elif o
== "--params":
5848 param_key
, _
, param_value
= a
.partition("=")
5849 text_index
= len(test_to_do
)
5850 if text_index
not in test_params
:
5851 test_params
[text_index
] = {}
5852 test_params
[text_index
][param_key
] = param_value
5853 elif o
== "--insecure":
5855 elif o
== "--timeout":
5857 elif o
== "--timeout-deploy":
5858 timeout_deploy
= int(a
)
5859 elif o
== "--timeout-configure":
5860 timeout_configure
= int(a
)
5862 assert False, "Unhandled option"
5864 logger
.setLevel(logging
.WARNING
)
5866 logger
.setLevel(logging
.DEBUG
)
5868 logger
.setLevel(logging
.ERROR
)
5870 test_rest
= TestRest(url
, user
=user
, password
=password
, project
=project
)
5871 # print("tests to do:", test_to_do)
5874 for test
in test_to_do
:
5875 if fail_fast
and test_rest
.failed_tests
:
5878 test_class
= test_classes
[test
]
5880 test_rest
, test_osm
, manual_check
, test_params
.get(text_index
)
5883 for test
, test_class
in sorted(test_classes
.items()):
5884 if fail_fast
and test_rest
.failed_tests
:
5886 test_class().run(test_rest
, test_osm
, manual_check
, test_params
.get(0))
5887 test_rest
.print_results()
5888 exit(1 if test_rest
.failed_tests
else 0)
5890 except TestException
as e
:
5891 logger
.error(test
+ "Test {} Exception: {}".format(test
, str(e
)))
5893 except getopt
.GetoptError
as e
:
5895 print(e
, file=sys
.stderr
)
5897 except Exception as e
:
5898 logger
.critical(test
+ " Exception: " + str(e
), exc_info
=True)