qontract-reconcile 0.10.2.dev44__py3-none-any.whl → 0.10.2.dev46__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev44
3
+ Version: 0.10.2.dev46
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
6
6
  Project-URL: repository, https://github.com/app-sre/qontract-reconcile
@@ -195,17 +195,17 @@ reconcile/endpoints_discovery/integration.py,sha256=fzy5tv4c_6WoAZGGBNJ276NVNB1O
195
195
  reconcile/endpoints_discovery/merge_request.py,sha256=_yLb4tnvoZMCko8rta2C_CvOInJa9pa3HzSmHNtjgGU,2978
196
196
  reconcile/endpoints_discovery/merge_request_manager.py,sha256=wUMsumxv8RnWaRattax4HfoRlhtVzmgro3GiJJ1C4Vc,6392
197
197
  reconcile/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
198
- reconcile/external_resources/aws.py,sha256=2vimGEtcwcIyVaFvt5Ab2PAAWu2hawJyCu4fuZWSobI,7783
199
- reconcile/external_resources/factories.py,sha256=ldvm3n13IdE899Ei850NSf0RQ35rzsKJBCUkROrbE5Y,5579
198
+ reconcile/external_resources/aws.py,sha256=KAs656zj4oZYpVbgWsDLXnJWJlLOZdR1JnRhikbF4x0,10712
199
+ reconcile/external_resources/factories.py,sha256=C0QHT0soEv6z99-ELAAE19S5MaMHhV0t1fSiQn0Coc4,5970
200
200
  reconcile/external_resources/integration.py,sha256=JF38M7R0Z4ADUTx57TZqSZH9k_xpPlbAxQAcGyIISuM,6925
201
201
  reconcile/external_resources/integration_secrets_sync.py,sha256=dX09O3r6KURziUYYfiki10orNjOGVma-XojhVqd0ww4,1667
202
- reconcile/external_resources/manager.py,sha256=DtxjWx34WdPjPR5TzqV4mZpN_Gn20LcNTZHBbPxqzuQ,16953
202
+ reconcile/external_resources/manager.py,sha256=ZagwLn6YQ1XmgmMN3qpuDzQsQxa4VOYl-IQPZBwCDqM,17103
203
203
  reconcile/external_resources/meta.py,sha256=noaytFzmShpzLA_ebGh7wuP45mOfHIOnnoUxivjDa1I,672
204
204
  reconcile/external_resources/metrics.py,sha256=KiBjMUaN_z0cSkF_7Ar_a8RiuiwVqjyMcVdISlxhzXE,3898
205
- reconcile/external_resources/model.py,sha256=EpgIgVRPUsyfHhgjHv_TLUKjzFiIQt0wUd30K0NJJpI,11826
206
- reconcile/external_resources/reconciler.py,sha256=K9QvbQCIOCuOHnPIxQE_P_jFtrkF3dGo8d_cCCh08Ys,8973
205
+ reconcile/external_resources/model.py,sha256=dxwiyI3J9xyLeue8_W9NJoap-CkKLMAoY0S0ml5-NbU,13450
206
+ reconcile/external_resources/reconciler.py,sha256=PK00cyMfBZLHH0W7w2bNomgAy85SotIVXbCBkGPSJdM,9432
207
207
  reconcile/external_resources/secrets_sync.py,sha256=50fK4fzgSz-K8uy5_DQQWA_ju_rTDYAC2HRymgfY7TA,16344
208
- reconcile/external_resources/state.py,sha256=ye8yjMoCtTHSRhDH7skFLDIHIuYTjisWYCTJrwnmbEw,9565
208
+ reconcile/external_resources/state.py,sha256=gF3ACdl7YiUlbQ4uEGrD6i_Txxqr6mT9f8IFlTQ-8dY,13176
209
209
  reconcile/glitchtip/README.md,sha256=rfXT6jNP9khJW65jL7I2PgoxvxgcGGuJF8NpbzufEQ4,4335
210
210
  reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
211
211
  reconcile/glitchtip/integration.py,sha256=vCyg8W4ZUGxjU8tB1Gkre_auSpzo83n05mmO8_-7al0,8263
@@ -215,7 +215,7 @@ reconcile/glitchtip_project_alerts/integration.py,sha256=BgMx-NyV9mTuv7Sotb2OioC
215
215
  reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
216
216
  reconcile/glitchtip_project_dsn/integration.py,sha256=2iugub-kHYkHNK33n0v9_TeWonuxCPah_VkoTPvaajE,8077
217
217
  reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
- reconcile/gql_definitions/introspection.json,sha256=6e7VKZ_Ds1-fNKLF8Jf3yOHZ0SiIeYhAY277cpSoPdE,2235110
218
+ reconcile/gql_definitions/introspection.json,sha256=jAWK0rPdJY39eevr2NWgD8lqbJew_m5BIhyEMbb_3lo,2236885
219
219
  reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
220
  reconcile/gql_definitions/acs/acs_instances.py,sha256=L91WW9LbhJbBSrECqShQpFtjoBOsmNIYLRpMbx1io5o,2181
221
221
  reconcile/gql_definitions/acs/acs_policies.py,sha256=bN5i4mks10Z23KJSj7jqp966Osq2dps4d-sPH9gjxEA,7008
@@ -299,9 +299,11 @@ reconcile/gql_definitions/endpoints_discovery/__init__.py,sha256=47DEQpj8HBSa-_T
299
299
  reconcile/gql_definitions/endpoints_discovery/apps.py,sha256=aBWRAwDUJQ32ghJS4cPQcR9SNl20Fcwd3pxHDB3YJQY,3172
300
300
  reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
301
301
  reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=XR69j9dpTQ0gv8y-AZN7AJ0dPvO-wbHscyCDgrax6Bk,2046
