qontract-reconcile 0.10.1rc965__py3-none-any.whl → 0.10.1rc967__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.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/RECORD +12 -12
- reconcile/external_resources/manager.py +15 -13
- reconcile/external_resources/meta.py +3 -0
- reconcile/external_resources/model.py +0 -5
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +2 -0
- reconcile/utils/external_resource_spec.py +4 -0
- reconcile/utils/jinja2/filters.py +10 -0
- reconcile/utils/jinja2/utils.py +2 -0
- {qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.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.1rc967
|
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.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/RECORD
RENAMED
@@ -188,10 +188,10 @@ reconcile/external_resources/aws.py,sha256=JvjKaABy2Pg8u8Lq82Acv4zMvpE3_qGKes7OG
|
|
188
188
|
reconcile/external_resources/factories.py,sha256=DXgaLxoO87zZ76VOpRpu2GeYGhsbfOnOx5mrzgo4Gf4,4767
|
189
189
|
reconcile/external_resources/integration.py,sha256=PJOpz-wUf7NzWvqCDalRWu5OxKjgi5RwiiB6HZfJs0k,5122
|
190
190
|
reconcile/external_resources/integration_secrets_sync.py,sha256=cMEZhgCvABAMf-DWF051L6CRnJQdfbsISA_b1xuS940,1670
|
191
|
-
reconcile/external_resources/manager.py,sha256=
|
192
|
-
reconcile/external_resources/meta.py,sha256=
|
191
|
+
reconcile/external_resources/manager.py,sha256=5H7anOL7ISIypX2V2Usjviu1vptUQOWoWRXSbyTc69s,14689
|
192
|
+
reconcile/external_resources/meta.py,sha256=cMT9OsKcUY26qwEjlQ02EkorvOBNqWj0JVMwfJa3Mg0,634
|
193
193
|
reconcile/external_resources/metrics.py,sha256=m2TIOao2N7pD6k45driFbBGVCC_N7ai44m-lLPfa5qk,454
|
194
|
-
reconcile/external_resources/model.py,sha256=
|
194
|
+
reconcile/external_resources/model.py,sha256=euc7spP3ZRfsn7NTFTv_1Ow6SzvLTskCYTUNWw0XY9Y,7219
|
195
195
|
reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYjHGyICWff9bxlc,9323
|
196
196
|
reconcile/external_resources/secrets_sync.py,sha256=GsNKhfUAbuER4bgc0p3ZKOrc3vTGNc01HItyuscpMAY,15102
|
197
197
|
reconcile/external_resources/state.py,sha256=Yk1YAebiJ7D5J1CFaGI_L-buxdFFx1UrZESVykLJaPM,9629
|
@@ -278,7 +278,7 @@ reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py
|
|
278
278
|
reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
279
279
|
reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=XR69j9dpTQ0gv8y-AZN7AJ0dPvO-wbHscyCDgrax6Bk,2046
|
280
280
|
reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=g2KB2wRnb8zF7xCmDJJFmiRdE4z4aYa9HtY3vCBVwMA,2441
|
281
|
-
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=
|
281
|
+
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=pXx58C8a2TfClsPqdRmRlQ3ILAX7Irnz-Ank8C8N_gM,40994
|
282
282
|
reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=Hw9n_90BPG6Lnt2PT3mHc6p0KEm2CxKxvSGRFc_Dhus,2982
|
283
283
|
reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
284
284
|
reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
|
@@ -651,7 +651,7 @@ reconcile/utils/environ.py,sha256=psk07d2xyjbUzjOCDdNWgavaNolL_t2sq3sn2gFfY9k,50
|
|
651
651
|
reconcile/utils/exceptions.py,sha256=DwfnWUpVOotpP79RWZ2pycmG6nKCL00RBIeZLYkQPW4,635
|
652
652
|
reconcile/utils/expiration.py,sha256=Yv-pBE-UZ6kNkLLgDUdmEUg62uxPEX_RZlA0XAKrs4w,1203
|
653
653
|
reconcile/utils/extended_early_exit.py,sha256=QSktrmfw37zSRMNk930tDbQsVeKxaPPPD43e79DGwZw,6754
|
654
|
-
reconcile/utils/external_resource_spec.py,sha256=
|
654
|
+
reconcile/utils/external_resource_spec.py,sha256=3z3Y2JGY8cO7hPc8JHkdczmrP81D7TKQ4uT128WhE_M,7006
|
655
655
|
reconcile/utils/external_resources.py,sha256=T6h172jzz_i9c10tMtoDfp5llRdLlIMkz6OuUZ7tH9Y,7558
|
656
656
|
reconcile/utils/filtering.py,sha256=S4PbMHuFr3ED0P2Q_ea5CAaB7FimI62B-F5YTaKrphA,402
|
657
657
|
reconcile/utils/git.py,sha256=actOWI2HiNpMIV6nHCzinhRa6b04Y9plWOCcPQa8lNA,1437
|
@@ -742,8 +742,8 @@ reconcile/utils/internal_groups/client.py,sha256=RL-fNDtMGfpD7pNjCEmrj_0PV3ClCtU
|
|
742
742
|
reconcile/utils/internal_groups/models.py,sha256=y_IqBVqfGqNXiu0VudvBWFrm_-uafVm5KgLG-ca8XAs,2281
|
743
743
|
reconcile/utils/jinja2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
744
744
|
reconcile/utils/jinja2/extensions.py,sha256=7K-uo6G2eCWa98MHT8fRPYIKCLQB_5D2keqQ_LyAfHM,1293
|
745
|
-
reconcile/utils/jinja2/filters.py,sha256=
|
746
|
-
reconcile/utils/jinja2/utils.py,sha256=
|
745
|
+
reconcile/utils/jinja2/filters.py,sha256=tmiaYMhji5fv4B66YtR7zc-mE3wQLyj5I5SeX0WA2l4,4754
|
746
|
+
reconcile/utils/jinja2/utils.py,sha256=W_LMB2KiGuwIo04GUNK7jKCpmhKy6wGOH1jgshzXBU0,8004
|
747
747
|
reconcile/utils/jobcontroller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
748
748
|
reconcile/utils/jobcontroller/controller.py,sha256=2V_vm5thFx6adW4bMy9CdHXFesuo6S4lSkEpGxkXSM0,14492
|
749
749
|
reconcile/utils/jobcontroller/models.py,sha256=tSRAkUX23iyn4YPsWEicFXwRxw3mXb5B2pDOWmXX8wQ,6350
|
@@ -847,8 +847,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
|
|
847
847
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
848
848
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
849
849
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
850
|
-
qontract_reconcile-0.10.
|
851
|
-
qontract_reconcile-0.10.
|
852
|
-
qontract_reconcile-0.10.
|
853
|
-
qontract_reconcile-0.10.
|
854
|
-
qontract_reconcile-0.10.
|
850
|
+
qontract_reconcile-0.10.1rc967.dist-info/METADATA,sha256=U1KHlHKS0EVLd-fnOLrjHk2OZaH3Y5t1BZW8ci9Np9s,2262
|
851
|
+
qontract_reconcile-0.10.1rc967.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
852
|
+
qontract_reconcile-0.10.1rc967.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
853
|
+
qontract_reconcile-0.10.1rc967.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
854
|
+
qontract_reconcile-0.10.1rc967.dist-info/RECORD,,
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import json
|
2
1
|
import logging
|
3
2
|
from collections.abc import Iterable
|
4
3
|
from datetime import UTC, datetime
|
@@ -43,6 +42,7 @@ from reconcile.utils.external_resource_spec import (
|
|
43
42
|
from reconcile.utils.secret_reader import SecretReaderBase
|
44
43
|
|
45
44
|
FLAG_RESOURCE_MANAGED_BY_ERV2 = "managed_by_erv2"
|
45
|
+
FLAG_DELETE_RESOURCE = "delete"
|
46
46
|
|
47
47
|
|
48
48
|
def setup_factories(
|
@@ -157,13 +157,13 @@ class ExternalResourcesManager:
|
|
157
157
|
def _get_desired_objects_reconciliations(self) -> set[Reconciliation]:
|
158
158
|
r: set[Reconciliation] = set()
|
159
159
|
for key, spec in self.er_inventory.items():
|
160
|
+
if spec.marked_to_delete:
|
161
|
+
continue
|
160
162
|
module = self.module_inventory.get_from_spec(spec)
|
161
|
-
|
162
163
|
try:
|
163
164
|
resource = self._build_external_resource(spec, self.er_inventory)
|
164
165
|
except ExternalResourceValidationError as e:
|
165
|
-
|
166
|
-
self.errors[k] = e
|
166
|
+
self.errors[key] = e
|
167
167
|
continue
|
168
168
|
|
169
169
|
reconciliation = Reconciliation(
|
@@ -179,21 +179,23 @@ class ExternalResourcesManager:
|
|
179
179
|
return r
|
180
180
|
|
181
181
|
def _get_deleted_objects_reconciliations(self) -> set[Reconciliation]:
|
182
|
-
|
183
|
-
|
184
|
-
deleted_keys = state_resource_keys - desired_keys
|
185
|
-
r: set[Reconciliation] = set()
|
182
|
+
to_reconcile: set[Reconciliation] = set()
|
183
|
+
deleted_keys = (k for k, v in self.er_inventory.items() if v.marked_to_delete)
|
186
184
|
for key in deleted_keys:
|
187
185
|
state = self.state_mgr.get_external_resource_state(key)
|
188
|
-
|
186
|
+
if state.resource_status == ResourceStatus.NOT_EXISTS:
|
187
|
+
logging.debug("Resource has already been removed. key: %s", key)
|
188
|
+
continue
|
189
|
+
|
190
|
+
r = Reconciliation(
|
189
191
|
key=key,
|
190
192
|
resource_hash=state.reconciliation.resource_hash,
|
191
193
|
module_configuration=state.reconciliation.module_configuration,
|
192
194
|
input=state.reconciliation.input,
|
193
195
|
action=Action.DESTROY,
|
194
196
|
)
|
195
|
-
|
196
|
-
return
|
197
|
+
to_reconcile.add(r)
|
198
|
+
return to_reconcile
|
197
199
|
|
198
200
|
def _update_in_progress_state(
|
199
201
|
self, r: Reconciliation, state: ExternalResourceState
|
@@ -310,8 +312,8 @@ class ExternalResourcesManager:
|
|
310
312
|
return resource
|
311
313
|
|
312
314
|
def _serialize_resource_input(self, resource: ExternalResource) -> str:
|
313
|
-
return json
|
314
|
-
|
315
|
+
return resource.json(
|
316
|
+
exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2, FLAG_DELETE_RESOURCE}}
|
315
317
|
)
|
316
318
|
|
317
319
|
def handle_resources(self) -> None:
|
@@ -11,3 +11,6 @@ SECRET_ANN_PROVIDER = SECRET_ANN_PREFIX + "/provider"
|
|
11
11
|
SECRET_ANN_IDENTIFIER = SECRET_ANN_PREFIX + "/identifier"
|
12
12
|
SECRET_UPDATED_AT = SECRET_ANN_PREFIX + "/updated_at"
|
13
13
|
SECRET_UPDATED_AT_TIMEFORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
14
|
+
|
15
|
+
FLAG_RESOURCE_MANAGED_BY_ERV2 = "managed_by_erv2"
|
16
|
+
FLAG_DELETE_RESOURCE = "delete"
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import base64
|
2
1
|
import hashlib
|
3
2
|
import json
|
4
3
|
from abc import (
|
@@ -88,7 +87,6 @@ class ExternalResourcesInventory(MutableMapping):
|
|
88
87
|
]
|
89
88
|
|
90
89
|
for spec in desired_specs:
|
91
|
-
# self.set(ExternalResourceKey.from_spec(spec), spec)
|
92
90
|
self._inventory[ExternalResourceKey.from_spec(spec)] = spec
|
93
91
|
|
94
92
|
def __getitem__(self, key: ExternalResourceKey) -> ExternalResourceSpec | None:
|
@@ -239,6 +237,3 @@ class ExternalResource(BaseModel):
|
|
239
237
|
return hashlib.md5(
|
240
238
|
json.dumps(self.data, sort_keys=True).encode("utf-8")
|
241
239
|
).hexdigest()
|
242
|
-
|
243
|
-
def serialize_input(self) -> str:
|
244
|
-
return base64.b64encode(json.dumps(self.dict()).encode()).decode()
|
@@ -108,6 +108,7 @@ query ExternalResourcesNamespaces {
|
|
108
108
|
loss_impact
|
109
109
|
}
|
110
110
|
managed_by_erv2
|
111
|
+
delete
|
111
112
|
}
|
112
113
|
... on NamespaceTerraformResourceS3_v1 {
|
113
114
|
region
|
@@ -552,6 +553,7 @@ class NamespaceTerraformResourceRDSV1(NamespaceTerraformResourceAWSV1):
|
|
552
553
|
event_notifications: Optional[list[AWSRDSEventNotificationV1]] = Field(..., alias="event_notifications")
|
553
554
|
data_classification: Optional[AWSRDSDataClassificationV1] = Field(..., alias="data_classification")
|
554
555
|
managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
|
556
|
+
delete: Optional[bool] = Field(..., alias="delete")
|
555
557
|
|
556
558
|
|
557
559
|
class AWSS3EventNotificationV1(ConfiguredBaseModel):
|
@@ -92,6 +92,10 @@ class ExternalResourceSpec:
|
|
92
92
|
init=False, compare=False, repr=False, hash=False, default_factory=lambda: {}
|
93
93
|
)
|
94
94
|
|
95
|
+
@property
|
96
|
+
def marked_to_delete(self) -> bool:
|
97
|
+
return self.resource.get("delete") or False
|
98
|
+
|
95
99
|
@property
|
96
100
|
def provider(self) -> str:
|
97
101
|
return self.resource["provider"]
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
6
6
|
from urllib import parse
|
7
7
|
|
8
8
|
import jinja2
|
9
|
+
import yaml
|
9
10
|
|
10
11
|
from reconcile.utils.jsonpath import parse_jsonpath
|
11
12
|
|
@@ -20,6 +21,15 @@ def json_to_dict(input: str) -> Any:
|
|
20
21
|
return data
|
21
22
|
|
22
23
|
|
24
|
+
def yaml_to_dict(input: str) -> Any:
|
25
|
+
"""Jinja2 filter to parse YAML strings into dictionaries.
|
26
|
+
:param input: yaml string
|
27
|
+
:return: dict with the parsed inputs contents
|
28
|
+
"""
|
29
|
+
data = yaml.safe_load(input)
|
30
|
+
return data
|
31
|
+
|
32
|
+
|
23
33
|
def urlescape(string: str, safe: str = "/", encoding: str | None = None) -> str:
|
24
34
|
"""Jinja2 filter that is a simple wrapper around urllib's URL quoting
|
25
35
|
functions that takes a string value and makes it safe for use as URL
|
reconcile/utils/jinja2/utils.py
CHANGED
@@ -23,6 +23,7 @@ from reconcile.utils.jinja2.filters import (
|
|
23
23
|
matches_jsonpath,
|
24
24
|
urlescape,
|
25
25
|
urlunescape,
|
26
|
+
yaml_to_dict,
|
26
27
|
)
|
27
28
|
from reconcile.utils.secret_reader import SecretNotFound, SecretReader, SecretReaderBase
|
28
29
|
from reconcile.utils.vault import SecretFieldNotFound
|
@@ -81,6 +82,7 @@ def compile_jinja2_template(
|
|
81
82
|
)
|
82
83
|
jinja_env.filters.update({
|
83
84
|
"json_to_dict": json_to_dict,
|
85
|
+
"yaml_to_dict": yaml_to_dict,
|
84
86
|
"urlescape": urlescape,
|
85
87
|
"urlunescape": urlunescape,
|
86
88
|
"eval": eval_filter,
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc965.dist-info → qontract_reconcile-0.10.1rc967.dist-info}/top_level.txt
RENAMED
File without changes
|