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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc965
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
@@ -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=sprARDkMujYreN38sWUDPuZc7hokTL5bM0zEnlPVQKk,14563
192
- reconcile/external_resources/meta.py,sha256=Z5guBceyaGyAzzA9kVb0-WaNpSli368NVUnWulxtMb4,551
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=PZbCLbZ6UGjUzeqcK7RdV4Yh_C7H2FvsfI1GsQGGDxk,7413
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=UyOAUY1rROenjTz6y-uSEFjrEwhh-lPsIQPbi6EQLFg,40915
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=YTUxo6lyF7UrBzsBRd1Zse72jEmWmYQPODTcj1Yxpw0,6899
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=RVVkpf87FllrPUpqk_8KN-r1IsmnS0bpygAVvsvIr5g,4504
746
- reconcile/utils/jinja2/utils.py,sha256=4KT3r7k5b9rL7l3h3kUzcehjU1eOXYP4KocboVbMqsg,7948
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.1rc965.dist-info/METADATA,sha256=dhDXF0tDhZMesAYNbk_FAaWNPiI-Yigm-PUmjwWxaFE,2262
851
- qontract_reconcile-0.10.1rc965.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
852
- qontract_reconcile-0.10.1rc965.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
853
- qontract_reconcile-0.10.1rc965.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
854
- qontract_reconcile-0.10.1rc965.dist-info/RECORD,,
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
- k = ExternalResourceKey.from_spec(spec)
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
- desired_keys = set(self.er_inventory.keys())
183
- state_resource_keys = self.state_mgr.get_all_resource_keys()
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
- reconciliation = Reconciliation(
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
- r.add(reconciliation)
196
- return r
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.dumps(
314
- resource.dict(exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}})
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
@@ -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,