302
- reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=cbbvGq1Te9DP8XiFg3bp4Y0q6LxpGYov8ugcROPyPLI,2647
303
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=dW7RrIA9gAJS7AHQwHggsJXhlSVnX0jV1c4W9e7a7Jc,45393
304
- reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=K8m9EKlfIVGP2KyqTduo7MMSKFjVC3yk5ZfO9hgdA7A,3192
302
+ reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=JViHtDWEBwjStBUo_bUdm_sxdpjCHcoATeFvwFRLQpU,3009
303
+ reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=-0Q48lfH-fxAvwqYfXbLQ1aP7bFFh1BRQIYPnF7W9ZI,43067
304
+ reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=WBkJqnoyYCe1Vimwbp_Pa0RdyTdmWNf6oEWyA749QzA,3589
305
+ reconcile/gql_definitions/external_resources/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
306
+ reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py,sha256=T_qWCRtzU8F9frebBXG9TkeQdrKGt3R9YinSngPoFqM,1262
305
307
  reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
306
308
  reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
307
309
  reconcile/gql_definitions/fragments/aws_account_common.py,sha256=3-7ZAP6GSff7Z2Syz2VQCLY4IySqBOSVmceaRiVNQpw,2385
@@ -751,7 +753,7 @@ tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaB
751
753
  tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
752
754
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
753
755
  tools/cli_commands/container_images_report.py,sha256=8fG9XU-eEhJ7hKCdQzBcdPpvIJR-8WGkHOgFEulpfYQ,5213
754
- tools/cli_commands/erv2.py,sha256=iqihq908iJYIQoaNq3Iofp5SQP8S-DhTurzGdnEragU,23218
756
+ tools/cli_commands/erv2.py,sha256=VxUlNXllo947UwmtvS-42IeI9x_t_X3MHrrSI3K_GRo,23274
755
757
  tools/cli_commands/gpg_encrypt.py,sha256=NhzwN49UN7P5_FJgTUN5A4BIwNbFokIE4lwDax2iP5k,4891
756
758
  tools/cli_commands/systems_and_tools.py,sha256=EMHOF1AtUDaoSk0bbjl6oUKYAz4rTZjIBaF-6E6GspM,16816
757
759
  tools/cli_commands/cost_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -773,7 +775,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
773
775
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
774
776
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
775
777
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
776
- qontract_reconcile-0.10.2.dev44.dist-info/METADATA,sha256=VYLbNmLeQFocQBk-JLSHKadTfEMFX8Oq3W0GgOBUpkk,24665
777
- qontract_reconcile-0.10.2.dev44.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
778
- qontract_reconcile-0.10.2.dev44.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
779
- qontract_reconcile-0.10.2.dev44.dist-info/RECORD,,
778
+ qontract_reconcile-0.10.2.dev46.dist-info/METADATA,sha256=C5aPbZDbkFrj5j4y25HOkeCX-7xvvhvxDFYG1ymRabE,24665
779
+ qontract_reconcile-0.10.2.dev46.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
780
+ qontract_reconcile-0.10.2.dev46.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
781
+ qontract_reconcile-0.10.2.dev46.dist-info/RECORD,,
@@ -1,9 +1,11 @@
1
+ import re
1
2
  from abc import ABC, abstractmethod
2
3
  from typing import Any
3
4
 
4
5
  from reconcile.external_resources.model import (
5
6
  ExternalResource,
6
7
  ExternalResourceKey,
8
+ ExternalResourceModuleConfiguration,
7
9
  ExternalResourcesInventory,
8
10
  )
9
11
  from reconcile.utils.external_resource_spec import (
@@ -21,10 +23,18 @@ class AWSResourceFactory(ABC):
21
23
  self.secret_reader = secret_reader
22
24
 
23
25
  @abstractmethod
24
- def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]: ...
26
+ def resolve(
27
+ self,
28
+ spec: ExternalResourceSpec,
29
+ module_conf: ExternalResourceModuleConfiguration,
30
+ ) -> dict[str, Any]: ...
25
31
 
26
32
  @abstractmethod
27
- def validate(self, resource: ExternalResource) -> None: ...
33
+ def validate(
34
+ self,
35
+ resource: ExternalResource,
36
+ module_conf: ExternalResourceModuleConfiguration,
37
+ ) -> None: ...
28
38
 
29
39
  def find_linked_resources(
30
40
  self, spec: ExternalResourceSpec
@@ -35,10 +45,18 @@ class AWSResourceFactory(ABC):
35
45
 
36
46
 
37
47
  class AWSDefaultResourceFactory(AWSResourceFactory):
38
- def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
48
+ def resolve(
49
+ self,
50
+ spec: ExternalResourceSpec,
51
+ module_conf: ExternalResourceModuleConfiguration,
52
+ ) -> dict[str, Any]:
39
53
  return ResourceValueResolver(spec=spec, identifier_as_value=True).resolve()
40
54
 
41
- def validate(self, resource: ExternalResource) -> None: ...
55
+ def validate(
56
+ self,
57
+ resource: ExternalResource,
58
+ module_conf: ExternalResourceModuleConfiguration,
59
+ ) -> None: ...
42
60
 
43
61
 
44
62
  class AWSElasticacheFactory(AWSDefaultResourceFactory):
@@ -49,7 +67,11 @@ class AWSElasticacheFactory(AWSDefaultResourceFactory):
49
67
  "aws", provisioner, "elasticache", identifier
50
68
  )
51
69
 
52
- def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
70
+ def resolve(
71
+ self,
72
+ spec: ExternalResourceSpec,
73
+ module_conf: ExternalResourceModuleConfiguration,
74
+ ) -> dict[str, Any]:
53
75
  """Resolve the elasticache resource specification and translate some attributes to AWS >= 5.60.0 provider format."""
54
76
  rvr = ResourceValueResolver(spec=spec, identifier_as_value=True)
55
77
  data = rvr.resolve()
@@ -70,7 +92,11 @@ class AWSElasticacheFactory(AWSDefaultResourceFactory):
70
92
 
71
93
  return data
72
94
 
73
- def validate(self, resource: ExternalResource) -> None:
95
+ def validate(
96
+ self,
97
+ resource: ExternalResource,
98
+ module_conf: ExternalResourceModuleConfiguration,
99
+ ) -> None:
74
100
  """Validate the elasticache resource specification."""
75
101
  data = resource.data
