2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
8 # Unless otherwise specified, all software contained herein is licensed
9 # under the Apache License, Version 2.0 (the "License");
10 # you may not use this software except in compliance with the License.
11 # You may obtain a copy of the License at
13 # http://www.apache.org/licenses/LICENSE-2.0
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
23 # Unless otherwise specified, all documentation contained herein is licensed
24 # under the Creative Commons License, Attribution 4.0 Intl. (the "License");
25 # you may not use this documentation except in compliance with the License.
26 # You may obtain a copy of the License at
28 # https://creativecommons.org/licenses/by/4.0/
30 # Unless required by applicable law or agreed to in writing, documentation
31 # distributed under the License is distributed on an "AS IS" BASIS,
32 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33 # See the License for the specific language governing permissions and
34 # limitations under the License.
36 # ============LICENSE_END============================================
38 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
41 """ environment file structure
46 from .helpers import validates, get_environment_pair
51 # pylint: disable=invalid-name
54 def check_parameter_exists(pattern, parameters):
58 for param in parameters:
59 if pattern.search(param):
65 def check_param_in_env_file(environment_pair, param, DESIRED, exclude_parameter=None):
67 # workaround for internal/external parameters
68 if exclude_parameter and re.match(exclude_parameter, param):
71 if not environment_pair:
72 pytest.skip("No heat/env pair could be identified")
74 env_file = environment_pair.get("eyml")
76 pattern = re.compile(r"^{}$".format(param))
78 if "parameters" not in env_file:
79 pytest.skip("No parameters specified in the environment file")
82 check_parameter_exists(pattern, env_file.get("parameters", {})) is not DESIRED
87 This function supports this structure, deviations
88 may or may not work without enhancement
93 prop0: { get_param: parameter_0 }
94 prop1: # this is a list of dicts
95 - nested_prop_0: { get_param: parameter_1 }
96 - nested_prop_1: { get_param: [parameter_2, {index}] }
97 prop2: # this is a dict of dicts
98 nested_prop_0: { get_param: parameter_1 }
102 def check_resource_parameter(
107 resource_type_inverse=False,
110 exclude_parameter="",
113 if not environment_pair:
114 pytest.skip("No heat/env pair could be identified")
116 env_file = environment_pair.get("eyml")
117 template_file = environment_pair.get("yyml")
119 if "parameters" not in env_file:
120 pytest.skip("No parameters specified in the environment file")
122 invalid_parameters = []
125 for resource, resource_prop in template_file.get("resources", {}).items():
127 # workaround for subinterface resource groups
128 if exclude_resource and re.match(exclude_resource, resource):
132 resource_prop.get("type") == resource_type and not resource_type_inverse
133 ) or (resource_prop.get("type") != resource_type and resource_type_inverse):
137 if not resource_prop.get("properties"):
140 resource_parameter = resource_prop.get("properties").get(prop)
142 if not resource_parameter:
145 if isinstance(resource_parameter, list) and nested_prop:
146 for param in resource_parameter:
148 nested_param = param.get(nested_prop)
152 if isinstance(nested_param, dict):
153 pattern = nested_param.get("get_param")
160 if isinstance(pattern, list):
163 if check_param_in_env_file(
167 exclude_parameter=exclude_parameter,
169 invalid_parameters.append(pattern)
171 elif isinstance(resource_parameter, dict):
173 if nested_prop and nested_prop in resource_parameter:
174 resource_parameter = resource_parameter.get(nested_prop)
176 pattern = resource_parameter.get("get_param")
180 if check_param_in_env_file(
184 exclude_parameter=exclude_parameter,
186 invalid_parameters.append(pattern)
190 return set(invalid_parameters)
193 @validates("R-91125")
194 def test_nova_server_image_parameter_exists_in_environment_file(heat_template):
196 if pytest.config.getoption("validation_profile") == "heat_only":
197 pytest.skip("skipping test because validation profile is heat only")
199 environment_pair = get_environment_pair(heat_template)
203 resource_type = "OS::Nova::Server"
205 invalid_parameters = check_resource_parameter(
206 environment_pair, prop, DESIRED, resource_type
209 assert not invalid_parameters, (
210 "OS::Nova::Server {} parameters not"
211 " found in {} environment file {}".format(
212 prop, environment_pair.get("name"), invalid_parameters
217 @validates("R-69431")
218 def test_nova_server_flavor_parameter_exists_in_environment_file(heat_template):
220 if pytest.config.getoption("validation_profile") == "heat_only":
221 pytest.skip("skipping test because validation profile is heat only")
223 environment_pair = get_environment_pair(heat_template)
227 resource_type = "OS::Nova::Server"
229 invalid_parameters = check_resource_parameter(
230 environment_pair, prop, DESIRED, resource_type
233 assert not invalid_parameters, (
234 "OS::Nova::Server {} parameters not"
235 " found in {} environment file {}".format(
236 prop, environment_pair.get("name"), invalid_parameters
241 @validates("R-22838")
242 def test_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
244 if pytest.config.getoption("validation_profile") == "heat_only":
245 pytest.skip("skipping test because validation profile is heat only")
247 environment_pair = get_environment_pair(heat_template)
251 resource_type = "OS::Nova::Server"
253 invalid_parameters = check_resource_parameter(
254 environment_pair, prop, DESIRED, resource_type
257 assert not invalid_parameters, (
258 "OS::Nova::Server {} parameters"
259 " found in {} environment file {}".format(
260 prop, environment_pair.get("name"), invalid_parameters
265 @validates("R-59568")
266 def test_nova_server_az_parameter_doesnt_exist_in_environment_file(heat_template):
268 if pytest.config.getoption("validation_profile") == "heat_only":
269 pytest.skip("skipping test because validation profile is heat only")
271 environment_pair = get_environment_pair(heat_template)
273 prop = "availability_zone"
275 resource_type = "OS::Nova::Server"
277 invalid_parameters = check_resource_parameter(
278 environment_pair, prop, DESIRED, resource_type
281 assert not invalid_parameters, (
282 "OS::Nova::Server {} parameters"
283 " found in {} environment file {}".format(
284 prop, environment_pair.get("name"), invalid_parameters
289 @validates("R-20856")
290 def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(heat_template):
292 if pytest.config.getoption("validation_profile") == "heat_only":
293 pytest.skip("skipping test because validation profile is heat only")
295 environment_pair = get_environment_pair(heat_template)
300 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
302 assert not invalid_parameters, (
304 " found in {} environment file {}".format(
305 prop, environment_pair.get("name"), invalid_parameters
310 @validates("R-72871")
311 def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(
315 if pytest.config.getoption("validation_profile") == "heat_only":
316 pytest.skip("skipping test because validation profile is heat only")
318 environment_pair = get_environment_pair(heat_template)
320 prop = "vf_module_id"
323 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
325 assert not invalid_parameters, (
327 " found in {} environment file {}".format(
328 prop, environment_pair.get("name"), invalid_parameters
333 @validates("R-37039")
334 def test_nova_server_vf_module_index_parameter_doesnt_exist_in_environment_file(
338 if pytest.config.getoption("validation_profile") == "heat_only":
339 pytest.skip("skipping test because validation profile is heat only")
341 environment_pair = get_environment_pair(heat_template)
343 prop = "vf_module_index"
346 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
348 assert not invalid_parameters, (
350 " found in {} environment file {}".format(
351 prop, environment_pair.get("name"), invalid_parameters
356 @validates("R-36542")
357 def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(heat_template):
359 if pytest.config.getoption("validation_profile") == "heat_only":
360 pytest.skip("skipping test because validation profile is heat only")
362 environment_pair = get_environment_pair(heat_template)
367 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
369 assert not invalid_parameters, (
371 " found in {} environment file {}".format(
372 prop, environment_pair.get("name"), invalid_parameters
377 @validates("R-80374")
378 def test_nova_server_vf_module_name_parameter_doesnt_exist_in_environment_file(
382 if pytest.config.getoption("validation_profile") == "heat_only":
383 pytest.skip("skipping test because validation profile is heat only")
385 environment_pair = get_environment_pair(heat_template)
387 prop = "vf_module_name"
390 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
392 assert not invalid_parameters, (
394 " found in {} environment file {}".format(
395 prop, environment_pair.get("name"), invalid_parameters
400 @validates("R-02691")
401 def test_nova_server_workload_context_parameter_doesnt_exist_in_environment_file(
405 if pytest.config.getoption("validation_profile") == "heat_only":
406 pytest.skip("skipping test because validation profile is heat only")
408 environment_pair = get_environment_pair(heat_template)
410 prop = "workload_context"
413 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
415 assert not invalid_parameters, (
417 " found in {} environment file {}".format(
418 prop, environment_pair.get("name"), invalid_parameters
423 @validates("R-13194")
424 def test_nova_server_environment_context_parameter_doesnt_exist_in_environment_file(
428 if pytest.config.getoption("validation_profile") == "heat_only":
429 pytest.skip("skipping test because validation profile is heat only")
431 environment_pair = get_environment_pair(heat_template)
433 prop = "environment_context"
436 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
438 assert not invalid_parameters, (
440 " found in {} environment file {}".format(
441 prop, environment_pair.get("name"), invalid_parameters
446 @validates("R-29872")
447 def test_nova_server_network_parameter_doesnt_exist_in_environment_file(heat_template):
449 if pytest.config.getoption("validation_profile") == "heat_only":
450 pytest.skip("skipping test because validation profile is heat only")
452 environment_pair = get_environment_pair(heat_template)
455 nested_prop = "network"
457 resource_type = "OS::Nova::Server"
459 invalid_parameters = check_resource_parameter(
460 environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
463 assert not invalid_parameters, (
465 " found in {} environment file {}".format(
466 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
471 @validates("R-39841", "R-87123", "R-62590", "R-98905", "R-93030", "R-62590")
472 def test_neutron_port_external_fixedips_ipaddress_parameter_doesnt_exist_in_environment_file(
476 if pytest.config.getoption("validation_profile") == "heat_only":
477 pytest.skip("skipping test because validation profile is heat only")
479 environment_pair = get_environment_pair(heat_template)
482 nested_prop = "ip_address"
484 resource_type = "OS::Neutron::Port"
485 exclude_parameter = re.compile(r"^(.+?)_int_(.+?)$")
487 invalid_parameters = check_resource_parameter(
492 nested_prop=nested_prop,
493 exclude_parameter=exclude_parameter,
496 assert not invalid_parameters, (
497 "{} {} external parameters"
498 " found in {} environment file {}".format(
499 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
504 @validates("R-28795", "R-97201", "R-93496", "R-90206", "R-98569", "R-93496")
505 def test_neutron_port_internal_fixedips_ipaddress_parameter_exists_in_environment_file(
509 if pytest.config.getoption("validation_profile") == "heat_only":
510 pytest.skip("skipping test because validation profile is heat only")
512 environment_pair = get_environment_pair(heat_template)
515 nested_prop = "ip_address"
517 resource_type = "OS::Neutron::Port"
518 exclude_parameter = re.compile(r"^((?!_int_).)*$")
520 invalid_parameters = check_resource_parameter(
525 nested_prop=nested_prop,
526 exclude_parameter=exclude_parameter,
529 assert not invalid_parameters, (
530 "{} {} internal parameters"
531 " not found in {} environment file {}".format(
532 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
537 @validates("R-83677", "R-80829", "R-69634", "R-22288")
538 def test_neutron_port_fixedips_subnet_parameter_doesnt_exist_in_environment_file(
542 if pytest.config.getoption("validation_profile") == "heat_only":
543 pytest.skip("skipping test because validation profile is heat only")
545 environment_pair = get_environment_pair(heat_template)
548 nested_prop = "subnet"
550 resource_type = "OS::Neutron::Port"
552 invalid_parameters = check_resource_parameter(
553 environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
556 assert not invalid_parameters, (
558 " found in {} environment file {}".format(
559 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
564 @validates("R-83412", "R-83418")
565 def test_neutron_port_aap_ip_parameter_doesnt_exist_in_environment_file(heat_template):
567 if pytest.config.getoption("validation_profile") == "heat_only":
568 pytest.skip("skipping test because validation profile is heat only")
570 environment_pair = get_environment_pair(heat_template)
572 prop = "allowed_address_pairs"
573 nested_prop = "ip_address"
575 resource_type = "OS::Neutron::Port"
577 invalid_parameters = check_resource_parameter(
578 environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
581 assert not invalid_parameters, (
583 " found in {} environment file {}".format(
584 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
589 @validates("R-99812")
590 def test_non_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
592 if pytest.config.getoption("validation_profile") == "heat_only":
593 pytest.skip("skipping test because validation profile is heat only")
595 environment_pair = get_environment_pair(heat_template)
599 resource_type = "OS::Nova::Server"
601 invalid_parameters = check_resource_parameter(
602 environment_pair, prop, DESIRED, resource_type, resource_type_inverse=True
605 assert not invalid_parameters, (
606 "non-{} {} parameters"
607 " found in {} environment file {}".format(
608 resource_type, prop, environment_pair.get("name"), invalid_parameters
613 @validates("R-92193")
614 def test_network_fqdn_parameter_doesnt_exist_in_environment_file(heat_template):
616 if pytest.config.getoption("validation_profile") == "heat_only":
617 pytest.skip("skipping test because validation profile is heat only")
619 environment_pair = get_environment_pair(heat_template)
621 prop = r"^(.+?)_net_fqdn$"
624 invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
626 assert not invalid_parameters, (
628 " found in {} environment file {}".format(
629 prop, environment_pair.get("name"), invalid_parameters
634 @validates("R-76682")
635 def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(
639 if pytest.config.getoption("validation_profile") == "heat_only":
640 pytest.skip("skipping test because validation profile is heat only")
642 environment_pair = get_environment_pair(heat_template)
644 prop = "interface_route_table_routes"
645 nested_prop = "interface_route_table_routes_route"
647 resource_type = "OS::ContrailV2::InterfaceRouteTable"
649 invalid_parameters = check_resource_parameter(
650 environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
653 assert not invalid_parameters, (
655 " found in {} environment file {}".format(
656 resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
661 @validates("R-50011")
662 def test_heat_rg_count_parameter_exists_in_environment_file(heat_template):
664 if pytest.config.getoption("validation_profile") == "heat_only":
665 pytest.skip("skipping test because validation profile is heat only")
667 environment_pair = get_environment_pair(heat_template)
671 resource_type = "OS::Heat::ResourceGroup"
672 exclude_resource = re.compile(r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$")
674 invalid_parameters = check_resource_parameter(
679 exclude_resource=exclude_resource,
682 assert not invalid_parameters, (
683 "{} {} parameters not"
684 " found in {} environment file {}".format(
685 resource_type, prop, environment_pair.get("name"), invalid_parameters