1
1
# pylint: disable=no-name-in-module,line-too-long
2
2
import logging
3
- from enum import Enum
4
3
from typing import Any , Dict , List , Optional
5
4
6
5
from botocore .config import Config
7
6
8
7
from aws_lambda_powertools .utilities .parameters import AppConfigProvider , GetParameterError , TransformParameterError
9
8
9
+ from . import schema
10
10
from .exceptions import ConfigurationException
11
11
12
12
TRANSFORM_TYPE = "json"
13
- FEATURES_KEY = "features"
14
- RULES_KEY = "rules"
15
- DEFAULT_VAL_KEY = "feature_default_value"
16
- RESTRICTIONS_KEY = "restrictions"
17
- RULE_NAME_KEY = "name"
18
- RULE_DEFAULT_VALUE = "rule_default_value"
19
- RESTRICTION_KEY = "key"
20
- RESTRICTION_VALUE = "value"
21
- RESTRICTION_ACTION = "action"
22
-
23
-
24
- class ACTION (str , Enum ):
25
- EQUALS = "EQUALS"
26
- STARTSWITH = "STARTSWITH"
27
- ENDSWITH = "ENDSWITH"
28
- CONTAINS = "CONTAINS"
29
-
30
13
31
14
logger = logging .getLogger (__name__ )
32
15
@@ -44,28 +27,26 @@ def __init__(
44
27
cache_seconds (int): cache expiration time, how often to call AppConfig to fetch latest configuration
45
28
"""
46
29
self ._cache_seconds = cache_seconds
47
- self .logger = logger
30
+ self ._logger = logger
48
31
self ._conf_name = conf_name
32
+ self ._schema_validator = schema .SchemaValidator (self ._logger )
49
33
self ._conf_store = AppConfigProvider (environment = environment , application = service , config = config )
50
34
51
- def _validate_json_schema (self , schema : Dict [str , Any ]) -> bool :
52
- #
53
- return True
54
-
55
35
def _match_by_action (self , action : str , restriction_value : Any , context_value : Any ) -> bool :
56
36
if not context_value :
57
37
return False
58
38
mapping_by_action = {
59
- ACTION .EQUALS .value : lambda a , b : a == b ,
60
- ACTION .STARTSWITH .value : lambda a , b : a .startswith (b ),
61
- ACTION .ENDSWITH .value : lambda a , b : a .endswith (b ),
62
- ACTION .CONTAINS .value : lambda a , b : a in b ,
39
+ schema . ACTION .EQUALS .value : lambda a , b : a == b ,
40
+ schema . ACTION .STARTSWITH .value : lambda a , b : a .startswith (b ),
41
+ schema . ACTION .ENDSWITH .value : lambda a , b : a .endswith (b ),
42
+ schema . ACTION .CONTAINS .value : lambda a , b : a in b ,
63
43
}
64
44
65
45
try :
66
46
func = mapping_by_action .get (action , lambda a , b : False )
67
47
return func (context_value , restriction_value )
68
- except Exception :
48
+ except Exception as exc :
49
+ self ._logger .error (f"caught exception while matching action, action={ action } , exception={ str (exc )} " )
69
50
return False
70
51
71
52
def _handle_rules (
@@ -77,15 +58,17 @@ def _handle_rules(
77
58
rules : List [Dict [str , Any ]],
78
59
) -> bool :
79
60
for rule in rules :
80
- rule_name = rule .get (RULE_NAME_KEY , "" )
81
- rule_default_value = rule .get (RULE_DEFAULT_VALUE )
61
+ rule_name = rule .get (schema . RULE_NAME_KEY , "" )
62
+ rule_default_value = rule .get (schema . RULE_DEFAULT_VALUE )
82
63
is_match = True
83
- restrictions : Dict [str , str ] = rule .get (RESTRICTIONS_KEY )
64
+ restrictions : Dict [str , str ] = rule .get (schema . RESTRICTIONS_KEY )
84
65
85
66
for restriction in restrictions :
86
- context_value = rules_context .get (restriction .get (RESTRICTION_KEY , "" ), "" )
67
+ context_value = rules_context .get (restriction .get (schema . RESTRICTION_KEY ) )
87
68
if not self ._match_by_action (
88
- restriction .get (RESTRICTION_ACTION ), restriction .get (RESTRICTION_VALUE ), context_value
69
+ restriction .get (schema .RESTRICTION_ACTION ),
70
+ restriction .get (schema .RESTRICTION_VALUE ),
71
+ context_value ,
89
72
):
90
73
logger .debug (
91
74
f"rule did not match action, rule_name={ rule_name } , rule_default_value={ rule_default_value } , feature_name={ feature_name } , context_value={ str (context_value )} " # noqa: E501
@@ -121,13 +104,11 @@ def get_configuration(self) -> Dict[str, Any]:
121
104
) # parse result conf as JSON, keep in cache for self.max_age seconds
122
105
except (GetParameterError , TransformParameterError ) as exc :
123
106
error_str = f"unable to get AWS AppConfig configuration file, exception={ str (exc )} "
124
- logger .error (error_str )
107
+ self . _logger .error (error_str )
125
108
raise ConfigurationException (error_str )
109
+
126
110
# validate schema
127
- if not self ._validate_json_schema (schema ):
128
- error_str = "AWS AppConfig schema failed validation"
129
- logger .error (error_str )
130
- raise ConfigurationException (error_str )
111
+ self ._schema_validator .validate_json_schema (schema )
131
112
return schema
132
113
133
114
def get_feature_toggle (self , * , feature_name : str , rules_context : Dict [str , Any ], value_if_missing : bool ) -> bool :
@@ -156,15 +137,15 @@ def get_feature_toggle(self, *, feature_name: str, rules_context: Dict[str, Any]
156
137
logger .error ("unable to get feature toggles JSON, returning provided value_if_missing value" ) # noqa: E501
157
138
return value_if_missing
158
139
159
- feature : Dict [str , Dict ] = toggles_dict .get (FEATURES_KEY , {}).get (feature_name , None )
140
+ feature : Dict [str , Dict ] = toggles_dict .get (schema . FEATURES_KEY , {}).get (feature_name , None )
160
141
if feature is None :
161
142
logger .warning (
162
143
f"feature does not appear in configuration, using provided value_if_missing, feature_name={ feature_name } , value_if_missing={ value_if_missing } " # noqa: E501
163
144
)
164
145
return value_if_missing
165
146
166
- rules_list = feature .get (RULES_KEY , [] )
167
- feature_default_value = feature .get (DEFAULT_VAL_KEY )
147
+ rules_list = feature .get (schema . RULES_KEY )
148
+ feature_default_value = feature .get (schema . FEATURE_DEFAULT_VAL_KEY )
168
149
if not rules_list :
169
150
# not rules but has a value
170
151
logger .debug (
0 commit comments