76
102
  if data.get("parameter_group"):
@@ -96,6 +122,8 @@ class AWSElasticacheFactory(AWSDefaultResourceFactory):
96
122
 
97
123
 
98
124
  class AWSRdsFactory(AWSDefaultResourceFactory):
125
+ TIMEOUT_RE = re.compile(r"^\d+m$")
126
+
99
127
  def _get_source_db_spec(
100
128
  self, provisioner: str, identifier: str
101
129
  ) -> ExternalResourceSpec:
@@ -110,7 +138,11 @@ class AWSRdsFactory(AWSDefaultResourceFactory):
110
138
  "aws", provisioner, "kms", identifier
111
139
  )
112
140
 
113
- def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
141
+ def resolve(
142
+ self,
143
+ spec: ExternalResourceSpec,
144
+ module_conf: ExternalResourceModuleConfiguration,
145
+ ) -> dict[str, Any]:
114
146
  rvr = ResourceValueResolver(spec=spec, identifier_as_value=True)
115
147
  data = rvr.resolve()
116
148
 
@@ -126,7 +158,7 @@ class AWSRdsFactory(AWSDefaultResourceFactory):
126
158
  sourcedb_spec = self._get_source_db_spec(
127
159
  spec.provisioner_name, data["replica_source"]
128
160
  )
129
- sourcedb = self.resolve(sourcedb_spec)
161
+ sourcedb = self.resolve(sourcedb_spec, module_conf)
130
162
  sourcedb_region = (
131
163
  sourcedb.get("region", None)
132
164
  or sourcedb_spec.provisioner["resources_default_region"]
@@ -142,9 +174,59 @@ class AWSRdsFactory(AWSDefaultResourceFactory):
142
174
  spec.provisioner_name, kms_key_id
143
175
  ).identifier
144
176
 
177
+ # If not timeouts are set, set default timeouts according to the module reconcile timeout configuration
178
+ # 5 minutes are substracted to let terraform finish gracefully before the Job is killed.
179
+ if "timeouts" not in data:
180
+ data["timeouts"] = {
181
+ "create": f"{module_conf.reconcile_timeout_minutes - 5}m",
182
+ "update": f"{module_conf.reconcile_timeout_minutes - 5}m",
183
+ "delete": f"{module_conf.reconcile_timeout_minutes - 5}m",
184
+ }
145
185
  return data
146
186
 
147
- def validate(self, resource: ExternalResource) -> None: ...
187
+ def _get_timeout_minutes(
188
+ self,
189
+ timeout: str,
190
+ ) -> int:
191
+ if not re.match(AWSRdsFactory.TIMEOUT_RE, timeout):
192
+ raise ValueError(
193
+ f"Invalid RDS instance timeout format: {timeout}. Specify timeout in minutes(m)."
194
+ )
195
+ return int(timeout[:-1])
196
+
197
+ def _validate_timeouts(
198
+ self,
199
+ resource: ExternalResource,
200
+ module_conf: ExternalResourceModuleConfiguration,
201
+ ) -> None:
202
+ timeouts = resource.data.get("timeouts")
203
+ if not timeouts:
204
+ return
205
+
206
+ if not isinstance(timeouts, dict):
207
+ raise ValueError(
208
+ "Timeouts must be a dictionary with 'create', 'update' and/or 'delete' keys."
209
+ )
210
+
211
+ allowed_keys = {"create", "update", "delete"}
212
+ if unknown_keys := timeouts.keys() - allowed_keys:
213
+ raise ValueError(
214
+ f"Timeouts must be a dictionary with 'create', 'update' and/or 'delete' keys. Offending keys: {unknown_keys}."
215
+ )
216
+
217
+ for option, timeout in timeouts.items():
218
+ timeout_minutes = self._get_timeout_minutes(timeout)
219
+ if timeout_minutes >= module_conf.reconcile_timeout_minutes:
220
+ raise ValueError(
221
+ f"RDS instance {option} timeout value {timeout_minutes} must be lower than the module reconcile_timeout_minutes value {module_conf.reconcile_timeout_minutes}."
222
+ )
223
+
224
+ def validate(
225
+ self,
226
+ resource: ExternalResource,
227
+ module_conf: ExternalResourceModuleConfiguration,
228
+ ) -> None:
229
+ self._validate_timeouts(resource, module_conf)
148
230
 
149
231
  def find_linked_resources(
150
232
  self, spec: ExternalResourceSpec
@@ -166,7 +248,11 @@ class AWSMskFactory(AWSDefaultResourceFactory):
166
248
  "aws", provisioner, "msk", identifier
167
249
  )
168
250
 
169
- def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
251
+ def resolve(
252
+ self,
253
+ spec: ExternalResourceSpec,
254
+ module_conf: ExternalResourceModuleConfiguration,
255
+ ) -> dict[str, Any]:
170
256
  rvr = ResourceValueResolver(spec=spec, identifier_as_value=True)
171
257
  data = rvr.resolve()
172
258
  data["output_prefix"] = spec.output_prefix
@@ -188,7 +274,11 @@ class AWSMskFactory(AWSDefaultResourceFactory):
188
274
  del data["users"]
189
275
  return data
190
276
 
191
- def validate(self, resource: ExternalResource) -> None:
277
+ def validate(
278
+ self,
279
+ resource: ExternalResource,
280
+ module_conf: ExternalResourceModuleConfiguration,
281
+ ) -> None:
192
282
  data = resource.data
