qontract-reconcile 0.10.1rc1024__py3-none-any.whl → 0.10.1rc1026__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.
- {qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/RECORD +13 -13
- reconcile/dynatrace_token_provider/integration.py +60 -10
- reconcile/external_resources/manager.py +1 -6
- reconcile/external_resources/meta.py +1 -0
- reconcile/external_resources/model.py +51 -20
- reconcile/gql_definitions/external_resources/external_resources_modules.py +4 -4
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +14 -0
- reconcile/utils/external_resource_spec.py +2 -2
- tools/qontract_cli.py +1 -1
- {qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1rc1026
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Home-page: https://github.com/app-sre/qontract-reconcile
|
6
6
|
Author: Red Hat App-SRE Team
|
{qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/RECORD
RENAMED
@@ -181,7 +181,7 @@ reconcile/cna/assets/asset_factory.py,sha256=7T7X_J6xIsoGETqBRI45_EyIKEdQcnRPt_G
|
|
181
181
|
reconcile/cna/assets/null.py,sha256=85mVh97atCoC0aLuX47poTZiyOthmziJeBsUw0c924w,1658
|
182
182
|
reconcile/dynatrace_token_provider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
183
183
|
reconcile/dynatrace_token_provider/dependencies.py,sha256=41q05A4C_eS3E8-MR4veeMxtQNsPoGdxmEa3d-OKxq4,2814
|
184
|
-
reconcile/dynatrace_token_provider/integration.py,sha256=
|
184
|
+
reconcile/dynatrace_token_provider/integration.py,sha256=jOpj2qtkI95b_Ih0IH3cYV5G63RBuxhG6kX4RADBWeg,23003
|
185
185
|
reconcile/dynatrace_token_provider/metrics.py,sha256=xiKkl8fTEBQaXJelGCPNTZhHAWdO1M3pCXNr_Tei63c,1285
|
186
186
|
reconcile/dynatrace_token_provider/model.py,sha256=gkpqo5rRRueBXnIMjp4EEHqBUBuU65TRI8zpdb8GJ0A,241
|
187
187
|
reconcile/dynatrace_token_provider/ocm.py,sha256=iHMsgbsLs-dlrB9UXmWNDF7E4UDe49JOsLa9rnowKfo,4282
|
@@ -194,10 +194,10 @@ reconcile/external_resources/aws.py,sha256=JvjKaABy2Pg8u8Lq82Acv4zMvpE3_qGKes7OG
|
|
194
194
|
reconcile/external_resources/factories.py,sha256=DXgaLxoO87zZ76VOpRpu2GeYGhsbfOnOx5mrzgo4Gf4,4767
|
195
195
|
reconcile/external_resources/integration.py,sha256=y1gJ16woMBC3J9qniMmS5y3lCkAs7V_ETZRUwjKqaO0,6628
|
196
196
|
reconcile/external_resources/integration_secrets_sync.py,sha256=cMEZhgCvABAMf-DWF051L6CRnJQdfbsISA_b1xuS940,1670
|
197
|
-
reconcile/external_resources/manager.py,sha256=
|
198
|
-
reconcile/external_resources/meta.py,sha256=
|
197
|
+
reconcile/external_resources/manager.py,sha256=Q1l53Q0QHS7dvxCU66_BBpWLpNf6he0FfNzxVKJmVN8,15102
|
198
|
+
reconcile/external_resources/meta.py,sha256=noaytFzmShpzLA_ebGh7wuP45mOfHIOnnoUxivjDa1I,672
|
199
199
|
reconcile/external_resources/metrics.py,sha256=m2TIOao2N7pD6k45driFbBGVCC_N7ai44m-lLPfa5qk,454
|
200
|
-
reconcile/external_resources/model.py,sha256=
|
200
|
+
reconcile/external_resources/model.py,sha256=RjGMHgt_J1_HQjfBodFGvdWpYKJupKB4xtWuggSnMtA,8270
|
201
201
|
reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYjHGyICWff9bxlc,9323
|
202
202
|
reconcile/external_resources/secrets_sync.py,sha256=6n0oDPLjd9Ql0lf6zsr1AZw8A6EEe3yCzl20XodtgkE,16229
|
203
203
|
reconcile/external_resources/state.py,sha256=fKU6PLYOZ2ZTaIwvt1BNlNOnIqcewLijOyT3Lgcd1NE,9677
|
@@ -288,8 +288,8 @@ reconcile/gql_definitions/endpoints_discovery/__init__.py,sha256=47DEQpj8HBSa-_T
|
|
288
288
|
reconcile/gql_definitions/endpoints_discovery/namespaces.py,sha256=FqJ0H7NdsIm5BgVnuJV9wLcj7i667VhCN559tWJ-WsA,3054
|
289
289
|
reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
290
290
|
reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=XR69j9dpTQ0gv8y-AZN7AJ0dPvO-wbHscyCDgrax6Bk,2046
|
291
|
-
reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=
|
292
|
-
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=
|
291
|
+
reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=HFOQjmNbNxk0j5nChxppQeCnJjeDsqibJkPgA7R1zRw,2417
|
292
|
+
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=uNk0HOAH96qdLuDBE6VzjcIPB--PHvOLDitJ2IzPM40,41618
|
293
293
|
reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=Hw9n_90BPG6Lnt2PT3mHc6p0KEm2CxKxvSGRFc_Dhus,2982
|
294
294
|
reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
295
295
|
reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
|
@@ -668,7 +668,7 @@ reconcile/utils/environ.py,sha256=psk07d2xyjbUzjOCDdNWgavaNolL_t2sq3sn2gFfY9k,50
|
|
668
668
|
reconcile/utils/exceptions.py,sha256=DwfnWUpVOotpP79RWZ2pycmG6nKCL00RBIeZLYkQPW4,635
|
669
669
|
reconcile/utils/expiration.py,sha256=3JaXH4psksR7z262k7FmdyREjCLqm66OpVMEbcfdWRo,1213
|
670
670
|
reconcile/utils/extended_early_exit.py,sha256=QSktrmfw37zSRMNk930tDbQsVeKxaPPPD43e79DGwZw,6754
|
671
|
-
reconcile/utils/external_resource_spec.py,sha256=
|
671
|
+
reconcile/utils/external_resource_spec.py,sha256=bhH_xneFwATdFumTPkiQmcVKYI0gcaWuqV6FpFdf_P0,7006
|
672
672
|
reconcile/utils/external_resources.py,sha256=ObBOGBRTsDQ2s9rojfeUfFMoR8ls4Kg-AnpsyF6m7u8,7539
|
673
673
|
reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,402
|
674
674
|
reconcile/utils/git.py,sha256=JkpbUO10oBTtNHZ1IhjyG6dTOUizc7I5H0vm7NvDVNw,1409
|
@@ -834,7 +834,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
834
834
|
tools/app_interface_reporter.py,sha256=1ZP58LYV6ww3XOLVxgy8NKasMb1jQmp4BNqzTEB0VBE,17723
|
835
835
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
836
836
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
837
|
-
tools/qontract_cli.py,sha256=
|
837
|
+
tools/qontract_cli.py,sha256=8HbIKtepnmoQteb9Q31iJXFG7_y2o_g6JEkIhXnoncM,128916
|
838
838
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
839
839
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
840
840
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -865,8 +865,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
|
|
865
865
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
866
866
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
867
867
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
868
|
-
qontract_reconcile-0.10.
|
869
|
-
qontract_reconcile-0.10.
|
870
|
-
qontract_reconcile-0.10.
|
871
|
-
qontract_reconcile-0.10.
|
872
|
-
qontract_reconcile-0.10.
|
868
|
+
qontract_reconcile-0.10.1rc1026.dist-info/METADATA,sha256=h_rqqk8rQyYaSa2vo9DevQxSauMk3iFNdbW8186aen0,2213
|
869
|
+
qontract_reconcile-0.10.1rc1026.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
870
|
+
qontract_reconcile-0.10.1rc1026.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
871
|
+
qontract_reconcile-0.10.1rc1026.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
872
|
+
qontract_reconcile-0.10.1rc1026.dist-info/RECORD,,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import base64
|
2
|
+
import hashlib
|
2
3
|
import logging
|
3
|
-
from collections.abc import Iterable, Mapping
|
4
|
+
from collections.abc import Iterable, Mapping, MutableMapping
|
4
5
|
from datetime import timedelta
|
5
6
|
from typing import Any
|
6
7
|
|
@@ -140,7 +141,7 @@ class DynatraceTokenProviderIntegration(
|
|
140
141
|
if tenant_id not in existing_dtp_tokens:
|
141
142
|
existing_dtp_tokens[tenant_id] = (
|
142
143
|
dt_client.get_token_ids_map_for_name_prefix(
|
143
|
-
prefix="dtp
|
144
|
+
prefix="dtp"
|
144
145
|
)
|
145
146
|
)
|
146
147
|
|
@@ -172,7 +173,7 @@ class DynatraceTokenProviderIntegration(
|
|
172
173
|
cluster: Cluster,
|
173
174
|
dt_client: DynatraceClient,
|
174
175
|
ocm_client: OCMClient,
|
175
|
-
existing_dtp_tokens:
|
176
|
+
existing_dtp_tokens: MutableMapping[str, str],
|
176
177
|
tenant_id: str,
|
177
178
|
token_spec: DynatraceTokenProviderTokenSpecV1,
|
178
179
|
) -> None:
|
@@ -276,12 +277,52 @@ class DynatraceTokenProviderIntegration(
|
|
276
277
|
f"Patched {token_spec.name=} for {SYNCSET_AND_MANIFEST_ID} in {cluster.external_id=}."
|
277
278
|
)
|
278
279
|
|
280
|
+
def scopes_hash(self, scopes: Iterable[str], length: int) -> str:
|
281
|
+
m = hashlib.sha256()
|
282
|
+
msg = ",".join(sorted(scopes))
|
283
|
+
m.update(msg.encode("utf-8"))
|
284
|
+
return m.hexdigest()[:length]
|
285
|
+
|
286
|
+
def dynatrace_token_name(self, spec: DynatraceAPITokenV1, cluster_uuid: str) -> str:
|
287
|
+
scopes_hash = self.scopes_hash(scopes=spec.scopes, length=12)
|
288
|
+
# We have a limit of 100 chars
|
289
|
+
# cluster_uuid = 36 chars
|
290
|
+
# scopes_hash = 12 chars
|
291
|
+
# prefix + separators = 6 chars
|
292
|
+
return f"dtp_{spec.name[:46]}_{cluster_uuid}_{scopes_hash}"
|
293
|
+
|
294
|
+
def sync_token_in_dynatrace(
|
295
|
+
self,
|
296
|
+
token_id: str,
|
297
|
+
spec: DynatraceAPITokenV1,
|
298
|
+
cluster_uuid: str,
|
299
|
+
dt_client: DynatraceClient,
|
300
|
+
token_name_in_dt_api: str,
|
301
|
+
dry_run: bool,
|
302
|
+
) -> None:
|
303
|
+
"""
|
304
|
+
We ensure that the given token is properly configured in Dynatrace
|
305
|
+
according to the given spec.
|
306
|
+
|
307
|
+
A list query on the tokens does not return each tokens configuration.
|
308
|
+
We encode the token configuration in the token name to save API calls.
|
309
|
+
"""
|
310
|
+
expected_name = self.dynatrace_token_name(spec=spec, cluster_uuid=cluster_uuid)
|
311
|
+
if token_name_in_dt_api != expected_name:
|
312
|
+
logging.info(
|
313
|
+
f"{token_name_in_dt_api=} != {expected_name=}. Sync dynatrace token {token_id=} with {spec=} for {cluster_uuid=}."
|
314
|
+
)
|
315
|
+
if not dry_run:
|
316
|
+
dt_client.update_token(
|
317
|
+
token_id=token_id, name=expected_name, scopes=spec.scopes
|
318
|
+
)
|
319
|
+
|
279
320
|
def generate_desired(
|
280
321
|
self,
|
281
322
|
dry_run: bool,
|
282
323
|
current_k8s_secrets: Iterable[K8sSecret],
|
283
324
|
desired_spec: DynatraceTokenProviderTokenSpecV1,
|
284
|
-
existing_dtp_tokens:
|
325
|
+
existing_dtp_tokens: MutableMapping[str, str],
|
285
326
|
dt_client: DynatraceClient,
|
286
327
|
cluster_uuid: str,
|
287
328
|
) -> tuple[bool, Iterable[K8sSecret]]:
|
@@ -301,15 +342,24 @@ class DynatraceTokenProviderIntegration(
|
|
301
342
|
else {}
|
302
343
|
)
|
303
344
|
for desired_token in secret.tokens:
|
304
|
-
|
305
|
-
if not
|
345
|
+
cur_token = current_tokens_by_name.get(desired_token.name)
|
346
|
+
if not cur_token or cur_token.id not in existing_dtp_tokens:
|
306
347
|
has_diff = True
|
307
348
|
if not dry_run:
|
308
|
-
|
349
|
+
cur_token = self.create_dynatrace_token(
|
309
350
|
dt_client, cluster_uuid, desired_token
|
310
351
|
)
|
311
|
-
|
312
|
-
|
352
|
+
existing_dtp_tokens[cur_token.id] = cur_token.name
|
353
|
+
if cur_token:
|
354
|
+
self.sync_token_in_dynatrace(
|
355
|
+
token_id=cur_token.id,
|
356
|
+
spec=desired_token,
|
357
|
+
cluster_uuid=cluster_uuid,
|
358
|
+
dt_client=dt_client,
|
359
|
+
dry_run=dry_run,
|
360
|
+
token_name_in_dt_api=existing_dtp_tokens[cur_token.id],
|
361
|
+
)
|
362
|
+
desired_tokens.append(cur_token)
|
313
363
|
desired.append(
|
314
364
|
K8sSecret(
|
315
365
|
secret_name=secret.name,
|
@@ -323,7 +373,7 @@ class DynatraceTokenProviderIntegration(
|
|
323
373
|
def create_dynatrace_token(
|
324
374
|
self, dt_client: DynatraceClient, cluster_uuid: str, token: DynatraceAPITokenV1
|
325
375
|
) -> DynatraceAPIToken:
|
326
|
-
token_name =
|
376
|
+
token_name = self.dynatrace_token_name(spec=token, cluster_uuid=cluster_uuid)
|
327
377
|
new_token = dt_client.create_api_token(
|
328
378
|
name=token_name,
|
329
379
|
scopes=token.scopes,
|
@@ -41,9 +41,6 @@ from reconcile.utils.external_resource_spec import (
|
|
41
41
|
)
|
42
42
|
from reconcile.utils.secret_reader import SecretReaderBase
|
43
43
|
|
44
|
-
FLAG_RESOURCE_MANAGED_BY_ERV2 = "managed_by_erv2"
|
45
|
-
FLAG_DELETE_RESOURCE = "delete"
|
46
|
-
|
47
44
|
|
48
45
|
def setup_factories(
|
49
46
|
settings: ExternalResourcesSettingsV1,
|
@@ -323,9 +320,7 @@ class ExternalResourcesManager:
|
|
323
320
|
return resource
|
324
321
|
|
325
322
|
def _serialize_resource_input(self, resource: ExternalResource) -> str:
|
326
|
-
return resource.json(
|
327
|
-
exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2, FLAG_DELETE_RESOURCE}}
|
328
|
-
)
|
323
|
+
return resource.json()
|
329
324
|
|
330
325
|
def handle_resources(self) -> None:
|
331
326
|
desired_r = self._get_desired_objects_reconciliations()
|
@@ -13,13 +13,18 @@ from typing import Any
|
|
13
13
|
|
14
14
|
from pydantic import BaseModel
|
15
15
|
|
16
|
+
from reconcile.external_resources.meta import (
|
17
|
+
FLAG_DELETE_RESOURCE,
|
18
|
+
FLAG_RESOURCE_MANAGED_BY_ERV2,
|
19
|
+
MODULE_OVERRIDES,
|
20
|
+
)
|
16
21
|
from reconcile.gql_definitions.external_resources.external_resources_modules import (
|
17
22
|
ExternalResourcesModuleV1,
|
18
23
|
)
|
19
24
|
from reconcile.gql_definitions.external_resources.external_resources_namespaces import (
|
25
|
+
ExternalResourcesModuleOverridesV1,
|
20
26
|
NamespaceTerraformProviderResourceAWSV1,
|
21
27
|
NamespaceTerraformResourceRDSV1,
|
22
|
-
NamespaceTerraformResourceRoleV1,
|
23
28
|
NamespaceV1,
|
24
29
|
)
|
25
30
|
from reconcile.utils.exceptions import FetchResourceError
|
@@ -60,30 +65,48 @@ class ExternalResourceKey(BaseModel, frozen=True):
|
|
60
65
|
return f"{self.provision_provider}/{self.provisioner_name}/{self.provider}/{self.identifier}"
|
61
66
|
|
62
67
|
|
68
|
+
SUPPORTED_RESOURCE_PROVIDERS = NamespaceTerraformProviderResourceAWSV1
|
69
|
+
SUPPORTED_RESOURCE_TYPES = NamespaceTerraformResourceRDSV1
|
70
|
+
|
71
|
+
|
63
72
|
class ExternalResourcesInventory(MutableMapping):
|
64
73
|
_inventory: dict[ExternalResourceKey, ExternalResourceSpec] = {}
|
65
74
|
|
75
|
+
def _build_external_resource_spec(
|
76
|
+
self,
|
77
|
+
namespace: NamespaceV1,
|
78
|
+
provider: SUPPORTED_RESOURCE_PROVIDERS,
|
79
|
+
resource: SUPPORTED_RESOURCE_TYPES,
|
80
|
+
) -> ExternalResourceSpec:
|
81
|
+
spec = ExternalResourceSpec(
|
82
|
+
provision_provider=provider.provider,
|
83
|
+
provisioner=provider.provisioner.dict(),
|
84
|
+
resource=resource.dict(
|
85
|
+
exclude={
|
86
|
+
FLAG_RESOURCE_MANAGED_BY_ERV2,
|
87
|
+
FLAG_DELETE_RESOURCE,
|
88
|
+
MODULE_OVERRIDES,
|
89
|
+
}
|
90
|
+
),
|
91
|
+
namespace=namespace.dict(),
|
92
|
+
)
|
93
|
+
spec.metadata[FLAG_DELETE_RESOURCE] = resource.delete
|
94
|
+
spec.metadata[MODULE_OVERRIDES] = resource.module_overrides
|
95
|
+
return spec
|
96
|
+
|
66
97
|
def __init__(self, namespaces: Iterable[NamespaceV1]) -> None:
|
67
98
|
desired_providers = [
|
68
99
|
(p, ns)
|
69
100
|
for ns in namespaces
|
70
101
|
for p in ns.external_resources or []
|
71
|
-
if isinstance(p,
|
102
|
+
if isinstance(p, SUPPORTED_RESOURCE_PROVIDERS) and p.resources
|
72
103
|
]
|
73
104
|
|
74
105
|
desired_specs = [
|
75
|
-
|
76
|
-
provision_provider=p.provider,
|
77
|
-
provisioner=p.provisioner.dict(),
|
78
|
-
resource=r.dict(),
|
79
|
-
namespace=ns.dict(),
|
80
|
-
)
|
106
|
+
self._build_external_resource_spec(ns, p, r)
|
81
107
|
for (p, ns) in desired_providers
|
82
108
|
for r in p.resources
|
83
|
-
if isinstance(
|
84
|
-
r, NamespaceTerraformResourceRDSV1 | NamespaceTerraformResourceRoleV1
|
85
|
-
)
|
86
|
-
and r.managed_by_erv2
|
109
|
+
if isinstance(r, SUPPORTED_RESOURCE_TYPES) and r.managed_by_erv2
|
87
110
|
]
|
88
111
|
|
89
112
|
for spec in desired_specs:
|
@@ -181,14 +204,22 @@ class ExternalResourceModuleConfiguration(BaseModel, frozen=True):
|
|
181
204
|
def resolve_configuration(
|
182
205
|
module: ExternalResourcesModuleV1, spec: ExternalResourceSpec
|
183
206
|
) -> "ExternalResourceModuleConfiguration":
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
207
|
+
module_overrides = spec.metadata.get(
|
208
|
+
"module_overrides"
|
209
|
+
) or ExternalResourcesModuleOverridesV1(
|
210
|
+
module_type=None,
|
211
|
+
image=None,
|
212
|
+
version=None,
|
213
|
+
reconcile_timeout_minutes=None,
|
214
|
+
)
|
215
|
+
|
216
|
+
return ExternalResourceModuleConfiguration(
|
217
|
+
image=module_overrides.image or module.image,
|
218
|
+
version=module_overrides.version or module.version,
|
219
|
+
reconcile_drift_interval_minutes=module.reconcile_drift_interval_minutes,
|
220
|
+
reconcile_timeout_minutes=module_overrides.reconcile_timeout_minutes
|
221
|
+
or module.reconcile_timeout_minutes,
|
222
|
+
)
|
192
223
|
|
193
224
|
|
194
225
|
class Reconciliation(BaseModel, frozen=True):
|
@@ -25,7 +25,7 @@ query ExternalResourcesModules {
|
|
25
25
|
provider
|
26
26
|
module_type
|
27
27
|
image
|
28
|
-
|
28
|
+
version
|
29
29
|
reconcile_drift_interval_minutes
|
30
30
|
reconcile_timeout_minutes
|
31
31
|
outputs_secret_sync
|
@@ -45,9 +45,9 @@ class ExternalResourcesModuleV1(ConfiguredBaseModel):
|
|
45
45
|
provider: str = Field(..., alias="provider")
|
46
46
|
module_type: str = Field(..., alias="module_type")
|
47
47
|
image: str = Field(..., alias="image")
|
48
|
-
|
49
|
-
reconcile_drift_interval_minutes:
|
50
|
-
reconcile_timeout_minutes:
|
48
|
+
version: str = Field(..., alias="version")
|
49
|
+
reconcile_drift_interval_minutes: int = Field(..., alias="reconcile_drift_interval_minutes")
|
50
|
+
reconcile_timeout_minutes: int = Field(..., alias="reconcile_timeout_minutes")
|
51
51
|
outputs_secret_sync: bool = Field(..., alias="outputs_secret_sync")
|
52
52
|
|
53
53
|
|
@@ -109,6 +109,12 @@ query ExternalResourcesNamespaces {
|
|
109
109
|
}
|
110
110
|
managed_by_erv2
|
111
111
|
delete
|
112
|
+
module_overrides {
|
113
|
+
module_type
|
114
|
+
image
|
115
|
+
version
|
116
|
+
reconcile_timeout_minutes
|
117
|
+
}
|
112
118
|
}
|
113
119
|
... on NamespaceTerraformResourceS3_v1 {
|
114
120
|
region
|
@@ -535,6 +541,13 @@ class AWSRDSDataClassificationV1(ConfiguredBaseModel):
|
|
535
541
|
loss_impact: Optional[str] = Field(..., alias="loss_impact")
|
536
542
|
|
537
543
|
|
544
|
+
class ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
|
545
|
+
module_type: Optional[str] = Field(..., alias="module_type")
|
546
|
+
image: Optional[str] = Field(..., alias="image")
|
547
|
+
version: Optional[str] = Field(..., alias="version")
|
548
|
+
reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
|
549
|
+
|
550
|
+
|
538
551
|
class NamespaceTerraformResourceRDSV1(NamespaceTerraformResourceAWSV1):
|
539
552
|
region: Optional[str] = Field(..., alias="region")
|
540
553
|
identifier: str = Field(..., alias="identifier")
|
@@ -554,6 +567,7 @@ class NamespaceTerraformResourceRDSV1(NamespaceTerraformResourceAWSV1):
|
|
554
567
|
data_classification: Optional[AWSRDSDataClassificationV1] = Field(..., alias="data_classification")
|
555
568
|
managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
|
556
569
|
delete: Optional[bool] = Field(..., alias="delete")
|
570
|
+
module_overrides: Optional[ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
|
557
571
|
|
558
572
|
|
559
573
|
class AWSS3EventNotificationV1(ConfiguredBaseModel):
|
@@ -88,13 +88,13 @@ class ExternalResourceSpec:
|
|
88
88
|
secret: Mapping[str, str] = field(init=False, default_factory=lambda: {})
|
89
89
|
# Metadata is used for processing data that shuold not be included in the secret data
|
90
90
|
# e.g: ERV2 adds a updated_at attribute that acts as optimistic lock.
|
91
|
-
metadata: MutableMapping[str,
|
91
|
+
metadata: MutableMapping[str, Any] = field(
|
92
92
|
init=False, compare=False, repr=False, hash=False, default_factory=lambda: {}
|
93
93
|
)
|
94
94
|
|
95
95
|
@property
|
96
96
|
def marked_to_delete(self) -> bool:
|
97
|
-
return self.
|
97
|
+
return self.metadata.get("delete") or False
|
98
98
|
|
99
99
|
@property
|
100
100
|
def provider(self) -> str:
|
tools/qontract_cli.py
CHANGED
@@ -60,9 +60,9 @@ from reconcile.external_resources.integration import (
|
|
60
60
|
get_aws_api,
|
61
61
|
)
|
62
62
|
from reconcile.external_resources.manager import (
|
63
|
-
FLAG_RESOURCE_MANAGED_BY_ERV2,
|
64
63
|
setup_factories,
|
65
64
|
)
|
65
|
+
from reconcile.external_resources.meta import FLAG_RESOURCE_MANAGED_BY_ERV2
|
66
66
|
from reconcile.external_resources.model import (
|
67
67
|
ExternalResourceKey,
|
68
68
|
ExternalResourcesInventory,
|
{qontract_reconcile-0.10.1rc1024.dist-info → qontract_reconcile-0.10.1rc1026.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|