[VVP] updating validation scripts in dublin
[vvp/validation-scripts.git] / ice_validator / tests / test_environment_file_parameters.py
1 # -*- coding: utf8 -*-
2 # ============LICENSE_START====================================================
3 # org.onap.vvp/validation-scripts
4 # ===================================================================
5 # Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 # ===================================================================
7 #
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
12 #
13 #             http://www.apache.org/licenses/LICENSE-2.0
14 #
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.
20 #
21 #
22 #
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
27 #
28 #             https://creativecommons.org/licenses/by/4.0/
29 #
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.
35 #
36 # ============LICENSE_END============================================
37 #
38 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
39 #
40
41 """ environment file structure
42 """
43 import re
44 import pytest
45
46 from .helpers import validates, get_environment_pair
47
48
49 VERSION = "1.0.0"
50
51 # pylint: disable=invalid-name
52
53
54 def check_parameter_exists(pattern, parameters):
55     if not parameters:
56         return False
57
58     for param in parameters:
59         if pattern.search(param):
60             return True
61
62     return False
63
64
65 def check_param_in_env_file(environment_pair, param, DESIRED, exclude_parameter=None):
66
67     # workaround for internal/external parameters
68     if exclude_parameter and re.match(exclude_parameter, param):
69         return False
70
71     if not environment_pair:
72         pytest.skip("No heat/env pair could be identified")
73
74     env_file = environment_pair.get("eyml")
75
76     pattern = re.compile(r"^{}$".format(param))
77
78     if "parameters" not in env_file:
79         pytest.skip("No parameters specified in the environment file")
80
81     return (
82         check_parameter_exists(pattern, env_file.get("parameters", {})) is not DESIRED
83     )
84
85
86 """
87 This function supports this structure, deviations
88 may or may not work without enhancement
89
90 resource_id:
91     type: <resource_type>
92     properties:
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 }
99 """
100
101
102 def check_resource_parameter(
103     environment_pair,
104     prop,
105     DESIRED,
106     resource_type,
107     resource_type_inverse=False,
108     nested_prop="",
109     exclude_resource="",
110     exclude_parameter="",
111 ):
112
113     if not environment_pair:
114         pytest.skip("No heat/env pair could be identified")
115
116     env_file = environment_pair.get("eyml")
117     template_file = environment_pair.get("yyml")
118
119     if "parameters" not in env_file:
120         pytest.skip("No parameters specified in the environment file")
121
122     invalid_parameters = []
123
124     if template_file:
125         for resource, resource_prop in template_file.get("resources", {}).items():
126
127             # workaround for subinterface resource groups
128             if exclude_resource and re.match(exclude_resource, resource):
129                 continue
130
131             if (
132                 resource_prop.get("type") == resource_type and not resource_type_inverse
133             ) or (resource_prop.get("type") != resource_type and resource_type_inverse):
134
135                 pattern = False
136
137                 if not resource_prop.get("properties"):
138                     continue
139
140                 resource_parameter = resource_prop.get("properties").get(prop)
141
142                 if not resource_parameter:
143                     continue
144
145                 if isinstance(resource_parameter, list) and nested_prop:
146                     for param in resource_parameter:
147
148                         nested_param = param.get(nested_prop)
149                         if not nested_param:
150                             continue
151
152                         if isinstance(nested_param, dict):
153                             pattern = nested_param.get("get_param")
154                         else:
155                             pattern = ""
156
157                         if not pattern:
158                             continue
159
160                         if isinstance(pattern, list):
161                             pattern = pattern[0]
162
163                         if check_param_in_env_file(
164                             environment_pair,
165                             pattern,
166                             DESIRED,
167                             exclude_parameter=exclude_parameter,
168                         ):
169                             invalid_parameters.append(pattern)
170
171                 elif isinstance(resource_parameter, dict):
172
173                     if nested_prop and nested_prop in resource_parameter:
174                         resource_parameter = resource_parameter.get(nested_prop)
175
176                     pattern = resource_parameter.get("get_param")
177                     if not pattern:
178                         continue
179
180                     if check_param_in_env_file(
181                         environment_pair,
182                         pattern,
183                         DESIRED,
184                         exclude_parameter=exclude_parameter,
185                     ):
186                         invalid_parameters.append(pattern)
187                 else:
188                     continue
189
190     return set(invalid_parameters)
191
192
193 @validates("R-91125")
194 def test_nova_server_image_parameter_exists_in_environment_file(heat_template):
195
196     if pytest.config.getoption("validation_profile") == "heat_only":
197         pytest.skip("skipping test because validation profile is heat only")
198
199     environment_pair = get_environment_pair(heat_template)
200
201     prop = "image"
202     DESIRED = True
203     resource_type = "OS::Nova::Server"
204
205     invalid_parameters = check_resource_parameter(
206         environment_pair, prop, DESIRED, resource_type
207     )
208
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
213         )
214     )
215
216
217 @validates("R-69431")
218 def test_nova_server_flavor_parameter_exists_in_environment_file(heat_template):
219
220     if pytest.config.getoption("validation_profile") == "heat_only":
221         pytest.skip("skipping test because validation profile is heat only")
222
223     environment_pair = get_environment_pair(heat_template)
224
225     prop = "flavor"
226     DESIRED = True
227     resource_type = "OS::Nova::Server"
228
229     invalid_parameters = check_resource_parameter(
230         environment_pair, prop, DESIRED, resource_type
231     )
232
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
237         )
238     )
239
240
241 @validates("R-22838")
242 def test_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
243
244     if pytest.config.getoption("validation_profile") == "heat_only":
245         pytest.skip("skipping test because validation profile is heat only")
246
247     environment_pair = get_environment_pair(heat_template)
248
249     prop = "name"
250     DESIRED = False
251     resource_type = "OS::Nova::Server"
252
253     invalid_parameters = check_resource_parameter(
254         environment_pair, prop, DESIRED, resource_type
255     )
256
257     assert not invalid_parameters, (
258         "OS::Nova::Server {} parameters"
259         " found in {} environment file {}".format(
260             prop, environment_pair.get("name"), invalid_parameters
261         )
262     )
263
264
265 @validates("R-59568")
266 def test_nova_server_az_parameter_doesnt_exist_in_environment_file(heat_template):
267
268     if pytest.config.getoption("validation_profile") == "heat_only":
269         pytest.skip("skipping test because validation profile is heat only")
270
271     environment_pair = get_environment_pair(heat_template)
272
273     prop = "availability_zone"
274     DESIRED = False
275     resource_type = "OS::Nova::Server"
276
277     invalid_parameters = check_resource_parameter(
278         environment_pair, prop, DESIRED, resource_type
279     )
280
281     assert not invalid_parameters, (
282         "OS::Nova::Server {} parameters"
283         " found in {} environment file {}".format(
284             prop, environment_pair.get("name"), invalid_parameters
285         )
286     )
287
288
289 @validates("R-20856")
290 def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(heat_template):
291
292     if pytest.config.getoption("validation_profile") == "heat_only":
293         pytest.skip("skipping test because validation profile is heat only")
294
295     environment_pair = get_environment_pair(heat_template)
296
297     prop = "vnf_id"
298     DESIRED = False
299
300     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
301
302     assert not invalid_parameters, (
303         "{} parameters"
304         " found in {} environment file {}".format(
305             prop, environment_pair.get("name"), invalid_parameters
306         )
307     )
308
309
310 @validates("R-72871")
311 def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(
312     heat_template
313 ):
314
315     if pytest.config.getoption("validation_profile") == "heat_only":
316         pytest.skip("skipping test because validation profile is heat only")
317
318     environment_pair = get_environment_pair(heat_template)
319
320     prop = "vf_module_id"
321     DESIRED = False
322
323     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
324
325     assert not invalid_parameters, (
326         "{} parameters"
327         " found in {} environment file {}".format(
328             prop, environment_pair.get("name"), invalid_parameters
329         )
330     )
331
332
333 @validates("R-37039")
334 def test_nova_server_vf_module_index_parameter_doesnt_exist_in_environment_file(
335     heat_template
336 ):
337
338     if pytest.config.getoption("validation_profile") == "heat_only":
339         pytest.skip("skipping test because validation profile is heat only")
340
341     environment_pair = get_environment_pair(heat_template)
342
343     prop = "vf_module_index"
344     DESIRED = False
345
346     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
347
348     assert not invalid_parameters, (
349         "{} parameters"
350         " found in {} environment file {}".format(
351             prop, environment_pair.get("name"), invalid_parameters
352         )
353     )
354
355
356 @validates("R-36542")
357 def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(heat_template):
358
359     if pytest.config.getoption("validation_profile") == "heat_only":
360         pytest.skip("skipping test because validation profile is heat only")
361
362     environment_pair = get_environment_pair(heat_template)
363
364     prop = "vnf_name"
365     DESIRED = False
366
367     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
368
369     assert not invalid_parameters, (
370         "{} parameters"
371         " found in {} environment file {}".format(
372             prop, environment_pair.get("name"), invalid_parameters
373         )
374     )
375
376
377 @validates("R-80374")
378 def test_nova_server_vf_module_name_parameter_doesnt_exist_in_environment_file(
379     heat_template
380 ):
381
382     if pytest.config.getoption("validation_profile") == "heat_only":
383         pytest.skip("skipping test because validation profile is heat only")
384
385     environment_pair = get_environment_pair(heat_template)
386
387     prop = "vf_module_name"
388     DESIRED = False
389
390     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
391
392     assert not invalid_parameters, (
393         "{} parameters"
394         " found in {} environment file {}".format(
395             prop, environment_pair.get("name"), invalid_parameters
396         )
397     )
398
399
400 @validates("R-02691")
401 def test_nova_server_workload_context_parameter_doesnt_exist_in_environment_file(
402     heat_template
403 ):
404
405     if pytest.config.getoption("validation_profile") == "heat_only":
406         pytest.skip("skipping test because validation profile is heat only")
407
408     environment_pair = get_environment_pair(heat_template)
409
410     prop = "workload_context"
411     DESIRED = False
412
413     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
414
415     assert not invalid_parameters, (
416         "{} parameters"
417         " found in {} environment file {}".format(
418             prop, environment_pair.get("name"), invalid_parameters
419         )
420     )
421
422
423 @validates("R-13194")
424 def test_nova_server_environment_context_parameter_doesnt_exist_in_environment_file(
425     heat_template
426 ):
427
428     if pytest.config.getoption("validation_profile") == "heat_only":
429         pytest.skip("skipping test because validation profile is heat only")
430
431     environment_pair = get_environment_pair(heat_template)
432
433     prop = "environment_context"
434     DESIRED = False
435
436     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
437
438     assert not invalid_parameters, (
439         "{} parameters"
440         " found in {} environment file {}".format(
441             prop, environment_pair.get("name"), invalid_parameters
442         )
443     )
444
445
446 @validates("R-29872")
447 def test_nova_server_network_parameter_doesnt_exist_in_environment_file(heat_template):
448
449     if pytest.config.getoption("validation_profile") == "heat_only":
450         pytest.skip("skipping test because validation profile is heat only")
451
452     environment_pair = get_environment_pair(heat_template)
453
454     prop = "networks"
455     nested_prop = "network"
456     DESIRED = False
457     resource_type = "OS::Nova::Server"
458
459     invalid_parameters = check_resource_parameter(
460         environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
461     )
462
463     assert not invalid_parameters, (
464         "{} {} parameters"
465         " found in {} environment file {}".format(
466             resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
467         )
468     )
469
470
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(
473     heat_template
474 ):
475
476     if pytest.config.getoption("validation_profile") == "heat_only":
477         pytest.skip("skipping test because validation profile is heat only")
478
479     environment_pair = get_environment_pair(heat_template)
480
481     prop = "fixed_ips"
482     nested_prop = "ip_address"
483     DESIRED = False
484     resource_type = "OS::Neutron::Port"
485     exclude_parameter = re.compile(r"^(.+?)_int_(.+?)$")
486
487     invalid_parameters = check_resource_parameter(
488         environment_pair,
489         prop,
490         DESIRED,
491         resource_type,
492         nested_prop=nested_prop,
493         exclude_parameter=exclude_parameter,
494     )
495
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
500         )
501     )
502
503
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(
506     heat_template
507 ):
508
509     if pytest.config.getoption("validation_profile") == "heat_only":
510         pytest.skip("skipping test because validation profile is heat only")
511
512     environment_pair = get_environment_pair(heat_template)
513
514     prop = "fixed_ips"
515     nested_prop = "ip_address"
516     DESIRED = True
517     resource_type = "OS::Neutron::Port"
518     exclude_parameter = re.compile(r"^((?!_int_).)*$")
519
520     invalid_parameters = check_resource_parameter(
521         environment_pair,
522         prop,
523         DESIRED,
524         resource_type,
525         nested_prop=nested_prop,
526         exclude_parameter=exclude_parameter,
527     )
528
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
533         )
534     )
535
536
537 @validates("R-83677", "R-80829", "R-69634", "R-22288")
538 def test_neutron_port_fixedips_subnet_parameter_doesnt_exist_in_environment_file(
539     heat_template
540 ):
541
542     if pytest.config.getoption("validation_profile") == "heat_only":
543         pytest.skip("skipping test because validation profile is heat only")
544
545     environment_pair = get_environment_pair(heat_template)
546
547     prop = "fixed_ips"
548     nested_prop = "subnet"
549     DESIRED = False
550     resource_type = "OS::Neutron::Port"
551
552     invalid_parameters = check_resource_parameter(
553         environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
554     )
555
556     assert not invalid_parameters, (
557         "{} {} parameters"
558         " found in {} environment file {}".format(
559             resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
560         )
561     )
562
563
564 @validates("R-83412", "R-83418")
565 def test_neutron_port_aap_ip_parameter_doesnt_exist_in_environment_file(heat_template):
566
567     if pytest.config.getoption("validation_profile") == "heat_only":
568         pytest.skip("skipping test because validation profile is heat only")
569
570     environment_pair = get_environment_pair(heat_template)
571
572     prop = "allowed_address_pairs"
573     nested_prop = "ip_address"
574     DESIRED = False
575     resource_type = "OS::Neutron::Port"
576
577     invalid_parameters = check_resource_parameter(
578         environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
579     )
580
581     assert not invalid_parameters, (
582         "{} {} parameters"
583         " found in {} environment file {}".format(
584             resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
585         )
586     )
587
588
589 @validates("R-99812")
590 def test_non_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
591
592     if pytest.config.getoption("validation_profile") == "heat_only":
593         pytest.skip("skipping test because validation profile is heat only")
594
595     environment_pair = get_environment_pair(heat_template)
596
597     prop = "name"
598     DESIRED = False
599     resource_type = "OS::Nova::Server"
600
601     invalid_parameters = check_resource_parameter(
602         environment_pair, prop, DESIRED, resource_type, resource_type_inverse=True
603     )
604
605     assert not invalid_parameters, (
606         "non-{} {} parameters"
607         " found in {} environment file {}".format(
608             resource_type, prop, environment_pair.get("name"), invalid_parameters
609         )
610     )
611
612
613 @validates("R-92193")
614 def test_network_fqdn_parameter_doesnt_exist_in_environment_file(heat_template):
615
616     if pytest.config.getoption("validation_profile") == "heat_only":
617         pytest.skip("skipping test because validation profile is heat only")
618
619     environment_pair = get_environment_pair(heat_template)
620
621     prop = r"^(.+?)_net_fqdn$"
622     DESIRED = False
623
624     invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
625
626     assert not invalid_parameters, (
627         "{} parameters"
628         " found in {} environment file {}".format(
629             prop, environment_pair.get("name"), invalid_parameters
630         )
631     )
632
633
634 @validates("R-76682")
635 def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(
636     heat_template
637 ):
638
639     if pytest.config.getoption("validation_profile") == "heat_only":
640         pytest.skip("skipping test because validation profile is heat only")
641
642     environment_pair = get_environment_pair(heat_template)
643
644     prop = "interface_route_table_routes"
645     nested_prop = "interface_route_table_routes_route"
646     DESIRED = False
647     resource_type = "OS::ContrailV2::InterfaceRouteTable"
648
649     invalid_parameters = check_resource_parameter(
650         environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
651     )
652
653     assert not invalid_parameters, (
654         "{} {} parameters"
655         " found in {} environment file {}".format(
656             resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
657         )
658     )
659
660
661 @validates("R-50011")
662 def test_heat_rg_count_parameter_exists_in_environment_file(heat_template):
663
664     if pytest.config.getoption("validation_profile") == "heat_only":
665         pytest.skip("skipping test because validation profile is heat only")
666
667     environment_pair = get_environment_pair(heat_template)
668
669     prop = "count"
670     DESIRED = True
671     resource_type = "OS::Heat::ResourceGroup"
672     exclude_resource = re.compile(r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$")
673
674     invalid_parameters = check_resource_parameter(
675         environment_pair,
676         prop,
677         DESIRED,
678         resource_type,
679         exclude_resource=exclude_resource,
680     )
681
682     assert not invalid_parameters, (
683         "{} {} parameters not"
684         " found in {} environment file {}".format(
685             resource_type, prop, environment_pair.get("name"), invalid_parameters
686         )
687     )