193
283
  if (
194
284
  data["number_of_broker_nodes"]
@@ -15,6 +15,7 @@ from reconcile.external_resources.meta import QONTRACT_INTEGRATION
15
15
  from reconcile.external_resources.model import (
16
16
  ExternalResource,
17
17
  ExternalResourceKey,
18
+ ExternalResourceModuleConfiguration,
18
19
  ExternalResourceProvision,
19
20
  ExternalResourcesInventory,
20
21
  ModuleInventory,
@@ -55,11 +56,19 @@ class ObjectFactory(Generic[T]):
55
56
 
56
57
  class ExternalResourceFactory(ABC):
57
58
  @abstractmethod
58
- def create_external_resource(self, spec: ExternalResourceSpec) -> ExternalResource:
59
+ def create_external_resource(
60
+ self,
61
+ spec: ExternalResourceSpec,
62
+ module_conf: ExternalResourceModuleConfiguration,
63
+ ) -> ExternalResource:
59
64
  pass
60
65
 
61
66
  @abstractmethod
62
- def validate_external_resource(self, resource: ExternalResource) -> None:
67
+ def validate_external_resource(
68
+ self,
69
+ resource: ExternalResource,
70
+ module_conf: ExternalResourceModuleConfiguration,
71
+ ) -> None:
63
72
  pass
64
73
 
65
74
  def find_linked_resources(
@@ -121,9 +130,13 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
121
130
  self.er_inventory = er_inventory
122
131
  self.secret_reader = secret_reader
123
132
 
124
- def create_external_resource(self, spec: ExternalResourceSpec) -> ExternalResource:
133
+ def create_external_resource(
134
+ self,
135
+ spec: ExternalResourceSpec,
136
+ module_conf: ExternalResourceModuleConfiguration,
137
+ ) -> ExternalResource:
125
138
  f = self.resource_factories.get_factory(spec.provider)
126
- data = f.resolve(spec)
139
+ data = f.resolve(spec, module_conf)
127
140
  data["tags"] = spec.tags(integration=QONTRACT_INTEGRATION)
128
141
  data["default_tags"] = AWS_DEFAULT_TAGS
129
142
 
@@ -152,9 +165,13 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
152
165
 
153
166
  return ExternalResource(data=data, provision=provision)
154
167
 
155
- def validate_external_resource(self, resource: ExternalResource) -> None:
168
+ def validate_external_resource(
169
+ self,
170
+ resource: ExternalResource,
171
+ module_conf: ExternalResourceModuleConfiguration,
172
+ ) -> None:
156
173
  f = self.resource_factories.get_factory(resource.provision.provider)
157
- f.validate(resource)
174
+ f.validate(resource, module_conf)
158
175
 
159
176
  def find_linked_resources(
160
177
  self, spec: ExternalResourceSpec
@@ -197,8 +197,11 @@ class ExternalResourcesManager:
197
197
  if spec.marked_to_delete:
198
198
  continue
199
199
  module = self.module_inventory.get_from_spec(spec)
200
+ module_conf = ExternalResourceModuleConfiguration.resolve_configuration(
201
+ module, spec, self.settings
202
+ )
200
203
  try:
201
- resource = self._build_external_resource(spec)
204
+ resource = self._build_external_resource(spec, module_conf)
202
205
  except ExternalResourceValidationError as e:
203
206
  self.errors[key] = e
204
207
  continue
@@ -208,9 +211,7 @@ class ExternalResourcesManager:
208
211
  resource_hash=resource.hash(),
209
212
  input=resource.json(),
210
213
  action=Action.APPLY,
211
- module_configuration=ExternalResourceModuleConfiguration.resolve_configuration(
212
- module, spec, self.settings
213
- ),
214
+ module_configuration=module_conf,
214
215
  linked_resources=self._find_linked_resources(spec),
215
216
  )
216
217
  r.add(reconciliation)
@@ -362,10 +363,14 @@ class ExternalResourcesManager:
362
363
  )
363
364
  self.state_mgr.update_resource_status(key, ResourceStatus.CREATED)
364
365
 
365
- def _build_external_resource(self, spec: ExternalResourceSpec) -> ExternalResource:
366
+ def _build_external_resource(
367
+ self,
368
+ spec: ExternalResourceSpec,
369
+ module_conf: ExternalResourceModuleConfiguration,
370
+ ) -> ExternalResource:
366
371
  f = self.factories.get_factory(spec.provision_provider)
367
- resource = f.create_external_resource(spec)
368
- f.validate_external_resource(resource)
372
+ resource = f.create_external_resource(spec, module_conf)
373
+ f.validate_external_resource(resource, module_conf)
369
374
  return resource
370
375
 
371
376
  def _find_linked_resources(
@@ -18,7 +18,6 @@ from reconcile.gql_definitions.external_resources.external_resources_modules imp
18
18
  ExternalResourcesModuleV1,
19
19
  )
20
20
  from reconcile.gql_definitions.external_resources.external_resources_namespaces import (
21
- ExternalResourcesModuleOverridesV1,
22
21
  NamespaceTerraformProviderResourceAWSV1,
23
22
  NamespaceTerraformResourceElastiCacheV1,
24
23
  NamespaceTerraformResourceKMSV1,
@@ -29,6 +28,10 @@ from reconcile.gql_definitions.external_resources.external_resources_namespaces
29
28
  from reconcile.gql_definitions.external_resources.external_resources_settings import (
30
29
  ExternalResourcesSettingsV1,
31
30
  )
31
+ from reconcile.gql_definitions.external_resources.fragments.external_resources_module_overrides import (
32
+ ExternalResourcesModuleOverrides,
33
+ )
34
+ from reconcile.gql_definitions.fragments.deplopy_resources import DeployResourcesFields
32
35
  from reconcile.utils.exceptions import FetchResourceError
33
36
  from reconcile.utils.external_resource_spec import (
34
37
  ExternalResourceSpec,
@@ -220,6 +223,38 @@ def load_module_inventory(
220
223
  })
221
224
 
222
225
 
226
+ class ResourcesSpec(BaseModel, frozen=True):
227
+ cpu: str | None = None
228
+ memory: str | None = None
229
+
230
+
231
+ class Resources(BaseModel, frozen=True):
232
+ """Hashable class to store module resources in reconciliations.
233
+ Default values are used as a fallback for existent objects that were
234
+ created without container resources, hence they don't have mem/cpu resources
235
+ in the ERv2 State. Eventually, all resources will have resources assignments
236
+ from the module spec, module_overrides, or app-interface settings.
237
+ """
238
+
239
+ requests: ResourcesSpec = ResourcesSpec()
240
+ limits: ResourcesSpec = ResourcesSpec()
241
+
242
+ @staticmethod
243
+ def from_deploy_resources_fields(fields: DeployResourcesFields) -> "Resources":
244
+ """Create Resource obect from GQL DeployResourcesFields.
245
+
246
+ DeployResourceFields can not be used directly as it not hashable."""
247
+ return Resources(
248
+ requests=ResourcesSpec(
249
+ cpu=fields.requests.cpu, memory=fields.requests.memory
250
+ ),
251
+ limits=ResourcesSpec(
252
+ cpu=fields.limits.cpu,
253
+ memory=fields.limits.memory,
254
+ ),
255
+ )
256
+
257
+
223
258
  class ExternalResourceModuleConfiguration(BaseModel, frozen=True):
224
259
  image: str = ""
225
260
  version: str = ""
@@ -227,6 +262,7 @@ class ExternalResourceModuleConfiguration(BaseModel, frozen=True):
227
262
  reconcile_timeout_minutes: int = -1000
228
263
  outputs_secret_image: str = ""
229
264
  outputs_secret_version: str = ""
265
+ resources: Resources = Resources()
230
266
 
231
267
  @property
232
268
  def image_version(self) -> str:
@@ -244,13 +280,14 @@ class ExternalResourceModuleConfiguration(BaseModel, frozen=True):
244
280
  ) -> "ExternalResourceModuleConfiguration":
245
281
  module_overrides = spec.metadata.get(
246
282
  "module_overrides"
247
- ) or ExternalResourcesModuleOverridesV1(
283
+ ) or ExternalResourcesModuleOverrides(
248
284
  module_type=None,
249
285
  image=None,
250
286
  version=None,
251
287
  reconcile_timeout_minutes=None,
252
288
  outputs_secret_image=None,
253
289
  outputs_secret_version=None,
290
+ resources=None,
254
291
  )
255
292
 
256
293
  return ExternalResourceModuleConfiguration(
@@ -265,6 +302,11 @@ class ExternalResourceModuleConfiguration(BaseModel, frozen=True):
265
302
  outputs_secret_version=module_overrides.outputs_secret_version
266
303
  or module.outputs_secret_version
267
304
  or settings.outputs_secret_version,
305
+ resources=Resources.from_deploy_resources_fields(
306
+ module_overrides.resources
307
+ or module.resources
308
+ or settings.module_default_resources
309
+ ),
268
310
  )
269
311
 
270
312
 
@@ -14,6 +14,7 @@ from kubernetes.client import (
14
14
  V1ObjectMeta,
15
15
  V1PodSpec,
16
16
  V1PodTemplateSpec,
17
+ V1ResourceRequirements,
17
18
  V1SecretVolumeSource,
18
19
  V1Volume,
19
20
  V1VolumeMount,
@@ -89,10 +90,19 @@ class ReconciliationK8sJob(K8sJob, BaseModel, frozen=True):
89
90
  }
90
91
 
91
92
  def job_spec(self) -> V1JobSpec:
93
+ assert self.reconciliation.module_configuration.resources is not None
92
94
  job_container = V1Container(
93
95
  name="job",
94
96
  image=self.reconciliation.module_configuration.image_version,
95
97
  image_pull_policy="Always",
98
+ resources=V1ResourceRequirements(
99
+ requests=self.reconciliation.module_configuration.resources.requests.dict(
100
+ exclude_none=True
101
+ ),
102
+ limits=self.reconciliation.module_configuration.resources.limits.dict(
103
+ exclude_none=True
104
+ ),
105
+ ),
96
106
  env=[
97
107
  V1EnvVar(
98
108
  name="DRY_RUN",
@@ -11,6 +11,8 @@ from reconcile.external_resources.model import (
11
11
  ExternalResourceModuleConfiguration,
12
12
  Reconciliation,
13
13
  ReconciliationStatus,
14
+ Resources,
15
+ ResourcesSpec,
14
16
  ResourceStatus,
15
17
  )
16
18
  from reconcile.utils.aws_api_typed.api import AWSApi
@@ -73,10 +75,48 @@ class DynamoDBStateAdapter:
73
75
  MODCONF_VERSION = "version"
74
76
  MODCONF_DRIFT_MINS = "drift_detection_minutes"
75
77
  MODCONF_TIMEOUT_MINS = "timeout_minutes"
78
+ MODCONF_RESOURCES = "resources"
79
+ MODCONF_RESOURCES_REQUESTS = "requests"
80
+ MODCONF_RESOURCES_REQUESTS_CPU = "cpu"
81
+ MODCONF_RESOURCES_REQUESTS_MEMORY = "memory"
82
+ MODCONF_RESOURCES_LIMITS = "limits"
83
+ MODCONF_RESOURCES_LIMITS_CPU = "cpu"
84
+ MODCONF_RESOURCES_LIMITS_MEMORY = "memory"
76
85
 
77
86
  def _get_value(self, item: Mapping[str, Any], key: str, type: str = "S") -> Any:
87
+ if item[key][type] == "None":
88
+ return None
78
89
  return item[key][type]
79
90
 
91
+ def _build_resources(self, modconf: Mapping[str, Any]) -> Resources | None:
92
+ if self.MODCONF_RESOURCES not in modconf:
93
+ return Resources()
94
+ mc_resources = self._get_value(modconf, self.MODCONF_RESOURCES, type="M")
95
+ mc_resources_requests = self._get_value(
96
+ mc_resources, self.MODCONF_RESOURCES_REQUESTS, type="M"
97
+ )
98
+ mc_resources_limits = self._get_value(
99
+ mc_resources, self.MODCONF_RESOURCES_LIMITS, type="M"
100
+ )
101
+ return Resources(
102
+ requests=ResourcesSpec(
103
+ cpu=self._get_value(
104
+ mc_resources_requests, self.MODCONF_RESOURCES_REQUESTS_CPU
105
+ ),
106
+ memory=self._get_value(
107
+ mc_resources_requests, self.MODCONF_RESOURCES_REQUESTS_MEMORY
108
+ ),
109
+ ),
110
+ limits=ResourcesSpec(
111
+ cpu=self._get_value(
112
+ mc_resources_limits, self.MODCONF_RESOURCES_LIMITS_CPU
113
+ ),
114
+ memory=self._get_value(
115
+ mc_resources_limits, self.MODCONF_RESOURCES_LIMITS_MEMORY
116
+ ),
117
+ ),
118
+ )
119
+
80
120
  def deserialize(
81
121
  self,
82
122
  item: Mapping[str, Any],
@@ -116,6 +156,7 @@ class DynamoDBStateAdapter:
116
156
  reconcile_timeout_minutes=self._get_value(
117
157
  modconf, self.MODCONF_TIMEOUT_MINS, type="N"
118
158
  ),
159
+ resources=self._build_resources(modconf),
119
160
  ),
120
161
  )
121
162
 
@@ -164,7 +205,39 @@ class DynamoDBStateAdapter:
164
205
  state.reconciliation.module_configuration.reconcile_timeout_minutes
165
206
  )
166
207
  },
167
- }
208
+ self.MODCONF_RESOURCES: {
209
+ "M": {
210
+ self.MODCONF_RESOURCES_REQUESTS: {
211
+ "M": {
212
+ self.MODCONF_RESOURCES_REQUESTS_CPU: {
213
+ "S": str(
214
+ state.reconciliation.module_configuration.resources.requests.cpu
215
+ )
216
+ },
217
+ self.MODCONF_RESOURCES_REQUESTS_MEMORY: {
218
+ "S": str(
219
+ state.reconciliation.module_configuration.resources.requests.memory
220
+ )
221
+ },
222
+ }
223
+ },
224
+ self.MODCONF_RESOURCES_LIMITS: {
225
+ "M": {
226
+ self.MODCONF_RESOURCES_LIMITS_CPU: {
227
+ "S": str(
228
+ state.reconciliation.module_configuration.resources.limits.cpu
229
+ )
230
+ },
231
+ self.MODCONF_RESOURCES_LIMITS_MEMORY: {
232
+ "S": str(
233
+ state.reconciliation.module_configuration.resources.limits.memory
234
+ )
235
+ },
236
+ }
237
+ },
238
+ }
239
+ },
240
+ },
168
241
  },
