1515 cleanup_global_controls
1616from chaoslib .deprecation import warn_about_deprecated_features
1717from chaoslib .exceptions import ActivityFailed , ChaosException , \
18- InterruptExecution , InvalidActivity , InvalidExperiment , ValidationError
18+ InterruptExecution , InvalidActivity , InvalidExperiment , \
19+ ValidationError as ValidationErrorException
1920from chaoslib .extension import validate_extensions
2021from chaoslib .configuration import load_configuration
2122from chaoslib .hypothesis import ensure_hypothesis_is_valid , \
2526from chaoslib .secret import load_secrets
2627from chaoslib .settings import get_loaded_settings
2728from chaoslib .types import Configuration , Experiment , Journal , Run , Secrets , \
28- Settings
29+ Settings , ValidationError
30+ from chaoslib .validation import Validation
2931
3032initialize_global_controls
3133__all__ = ["ensure_experiment_is_valid" , "run_experiment" , "load_experiment" ]
3234
3335
3436@with_cache
35- def ensure_experiment_is_valid (experiment : Experiment ):
37+ def ensure_experiment_is_valid (experiment : Experiment ,
38+ no_raise : bool = False
39+ ) -> List [ValidationError ]:
3640 """
3741 A chaos experiment consists of a method made of activities to carry
3842 sequentially.
@@ -52,66 +56,78 @@ def ensure_experiment_is_valid(experiment: Experiment):
5256 if the experiment is not valid.
5357 If multiple validation errors are found, the errors are listed
5458 as part of the exception message
59+
60+ If `no_raise` is True, the function will not raise any
61+ exception but rather return the list of validation errors
5562 """
5663 logger .info ("Validating the experiment's syntax" )
5764
58- full_validation_msg = 'Experiment is not valid, ' \
59- 'please fix the following errors'
60- errors = []
65+ full_validation_msg = "Experiment is not valid, " \
66+ "please fix the following errors. " \
67+ "\n {}"
68+ v = Validation ()
6169
6270 if not experiment :
71+ v .add_error ("$" , "an empty experiment is not an experiment" )
6372 # empty experiment, cannot continue validation any further
64- raise ValidationError (full_validation_msg ,
65- "an empty experiment is not an experiment" )
73+ if no_raise :
74+ return v .errors ()
75+ raise InvalidExperiment (full_validation_msg .format (str (v )))
6676
6777 if not experiment .get ("title" ):
68- errors . append ( InvalidExperiment ( " experiment requires a title") )
78+ v . add_error ( "title" , " experiment requires a title" )
6979
7080 if not experiment .get ("description" ):
71- errors . append ( InvalidExperiment ( " experiment requires a description") )
81+ v . add_error ( "description" , " experiment requires a description" )
7282
7383 tags = experiment .get ("tags" )
7484 if tags :
7585 if list (filter (lambda t : t == '' or not isinstance (t , str ), tags )):
76- errors .append (InvalidExperiment (
77- "experiment tags must be a non-empty string" ))
86+ v .add_error ("tags" , "experiment tags must be a non-empty string" )
7887
79- errors . extend (validate_extensions (experiment ))
88+ v . extend_errors (validate_extensions (experiment ))
8089
8190 config = load_configuration (experiment .get ("configuration" , {}))
8291 load_secrets (experiment .get ("secrets" , {}), config )
8392
84- errors . extend (ensure_hypothesis_is_valid (experiment ))
93+ v . extend_errors (ensure_hypothesis_is_valid (experiment ))
8594
8695 method = experiment .get ("method" )
8796 if not method :
88- errors .append (InvalidExperiment ("an experiment requires a method with "
89- "at least one activity" ))
97+ v .add_error (
98+ "method" ,
99+ "an experiment requires a method with at least one activity" )
90100 else :
91101 for activity in method :
92- errors . extend (ensure_activity_is_valid (activity ))
102+ v . extend_errors (ensure_activity_is_valid (activity ))
93103
94104 # let's see if a ref is indeed found in the experiment
95105 ref = activity .get ("ref" )
96106 if ref and not lookup_activity (ref ):
97- errors .append (
98- InvalidActivity ("referenced activity '{r}' could not be "
99- "found in the experiment" .format (r = ref )))
107+ v .add_error (
108+ "ref" ,
109+ "referenced activity '{r}' could not be "
110+ "found in the experiment" .format (r = ref ),
111+ value = ref
112+ )
100113
101114 rollbacks = experiment .get ("rollbacks" , [])
102115 for activity in rollbacks :
103- errors . extend (ensure_activity_is_valid (activity ))
116+ v . extend_errors (ensure_activity_is_valid (activity ))
104117
105118 warn_about_deprecated_features (experiment )
106119
107- errors . extend (validate_controls (experiment ))
120+ v . extend_errors (validate_controls (experiment ))
108121
109- if errors :
110- raise ValidationError (full_validation_msg , errors )
122+ if v .has_errors ():
123+ if no_raise :
124+ return v .errors ()
125+ raise InvalidExperiment (full_validation_msg .format (str (v )))
111126
112127 logger .info ("Experiment looks valid" )
113128
114129
130+
115131def initialize_run_journal (experiment : Experiment ) -> Journal :
116132 return {
117133 "chaoslib-version" : __version__ ,
0 commit comments