qontract-reconcile 0.10.1rc1090__py3-none-any.whl → 0.10.1rc1091__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.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/RECORD +10 -10
- reconcile/external_resources/manager.py +29 -14
- reconcile/external_resources/metrics.py +13 -7
- reconcile/external_resources/reconciler.py +11 -0
- reconcile/external_resources/state.py +0 -7
- reconcile/utils/jobcontroller/controller.py +20 -0
- {qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.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.1rc1091
|
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.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/RECORD
RENAMED
@@ -196,13 +196,13 @@ reconcile/external_resources/aws.py,sha256=7W-6d-lXO6JGwaxtO1Uc3Lw0p8csJ1EVgz__O
|
|
196
196
|
reconcile/external_resources/factories.py,sha256=nhdTqf1WEfRfgd5-70KAUJVz0ZvZ19C3Pz7wmotSdrs,4857
|
197
197
|
reconcile/external_resources/integration.py,sha256=y1gJ16woMBC3J9qniMmS5y3lCkAs7V_ETZRUwjKqaO0,6628
|
198
198
|
reconcile/external_resources/integration_secrets_sync.py,sha256=cMEZhgCvABAMf-DWF051L6CRnJQdfbsISA_b1xuS940,1670
|
199
|
-
reconcile/external_resources/manager.py,sha256=
|
199
|
+
reconcile/external_resources/manager.py,sha256=AvBYpC4p2BaGrxYEV1ut3V2FtJfs1h2z0Vk8Px6dCaQ,15641
|
200
200
|
reconcile/external_resources/meta.py,sha256=noaytFzmShpzLA_ebGh7wuP45mOfHIOnnoUxivjDa1I,672
|
201
|
-
reconcile/external_resources/metrics.py,sha256=
|
201
|
+
reconcile/external_resources/metrics.py,sha256=Ihhe39BX0h2w7eLvvdijJuCXjj-f7w1E3MfDL0YiGNU,668
|
202
202
|
reconcile/external_resources/model.py,sha256=UuQgrnv-SSkvSEQQGeCE2IZkhXjLTCVkP_mw8zBZsIQ,8349
|
203
|
-
reconcile/external_resources/reconciler.py,sha256=
|
203
|
+
reconcile/external_resources/reconciler.py,sha256=3KFmkHsN7YAwJUSBpN1Xd_D2zM9Ea5_c2uMGWsfruZo,9707
|
204
204
|
reconcile/external_resources/secrets_sync.py,sha256=6n0oDPLjd9Ql0lf6zsr1AZw8A6EEe3yCzl20XodtgkE,16229
|
205
|
-
reconcile/external_resources/state.py,sha256=
|
205
|
+
reconcile/external_resources/state.py,sha256=pjxqfjZ-DXmN_9dpfaAwhTtTDr4XrcPlwuQ7S3m25Eo,9326
|
206
206
|
reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
207
207
|
reconcile/glitchtip/integration.py,sha256=XtewM9nfTPLnPSpYebP50GrveYOnhTvKNq3seSvL6u8,8343
|
208
208
|
reconcile/glitchtip/reconciler.py,sha256=nUvDv7qG1ly0cA16MmlL6NV71yl1mJYLT2mui7lmi0Y,12402
|
@@ -767,7 +767,7 @@ reconcile/utils/jinja2/extensions.py,sha256=7K-uo6G2eCWa98MHT8fRPYIKCLQB_5D2keqQ
|
|
767
767
|
reconcile/utils/jinja2/filters.py,sha256=JfO_14APySBPidsMvHXG-8dULNPddZCE15Umjk_aSBk,4830
|
768
768
|
reconcile/utils/jinja2/utils.py,sha256=adxVFY4WvBGIToEEr8KwqLzp6uDxSipTBzZWwnRqbNQ,8700
|
769
769
|
reconcile/utils/jobcontroller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
770
|
-
reconcile/utils/jobcontroller/controller.py,sha256=
|
770
|
+
reconcile/utils/jobcontroller/controller.py,sha256=Vh08lZuCSIIceWGSDhBB00iFwTI9eeKZW1sfHlkAvSo,15373
|
771
771
|
reconcile/utils/jobcontroller/models.py,sha256=x9YIvWfYOOvXNKToFVx1H7qDrZb0Sa1KI_4Y0gl7rMM,6336
|
772
772
|
reconcile/utils/membershipsources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
773
773
|
reconcile/utils/membershipsources/app_interface_resolver.py,sha256=MqDFvK3aXhmmMuMiIygC-onFVrrIopKHriaYJQ5jnuY,1988
|
@@ -870,8 +870,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
|
|
870
870
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
871
871
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
872
872
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
873
|
-
qontract_reconcile-0.10.
|
874
|
-
qontract_reconcile-0.10.
|
875
|
-
qontract_reconcile-0.10.
|
876
|
-
qontract_reconcile-0.10.
|
877
|
-
qontract_reconcile-0.10.
|
873
|
+
qontract_reconcile-0.10.1rc1091.dist-info/METADATA,sha256=CLxB_EMfDQaVjFpxvKcZYESvRdIAyVLc9S3hlWpiDYM,2213
|
874
|
+
qontract_reconcile-0.10.1rc1091.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
875
|
+
qontract_reconcile-0.10.1rc1091.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
876
|
+
qontract_reconcile-0.10.1rc1091.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
877
|
+
qontract_reconcile-0.10.1rc1091.dist-info/RECORD,,
|
@@ -13,7 +13,10 @@ from reconcile.external_resources.factories import (
|
|
13
13
|
TerraformModuleProvisionDataFactory,
|
14
14
|
setup_aws_resource_factories,
|
15
15
|
)
|
16
|
-
from reconcile.external_resources.metrics import
|
16
|
+
from reconcile.external_resources.metrics import (
|
17
|
+
ExternalResourcesReconcileErrorsCounter,
|
18
|
+
ExternalResourcesReconcileTimeGauge,
|
19
|
+
)
|
17
20
|
from reconcile.external_resources.model import (
|
18
21
|
Action,
|
19
22
|
ExternalResource,
|
@@ -24,7 +27,10 @@ from reconcile.external_resources.model import (
|
|
24
27
|
ModuleInventory,
|
25
28
|
Reconciliation,
|
26
29
|
)
|
27
|
-
from reconcile.external_resources.reconciler import
|
30
|
+
from reconcile.external_resources.reconciler import (
|
31
|
+
ExternalResourcesReconciler,
|
32
|
+
ReconciliationK8sJob,
|
33
|
+
)
|
28
34
|
from reconcile.external_resources.secrets_sync import InClusterSecretsReconciler
|
29
35
|
from reconcile.external_resources.state import (
|
30
36
|
ExternalResourcesStateDynamoDB,
|
@@ -232,6 +238,7 @@ class ExternalResourcesManager:
|
|
232
238
|
|
233
239
|
# Need to check the reconciliation set in the state, not the desired one
|
234
240
|
# as the reconciliation object might be from a previous desired state
|
241
|
+
job_name = ReconciliationK8sJob(reconciliation=r).name()
|
235
242
|
error = False
|
236
243
|
match self.reconciler.get_resource_reconcile_status(state.reconciliation):
|
237
244
|
case ReconcileStatus.SUCCESS:
|
@@ -242,12 +249,22 @@ class ExternalResourcesManager:
|
|
242
249
|
)
|
243
250
|
if r.action == Action.APPLY:
|
244
251
|
state.resource_status = ResourceStatus.PENDING_SECRET_SYNC
|
245
|
-
state.reconciliation_errors = 0
|
246
252
|
self.state_mgr.set_external_resource_state(state)
|
247
253
|
need_secret_sync = True
|
248
254
|
elif r.action == Action.DESTROY:
|
249
255
|
state.resource_status = ResourceStatus.DELETED
|
250
256
|
self.state_mgr.del_external_resource_state(r.key)
|
257
|
+
|
258
|
+
metrics.set_gauge(
|
259
|
+
ExternalResourcesReconcileTimeGauge(
|
260
|
+
provision_provider=r.key.provision_provider,
|
261
|
+
provisioner_name=r.key.provisioner_name,
|
262
|
+
provider=r.key.provider,
|
263
|
+
identifier=r.key.identifier,
|
264
|
+
job_name=job_name,
|
265
|
+
),
|
266
|
+
self.reconciler.get_resource_reconcile_duration(r) or 0,
|
267
|
+
)
|
251
268
|
case ReconcileStatus.ERROR:
|
252
269
|
logging.info(
|
253
270
|
"Reconciliation ended with ERROR: Action:%s, Key:%s",
|
@@ -264,8 +281,16 @@ class ExternalResourcesManager:
|
|
264
281
|
error = True
|
265
282
|
if error:
|
266
283
|
state.resource_status = ResourceStatus.ERROR
|
267
|
-
state.reconciliation_errors += 1
|
268
284
|
self.state_mgr.set_external_resource_state(state)
|
285
|
+
metrics.inc_counter(
|
286
|
+
ExternalResourcesReconcileErrorsCounter(
|
287
|
+
provision_provider=r.key.provision_provider,
|
288
|
+
provisioner_name=r.key.provisioner_name,
|
289
|
+
provider=r.key.provider,
|
290
|
+
identifier=r.key.identifier,
|
291
|
+
job_name=job_name,
|
292
|
+
)
|
293
|
+
)
|
269
294
|
|
270
295
|
return need_secret_sync
|
271
296
|
|
@@ -332,16 +357,6 @@ class ExternalResourcesManager:
|
|
332
357
|
if need_sync:
|
333
358
|
to_sync_keys.add(r.key)
|
334
359
|
|
335
|
-
metrics.set_gauge(
|
336
|
-
ExternalResourcesReconcileErrorsGauge(
|
337
|
-
provision_provider=r.key.provision_provider,
|
338
|
-
provisioner_name=r.key.provisioner_name,
|
339
|
-
provider=r.key.provider,
|
340
|
-
identifier=r.key.identifier,
|
341
|
-
),
|
342
|
-
float(state.reconciliation_errors),
|
343
|
-
)
|
344
|
-
|
345
360
|
if self._resource_needs_reconciliation(reconciliation=r, state=state):
|
346
361
|
self.reconciler.reconcile_resource(reconciliation=r)
|
347
362
|
self._update_state(r, state)
|
@@ -1,20 +1,26 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
2
|
|
3
|
-
from reconcile.utils.metrics import
|
4
|
-
GaugeMetric,
|
5
|
-
)
|
3
|
+
from reconcile.utils.metrics import CounterMetric, GaugeMetric
|
6
4
|
|
7
5
|
|
8
6
|
class ExternalResourcesBaseMetric(BaseModel):
|
9
7
|
integration = "external_resources"
|
10
|
-
|
11
|
-
|
12
|
-
class ExternalResourcesReconcileErrorsGauge(ExternalResourcesBaseMetric, GaugeMetric):
|
13
8
|
provision_provider: str
|
14
9
|
provisioner_name: str
|
15
10
|
provider: str
|
16
11
|
identifier: str
|
12
|
+
job_name: str
|
13
|
+
|
14
|
+
|
15
|
+
class ExternalResourcesReconcileErrorsCounter(
|
16
|
+
ExternalResourcesBaseMetric, CounterMetric
|
17
|
+
):
|
18
|
+
@classmethod
|
19
|
+
def name(cls) -> str:
|
20
|
+
return "external_resources_reconcile_errors"
|
21
|
+
|
17
22
|
|
23
|
+
class ExternalResourcesReconcileTimeGauge(ExternalResourcesBaseMetric, GaugeMetric):
|
18
24
|
@classmethod
|
19
25
|
def name(cls) -> str:
|
20
|
-
return "
|
26
|
+
return "external_resources_reconcile_time"
|
@@ -38,6 +38,11 @@ class ExternalResourcesReconciler(ABC):
|
|
38
38
|
reconciliation: Reconciliation,
|
39
39
|
) -> ReconcileStatus: ...
|
40
40
|
|
41
|
+
@abstractmethod
|
42
|
+
def get_resource_reconcile_duration(
|
43
|
+
self, reconciliation: Reconciliation
|
44
|
+
) -> int | None: ...
|
45
|
+
|
41
46
|
@abstractmethod
|
42
47
|
def reconcile_resource(self, reconciliation: Reconciliation) -> None: ...
|
43
48
|
|
@@ -199,6 +204,12 @@ class K8sExternalResourcesReconciler(ExternalResourcesReconciler):
|
|
199
204
|
job_name = ReconciliationK8sJob(reconciliation=reconciliation).name()
|
200
205
|
return ReconcileStatus(self.controller.get_job_status(job_name))
|
201
206
|
|
207
|
+
def get_resource_reconcile_duration(
|
208
|
+
self, reconciliation: Reconciliation
|
209
|
+
) -> int | None:
|
210
|
+
job_name = ReconciliationK8sJob(reconciliation=reconciliation).name()
|
211
|
+
return self.controller.get_success_job_duration(job_name)
|
212
|
+
|
202
213
|
def reconcile_resource(self, reconciliation: Reconciliation) -> None:
|
203
214
|
concurrency_policy = (
|
204
215
|
JobConcurrencyPolicy.REPLACE_FAILED | JobConcurrencyPolicy.REPLACE_FINISHED
|
@@ -44,7 +44,6 @@ class ExternalResourceState(BaseModel):
|
|
44
44
|
ts: datetime
|
45
45
|
resource_status: ResourceStatus
|
46
46
|
reconciliation: Reconciliation
|
47
|
-
reconciliation_errors: int = 0
|
48
47
|
|
49
48
|
|
50
49
|
class DynamoDBStateAdapter:
|
@@ -53,7 +52,6 @@ class DynamoDBStateAdapter:
|
|
53
52
|
|
54
53
|
RESOURCE_STATUS = "resource_status"
|
55
54
|
TIMESTAMP = "time_stamp"
|
56
|
-
RECONCILIATION_ERRORS = "reconciliation_errors"
|
57
55
|
|
58
56
|
ER_KEY = "external_resource_key"
|
59
57
|
ER_KEY_PROVISION_PROVIDER = "provision_provider"
|
@@ -120,9 +118,6 @@ class DynamoDBStateAdapter:
|
|
120
118
|
ts=self._get_value(item, self.TIMESTAMP),
|
121
119
|
resource_status=self._get_value(item, self.RESOURCE_STATUS),
|
122
120
|
reconciliation=r,
|
123
|
-
reconciliation_errors=int(
|
124
|
-
self._get_value(item, self.RECONCILIATION_ERRORS, _type="N")
|
125
|
-
),
|
126
121
|
)
|
127
122
|
|
128
123
|
def serialize(self, state: ExternalResourceState) -> dict[str, Any]:
|
@@ -130,7 +125,6 @@ class DynamoDBStateAdapter:
|
|
130
125
|
self.ER_KEY_HASH: {"S": state.key.hash()},
|
131
126
|
self.TIMESTAMP: {"S": state.ts.isoformat()},
|
132
127
|
self.RESOURCE_STATUS: {"S": state.resource_status.value},
|
133
|
-
self.RECONCILIATION_ERRORS: {"N": str(state.reconciliation_errors)},
|
134
128
|
self.ER_KEY: {
|
135
129
|
"M": {
|
136
130
|
self.ER_KEY_PROVISION_PROVIDER: {"S": state.key.provision_provider},
|
@@ -176,7 +170,6 @@ class ExternalResourcesStateDynamoDB:
|
|
176
170
|
DynamoDBStateAdapter.ER_KEY,
|
177
171
|
DynamoDBStateAdapter.TIMESTAMP,
|
178
172
|
DynamoDBStateAdapter.RESOURCE_STATUS,
|
179
|
-
DynamoDBStateAdapter.RECONCILIATION_ERRORS,
|
180
173
|
f"{DynamoDBStateAdapter.RECONC}.{DynamoDBStateAdapter.RECONC_RESOURCE_HASH}",
|
181
174
|
])
|
182
175
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import time
|
3
|
+
from datetime import datetime
|
3
4
|
from typing import Protocol, TextIO
|
4
5
|
|
5
6
|
from kubernetes.client import ( # type: ignore[attr-defined]
|
@@ -143,6 +144,25 @@ class K8sJobController:
|
|
143
144
|
return JobStatus.ERROR
|
144
145
|
return JobStatus.IN_PROGRESS
|
145
146
|
|
147
|
+
def get_success_job_duration(self, job_name: str) -> int | None:
|
148
|
+
"""
|
149
|
+
Returns the number of seconds the job took to complete.
|
150
|
+
* If a job is not completed with success, returns None
|
151
|
+
"""
|
152
|
+
if self.get_job_status(job_name) != JobStatus.SUCCESS:
|
153
|
+
return None
|
154
|
+
job_resource = self.cache.get(job_name)
|
155
|
+
if job_resource is None:
|
156
|
+
return None
|
157
|
+
status = job_resource.body.get("status") or {}
|
158
|
+
start_time = status.get("startTime", None)
|
159
|
+
completion_time = status.get("completionTime", None)
|
160
|
+
if not completion_time or not start_time:
|
161
|
+
return None
|
162
|
+
dt_start_time = datetime.fromisoformat(start_time)
|
163
|
+
dt_completion_time = datetime.fromisoformat(completion_time)
|
164
|
+
return int((dt_completion_time - dt_start_time).total_seconds())
|
165
|
+
|
146
166
|
def wait_for_job_list_completion(
|
147
167
|
self, job_names: set[str], check_interval_seconds: int, timeout_seconds: int
|
148
168
|
) -> dict[str, JobStatus]:
|
{qontract_reconcile-0.10.1rc1090.dist-info → qontract_reconcile-0.10.1rc1091.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|