169
242
  }
170
243
  },
@@ -17,8 +17,21 @@ from pydantic import ( # noqa: F401 # pylint: disable=W0611
17
17
  Json,
18
18
  )
19
19
 
20
+ from reconcile.gql_definitions.fragments.deplopy_resources import DeployResourcesFields
21
+
20
22
 
21
23
  DEFINITION = """
24
+ fragment DeployResourcesFields on DeployResources_v1 {
25
+ requests {
26
+ cpu
27
+ memory
28
+ }
29
+ limits {
30
+ cpu
31
+ memory
32
+ }
33
+ }
34
+
22
35
  query ExternalResourcesModules {
23
36
  modules: external_resources_modules_v1 {
24
37
  provision_provider
@@ -31,6 +44,9 @@ query ExternalResourcesModules {
31
44
  outputs_secret_sync
32
45
  outputs_secret_image
33
46
  outputs_secret_version
47
+ resources {
48
+ ... DeployResourcesFields
49
+ }
34
50
  }
35
51
  }
36
52
  """
@@ -53,6 +69,7 @@ class ExternalResourcesModuleV1(ConfiguredBaseModel):
53
69
  outputs_secret_sync: bool = Field(..., alias="outputs_secret_sync")
54
70
  outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
55
71
  outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
72
+ resources: Optional[DeployResourcesFields] = Field(..., alias="resources")
56
73
 
