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: '{}', "
485 "vim_user: {}, vim_password: {}"
488 os
.environ
.get("OSMNBITEST_VIM_TYPE", "openstack"),
489 os
.environ
.get("OSMNBITEST_VIM_URL"),
490 os
.environ
.get("OSMNBITEST_VIM_TENANT"),
491 os
.environ
.get("OSMNBITEST_VIM_USER"),
492 os
.environ
.get("OSMNBITEST_VIM_PASSWORD"),
494 if os
.environ
.get("OSMNBITEST_VIM_CONFIG"):
495 vim_data
+= " ,config: {}".format(
496 os
.environ
.get("OSMNBITEST_VIM_CONFIG")
501 "{schema_version: '1.0', name: fakeVim, vim_type: openstack, vim_url: 'http://10.11.12.13/fake'"
502 ", vim_tenant_name: 'vimtenant', vim_user: vimuser, vim_password: vimpassword}"
507 "/admin/v1/vim_accounts",
511 {"Location": "/admin/v1/vim_accounts/", "Content-Type": "application/yaml"},
516 def print_results(self
):
517 print("\n\n\n--------------------------------------------")
519 "TEST RESULTS: Total: {}, Passed: {}, Failed: {}".format(
520 self
.passed_tests
+ self
.failed_tests
,
525 print("--------------------------------------------")
527 def wait_until_delete(self
, url_op
, timeout_delete
):
529 Make a pooling until topic is not present, because of deleted
531 :param timeout_delete:
534 description
= "Wait to topic being deleted"
535 test_description
= "Test {}{} {} {} {}".format(
536 self
.test_name
, self
.step
, description
, "GET", url_op
538 logger
.warning(test_description
)
541 wait
= timeout_delete
557 if r
.status_code
== 404:
558 self
.passed_tests
+= 1
560 elif r
.status_code
== 200:
565 "Topic is not deleted after {} seconds".format(timeout_delete
)
567 self
.failed_tests
+= 1
569 def wait_operation_ready(self
, ns_nsi
, opp_id
, timeout
, expected_fail
=False):
571 Wait until nslcmop or nsilcmop finished
572 :param ns_nsi: "ns" o "nsi"
573 :param opp_id: Id o fthe operation
575 :param expected_fail:
576 :return: None. Updates passed/failed_tests
579 url_op
= "/nslcm/v1/ns_lcm_op_occs/{}".format(opp_id
)
581 url_op
= "/nsilcm/v1/nsi_lcm_op_occs/{}".format(opp_id
)
582 description
= "Wait to {} lcm operation complete".format(ns_nsi
)
583 test_description
= "Test {}{} {} {} {}".format(
584 self
.test_name
, self
.step
, description
, "GET", url_op
586 logger
.warning(test_description
)
604 if "COMPLETED" in nslcmop
["operationState"]:
607 "NS terminate has success, expecting failing: {}".format(
608 nslcmop
["detailed-status"]
611 self
.failed_tests
+= 1
613 self
.passed_tests
+= 1
615 elif "FAILED" in nslcmop
["operationState"]:
616 if not expected_fail
:
618 "NS terminate has failed: {}".format(nslcmop
["detailed-status"])
620 self
.failed_tests
+= 1
622 self
.passed_tests
+= 1
625 print(".", end
="", file=stderr
)
629 self
.failed_tests
+= 1
631 "NS instantiate is not terminate after {} seconds".format(timeout
)
634 print("", file=stderr
)
637 class TestNonAuthorized
:
638 description
= "Test invalid URLs. methods and no authorization"
641 def run(engine
, test_osm
, manual_check
, test_params
=None):
642 engine
.set_test_name("NonAuth")
643 engine
.remove_authorization()
644 test_not_authorized_list
= (
658 "/admin/v1/nonexist",
676 for t
in test_not_authorized_list
:
680 class TestUsersProjects
:
681 description
= "test project and user creation"
684 def run(engine
, test_osm
, manual_check
, test_params
=None):
685 engine
.set_test_name("UserProject")
686 # backend = test_params.get("backend") if test_params else None # UNUSED
691 u1
= u2
= u3
= u4
= None
693 engine
.get_autorization()
696 "Create project non admin 1",
698 "/admin/v1/projects",
702 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
705 p1
= engine
.last_id
if res
else None
708 "Create project admin",
710 "/admin/v1/projects",
712 {"name": "Padmin", "admin": True},
714 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
717 padmin
= engine
.last_id
if res
else None
720 "Create project bad format",
722 "/admin/v1/projects",
729 pbad
= engine
.last_id
if res
else None
732 "Get project admin role",
734 "/admin/v1/roles?name=project_admin",
738 {"Content-Type": "application/json"},
741 rpa
= res
.json()[0]["_id"] if res
else None
743 "Get project user role",
745 "/admin/v1/roles?name=project_user",
749 {"Content-Type": "application/json"},
752 rpu
= res
.json()[0]["_id"] if res
else None
754 "Get system admin role",
756 "/admin/v1/roles?name=system_admin",
760 {"Content-Type": "application/json"},
763 rsa
= res
.json()[0]["_id"] if res
else None
765 data
= {"username": "U1", "password": "pw1"}
767 data
["project_role_mappings"] = [
768 {"project": p1
, "role": rpa
},
769 {"project": p2
, "role": rpa
},
770 {"project": padmin
, "role": rpu
},
773 xhd
= {"Location": "/admin/v1/users/", "Content-Type": "application/json"}
775 "Create user with bad project and force",
777 "/admin/v1/users?FORCE=True",
787 # User is created sometimes even though an exception is raised
791 "/admin/v1/users?username=U1",
795 {"Content-Type": "application/json"},
798 u1
= res
.json()[0]["_id"] if res
else None
800 data
= {"username": "U2", "password": "pw2"}
801 data
["project_role_mappings"] = [
802 {"project": p1
, "role": rpa
},
803 {"project": padmin
, "role": rsa
},
812 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
815 u2
= engine
.last_id
if res
else None
818 ftt
= "project_role_mappings"
819 xpr
= [{"project": p1
, "role": rpa
}, {"project": padmin
, "role": rpu
}]
822 "Edit user U1, delete P2 project",
824 "/admin/v1/users/" + u1
,
832 "Check user U1, contains the right projects",
834 "/admin/v1/users/" + u1
,
843 xpr
[0]["project_name"] = "P1"
844 xpr
[0]["role_name"] = "project_admin"
845 xpr
[1]["project_name"] = "Padmin"
846 xpr
[1]["role_name"] = "project_user"
852 if pr
not in rj
[ftt
]:
856 "User {} '{}' are different than expected '{}'. Edition was not done properly".format(
860 engine
.failed_tests
+= 1
862 p2
= None # To prevent deletion attempts
864 # Add a test of 'default project' for Keystone?
868 "Edit user U2, change password",
870 "/admin/v1/users/" + u2
,
872 {"password": "pw2_new"},
880 "Change to project P1 non existing",
892 "Change to user U2 project P1",
896 {"username": "U2", "password": "pw2_new", "project_id": "P1"},
903 engine
.set_header({"Authorization": "Bearer {}".format(rj
["id"])})
906 "Edit user projects non admin",
908 "/admin/v1/users/U1",
910 {"remove_project_role_mappings": [{"project": "P1", "role": None}]},
917 "Add new project non admin",
919 "/admin/v1/projects",
926 if res
is None or res
.status_code
== 201:
927 # The project has been created even though it shouldn't
931 "/admin/v1/projects/P2",
938 p2
= res
.json()["_id"] if res
else None
941 data
= {"username": "U3", "password": "pw3"}
942 data
["project_role_mappings"] = [{"project": p1
, "role": rpu
}]
944 "Add new user non admin",
953 if res
is None or res
.status_code
== 201:
954 # The user has been created even though it shouldn't
958 "/admin/v1/users/U3",
965 u3
= res
.json()["_id"] if res
else None
971 "Change to user U2 project Padmin",
976 "project_id": "Padmin"
977 }, # Caused a Keystone authentication error
978 # {"username": "U2", "password": "pw2_new", "project_id": "Padmin"},
986 {"Authorization": "Bearer {}".format(rj
["id"])}
990 "Add new project admin",
992 "/admin/v1/projects",
997 "Location": "/admin/v1/projects/",
998 "Content-Type": "application/json",
1002 p3
= engine
.last_id
if res
else None
1005 data
= {"username": "U4", "password": "pw4"}
1006 data
["project_role_mappings"] = [
1007 {"project": p1
, "role": rpa
}
1010 "Add new user admin",
1017 "Location": "/admin/v1/users/",
1018 "Content-Type": "application/json",
1022 u4
= engine
.last_id
if res
else None
1028 "project_role_mappings": [{"project": p3
, "role": rpa
}]
1031 "Edit user projects admin",
1033 "/admin/v1/users/U4",
1040 # Project is deleted even though it shouldn't - PROVISIONAL?
1042 "Delete project P3 conflict",
1044 "/admin/v1/projects/" + p3
,
1051 if res
and res
.status_code
in (200, 204):
1055 "Delete project P3 forcing",
1057 "/admin/v1/projects/" + p3
+ "?FORCE=True",
1064 if res
and res
.status_code
in (200, 204):
1069 "Delete user U2. Conflict deleting own user",
1071 "/admin/v1/users/" + u2
,
1078 if res
is None or res
.status_code
in (200, 204):
1084 "/admin/v1/users/" + u4
,
1091 if res
and res
.status_code
in (200, 204):
1095 "Delete project P3",
1097 "/admin/v1/projects/" + p3
,
1104 if res
and res
.status_code
in (200, 204):
1111 "/admin/v1/users/" + u3
,
1122 engine
.remove_authorization() # To force get authorization
1123 engine
.get_autorization()
1128 "/admin/v1/users/" + u1
,
1139 "/admin/v1/users/" + u2
,
1150 "/admin/v1/users/" + u3
,
1161 "/admin/v1/users/" + u4
,
1170 "Delete project P1",
1172 "/admin/v1/projects/" + p1
,
1181 "Delete project P2",
1183 "/admin/v1/projects/" + p2
,
1192 "Delete project P3",
1194 "/admin/v1/projects/" + p3
,
1203 "Delete project Padmin",
1205 "/admin/v1/projects/" + padmin
,
1214 "Delete bad project",
1216 "/admin/v1/projects/" + pbad
,
1224 # BEGIN New Tests - Addressing Projects/Users by Name/ID
1228 "Create new project P1",
1230 "/admin/v1/projects",
1234 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1238 pid1
= res
.json()["id"]
1239 # print("# pid =", pid1)
1241 "Create new project P2",
1243 "/admin/v1/projects",
1247 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1251 pid2
= res
.json()["id"]
1252 # print("# pid =", pid2)
1253 data
= {"username": "U1", "password": "pw1"}
1254 data
["project_role_mappings"] = [{"project": pid1
, "role": rpu
}]
1256 "Create new user U1",
1262 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1266 uid1
= res
.json()["id"]
1267 # print("# uid =", uid1)
1268 data
= {"username": "U2", "password": "pw2"}
1269 data
["project_role_mappings"] = [{"project": pid2
, "role": rpu
}]
1271 "Create new user U2",
1277 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1281 uid2
= res
.json()["id"]
1282 # print("# uid =", uid2)
1285 "Get Project P1 by Name",
1287 "/admin/v1/projects/P1",
1295 "Get Project P1 by ID",
1297 "/admin/v1/projects/" + pid1
,
1306 "Get User U1 by Name",
1308 "/admin/v1/users/U1",
1316 "Get User U1 by ID",
1318 "/admin/v1/users/" + uid1
,
1327 "Rename Project P1 by Name",
1329 "/admin/v1/projects/P1",
1338 "Get Project P1 by new Name",
1340 "/admin/v1/projects/P3",
1349 "Rename Project P2 by ID",
1351 "/admin/v1/projects/" + pid2
,
1360 "Get Project P2 by new Name",
1362 "/admin/v1/projects/P4",
1372 "Rename User U1 by Name",
1374 "/admin/v1/users/U1",
1383 "Get User U1 by new Name",
1385 "/admin/v1/users/U3",
1395 "Rename User U2 by ID",
1397 "/admin/v1/users/" + uid2
,
1406 "Get User U2 by new Name",
1408 "/admin/v1/users/U4",
1417 "Delete User U1 by Name",
1419 "/admin/v1/users/U3",
1431 "Delete User U2 by ID",
1433 "/admin/v1/users/" + uid2
,
1445 "Delete Project P1 by Name",
1447 "/admin/v1/projects/P3",
1459 "Delete Project P2 by ID",
1461 "/admin/v1/projects/" + pid2
,
1471 # END New Tests - Addressing Projects/Users by Name
1476 "Delete Project P1",
1478 "/admin/v1/projects/" + pid1
,
1487 "Delete Project P2",
1489 "/admin/v1/projects/" + pid2
,
1500 "/admin/v1/users/" + uid1
,
1511 "/admin/v1/users/" + uid2
,
1519 engine
.remove_authorization() # To finish
1522 class TestProjectsDescriptors
:
1523 description
= "test descriptors visibility among projects"
1526 def run(engine
, test_osm
, manual_check
, test_params
=None):
1528 engine
.set_test_name("ProjectDescriptors")
1529 engine
.get_autorization()
1531 project_admin_id
= None
1533 "Get my project Padmin",
1535 "/admin/v1/projects/{}".format(engine
.project
),
1543 response
= res
.json()
1544 project_admin_id
= response
["_id"]
1546 "Create project Padmin",
1548 "/admin/v1/projects",
1550 {"name": "Padmin", "admin": True},
1552 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1556 "Create project P2",
1558 "/admin/v1/projects",
1562 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1566 "Create project P3",
1568 "/admin/v1/projects",
1572 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
1584 "project_role_mappings": [
1585 {"project": "Padmin", "role": "system_admin"},
1586 {"project": "P2", "role": "project_admin"},
1587 {"project": "P3", "role": "project_admin"},
1591 {"Location": "/admin/v1/users/", "Content-Type": "application/json"},
1598 "/vnfpkgm/v1/vnf_packages_content?id=id1",
1600 TestDescriptors
.vnfd_empty
,
1602 r_headers_yaml_location_vnfd
,
1605 vnfd_ids
.append(engine
.last_id
)
1607 "Onboard VNFD id2 PUBLIC",
1609 "/vnfpkgm/v1/vnf_packages_content?id=id2&PUBLIC=TRUE",
1611 TestDescriptors
.vnfd_empty
,
1613 r_headers_yaml_location_vnfd
,
1616 vnfd_ids
.append(engine
.last_id
)
1620 "/vnfpkgm/v1/vnf_packages_content?id=id3&PUBLIC=FALSE",
1622 TestDescriptors
.vnfd_empty
,
1624 r_headers_yaml_location_vnfd
,
1627 vnfd_ids
.append(engine
.last_id
)
1630 "Get VNFD descriptors",
1632 "/vnfpkgm/v1/vnf_packages?id=id1,id2,id3",
1639 response
= res
.json()
1640 if len(response
) != 3:
1642 "Only 3 vnfds should be present for project admin. {} listed".format(
1646 engine
.failed_tests
+= 1
1648 # Change to other project Padmin
1650 "Change to user U1 project Padmin",
1654 {"username": "U1", "password": "pw1", "project_id": "Padmin"},
1660 response
= res
.json()
1661 engine
.set_header({"Authorization": "Bearer {}".format(response
["id"])})
1665 "List VNFD descriptors for Padmin",
1667 "/vnfpkgm/v1/vnf_packages",
1674 response
= res
.json()
1675 if len(response
) != 0:
1677 "Only 0 vnfds should be present for project Padmin. {} listed".format(
1681 engine
.failed_tests
+= 1
1685 "List VNFD public descriptors",
1687 "/vnfpkgm/v1/vnf_packages?PUBLIC=True",
1694 response
= res
.json()
1695 if len(response
) != 1:
1697 "Only 1 vnfds should be present for project Padmin. {} listed".format(
1701 engine
.failed_tests
+= 1
1703 # list vnfds belonging to project "admin"
1705 "List VNFD of admin project",
1707 "/vnfpkgm/v1/vnf_packages?ADMIN={}".format(project_admin_id
),
1715 response
= res
.json()
1716 if len(response
) != 3:
1718 "Only 3 vnfds should be present for project Padmin. {} listed".format(
1722 engine
.failed_tests
+= 1
1726 "Get VNFD public descriptors",
1728 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1735 # Edit not owned vnfd
1739 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[0]),
1749 "Add VNFD id2 to my catalog",
1751 "/vnfpkgm/v1/vnf_packages/{}?SET_PROJECT".format(vnfd_ids
[1]),
1763 "/vnfpkgm/v1/vnf_packages_content?id=id4",
1765 TestDescriptors
.vnfd_empty
,
1767 r_headers_yaml_location_vnfd
,
1770 vnfd_ids
.append(engine
.last_id
)
1774 "List VNFD public descriptors",
1776 "/vnfpkgm/v1/vnf_packages",
1783 response
= res
.json()
1784 if len(response
) != 2:
1786 "Only 2 vnfds should be present for project Padmin. {} listed".format(
1790 engine
.failed_tests
+= 1
1794 "VNFDs have been omboarded. Perform manual check and press enter to resume"
1800 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1808 # change to admin project
1809 engine
.remove_authorization() # To force get authorization
1810 engine
.get_autorization()
1814 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[0]),
1824 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[1]),
1834 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[2]),
1844 "/vnfpkgm/v1/vnf_packages/{}".format(vnfd_ids
[3]),
1854 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[3]),
1863 "Get VNFD deleted id1",
1865 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[0]),
1873 "Get VNFD deleted id2",
1875 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[1]),
1883 "Get VNFD deleted id3",
1885 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[2]),
1893 "Get VNFD deleted id4",
1895 "/vnfpkgm/v1/vnf_packages/{}?ADMIN".format(vnfd_ids
[3]),
1906 "/admin/v1/users/U1",
1914 "Delete project Padmin",
1916 "/admin/v1/projects/Padmin",
1924 "Delete project P2",
1926 "/admin/v1/projects/P2",
1934 "Delete project P3",
1936 "/admin/v1/projects/P3",
1946 description
= "Creates/edit/delete fake VIMs and SDN controllers"
1950 "schema_version": "1.0",
1951 "schema_type": "No idea",
1953 "description": "Descriptor name",
1954 "vim_type": "openstack",
1955 "vim_url": "http://localhost:/vim",
1956 "vim_tenant_name": "vimTenant",
1958 "vim_password": "password",
1959 "config": {"config_param": 1},
1963 "description": "sdn-description",
1964 "dpid": "50:50:52:54:00:94:21:21",
1965 "ip": "192.168.15.17",
1967 "type": "opendaylight",
1970 "password": "passwd",
1972 self
.port_mapping
= [
1974 "compute_node": "compute node 1",
1977 "pci": "0000:81:00.0",
1978 "switch_port": "port-2/1",
1979 "switch_mac": "52:54:00:94:21:21",
1982 "pci": "0000:81:00.1",
1983 "switch_port": "port-2/2",
1984 "switch_mac": "52:54:00:94:21:22",
1989 "compute_node": "compute node 2",
1992 "pci": "0000:81:00.0",
1993 "switch_port": "port-2/3",
1994 "switch_mac": "52:54:00:94:21:23",
1997 "pci": "0000:81:00.1",
1998 "switch_port": "port-2/4",
1999 "switch_mac": "52:54:00:94:21:24",
2005 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
2627 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2638 vnfr_list
= ns_data
["constituent-vnfr-ref"]
2640 _commands
= commands
if commands
is not None else self
.commands
2641 _users
= users
if users
is not None else self
.users
2642 _passwds
= passwds
if passwds
is not None else self
.passwords
2643 _keys
= keys
if keys
is not None else self
.keys
2644 _timeout
= timeout
if timeout
!= 0 else self
.timeout
2646 # vnfr_list=[d8272263-6bd3-4680-84ca-6a4be23b3f2d, 88b22e2f-994a-4b61-94fd-4a3c90de3dc4]
2647 for vnfr_id
in vnfr_list
:
2649 "Get VNFR to get IP_ADDRESS",
2651 "/nslcm/v1/vnfrs/{}".format(vnfr_id
),
2660 vnfr_data
= r
.json()
2662 vnf_index
= str(vnfr_data
["member-vnf-index-ref"])
2664 ip_address
= self
.get_vnfr_ip(engine
, vnf_index
)
2665 description
= "Exec command='{}' at VNFR={} IP={}".format(
2666 _commands
.get(vnf_index
)[0], vnf_index
, ip_address
2669 test_description
= "{}{} {}".format(
2670 engine
.test_name
, engine
.step
, description
2672 logger
.warning(test_description
)
2673 while _timeout
>= time
:
2674 result
, message
= self
.do_checks(
2676 vnf_index
=vnfr_data
["member-vnf-index-ref"],
2677 commands
=_commands
.get(vnf_index
),
2678 user
=_users
.get(vnf_index
),
2679 passwd
=_passwds
.get(vnf_index
),
2680 key
=_keys
.get(vnf_index
),
2683 engine
.passed_tests
+= 1
2684 logger
.debug(message
)
2690 engine
.failed_tests
+= 1
2691 logger
.error(message
)
2695 engine
.failed_tests
+= 1
2696 logger
.error(message
)
2698 engine
.failed_tests
+= 1
2700 "VNFR {} has not mgmt address. Check failed".format(vnf_index
)
2703 def do_checks(self
, ip
, vnf_index
, commands
=[], user
=None, passwd
=None, key
=None):
2706 from pssh
.clients
import ParallelSSHClient
2707 from pssh
.utils
import load_private_key
2708 from ssh2
import exceptions
as ssh2Exception
2709 except ImportError as e
:
2711 "Package <pssh> or/and <urllib3> is not installed. Please add them with 'pip3 install "
2712 "parallel-ssh urllib3': {}".format(e
)
2714 return -1, "install needed packages 'pip3 install parallel-ssh urllib3'"
2715 urllib3
.disable_warnings(urllib3
.exceptions
.InsecureRequestWarning
)
2717 p_host
= os
.environ
.get("PROXY_HOST")
2718 p_user
= os
.environ
.get("PROXY_USER")
2719 p_password
= os
.environ
.get("PROXY_PASSWD")
2722 pkey
= load_private_key(key
)
2726 client
= ParallelSSHClient(
2733 proxy_password
=p_password
,
2737 for cmd
in commands
:
2738 output
= client
.run_command(cmd
)
2740 if output
[ip
[0]].exit_code
:
2741 return -1, "VNFR {} command '{}' returns error: '{}'".format(
2742 ip
[0], cmd
, "\n".join(output
[ip
[0]].stderr
)
2745 return 1, "VNFR {} command '{}' successful".format(ip
[0], cmd
)
2747 ssh2Exception
.ChannelFailure
,
2748 ssh2Exception
.SocketDisconnectError
,
2749 ssh2Exception
.SocketTimeout
,
2750 ssh2Exception
.SocketRecvError
,
2752 return 0, "Timeout accessing the VNFR {}: {}".format(ip
[0], str(e
))
2753 except Exception as e
:
2754 return -1, "ERROR checking the VNFR {}: {}".format(ip
[0], str(e
))
2756 def additional_operations(self
, engine
, test_osm
, manual_check
):
2759 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
2760 engine
.set_test_name(self
.test_name
)
2761 engine
.get_autorization()
2762 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
2764 if "vnfd-files" in test_params
:
2765 self
.vnfd_filenames
= test_params
["vnfd-files"].split(",")
2766 if "nsd-file" in test_params
:
2767 self
.nsd_filename
= test_params
["nsd-file"]
2768 if test_params
.get("ns-name"):
2769 nsname
= test_params
["ns-name"]
2770 self
.create_descriptors(engine
)
2772 # create real VIM if not exist
2773 self
.vim_id
= engine
.get_create_vim(test_osm
)
2775 "nsDescription": "default description",
2777 "nsdId": self
.nsd_id
,
2778 "vimAccountId": self
.vim_id
,
2781 ns_data
.update(self
.ns_params
)
2782 if test_params
and test_params
.get("ns-config"):
2783 if isinstance(test_params
["ns-config"], str):
2784 ns_data
.update(yaml
.load(test_params
["ns-config"]), Loader
=yaml
.Loader
)
2786 ns_data
.update(test_params
["ns-config"])
2787 self
.instantiate(engine
, ns_data
)
2791 "NS has been deployed. Perform manual check and press enter to resume"
2793 if test_osm
and self
.commands
:
2794 self
.test_ns(engine
, test_osm
)
2795 self
.additional_operations(engine
, test_osm
, manual_check
)
2796 self
.terminate(engine
)
2797 self
.delete_descriptors(engine
)
2799 def get_first_ip(self
, ip_string
):
2800 # When using a floating IP, the vnfr_data['ip-address'] contains a semicolon-separated list of IP:s.
2801 first_ip
= ip_string
.split(";")[0] if ip_string
else ""
2804 def get_vnfr_ip(self
, engine
, vnfr_index_wanted
):
2805 # If the IP address list has been obtained before, it has been stored in 'vnfr_ip_list'
2806 ip
= self
.vnfr_ip_list
.get(vnfr_index_wanted
, "")
2808 return self
.get_first_ip(ip
)
2810 "Get VNFR to get IP_ADDRESS",
2812 "/nslcm/v1/vnfrs?member-vnf-index-ref={}&nsr-id-ref={}".format(
2813 vnfr_index_wanted
, self
.ns_id
2823 vnfr_data
= r
.json()
2824 if not (vnfr_data
and vnfr_data
[0]):
2826 # Store the IP (or list of IPs) in 'vnfr_ip_list'
2827 ip_list
= vnfr_data
[0].get("ip-address", "")
2829 self
.vnfr_ip_list
[vnfr_index_wanted
] = ip_list
2830 ip
= self
.get_first_ip(ip_list
)
2834 class TestDeployHackfestCirros(TestDeploy
):
2835 description
= "Load and deploy Hackfest cirros_2vnf_ns example"
2839 self
.test_name
= "CIRROS"
2840 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
2841 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
2850 self
.users
= {"1": "cirros", "2": "cirros"}
2851 self
.passwords
= {"1": "cubswin:)", "2": "cubswin:)"}
2853 def terminate(self
, engine
):
2854 # Make a delete in one step, overriding the normal two step of TestDeploy that launched terminate and delete
2857 "Terminate and delete NS in one step",
2859 "/nslcm/v1/ns_instances_content/{}".format(self
.ns_id
),
2867 engine
.wait_until_delete(
2868 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
), timeout_deploy
2872 "Delete NS with FORCE",
2874 "/nslcm/v1/ns_instances/{}?FORCE=True".format(self
.ns_id
),
2882 # check all it is deleted
2884 "Check NS is deleted",
2886 "/nslcm/v1/ns_instances/{}".format(self
.ns_id
),
2894 "Check NSLCMOPs are deleted",
2896 "/nslcm/v1/ns_lcm_op_occs?nsInstanceId={}".format(self
.ns_id
),
2906 if not isinstance(nslcmops
, list) or nslcmops
:
2907 raise TestException(
2908 "NS {} deleted but with ns_lcm_op_occ active: {}".format(
2909 self
.ns_id
, nslcmops
2914 class TestDeployHackfest1(TestDeploy
):
2915 description
= "Load and deploy Hackfest_1_vnfd example"
2919 self
.test_name
= "HACKFEST1-"
2920 self
.vnfd_filenames
= ("hackfest_1_vnfd.tar.gz",)
2921 self
.nsd_filename
= "hackfest_1_nsd.tar.gz"
2922 # self.commands = {'1': ['ls -lrt', ], '2': ['ls -lrt', ]}
2923 # self.users = {'1': "cirros", '2': "cirros"}
2924 # self.passwords = {'1': "cubswin:)", '2': "cubswin:)"}
2927 class TestDeployHackfestCirrosScaling(TestDeploy
):
2929 "Load and deploy Hackfest cirros_2vnf_ns example with scaling modifications"
2934 self
.test_name
= "CIRROS-SCALE"
2935 self
.vnfd_filenames
= ("cirros_vnf.tar.gz",)
2936 self
.nsd_filename
= "cirros_2vnf_ns.tar.gz"
2937 # Modify VNFD to add scaling and count=2
2938 self
.descriptor_edit
= {
2940 "vdu": {"$id: 'cirros_vnfd-VM'": {"count": 2}},
2941 "scaling-group-descriptor": [
2943 "name": "scale_cirros",
2944 "max-instance-count": 2,
2945 "vdu": [{"vdu-id-ref": "cirros_vnfd-VM", "count": 2}],
2951 def additional_operations(self
, engine
, test_osm
, manual_check
):
2954 # 2 perform scale out twice
2956 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: "
2957 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
2959 for i
in range(0, 2):
2961 "Execute scale action over NS",
2963 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
2967 r_headers_yaml_location_nslcmop
,
2970 nslcmop2_scale_out
= engine
.last_id
2971 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
2973 input("NS scale out done. Check that two more vdus are there")
2974 # TODO check automatic
2976 # 2 perform scale in
2978 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: "
2979 '{scaling-group-descriptor: scale_cirros, member-vnf-index: "1"}}}'
2981 for i
in range(0, 2):
2983 "Execute scale IN action over NS",
2985 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
2989 r_headers_yaml_location_nslcmop
,
2992 nslcmop2_scale_in
= engine
.last_id
2993 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
2995 input("NS scale in done. Check that two less vdus are there")
2996 # TODO check automatic
2998 # perform scale in that must fail as reached limit
3000 "Execute scale IN out of limit action over NS",
3002 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3006 r_headers_yaml_location_nslcmop
,
3009 nslcmop2_scale_in
= engine
.last_id
3010 engine
.wait_operation_ready(
3011 "ns", nslcmop2_scale_in
, timeout_deploy
, expected_fail
=True
3015 class TestDeployIpMac(TestDeploy
):
3016 description
= "Load and deploy descriptor examples setting mac, ip address at descriptor and instantiate params"
3020 self
.test_name
= "SetIpMac"
3021 self
.vnfd_filenames
= (
3022 "vnfd_2vdu_set_ip_mac2.yaml",
3023 "vnfd_2vdu_set_ip_mac.yaml",
3025 self
.nsd_filename
= "scenario_2vdu_set_ip_mac.yaml"
3026 self
.descriptor_url
= "https://osm.etsi.org/gitweb/?p=osm/RO.git;a=blob_plain;f=test/RO_tests/v3_2vdu_set_ip_mac/"
3035 self
.users
= {"1": "osm", "2": "osm"}
3036 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3039 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3040 # super().run(engine, test_osm, manual_check, test_params)
3041 # run again setting IPs with instantiate parameters
3042 instantiation_params
= {
3045 "member-vnf-index": "1",
3048 "name": "internal_vld1", # net_internal
3050 "ip-version": "ipv4",
3051 "subnet-address": "10.9.8.0/24",
3054 "start-address": "10.9.8.100",
3057 "internal-connection-point": [
3060 "ip-address": "10.9.8.2",
3064 "ip-address": "10.9.8.3",
3074 # "name": "iface11",
3075 # "floating-ip-required": True,
3077 {"name": "iface13", "mac-address": "52:33:44:55:66:13"},
3085 "ip-address": "10.31.31.22",
3086 "mac-address": "52:33:44:55:66:21",
3099 test_params
={"ns-config": instantiation_params
},
3103 class TestDeployHackfest4(TestDeploy
):
3104 description
= "Load and deploy Hackfest 4 example."
3108 self
.test_name
= "HACKFEST4-"
3109 self
.vnfd_filenames
= ("hackfest_4_vnfd.tar.gz",)
3110 self
.nsd_filename
= "hackfest_4_nsd.tar.gz"
3111 self
.uses_configuration
= True
3120 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3121 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3122 # Modify VNFD to add scaling
3123 # self.descriptor_edit = {
3125 # 'vnf-configuration': {
3126 # 'config-primitive': [{
3129 # 'name': 'filename',
3130 # 'data-type': 'STRING',
3131 # 'default-value': '/home/ubuntu/touched'
3135 # 'scaling-group-descriptor': [{
3136 # 'name': 'scale_dataVM',
3137 # 'scaling-policy': [{
3138 # 'threshold-time': 0,
3139 # 'name': 'auto_cpu_util_above_threshold',
3140 # 'scaling-type': 'automatic',
3141 # 'scaling-criteria': [{
3142 # 'name': 'cpu_util_above_threshold',
3143 # 'vnf-monitoring-param-ref': 'all_aaa_cpu_util',
3144 # 'scale-out-relational-operation': 'GE',
3145 # 'scale-in-threshold': 15,
3146 # 'scale-out-threshold': 60,
3147 # 'scale-in-relational-operation': 'LE'
3149 # 'cooldown-time': 60
3151 # 'max-instance-count': 10,
3152 # 'scaling-config-action': [
3153 # {'vnf-config-primitive-name-ref': 'touch',
3154 # 'trigger': 'post-scale-out'},
3155 # {'vnf-config-primitive-name-ref': 'touch',
3156 # 'trigger': 'pre-scale-in'}
3159 # 'vdu-id-ref': 'dataVM',
3167 class TestDeployHackfest3Charmed(TestDeploy
):
3168 description
= "Load and deploy Hackfest 3charmed_ns example"
3172 self
.test_name
= "HACKFEST3-"
3173 self
.vnfd_filenames
= ("hackfest_3charmed_vnfd.tar.gz",)
3174 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
3175 self
.uses_configuration
= True
3177 "1": ["ls -lrt /home/ubuntu/first-touch"],
3178 "2": ["ls -lrt /home/ubuntu/first-touch"],
3180 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3181 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3182 self
.descriptor_edit
= {
3183 "vnfd0": yaml
.safe_load(
3186 terminate-config-primitive:
3191 value: '/home/ubuntu/last-touch1'
3196 value: '/home/ubuntu/last-touch3'
3201 value: '/home/ubuntu/last-touch2'
3206 def additional_operations(self
, engine
, test_osm
, manual_check
):
3210 vnfr_index_selected
= "2"
3211 payload
= '{member_vnf_index: "2", primitive: touch, primitive_params: { filename: /home/ubuntu/OSMTESTNBI }}'
3213 "Exec service primitive over NS",
3215 "/nslcm/v1/ns_instances/{}/action".format(self
.ns_id
),
3219 r_headers_yaml_location_nslcmop
,
3222 nslcmop2_action
= engine
.last_id
3223 # Wait until status is Ok
3224 engine
.wait_operation_ready("ns", nslcmop2_action
, timeout_deploy
)
3225 vnfr_ip
= self
.get_vnfr_ip(engine
, vnfr_index_selected
)
3228 "NS service primitive has been executed."
3229 "Check that file /home/ubuntu/OSMTESTNBI is present at {}".format(
3237 "ls -lrt /home/ubuntu/OSMTESTNBI",
3240 self
.test_ns(engine
, test_osm
, commands
=commands
)
3242 # # 2 perform scale out
3243 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: ' \
3244 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3245 # engine.test("Execute scale action over NS", "POST",
3246 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
3247 # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
3248 # nslcmop2_scale_out = engine.last_id
3249 # engine.wait_operation_ready("ns", nslcmop2_scale_out, timeout_deploy)
3251 # input('NS scale out done. Check that file /home/ubuntu/touched is present and new VM is created')
3252 # # TODO check automatic
3254 # # 2 perform scale in
3255 # payload = '{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: ' \
3256 # '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3257 # engine.test("Execute scale action over NS", "POST",
3258 # "/nslcm/v1/ns_instances/{}/scale".format(self.ns_id), headers_yaml, payload,
3259 # (201, 202), r_headers_yaml_location_nslcmop, "yaml")
3260 # nslcmop2_scale_in = engine.last_id
3261 # engine.wait_operation_ready("ns", nslcmop2_scale_in, timeout_deploy)
3263 # input('NS scale in done. Check that file /home/ubuntu/touched is updated and new VM is deleted')
3264 # # TODO check automatic
3267 class TestDeployHackfest3Charmed2(TestDeployHackfest3Charmed
):
3269 "Load and deploy Hackfest 3charmed_ns example modified version of descriptors to have dots in "
3270 "ids and member-vnf-index."
3275 self
.test_name
= "HACKFEST3v2-"
3276 self
.qforce
= "?FORCE=True"
3277 self
.descriptor_edit
= {
3282 "$[0]": {"external-connection-point-ref": "pdu-mgmt"}
3287 "vnf-configuration": None,
3288 "connection-point": {
3292 "short-name": "pdu-mgmt",
3296 "mgmt-interface": {"cp": "pdu-mgmt"},
3297 "description": "A vnf single vdu to be used as PDU",
3301 "id": "pdu_internal",
3302 "name": "pdu_internal",
3303 "internal-connection-point": {"$[1]": None},
3304 "short-name": "pdu_internal",
3309 # Modify NSD accordingly
3311 "constituent-vnfd": {
3312 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
3315 "description": "A nsd to deploy the vnf to act as as PDU",
3317 "name": "nsd-as-pdu",
3318 "short-name": "nsd-as-pdu",
3323 "short-name": "mgmt_pdu",
3324 "vnfd-connection-point-ref": {
3326 "vnfd-connection-point-ref": "pdu-mgmt",
3327 "vnfd-id-ref": "vdu-as-pdu",
3339 class TestDeployHackfest3Charmed3(TestDeployHackfest3Charmed
):
3340 description
= "Load and deploy Hackfest 3charmed_ns example modified version to test scaling and NS parameters"
3344 self
.test_name
= "HACKFEST3v3-"
3346 "1": ["ls -lrt /home/ubuntu/first-touch-1"],
3347 "2": ["ls -lrt /home/ubuntu/first-touch-2"],
3349 self
.descriptor_edit
= {
3352 scaling-group-descriptor:
3353 - name: "scale_dataVM"
3354 max-instance-count: 10
3356 - name: "auto_cpu_util_above_threshold"
3357 scaling-type: "automatic"
3361 - name: "cpu_util_above_threshold"
3362 scale-in-threshold: 15
3363 scale-in-relational-operation: "LE"
3364 scale-out-threshold: 60
3365 scale-out-relational-operation: "GE"
3366 vnf-monitoring-param-ref: "monitor1"
3368 - vdu-id-ref: dataVM
3370 scaling-config-action:
3371 - trigger: post-scale-out
3372 vnf-config-primitive-name-ref: touch
3373 - trigger: pre-scale-in
3374 vnf-config-primitive-name-ref: touch
3378 - id: "dataVM_cpu_util"
3379 nfvi-metric: "cpu_utilization"
3384 aggregation-type: AVERAGE
3385 vdu-monitoring-param:
3387 vdu-monitoring-param-ref: "dataVM_cpu_util"
3389 initial-config-primitive:
3393 value: "<touch_filename>" # default-value: /home/ubuntu/first-touch
3398 default-value: "<touch_filename2>"
3404 "additionalParamsForVnf": [
3406 "member-vnf-index": "1",
3407 "additionalParams": {
3408 "touch_filename": "/home/ubuntu/first-touch-1",
3409 "touch_filename2": "/home/ubuntu/second-touch-1",
3413 "member-vnf-index": "2",
3414 "additionalParams": {
3415 "touch_filename": "/home/ubuntu/first-touch-2",
3416 "touch_filename2": "/home/ubuntu/second-touch-2",
3422 def additional_operations(self
, engine
, test_osm
, manual_check
):
3423 super().additional_operations(engine
, test_osm
, manual_check
)
3427 # 2 perform scale out
3429 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_OUT, scaleByStepData: "
3430 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3433 "Execute scale action over NS",
3435 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3439 r_headers_yaml_location_nslcmop
,
3442 nslcmop2_scale_out
= engine
.last_id
3443 engine
.wait_operation_ready("ns", nslcmop2_scale_out
, timeout_deploy
)
3446 "NS scale out done. Check that file /home/ubuntu/second-touch-1 is present and new VM is created"
3451 "ls -lrt /home/ubuntu/second-touch-1",
3454 self
.test_ns(engine
, test_osm
, commands
=commands
)
3455 # TODO check automatic connection to scaled VM
3457 # 2 perform scale in
3459 "{scaleType: SCALE_VNF, scaleVnfData: {scaleVnfType: SCALE_IN, scaleByStepData: "
3460 '{scaling-group-descriptor: scale_dataVM, member-vnf-index: "1"}}}'
3463 "Execute scale action over NS",
3465 "/nslcm/v1/ns_instances/{}/scale".format(self
.ns_id
),
3469 r_headers_yaml_location_nslcmop
,
3472 nslcmop2_scale_in
= engine
.last_id
3473 engine
.wait_operation_ready("ns", nslcmop2_scale_in
, timeout_deploy
)
3476 "NS scale in done. Check that file /home/ubuntu/second-touch-1 is updated and new VM is deleted"
3478 # TODO check automatic
3481 class TestDeploySimpleCharm(TestDeploy
):
3482 description
= "Deploy hackfest-4 hackfest_simplecharm example"
3486 self
.test_name
= "HACKFEST-SIMPLE"
3487 self
.descriptor_url
= (
3488 "https://osm-download.etsi.org/ftp/osm-4.0-four/4th-hackfest/packages/"
3490 self
.vnfd_filenames
= ("hackfest_simplecharm_vnf.tar.gz",)
3491 self
.nsd_filename
= "hackfest_simplecharm_ns.tar.gz"
3492 self
.uses_configuration
= True
3496 "ls -lrt /home/ubuntu/first-touch",
3499 self
.users
= {"1": "ubuntu", "2": "ubuntu"}
3500 self
.passwords
= {"1": "osm4u", "2": "osm4u"}
3503 class TestDeploySimpleCharm2(TestDeploySimpleCharm
):
3505 "Deploy hackfest-4 hackfest_simplecharm example changing naming to contain dots on ids and "
3511 self
.test_name
= "HACKFEST-SIMPLE2-"
3512 self
.qforce
= "?FORCE=True"
3513 self
.descriptor_edit
= {
3514 "vnfd0": {"id": "hackfest.simplecharm.vnf"},
3516 "id": "hackfest.simplecharm.ns",
3517 "constituent-vnfd": {
3519 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3520 "member-vnf-index": "$1",
3523 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3524 "member-vnf-index": "$2",
3529 "vnfd-connection-point-ref": {
3531 "member-vnf-index-ref": "$1",
3532 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3535 "member-vnf-index-ref": "$2",
3536 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3541 "vnfd-connection-point-ref": {
3543 "member-vnf-index-ref": "$1",
3544 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3547 "member-vnf-index-ref": "$2",
3548 "vnfd-id-ref": "hackfest.simplecharm.vnf",
3557 class TestDeploySingleVdu(TestDeployHackfest3Charmed
):
3559 "Generate a single VDU base on editing Hackfest3Charmed descriptors and deploy"
3564 self
.test_name
= "SingleVDU"
3565 self
.qforce
= "?FORCE=True"
3566 self
.descriptor_edit
= {
3567 # Modify VNFD to remove one VDU
3572 "$[0]": {"external-connection-point-ref": "pdu-mgmt"}
3577 "vnf-configuration": None,
3578 "connection-point": {
3582 "short-name": "pdu-mgmt",
3586 "mgmt-interface": {"cp": "pdu-mgmt"},
3587 "description": "A vnf single vdu to be used as PDU",
3591 "id": "pdu_internal",
3592 "name": "pdu_internal",
3593 "internal-connection-point": {"$[1]": None},
3594 "short-name": "pdu_internal",
3599 # Modify NSD accordingly
3601 "constituent-vnfd": {
3602 "$[0]": {"vnfd-id-ref": "vdu-as-pdu"},
3605 "description": "A nsd to deploy the vnf to act as as PDU",
3607 "name": "nsd-as-pdu",
3608 "short-name": "nsd-as-pdu",
3613 "short-name": "mgmt_pdu",
3614 "vnfd-connection-point-ref": {
3616 "vnfd-connection-point-ref": "pdu-mgmt",
3617 "vnfd-id-ref": "vdu-as-pdu",
3629 class TestDeployHnfd(TestDeployHackfest3Charmed
):
3631 "Generate a HNFD base on editing Hackfest3Charmed descriptors and deploy"
3636 self
.test_name
= "HNFD"
3637 self
.pduDeploy
= TestDeploySingleVdu()
3638 self
.pdu_interface_0
= {}
3639 self
.pdu_interface_1
= {}
3642 # self.vnf_to_pdu = """
3645 # pdu-type: PDU-TYPE-1
3650 # name: pdu-iface-internal
3652 # description: HFND, one PDU + One VDU
3658 self
.pdu_descriptor
= {
3660 "type": "PDU-TYPE-1",
3661 "vim_accounts": "to-override",
3664 "name": "mgmt-iface",
3667 "ip-address": "to override",
3668 "mac-address": "mac_address",
3669 "vim-network-name": "mgmt",
3672 "name": "pdu-iface-internal",
3675 "ip-address": "to override",
3676 "mac-address": "mac_address",
3677 "vim-network-name": "pdu_internal", # OSMNBITEST-PDU-pdu_internal
3681 self
.vnfd_filenames
= (
3682 "hackfest_3charmed_vnfd.tar.gz",
3683 "hackfest_3charmed_vnfd.tar.gz",
3686 self
.descriptor_edit
= {
3690 "short-name": "hfn1",
3693 "pdu-type": "PDU-TYPE-1",
3695 "$[0]": {"name": "mgmt-iface"},
3696 "$[1]": {"name": "pdu-iface-internal"},
3702 "constituent-vnfd": {"$[1]": {"vnfd-id-ref": "hfnd1"}},
3705 "vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}
3708 "vnfd-connection-point-ref": {"$[1]": {"vnfd-id-ref": "hfnd1"}}
3714 def create_descriptors(self
, engine
):
3715 super().create_descriptors(engine
)
3718 self
.pdu_descriptor
["interfaces"][0].update(self
.pdu_interface_0
)
3719 self
.pdu_descriptor
["interfaces"][1].update(self
.pdu_interface_1
)
3720 self
.pdu_descriptor
["vim_accounts"] = [self
.vim_id
]
3721 # TODO get vim-network-name from vnfr.vld.name
3722 self
.pdu_descriptor
["interfaces"][1]["vim-network-name"] = "{}-{}-{}".format(
3723 os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST"),
3725 self
.pdu_descriptor
["interfaces"][1]["vim-network-name"],
3728 "Onboard PDU descriptor",
3730 "/pdu/v1/pdu_descriptors",
3732 "Location": "/pdu/v1/pdu_descriptors/",
3733 "Content-Type": "application/yaml",
3735 self
.pdu_descriptor
,
3740 self
.pdu_id
= engine
.last_id
3742 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3743 engine
.get_autorization()
3744 engine
.set_test_name(self
.test_name
)
3745 nsname
= os
.environ
.get("OSMNBITEST_NS_NAME", "OSMNBITEST")
3747 # create real VIM if not exist
3748 self
.vim_id
= engine
.get_create_vim(test_osm
)
3750 self
.pduDeploy
.create_descriptors(engine
)
3751 self
.pduDeploy
.instantiate(
3754 "nsDescription": "to be used as PDU",
3755 "nsName": nsname
+ "-PDU",
3756 "nsdId": self
.pduDeploy
.nsd_id
,
3757 "vimAccountId": self
.vim_id
,
3762 "VNF to be used as PDU has been deployed. Perform manual check and press enter to resume"
3765 self
.pduDeploy
.test_ns(engine
, test_osm
)
3769 "Get VNFR to obtain IP_ADDRESS",
3771 "/nslcm/v1/vnfrs?nsr-id-ref={}".format(self
.pduDeploy
.ns_id
),
3780 vnfr_data
= r
.json()
3783 self
.pdu_interface_0
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3786 self
.pdu_interface_1
["ip-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3789 self
.pdu_interface_0
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3791 ].get("mac-address")
3792 self
.pdu_interface_1
["mac-address"] = vnfr_data
[0]["vdur"][0]["interfaces"][
3794 ].get("mac-address")
3795 if not self
.pdu_interface_0
["ip-address"]:
3796 raise TestException("Vnfr has not managment ip address")
3798 self
.pdu_interface_0
["ip-address"] = "192.168.10.10"
3799 self
.pdu_interface_1
["ip-address"] = "192.168.11.10"
3800 self
.pdu_interface_0
["mac-address"] = "52:33:44:55:66:13"
3801 self
.pdu_interface_1
["mac-address"] = "52:33:44:55:66:14"
3803 self
.create_descriptors(engine
)
3806 "nsDescription": "default description",
3808 "nsdId": self
.nsd_id
,
3809 "vimAccountId": self
.vim_id
,
3811 if test_params
and test_params
.get("ns-config"):
3812 if isinstance(test_params
["ns-config"], str):
3813 ns_data
.update(yaml
.load(test_params
["ns-config"]), Loader
=yaml
.Loader
)
3815 ns_data
.update(test_params
["ns-config"])
3817 self
.instantiate(engine
, ns_data
)
3820 "NS has been deployed. Perform manual check and press enter to resume"
3823 self
.test_ns(engine
, test_osm
)
3824 self
.additional_operations(engine
, test_osm
, manual_check
)
3825 self
.terminate(engine
)
3826 self
.pduDeploy
.terminate(engine
)
3827 self
.delete_descriptors(engine
)
3828 self
.pduDeploy
.delete_descriptors(engine
)
3830 def delete_descriptors(self
, engine
):
3831 super().delete_descriptors(engine
)
3834 "Delete PDU SOL005",
3836 "/pdu/v1/pdu_descriptors/{}".format(self
.pdu_id
),
3845 class TestDescriptors
:
3846 description
= "Test VNFD, NSD, PDU descriptors CRUD and dependencies"
3847 vnfd_empty
= """vnfd:vnfd-catalog:
3853 vnfd_prova
= """vnfd:vnfd-catalog:
3865 - external-connection-point-ref: cp_0h8m
3874 self
.vnfd_filename
= "hackfest_3charmed_vnfd.tar.gz"
3875 self
.nsd_filename
= "hackfest_3charmed_nsd.tar.gz"
3876 self
.descriptor_url
= (
3877 "https://osm-download.etsi.org/ftp/osm-3.0-three/2nd-hackfest/packages/"
3882 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
3883 engine
.set_test_name("Descriptors")
3884 engine
.get_autorization()
3885 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
3886 if not os
.path
.exists(temp_dir
):
3887 os
.makedirs(temp_dir
)
3890 for filename
in (self
.vnfd_filename
, self
.nsd_filename
):
3891 filename_path
= temp_dir
+ filename
3892 if not os
.path
.exists(filename_path
):
3893 with
open(filename_path
, "wb") as file:
3894 response
= requests
.get(self
.descriptor_url
+ filename
)
3895 if response
.status_code
>= 300:
3896 raise TestException(
3897 "Error downloading descriptor from '{}': {}".format(
3898 self
.descriptor_url
+ filename
, response
.status_code
3901 file.write(response
.content
)
3903 vnfd_filename_path
= temp_dir
+ self
.vnfd_filename
3904 nsd_filename_path
= temp_dir
+ self
.nsd_filename
3907 "Onboard empty VNFD in one step",
3909 "/vnfpkgm/v1/vnf_packages_content",
3913 r_headers_yaml_location_vnfd
,
3916 self
.vnfd_id
= engine
.last_id
3920 "Upload invalid VNFD ",
3922 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3931 "Upload VNFD {}".format(self
.vnfd_filename
),
3933 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3935 "@b" + vnfd_filename_path
,
3942 "mgmt-interface.cp=mgmt",
3943 "vdu.0.interface.0.external-connection-point-ref=mgmt",
3944 "vdu.0.interface.1.internal-connection-point-ref=internal",
3945 "internal-vld.0.internal-connection-point.0.id-ref=internal",
3946 # Detection of duplicated VLD names in VNF Descriptors
3947 # URL: internal-vld=[
3948 # {id: internal1, name: internal, type:ELAN,
3949 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]},
3950 # {id: internal2, name: internal, type:ELAN,
3951 # internal-connection-point: [{id-ref: mgmtVM-internal}, {id-ref: dataVM-internal}]}
3953 "internal-vld=%5B%7Bid%3A%20internal1%2C%20name%3A%20internal%2C%20type%3A%20ELAN%2C%20"
3954 "internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7Bid-ref%3A%20"
3955 "dataVM-internal%7D%5D%7D%2C%20%7Bid%3A%20internal2%2C%20name%3A%20internal%2C%20type%3A%20"
3956 "ELAN%2C%20internal-connection-point%3A%20%5B%7Bid-ref%3A%20mgmtVM-internal%7D%2C%20%7B"
3957 "id-ref%3A%20dataVM-internal%7D%5D%7D%5D",
3959 for query
in queries
:
3961 "Upload invalid VNFD ",
3963 "/vnfpkgm/v1/vnf_packages/{}/package_content?{}".format(
3967 "@b" + vnfd_filename_path
,
3975 "Upload invalid VNFD ",
3977 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
3985 # get vnfd descriptor
3987 "Get VNFD descriptor",
3989 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
3997 # get vnfd file descriptor
3999 "Get VNFD file descriptor",
4001 "/vnfpkgm/v1/vnf_packages/{}/vnfd".format(self
.vnfd_id
),
4007 temp_dir
+ "vnfd-yaml",
4009 # TODO compare files: diff vnfd-yaml hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml
4011 # get vnfd zip file package
4013 "Get VNFD zip package",
4015 "/vnfpkgm/v1/vnf_packages/{}/package_content".format(self
.vnfd_id
),
4021 temp_dir
+ "vnfd-zip",
4023 # TODO compare files: diff vnfd-zip hackfest_3charmed_vnfd.tar.gz
4027 "Get VNFD artifact package",
4029 "/vnfpkgm/v1/vnf_packages/{}/artifacts/icons/osm.png".format(self
.vnfd_id
),
4035 temp_dir
+ "vnfd-icon",
4037 # TODO compare files: diff vnfd-icon hackfest_3charmed_vnfd/icons/osm.png
4039 # nsd CREATE AND UPLOAD in one step:
4041 "Onboard NSD in one step",
4043 "/nsd/v1/ns_descriptors_content",
4045 "@b" + nsd_filename_path
,
4047 r_headers_yaml_location_nsd
,
4050 self
.nsd_id
= engine
.last_id
4052 queries
= ["vld.0.vnfd-connection-point-ref.0.vnfd-id-ref=hf"]
4053 for query
in queries
:
4055 "Upload invalid NSD ",
4057 "/nsd/v1/ns_descriptors/{}/nsd_content?{}".format(self
.nsd_id
, query
),
4059 "@b" + nsd_filename_path
,
4065 # get nsd descriptor
4067 "Get NSD descriptor",
4069 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
4077 # get nsd file descriptor
4079 "Get NSD file descriptor",
4081 "/nsd/v1/ns_descriptors/{}/nsd".format(self
.nsd_id
),
4087 temp_dir
+ "nsd-yaml",
4089 # TODO compare files: diff nsd-yaml hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml
4091 # get nsd zip file package
4093 "Get NSD zip package",
4095 "/nsd/v1/ns_descriptors/{}/nsd_content".format(self
.nsd_id
),
4101 temp_dir
+ "nsd-zip",
4103 # TODO compare files: diff nsd-zip hackfest_3charmed_nsd.tar.gz
4107 "Get NSD artifact package",
4109 "/nsd/v1/ns_descriptors/{}/artifacts/icons/osm.png".format(self
.nsd_id
),
4115 temp_dir
+ "nsd-icon",
4117 # TODO compare files: diff nsd-icon hackfest_3charmed_nsd/icons/osm.png
4121 "Delete VNFD conflict",
4123 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_id
),
4132 "Delete VNFD force",
4134 "/vnfpkgm/v1/vnf_packages/{}?FORCE=TRUE".format(self
.vnfd_id
),
4146 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_id
),
4155 class TestNetSliceTemplates
:
4156 description
= "Upload a NST to OSM"
4159 self
.vnfd_filename
= "@./slice_shared/vnfd/slice_shared_vnfd.yaml"
4160 self
.vnfd_filename_middle
= "@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml"
4161 self
.nsd_filename
= "@./slice_shared/nsd/slice_shared_nsd.yaml"
4162 self
.nsd_filename_middle
= "@./slice_shared/nsd/slice_shared_middle_nsd.yaml"
4163 self
.nst_filenames
= "@./slice_shared/slice_shared_nstd.yaml"
4165 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
4167 engine
.set_test_name("NST step ")
4168 engine
.get_autorization()
4169 temp_dir
= os
.path
.dirname(os
.path
.abspath(__file__
)) + "/temp/"
4170 if not os
.path
.exists(temp_dir
):
4171 os
.makedirs(temp_dir
)
4175 "Onboard edge VNFD",
4177 "/vnfpkgm/v1/vnf_packages_content",
4181 r_headers_yaml_location_vnfd
,
4184 self
.vnfd_edge_id
= engine
.last_id
4187 "Onboard middle VNFD",
4189 "/vnfpkgm/v1/vnf_packages_content",
4191 self
.vnfd_filename_middle
,
4193 r_headers_yaml_location_vnfd
,
4196 self
.vnfd_middle_id
= engine
.last_id
4202 "/nsd/v1/ns_descriptors_content",
4206 r_headers_yaml_location_nsd
,
4209 self
.nsd_edge_id
= engine
.last_id
4212 "Onboard NSD middle",
4214 "/nsd/v1/ns_descriptors_content",
4216 self
.nsd_filename_middle
,
4218 r_headers_yaml_location_nsd
,
4221 self
.nsd_middle_id
= engine
.last_id
4227 "/nst/v1/netslice_templates_content",
4231 r_headers_yaml_location_nst
,
4234 nst_id
= engine
.last_id
4236 # nstd SHOW OSM format
4238 "Show NSTD OSM format",
4240 "/nst/v1/netslice_templates/{}".format(nst_id
),
4252 "/nst/v1/netslice_templates/{}".format(nst_id
),
4262 "Delete NSD middle",
4264 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
4275 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
),
4287 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
4296 "Delete VNFD middle",
4298 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
4307 class TestNetSliceInstances
:
4310 1. Populate databases with VNFD, NSD, NST with the following scenario
4311 +-----------------management-----------------+
4313 +--+---+ +----+----+ +---+--+
4315 | edge +---data1----+ middle +---data2-----+ edge |
4317 +------+ +---------+ +------+
4320 3. Instantiate NSI-1
4322 5. Instantiate NSI-2
4323 Manual check - Are 2 slices instantiated correctly?
4324 NSI-1 3 nss (2 nss-edges + 1 nss-middle)
4325 NSI-2 2 nss (2 nss-edge sharing nss-middle)
4328 Manual check - Is slice NSI-1 deleted correctly?
4329 NSI-2 with 2 nss-edge + 1 nss-middle (The one from NSI-1)
4331 9. Instantiate NSI-3
4332 Manual check - Is slice NSI-3 instantiated correctly?
4333 NSI-3 reuse nss-middle. NSI-3 only create 2 nss-edge
4338 Manual check - All cleaned correctly?
4339 NSI-2 and NSI-3 were terminated and deleted
4340 14. Cleanup database
4343 description
= "Upload a NST to OSM"
4347 self
.vnfd_filename
= "@./slice_shared/vnfd/slice_shared_vnfd.yaml"
4348 self
.vnfd_filename_middle
= "@./slice_shared/vnfd/slice_shared_middle_vnfd.yaml"
4349 self
.nsd_filename
= "@./slice_shared/nsd/slice_shared_nsd.yaml"
4350 self
.nsd_filename_middle
= "@./slice_shared/nsd/slice_shared_middle_nsd.yaml"
4351 self
.nst_filenames
= "@./slice_shared/slice_shared_nstd.yaml"
4353 def create_slice(self
, engine
, nsi_data
, name
):
4354 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
4358 "/nsilcm/v1/netslice_instances",
4363 "Location": "nsilcm/v1/netslice_instances/",
4364 "Content-Type": "application/yaml",
4370 def instantiate_slice(self
, engine
, nsi_data
, nsi_id
, name
):
4371 ns_data_text
= yaml
.safe_dump(nsi_data
, default_flow_style
=True, width
=256)
4375 "/nsilcm/v1/netslice_instances/{}/instantiate".format(nsi_id
),
4379 r_headers_yaml_location_nsilcmop
,
4383 def terminate_slice(self
, engine
, nsi_id
, name
):
4387 "/nsilcm/v1/netslice_instances/{}/terminate".format(nsi_id
),
4391 r_headers_yaml_location_nsilcmop
,
4395 def delete_slice(self
, engine
, nsi_id
, name
):
4399 "/nsilcm/v1/netslice_instances/{}".format(nsi_id
),
4407 def run(self
, engine
, test_osm
, manual_check
, test_params
=None):
4409 engine
.set_test_name("NSI")
4410 engine
.get_autorization()
4414 "Onboard edge VNFD",
4416 "/vnfpkgm/v1/vnf_packages_content",
4420 r_headers_yaml_location_vnfd
,
4423 self
.vnfd_edge_id
= engine
.last_id
4426 "Onboard middle VNFD",
4428 "/vnfpkgm/v1/vnf_packages_content",
4430 self
.vnfd_filename_middle
,
4432 r_headers_yaml_location_vnfd
,
4435 self
.vnfd_middle_id
= engine
.last_id
4441 "/nsd/v1/ns_descriptors_content",
4445 r_headers_yaml_location_nsd
,
4448 self
.nsd_edge_id
= engine
.last_id
4451 "Onboard NSD middle",
4453 "/nsd/v1/ns_descriptors_content",
4455 self
.nsd_filename_middle
,
4457 r_headers_yaml_location_nsd
,
4460 self
.nsd_middle_id
= engine
.last_id
4466 "/nst/v1/netslice_templates_content",
4470 r_headers_yaml_location_nst
,
4473 nst_id
= engine
.last_id
4475 self
.vim_id
= engine
.get_create_vim(test_osm
)
4479 "nsiName": "Deploy-NSI-1",
4480 "vimAccountId": self
.vim_id
,
4482 "nsiDescription": "default",
4484 r
= self
.create_slice(engine
, ns_data
, "Create NSI-1 step 1")
4487 self
.nsi_id1
= engine
.last_id
4490 self
.instantiate_slice(
4491 engine
, ns_data
, self
.nsi_id1
, "Instantiate NSI-1 step 2"
4493 nsilcmop_id1
= engine
.last_id
4497 engine
.wait_operation_ready("nsi", nsilcmop_id1
, timeout_deploy
)
4501 "nsiName": "Deploy-NSI-2",
4502 "vimAccountId": self
.vim_id
,
4504 "nsiDescription": "default",
4506 r
= self
.create_slice(engine
, ns_data
, "Create NSI-2 step 1")
4509 self
.nsi_id2
= engine
.last_id
4512 self
.instantiate_slice(
4513 engine
, ns_data
, self
.nsi_id2
, "Instantiate NSI-2 step 2"
4515 nsilcmop_id2
= engine
.last_id
4519 engine
.wait_operation_ready("nsi", nsilcmop_id2
, timeout_deploy
)
4523 "NSI-1 AND NSI-2 has been deployed. Perform manual check and press enter to resume"
4528 self
.terminate_slice(engine
, self
.nsi_id1
, "Terminate NSI-1")
4529 nsilcmop1_id
= engine
.last_id
4531 # Wait terminate NSI-1
4532 engine
.wait_operation_ready("nsi", nsilcmop1_id
, timeout_deploy
)
4535 self
.delete_slice(engine
, self
.nsi_id1
, "Delete NS")
4539 "NSI-1 has been deleted. Perform manual check and press enter to resume"
4544 "nsiName": "Deploy-NSI-3",
4545 "vimAccountId": self
.vim_id
,
4547 "nsiDescription": "default",
4549 r
= self
.create_slice(engine
, ns_data
, "Create NSI-3 step 1")
4553 self
.nsi_id3
= engine
.last_id
4556 self
.instantiate_slice(
4557 engine
, ns_data
, self
.nsi_id3
, "Instantiate NSI-3 step 2"
4559 nsilcmop_id3
= engine
.last_id
4561 # Wait Instantiate NSI-3
4563 engine
.wait_operation_ready("nsi", nsilcmop_id3
, timeout_deploy
)
4567 "NSI-3 has been deployed. Perform manual check and press enter to resume"
4572 self
.terminate_slice(engine
, self
.nsi_id2
, "Terminate NSI-2")
4573 nsilcmop2_id
= engine
.last_id
4575 # Wait terminate NSI-2
4576 engine
.wait_operation_ready("nsi", nsilcmop2_id
, timeout_deploy
)
4579 self
.delete_slice(engine
, self
.nsi_id2
, "DELETE NSI-2")
4583 self
.terminate_slice(engine
, self
.nsi_id3
, "Terminate NSI-3")
4584 nsilcmop3_id
= engine
.last_id
4586 # Wait terminate NSI-3
4587 engine
.wait_operation_ready("nsi", nsilcmop3_id
, timeout_deploy
)
4590 self
.delete_slice(engine
, self
.nsi_id3
, "DELETE NSI-3")
4594 "NSI-2 and NSI-3 has been deleted. Perform manual check and press enter to resume"
4601 "/nst/v1/netslice_templates/{}".format(nst_id
),
4611 "Delete NSD middle",
4613 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_middle_id
),
4624 "/nsd/v1/ns_descriptors/{}".format(self
.nsd_edge_id
),
4636 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_edge_id
),
4645 "Delete VNFD middle",
4647 "/vnfpkgm/v1/vnf_packages/{}".format(self
.vnfd_middle_id
),
4656 class TestAuthentication
:
4657 description
= "Test Authentication"
4660 def run(engine
, test_osm
, manual_check
, test_params
=None):
4661 engine
.set_test_name("Authentication")
4662 # backend = test_params.get("backend") if test_params else None # UNUSED
4664 admin_project_id
= test_project_id
= None
4665 project_admin_role_id
= project_user_role_id
= None
4666 test_user_id
= empty_user_id
= None
4667 default_role_id
= empty_role_id
= token_role_id
= None
4669 engine
.get_autorization()
4679 {"Content-Type": "application/json"},
4685 "/admin/v1/projects",
4689 {"Content-Type": "application/json"},
4699 {"Content-Type": "application/json"},
4709 {"Content-Type": "application/json"},
4713 "Get admin project",
4715 "/admin/v1/projects?name=admin",
4719 {"Content-Type": "application/json"},
4722 admin_project_id
= res
.json()[0]["_id"] if res
else None
4724 "Get project admin role",
4726 "/admin/v1/roles?name=project_admin",
4730 {"Content-Type": "application/json"},
4733 project_admin_role_id
= res
.json()[0]["_id"] if res
else None
4735 "Get project user role",
4737 "/admin/v1/roles?name=project_user",
4741 {"Content-Type": "application/json"},
4744 project_user_role_id
= res
.json()[0]["_id"] if res
else None
4748 "Create test project",
4750 "/admin/v1/projects",
4754 {"Location": "/admin/v1/projects/", "Content-Type": "application/json"},
4757 test_project_id
= engine
.last_id
if res
else None
4759 "Create role without permissions",
4765 {"Content-Type": "application/json"},
4768 empty_role_id
= engine
.last_id
if res
else None
4770 "Create role with default permissions",
4774 {"name": "default", "permissions": {"default": True}},
4776 {"Location": "/admin/v1/roles/", "Content-Type": "application/json"},
4779 default_role_id
= engine
.last_id
if res
else None
4781 "Create role with token permissions",
4787 "permissions": {"tokens": True},
4788 }, # is default required ?
4790 {"Location": "/admin/v1/roles/", "Content-Type": "application/json"},
4793 token_role_id
= engine
.last_id
if res
else None
4794 pr
= "project-role mappings"
4796 "Create user without " + pr
,
4800 {"username": "empty", "password": "empty"},
4802 {"Content-Type": "application/json"},
4805 empty_user_id
= engine
.last_id
if res
else None
4809 and project_admin_role_id
4810 and project_user_role_id
4812 data
= {"username": "test", "password": "test"}
4813 data
["project_role_mappings"] = [
4814 {"project": test_project_id
, "role": project_admin_role_id
},
4815 {"project": admin_project_id
, "role": project_user_role_id
},
4818 "Create user with " + pr
,
4824 {"Content-Type": "application/json"},
4827 test_user_id
= engine
.last_id
if res
else None
4832 "Modify test user's password",
4834 "/admin/v1/users/" + test_user_id
,
4836 {"password": "password"},
4843 and admin_project_id
4845 and project_admin_role_id
4846 and project_user_role_id
4849 "project_role_mappings": [
4850 {"project": test_project_id
, "role": project_admin_role_id
},
4851 {"project": admin_project_id
, "role": project_user_role_id
},
4855 "Modify empty user's " + pr
,
4857 "/admin/v1/users/" + empty_user_id
,
4868 "Delete empty user",
4870 "/admin/v1/users/" + empty_user_id
,
4881 "/admin/v1/users/" + test_user_id
,
4890 "Delete empty role",
4892 "/admin/v1/roles/" + empty_role_id
,
4901 "Delete default role",
4903 "/admin/v1/roles/" + default_role_id
,
4912 "Delete token role",
4914 "/admin/v1/roles/" + token_role_id
,
4923 "Delete test project",
4925 "/admin/v1/projects/" + test_project_id
,
4935 engine
.remove_authorization() # To finish
4938 class TestNbiQuotas
:
4939 description
= "Test NBI Quotas"
4942 def run(engine
, test_osm
, manual_check
, test_params
=None):
4943 engine
.set_test_name("NBI-Quotas_")
4944 # backend = test_params.get("backend") if test_params else None # UNUSED
4946 test_username
= "test-nbi-quotas"
4947 test_password
= "test-nbi-quotas"
4948 test_project
= "test-nbi-quotas"
4950 test_vim
= "test-nbi-quotas"
4951 test_wim
= "test-nbi-quotas"
4952 test_sdn
= "test-nbi-quotas"
4955 test_project_id
= None
4967 # Save admin access data
4968 admin_username
= engine
.user
4969 admin_password
= engine
.password
4970 admin_project
= engine
.project
4973 engine
.get_autorization()
4974 admin_token
= engine
.last_id
4976 # Check that test project,user do not exist
4978 "Check that test project doesn't exist",
4980 "/admin/v1/projects/" + test_project
,
4988 "Check that test user doesn't exist",
4990 "/admin/v1/users/" + test_username
,
4997 if None in [res1
, res2
]:
4998 engine
.remove_authorization()
4999 logger
.error("Test project and/or user already exist")
5002 # Create test project&user
5004 "Create test project",
5006 "/admin/v1/projects",
5009 "name": test_username
,
5026 test_project_id
= engine
.last_id
if res
else None
5033 "username": test_username
,
5034 "password": test_password
,
5035 "project_role_mappings": [
5036 {"project": test_project
, "role": "project_admin"}
5043 test_user_id
= engine
.last_id
if res
else None
5045 if test_project_id
and test_user_id
:
5048 engine
.user
= test_username
5049 engine
.password
= test_password
5050 engine
.project
= test_project
5051 engine
.get_autorization()
5052 user_token
= engine
.last_id
5058 "/admin/v1/vim_accounts",
5062 "vim_type": "openvim",
5063 "vim_user": test_username
,
5064 "vim_password": test_password
,
5065 "vim_tenant_name": test_project
,
5066 "vim_url": "https://0.0.0.0:0/v0.0",
5072 test_vim_ids
+= [engine
.last_id
if res
else None]
5075 "Try to create second test VIM",
5077 "/admin/v1/vim_accounts",
5080 "name": test_vim
+ "_2",
5081 "vim_type": "openvim",
5082 "vim_user": test_username
,
5083 "vim_password": test_password
,
5084 "vim_tenant_name": test_project
,
5085 "vim_url": "https://0.0.0.0:0/v0.0",
5091 test_vim_ids
+= [engine
.last_id
if res
is None else None]
5094 "Try to create second test VIM with FORCE",
5096 "/admin/v1/vim_accounts?FORCE",
5099 "name": test_vim
+ "_3",
5100 "vim_type": "openvim",
5101 "vim_user": test_username
,
5102 "vim_password": test_password
,
5103 "vim_tenant_name": test_project
,
5104 "vim_url": "https://0.0.0.0:0/v0.0",
5110 test_vim_ids
+= [engine
.last_id
if res
else None]
5113 # Download descriptor files (if required)
5114 test_dir
= "/tmp/" + test_username
+ "/"
5115 test_url
= "https://osm-download.etsi.org/ftp/osm-6.0-six/7th-hackfest/packages/"
5117 "slice_hackfest_vnfd.tar.gz",
5118 "slice_hackfest_middle_vnfd.tar.gz",
5121 "slice_hackfest_nsd.tar.gz",
5122 "slice_hackfest_middle_nsd.tar.gz",
5124 nst_filenames
= ["slice_hackfest_nstd.yaml"]
5125 pdu_filenames
= ["PDU_router.yaml"]
5127 vnfd_filenames
+ nsd_filenames
+ nst_filenames
+ pdu_filenames
5129 if not os
.path
.exists(test_dir
):
5130 os
.makedirs(test_dir
)
5131 for filename
in desc_filenames
:
5132 if not os
.path
.exists(test_dir
+ filename
):
5133 res
= requests
.get(test_url
+ filename
)
5134 if res
.status_code
< 300:
5135 with
open(test_dir
+ filename
, "wb") as file:
5136 file.write(res
.content
)
5138 if all([os
.path
.exists(test_dir
+ p
) for p
in desc_filenames
]):
5141 "Create test VNFD #1",
5143 "/vnfpkgm/v1/vnf_packages_content",
5145 "@b" + test_dir
+ vnfd_filenames
[0],
5150 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5152 "Create test VNFD #2",
5154 "/vnfpkgm/v1/vnf_packages_content",
5156 "@b" + test_dir
+ vnfd_filenames
[1],
5161 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5163 "Try to create extra test VNFD",
5165 "/vnfpkgm/v1/vnf_packages_content",
5167 "@b" + test_dir
+ vnfd_filenames
[0],
5172 test_vnfd_ids
+= [engine
.last_id
if res
is None else None]
5174 "Try to create extra test VNFD with FORCE",
5176 "/vnfpkgm/v1/vnf_packages_content?FORCE",
5178 "@b" + test_dir
+ vnfd_filenames
[0],
5183 test_vnfd_ids
+= [engine
.last_id
if res
else None]
5185 # Remove extra VNFDs to prevent further errors
5187 if test_vnfd_ids
[i
]:
5189 "Delete test VNFD #" + str(i
),
5191 "/vnfpkgm/v1/vnf_packages_content/"
5201 test_vnfd_ids
[i
] = None
5203 if test_vnfd_ids
[0] and test_vnfd_ids
[1]:
5206 "Create test NSD #1",
5208 "/nsd/v1/ns_descriptors_content",
5210 "@b" + test_dir
+ nsd_filenames
[0],
5215 test_nsd_ids
+= [engine
.last_id
if res
else None]
5217 "Create test NSD #2",
5219 "/nsd/v1/ns_descriptors_content",
5221 "@b" + test_dir
+ nsd_filenames
[1],
5226 test_nsd_ids
+= [engine
.last_id
if res
else None]
5228 "Try to create extra test NSD",
5230 "/nsd/v1/ns_descriptors_content",
5232 "@b" + test_dir
+ nsd_filenames
[0],
5237 test_nsd_ids
+= [engine
.last_id
if res
is None else None]
5239 "Try to create extra test NSD with FORCE",
5241 "/nsd/v1/ns_descriptors_content?FORCE",
5243 "@b" + test_dir
+ nsd_filenames
[0],
5248 test_nsd_ids
+= [engine
.last_id
if res
else None]
5250 # Remove extra NSDs to prevent further errors
5254 "Delete test NSD #" + str(i
),
5256 "/nsd/v1/ns_descriptors_content/"
5266 test_nsd_ids
[i
] = None
5268 if test_nsd_ids
[0] and test_nsd_ids
[1]:
5271 "Create test NSR #1",
5273 "/nslcm/v1/ns_instances_content",
5276 "nsName": test_username
+ "_1",
5277 "nsdId": test_nsd_ids
[0],
5278 "vimAccountId": test_vim_ids
[0],
5284 test_nsr_ids
+= [engine
.last_id
if res
else None]
5286 "Create test NSR #2",
5288 "/nslcm/v1/ns_instances_content",
5291 "nsName": test_username
+ "_2",
5292 "nsdId": test_nsd_ids
[1],
5293 "vimAccountId": test_vim_ids
[0],
5299 test_nsr_ids
+= [engine
.last_id
if res
else None]
5301 "Try to create extra test NSR",
5303 "/nslcm/v1/ns_instances_content",
5306 "nsName": test_username
+ "_3",
5307 "nsdId": test_nsd_ids
[0],
5308 "vimAccountId": test_vim_ids
[0],
5314 test_nsr_ids
+= [engine
.last_id
if res
is None else None]
5316 "Try to create test NSR with FORCE",
5318 "/nslcm/v1/ns_instances_content?FORCE",
5321 "nsName": test_username
+ "_4",
5322 "nsdId": test_nsd_ids
[0],
5323 "vimAccountId": test_vim_ids
[0],
5329 test_nsr_ids
+= [engine
.last_id
if res
else None]
5335 "/nst/v1/netslice_templates_content",
5337 "@b" + test_dir
+ nst_filenames
[0],
5342 test_nst_ids
+= [engine
.last_id
if res
else None]
5344 "Try to create extra test NST",
5346 "/nst/v1/netslice_templates_content",
5348 "@b" + test_dir
+ nst_filenames
[0],
5353 test_nst_ids
+= [engine
.last_id
if res
is None else None]
5355 "Try to create extra test NST with FORCE",
5357 "/nst/v1/netslice_templates_content?FORCE",
5359 "@b" + test_dir
+ nst_filenames
[0],
5364 test_nst_ids
+= [engine
.last_id
if res
else None]
5369 {"Authorization": "Bearer {}".format(admin_token
)}
5374 "/admin/v1/projects/" + test_project_id
,
5376 {"quotas": {"nsrs": None}},
5382 {"Authorization": "Bearer {}".format(user_token
)}
5389 "/nsilcm/v1/netslice_instances_content",
5392 "nsiName": test_username
,
5393 "nstId": test_nst_ids
[0],
5394 "vimAccountId": test_vim_ids
[0],
5400 test_nsi_ids
+= [engine
.last_id
if res
else None]
5402 "Try to create extra test NSI",
5404 "/nsilcm/v1/netslice_instances_content",
5407 "nsiName": test_username
,
5408 "nstId": test_nst_ids
[0],
5409 "vimAccountId": test_vim_ids
[0],
5416 engine
.last_id
if res
is None else None
5419 "Try to create extra test NSI with FORCE",
5421 "/nsilcm/v1/netslice_instances_content?FORCE",
5424 "nsiName": test_username
,
5425 "nstId": test_nst_ids
[0],
5426 "vimAccountId": test_vim_ids
[0],
5432 test_nsi_ids
+= [engine
.last_id
if res
else None]
5435 with
open(test_dir
+ pdu_filenames
[0], "rb") as file:
5437 r
"ip-address: *\[[^\]]*\]",
5438 "ip-address: '0.0.0.0'",
5439 file.read().decode("utf-8"),
5441 with
open(test_dir
+ pdu_filenames
[0], "wb") as file:
5442 file.write(pdu_text
.encode("utf-8"))
5446 "/pdu/v1/pdu_descriptors",
5448 "@b" + test_dir
+ pdu_filenames
[0],
5453 test_pdu_ids
+= [engine
.last_id
if res
else None]
5455 "Try to create extra test PDU",
5457 "/pdu/v1/pdu_descriptors",
5459 "@b" + test_dir
+ pdu_filenames
[0],
5464 test_pdu_ids
+= [engine
.last_id
if res
is None else None]
5466 "Try to create extra test PDU with FORCE",
5468 "/pdu/v1/pdu_descriptors?FORCE",
5470 "@b" + test_dir
+ pdu_filenames
[0],
5475 test_pdu_ids
+= [engine
.last_id
if res
else None]
5478 for i
, id in enumerate(test_nsi_ids
):
5481 "Delete test NSI #" + str(i
),
5483 "/nsilcm/v1/netslice_instances_content/"
5492 for i
, id in enumerate(test_nsr_ids
):
5495 "Delete test NSR #" + str(i
),
5497 "/nslcm/v1/ns_instances_content/" + id + "?FORCE",
5504 for i
, id in enumerate(test_nst_ids
):
5507 "Delete test NST #" + str(i
),
5509 "/nst/v1/netslice_templates_content/" + id + "?FORCE",
5516 for i
, id in enumerate(test_nsd_ids
):
5519 "Delete test NSD #" + str(i
),
5521 "/nsd/v1/ns_descriptors_content/" + id + "?FORCE",
5528 for i
, id in enumerate(test_vnfd_ids
):
5531 "Delete test VNFD #" + str(i
),
5533 "/vnfpkgm/v1/vnf_packages_content/" + id + "?FORCE",
5540 for i
, id in enumerate(test_pdu_ids
):
5543 "Delete test PDU #" + str(i
),
5545 "/pdu/v1/pdu_descriptors/" + id + "?FORCE",
5553 # END Test NBI Quotas
5559 "/admin/v1/wim_accounts",
5564 "wim_url": "https://0.0.0.0:0/v0.0",
5570 test_wim_ids
+= [engine
.last_id
if res
else None]
5572 "Try to create second test WIM",
5574 "/admin/v1/wim_accounts",
5577 "name": test_wim
+ "_2",
5579 "wim_url": "https://0.0.0.0:0/v0.0",
5585 test_wim_ids
+= [engine
.last_id
if res
is None else None]
5587 "Try to create second test WIM with FORCE",
5589 "/admin/v1/wim_accounts?FORCE",
5592 "name": test_wim
+ "_3",
5594 "wim_url": "https://0.0.0.0:0/v0.0",
5600 test_wim_ids
+= [engine
.last_id
if res
else None]
5613 "dpid": "00:00:00:00:00:00:00:00",
5619 test_sdn_ids
+= [engine
.last_id
if res
else None]
5621 "Try to create second test SDN",
5626 "name": test_sdn
+ "_2",
5630 "dpid": "00:00:00:00:00:00:00:00",
5636 test_sdn_ids
+= [engine
.last_id
if res
is None else None]
5638 "Try to create second test SDN with FORCE",
5640 "/admin/v1/sdns?FORCE",
5643 "name": test_sdn
+ "_3",
5647 "dpid": "00:00:00:00:00:00:00:00",
5653 test_sdn_ids
+= [engine
.last_id
if res
else None]
5656 for i
, id in enumerate(test_vim_ids
):
5659 "Delete test VIM #" + str(i
),
5661 "/admin/v1/vim_accounts/" + id + "?FORCE",
5668 for i
, id in enumerate(test_wim_ids
):
5671 "Delete test WIM #" + str(i
),
5673 "/admin/v1/wim_accounts/" + id + "?FORCE",
5680 for i
, id in enumerate(test_sdn_ids
):
5683 "Delete test SDN #" + str(i
),
5685 "/admin/v1/sdns/" + id + "?FORCE",
5693 # Release user access
5694 engine
.remove_authorization()
5697 engine
.user
= admin_username
5698 engine
.password
= admin_password
5699 engine
.project
= admin_project
5700 engine
.get_autorization()
5705 "/admin/v1/users/" + test_user_id
+ "?FORCE",
5714 "Delete test project",
5716 "/admin/v1/projects/" + test_project_id
+ "?FORCE",
5723 engine
.remove_authorization()
5725 # END class TestNbiQuotas
5728 if __name__
== "__main__":
5732 # Disable warnings from self-signed certificates.
5733 requests
.packages
.urllib3
.disable_warnings()
5735 logging
.basicConfig(format
="%(levelname)s %(message)s", level
=logging
.ERROR
)
5736 logger
= logging
.getLogger("NBI")
5737 # load parameters and configuration
5738 opts
, args
= getopt
.getopt(
5753 "timeout-configure",
5762 url
= "https://localhost:9999/osm"
5763 user
= password
= project
= "admin"
5765 manual_check
= False
5770 "NonAuthorized": TestNonAuthorized
,
5771 "FakeVIM": TestFakeVim
,
5772 "Users-Projects": TestUsersProjects
,
5773 "Projects-Descriptors": TestProjectsDescriptors
,
5774 "VIM-SDN": TestVIMSDN
,
5775 "Deploy-Custom": TestDeploy
,
5776 "Deploy-Hackfest-Cirros": TestDeployHackfestCirros
,
5777 "Deploy-Hackfest-Cirros-Scaling": TestDeployHackfestCirrosScaling
,
5778 "Deploy-Hackfest-3Charmed": TestDeployHackfest3Charmed
,
5779 "Deploy-Hackfest-3Charmed2": TestDeployHackfest3Charmed2
,
5780 "Deploy-Hackfest-3Charmed3": TestDeployHackfest3Charmed3
,
5781 "Deploy-Hackfest-4": TestDeployHackfest4
,
5782 "Deploy-CirrosMacIp": TestDeployIpMac
,
5783 "Descriptors": TestDescriptors
,
5784 "Deploy-Hackfest1": TestDeployHackfest1
,
5785 # "Deploy-MultiVIM": TestDeployMultiVIM,
5786 "Deploy-SingleVdu": TestDeploySingleVdu
,
5787 "Deploy-Hnfd": TestDeployHnfd
,
5788 "Upload-Slice-Template": TestNetSliceTemplates
,
5789 "Deploy-Slice-Instance": TestNetSliceInstances
,
5790 "Deploy-SimpleCharm": TestDeploySimpleCharm
,
5791 "Deploy-SimpleCharm2": TestDeploySimpleCharm2
,
5792 "Authentication": TestAuthentication
,
5793 "NBI-Quotas": TestNbiQuotas
,
5799 # print("parameter:", o, a)
5800 if o
== "--version":
5801 print("test version " + __version__
+ " " + version_date
)
5804 for test
, test_class
in sorted(test_classes
.items()):
5805 print("{:32} {}".format(test
+ ":", test_class
.description
))
5807 elif o
in ("-v", "--verbose"):
5809 elif o
== "no-verbose":
5811 elif o
in ("-h", "--help"):
5814 elif o
== "--test-osm":
5816 elif o
== "--manual-check":
5820 elif o
in ("-u", "--user"):
5822 elif o
in ("-p", "--password"):
5824 elif o
== "--project":
5826 elif o
== "--fail-fast":
5829 for _test
in a
.split(","):
5830 if _test
not in test_classes
:
5832 "Invalid test name '{}'. Use option '--list' to show available tests".format(
5838 test_to_do
.append(_test
)
5839 elif o
== "--params":
5840 param_key
, _
, param_value
= a
.partition("=")
5841 text_index
= len(test_to_do
)
5842 if text_index
not in test_params
:
5843 test_params
[text_index
] = {}
5844 test_params
[text_index
][param_key
] = param_value
5845 elif o
== "--insecure":
5847 elif o
== "--timeout":
5849 elif o
== "--timeout-deploy":
5850 timeout_deploy
= int(a
)
5851 elif o
== "--timeout-configure":
5852 timeout_configure
= int(a
)
5854 assert False, "Unhandled option"
5856 logger
.setLevel(logging
.WARNING
)
5858 logger
.setLevel(logging
.DEBUG
)
5860 logger
.setLevel(logging
.ERROR
)
5862 test_rest
= TestRest(url
, user
=user
, password
=password
, project
=project
)
5863 # print("tests to do:", test_to_do)
5866 for test
in test_to_do
:
5867 if fail_fast
and test_rest
.failed_tests
:
5870 test_class
= test_classes
[test
]
5872 test_rest
, test_osm
, manual_check
, test_params
.get(text_index
)
5875 for test
, test_class
in sorted(test_classes
.items()):
5876 if fail_fast
and test_rest
.failed_tests
:
5878 test_class().run(test_rest
, test_osm
, manual_check
, test_params
.get(0))
5879 test_rest
.print_results()
5880 exit(1 if test_rest
.failed_tests
else 0)
5882 except TestException
as e
:
5883 logger
.error(test
+ "Test {} Exception: {}".format(test
, str(e
)))
5885 except getopt
.GetoptError
as e
:
5887 print(e
, file=sys
.stderr
)
5889 except Exception as e
:
5890 logger
.critical(test
+ " Exception: " + str(e
), exc_info
=True)