57
74
 
58
75
  class ExternalResourcesModulesQueryData(ConfiguredBaseModel):
@@ -19,6 +19,7 @@ from pydantic import ( # noqa: F401 # pylint: disable=W0611
19
19
 
20
20
  from reconcile.gql_definitions.fragments.aws_vpc import AWSVPC
21
21
  from reconcile.gql_definitions.fragments.jumphost_common_fields import CommonJumphostFields
22
+ from reconcile.gql_definitions.external_resources.fragments.external_resources_module_overrides import ExternalResourcesModuleOverrides
22
23
  from reconcile.gql_definitions.fragments.vault_secret import VaultSecret
23
24
 
24
25
 
@@ -53,6 +54,29 @@ fragment CommonJumphostFields on ClusterJumpHost_v1 {
53
54
  }
54
55
  }
55
56
 
57
+ fragment DeployResourcesFields on DeployResources_v1 {
58
+ requests {
59
+ cpu
60
+ memory
61
+ }
62
+ limits {
63
+ cpu
64
+ memory
65
+ }
66
+ }
67
+
68
+ fragment ExternalResourcesModuleOverrides on ExternalResourcesModuleOverrides_v1 {
69
+ module_type
70
+ image
71
+ version
72
+ reconcile_timeout_minutes
73
+ outputs_secret_image
74
+ outputs_secret_version
75
+ resources {
76
+ ... DeployResourcesFields
77
+ }
78
+ }
79
+
56
80
  fragment VaultSecret on VaultSecret_v1 {
57
81
  path
58
82
  field
@@ -111,12 +135,7 @@ query ExternalResourcesNamespaces {
111
135
  managed_by_erv2
112
136
  delete
113
137
  module_overrides {
114
- module_type
115
- image
116
- version
117
- reconcile_timeout_minutes
118
- outputs_secret_image
119
- outputs_secret_version
138
+ ... ExternalResourcesModuleOverrides
120
139
  }
121
140
  }
122
141
  ... on NamespaceTerraformResourceS3_v1 {
@@ -149,12 +168,7 @@ query ExternalResourcesNamespaces {
149
168
  managed_by_erv2
150
169
  delete
151
170
  module_overrides {
152
- module_type
153
- image
154
- version
155
- reconcile_timeout_minutes
156
- outputs_secret_image
157
- outputs_secret_version
171
+ ... ExternalResourcesModuleOverrides
158
172
  }
159
173
  }
160
174
  ... on NamespaceTerraformResourceServiceAccount_v1 {
@@ -275,12 +289,7 @@ query ExternalResourcesNamespaces {
275
289
  managed_by_erv2
276
290
  delete
277
291
  module_overrides {
278
- module_type
279
- image
280
- version
281
- reconcile_timeout_minutes
282
- outputs_secret_image
283
- outputs_secret_version
292
+ ... ExternalResourcesModuleOverrides
284
293
  }
285
294
  }
286
295
  ... on NamespaceTerraformResourceElasticSearch_v1 {
@@ -492,12 +501,7 @@ query ExternalResourcesNamespaces {
492
501
  managed_by_erv2
493
502
  delete
494
503
  module_overrides {
495
- module_type
496
- image
497
- version
498
- reconcile_timeout_minutes
499
- outputs_secret_image
500
- outputs_secret_version
504
+ ... ExternalResourcesModuleOverrides
501
505
  }
502
506
  }
503
507
  }
@@ -576,15 +580,6 @@ class AWSRDSDataClassificationV1(ConfiguredBaseModel):
576
580
  loss_impact: Optional[str] = Field(..., alias="loss_impact")
577
581
 
578
582
 
579
- class ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
580
- module_type: Optional[str] = Field(..., alias="module_type")
581
- image: Optional[str] = Field(..., alias="image")
582
- version: Optional[str] = Field(..., alias="version")
583
- reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
584
- outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
585
- outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
586
-
587
-
588
583
  class NamespaceTerraformResourceRDSV1(NamespaceTerraformResourceAWSV1):
589
584
  region: Optional[str] = Field(..., alias="region")
590
585
  identifier: str = Field(..., alias="identifier")
@@ -604,7 +599,7 @@ class NamespaceTerraformResourceRDSV1(NamespaceTerraformResourceAWSV1):
604
599
  data_classification: Optional[AWSRDSDataClassificationV1] = Field(..., alias="data_classification")
605
600
  managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
606
601
  delete: Optional[bool] = Field(..., alias="delete")
607
- module_overrides: Optional[ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
602
+ module_overrides: Optional[ExternalResourcesModuleOverrides] = Field(..., alias="module_overrides")
608
603
 
609
604
 
610
605
  class AWSS3EventNotificationV1(ConfiguredBaseModel):
@@ -629,15 +624,6 @@ class NamespaceTerraformResourceS3V1(NamespaceTerraformResourceAWSV1):
629
624
  annotations: Optional[str] = Field(..., alias="annotations")
630
625
 
631
626
 
632
- class NamespaceTerraformResourceElastiCacheV1_ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
633
- module_type: Optional[str] = Field(..., alias="module_type")
634
- image: Optional[str] = Field(..., alias="image")
635
- version: Optional[str] = Field(..., alias="version")
636
- reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
637
- outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
638
- outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
639
-
640
-
641
627
  class NamespaceTerraformResourceElastiCacheV1(NamespaceTerraformResourceAWSV1):
642
628
  identifier: str = Field(..., alias="identifier")
643
629
  defaults: str = Field(..., alias="defaults")
@@ -648,7 +634,7 @@ class NamespaceTerraformResourceElastiCacheV1(NamespaceTerraformResourceAWSV1):
648
634
  annotations: Optional[str] = Field(..., alias="annotations")
649
635
  managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
650
636
  delete: Optional[bool] = Field(..., alias="delete")
651
- module_overrides: Optional[NamespaceTerraformResourceElastiCacheV1_ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
637
+ module_overrides: Optional[ExternalResourcesModuleOverrides] = Field(..., alias="module_overrides")
652
638
 
653
639
 
654
640
  class ClusterV1(ConfiguredBaseModel):
@@ -784,15 +770,6 @@ class NamespaceTerraformResourceCloudWatchV1(NamespaceTerraformResourceAWSV1):
784
770
  annotations: Optional[str] = Field(..., alias="annotations")
785
771
 
786
772
 
787
- class NamespaceTerraformResourceKMSV1_ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
788
- module_type: Optional[str] = Field(..., alias="module_type")
789
- image: Optional[str] = Field(..., alias="image")
790
- version: Optional[str] = Field(..., alias="version")
791
- reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
792
- outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
793
- outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
794
-
795
-
796
773
  class NamespaceTerraformResourceKMSV1(NamespaceTerraformResourceAWSV1):
797
774
  region: Optional[str] = Field(..., alias="region")
798
775
  identifier: str = Field(..., alias="identifier")
@@ -802,7 +779,7 @@ class NamespaceTerraformResourceKMSV1(NamespaceTerraformResourceAWSV1):
802
779
  annotations: Optional[str] = Field(..., alias="annotations")
803
780
  managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
804
781
  delete: Optional[bool] = Field(..., alias="delete")
805
- module_overrides: Optional[NamespaceTerraformResourceKMSV1_ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
782
+ module_overrides: Optional[ExternalResourcesModuleOverrides] = Field(..., alias="module_overrides")
806
783
 
807
784
 
808
785
  class NamespaceTerraformResourceElasticSearchV1(NamespaceTerraformResourceAWSV1):
@@ -1044,15 +1021,6 @@ class MskSecretParametersV1(ConfiguredBaseModel):
1044
1021
  secret: VaultSecret = Field(..., alias="secret")
1045
1022
 
1046
1023
 
1047
- class NamespaceTerraformResourceMskV1_ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
1048
- module_type: Optional[str] = Field(..., alias="module_type")
1049
- image: Optional[str] = Field(..., alias="image")
1050
- version: Optional[str] = Field(..., alias="version")
1051
- reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
1052
- outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
1053
- outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
1054
-
1055
-
1056
1024
  class NamespaceTerraformResourceMskV1(NamespaceTerraformResourceAWSV1):
1057
1025
  region: Optional[str] = Field(..., alias="region")
1058
1026
  identifier: str = Field(..., alias="identifier")
@@ -1062,7 +1030,7 @@ class NamespaceTerraformResourceMskV1(NamespaceTerraformResourceAWSV1):
1062
1030
  users: Optional[list[MskSecretParametersV1]] = Field(..., alias="users")
1063
1031
  managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
1064
1032
  delete: Optional[bool] = Field(..., alias="delete")
1065
- module_overrides: Optional[NamespaceTerraformResourceMskV1_ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
1033
+ module_overrides: Optional[ExternalResourcesModuleOverrides] = Field(..., alias="module_overrides")
1066
1034
 
1067
1035
 
1068
1036
  class NamespaceTerraformProviderResourceAWSV1(NamespaceExternalResourceV1):
@@ -17,8 +17,21 @@ from pydantic import ( # noqa: F401 # pylint: disable=W0611
17
17
  Json,
18
18
  )
19
19
 
20
+ from reconcile.gql_definitions.fragments.deplopy_resources import DeployResourcesFields
21
+
20
22
 
21
23
  DEFINITION = """
24
+ fragment DeployResourcesFields on DeployResources_v1 {
25
+ requests {
26
+ cpu
27
+ memory
28
+ }
29
+ limits {
30
+ cpu
31
+ memory
32
+ }
33
+ }
34
+
22
35
  query ExternalResourcesSettings {
23
36
  settings: external_resources_settings_v1 {
24
37
  state_dynamodb_account {
@@ -38,6 +51,9 @@ query ExternalResourcesSettings {
38
51
  vault_secrets_path
39
52
  outputs_secret_image
40
53
  outputs_secret_version
54
+ module_default_resources {
55
+ ... DeployResourcesFields
56
+ }
41
57
  }
42
58
  }
43
59
  """
@@ -73,6 +89,7 @@ class ExternalResourcesSettingsV1(ConfiguredBaseModel):
73
89
  vault_secrets_path: str = Field(..., alias="vault_secrets_path")
74
90
  outputs_secret_image: str = Field(..., alias="outputs_secret_image")
75
91
  outputs_secret_version: str = Field(..., alias="outputs_secret_version")
92
+ module_default_resources: DeployResourcesFields = Field(..., alias="module_default_resources")
76
93
 
77
94
 
78
95
  class ExternalResourcesSettingsQueryData(ConfiguredBaseModel):
@@ -0,0 +1,36 @@
1
+ """
2
+ Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
+ """
4
+ from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
+ from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
+ from enum import Enum # noqa: F401 # pylint: disable=W0611
7
+ from typing import ( # noqa: F401 # pylint: disable=W0611
8
+ Any,
9
+ Optional,
10
+ Union,
11
+ )
12
+
13
+ from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
+ BaseModel,
15
+ Extra,
16
+ Field,
17
+ Json,
18
+ )
19
+
20
+ from reconcile.gql_definitions.fragments.deplopy_resources import DeployResourcesFields
21
+
22
+
23
+ class ConfiguredBaseModel(BaseModel):
24
+ class Config:
25
+ smart_union=True
26
+ extra=Extra.forbid
27
+
28
+
29
+ class ExternalResourcesModuleOverrides(ConfiguredBaseModel):
30
+ module_type: Optional[str] = Field(..., alias="module_type")
31
+ image: Optional[str] = Field(..., alias="image")
32
+ version: Optional[str] = Field(..., alias="version")
33
+ reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
34
+ outputs_secret_image: Optional[str] = Field(..., alias="outputs_secret_image")
35
+ outputs_secret_version: Optional[str] = Field(..., alias="outputs_secret_version")
36
+ resources: Optional[DeployResourcesFields] = Field(..., alias="resources")
@@ -33879,6 +33879,22 @@
33879
33879
  },
33880
33880
  "isDeprecated": false,
33881
33881
  "deprecationReason": null
33882
+ },
33883
+ {
33884
+ "name": "module_default_resources",
33885
+ "description": null,
33886
+ "args": [],
33887
+ "type": {
33888
+ "kind": "NON_NULL",
33889
+ "name": null,
33890
+ "ofType": {
33891
+ "kind": "OBJECT",
33892
+ "name": "DeployResources_v1",
33893
+ "ofType": null
33894
+ }
33895
+ },
33896
+ "isDeprecated": false,
33897
+ "deprecationReason": null
33882
33898
  }
33883
33899
  ],
33884
33900
  "inputFields": null,
@@ -34080,6 +34096,18 @@
34080
34096
  },
34081
34097
  "isDeprecated": false,
34082
34098
  "deprecationReason": null
34099
+ },
34100
+ {
34101
+ "name": "resources",
34102
+ "description": null,
34103
+ "args": [],
34104
+ "type": {
34105
+ "kind": "OBJECT",
34106
+ "name": "DeployResources_v1",
34107
+ "ofType": null
34108
+ },
34109
+ "isDeprecated": false,
34110
+ "deprecationReason": null
34083
34111
  }
34084
34112
  ],
34085
34113
  "inputFields": null,
@@ -43321,6 +43349,18 @@
43321
43349
  },
43322
43350
  "isDeprecated": false,
43323
43351
  "deprecationReason": null
43352
+ },
43353
+ {
43354
+ "name": "resources",
43355
+ "description": null,
43356
+ "args": [],
43357
+ "type": {
43358
+ "kind": "OBJECT",
43359
+ "name": "DeployResources_v1",
43360
+ "ofType": null
43361
+ },
43362
+ "isDeprecated": false,
43363
+ "deprecationReason": null
43324
43364
  }
43325
43365
  ],
43326
43366
  "inputFields": null,
@@ -118,13 +118,13 @@ class Erv2Cli:
118
118
  self._er_settings, m_inventory, er_inventory, self._secret_reader
119
119
  )
120
120
  f = factories.get_factory(spec.provision_provider)
121
- self._resource = f.create_external_resource(spec)
122
- f.validate_external_resource(self._resource)
123
121
  self._module_configuration = (
124
122
  ExternalResourceModuleConfiguration.resolve_configuration(
125
123
  m_inventory.get_from_spec(spec), spec, self._er_settings
126
124
  )
127
125
  )
126
+ self._resource = f.create_external_resource(spec, self._module_configuration)
127
+ f.validate_external_resource(self._resource, self._module_configuration)
128
128
 
129
129
  @property
130
130
  def input_data(self) -> str: