qontract-reconcile 0.10.2.dev282__py3-none-any.whl → 0.10.2.dev284__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.dev282
3
+ Version: 0.10.2.dev284
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
@@ -445,6 +445,12 @@ GQL definitions and generated classes can be found [here](reconcile/gql_definiti
445
445
  5. `make gql-introspection` gets the type definitions. They will be stored in `reconcile/gql_definitions/introspection.json`
446
446
  6. `make gql-query-classes` generates the data classes for your queries and fragments
447
447
 
448
+ ## Design Patterns
449
+
450
+ This project follows a set of established architectural and implementation patterns to ensure consistency, reliability, and scalability. For a detailed explanation of these concepts, please see the **[Design Patterns Documentation](docs/patterns/README.md)**.
451
+
452
+ Understanding these patterns, especially the `qenerate` workflow for GraphQL data binding, is highly recommended for new developers.
453
+
448
454
  ## Troubleshooting
449
455
 
450
456
  `faulthandler` is enabled for this project and SIGUSR1 is registered to dump the traceback. To do so, you can use `kill -USR1 pid` where pid is the ID of the qontract-reconcile process.
@@ -152,7 +152,7 @@ reconcile/aws_saml_idp/integration.py,sha256=rop8ahl7v0WUheSgVLb-4MU3Ldy6Eb3LknF
152
152
  reconcile/aws_saml_roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
153
  reconcile/aws_saml_roles/integration.py,sha256=mLRCnSfClp2ia8UynSmY5HZe5YmrJTc1RwxyMeU2yBw,11319
154
154
  reconcile/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
- reconcile/aws_version_sync/integration.py,sha256=YeqvWMfMtTqTMG6_2iL8-wLds8Lb3CAbSQcR6ebeSlA,17863
155
+ reconcile/aws_version_sync/integration.py,sha256=7D76Zy5TLndLgLdKJEnDl1OWex148dMEvtNkSDjnijo,19461
156
156
  reconcile/aws_version_sync/utils.py,sha256=x-45QT7zAwdNvCg7w_qJNwLaksFcfz1_6KQoD_0IVuA,1727
157
157
  reconcile/aws_version_sync/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
158
158
  reconcile/aws_version_sync/merge_request_manager/merge_request.py,sha256=2FbqLLdqxycWNvX1eNbwMjWSVBb7q0p-8t5Db0m7b4Q,4842
@@ -797,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
797
797
  tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
798
798
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
799
799
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
800
- qontract_reconcile-0.10.2.dev282.dist-info/METADATA,sha256=IkB4oW__-NStwFmVIV9PRV2K-Qy4ZLukxlyyCPdKwzI,24501
801
- qontract_reconcile-0.10.2.dev282.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
802
- qontract_reconcile-0.10.2.dev282.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
803
- qontract_reconcile-0.10.2.dev282.dist-info/RECORD,,
800
+ qontract_reconcile-0.10.2.dev284.dist-info/METADATA,sha256=Mkg_lPvaw2v0063lTEZmUBIwY35vmjQz-6LOZDFYpd8,24916
801
+ qontract_reconcile-0.10.2.dev284.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
802
+ qontract_reconcile-0.10.2.dev284.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
803
+ qontract_reconcile-0.10.2.dev284.dist-info/RECORD,,
@@ -9,6 +9,7 @@ from typing import Any
9
9
  import semver
10
10
  from pydantic import (
11
11
  BaseModel,
12
+ ValidationError,
12
13
  root_validator,
13
14
  validator,
14
15
  )
@@ -168,6 +169,7 @@ AwsExternalResources = list[ExternalResource]
168
169
  AppInterfaceExternalResources = list[ExternalResource]
169
170
  UidAndReplicationGroupId = tuple[str, str]
170
171
  ReplicationGroupIdToIdentifier = dict[UidAndReplicationGroupId, str]
172
+ EXTENDED_SUPPORT_VERSION_INDICATOR = "-rds."
171
173
 
172
174
 
173
175
  class AVSIntegration(QontractReconcileIntegration[AVSIntegrationParams]):
@@ -228,56 +230,85 @@ class AVSIntegration(QontractReconcileIntegration[AVSIntegrationParams]):
228
230
  if cluster.automation_token
229
231
  else None
230
232
  )
233
+
234
+ # RDS resources
231
235
  try:
232
- # RDS resources
233
- metrics += [
234
- ExternalResource(
235
- provider="aws",
236
- provisioner=ExternalResourceProvisioner(
237
- uid=m["aws_account_id"]
238
- ),
239
- resource_provider=SupportedResourceProvider.RDS,
240
- resource_identifier=m["dbinstance_identifier"],
241
- resource_engine=m["engine"],
242
- resource_engine_version=m["engine_version"],
243
- )
244
- for m in prom_get_func(
245
- url=cluster.prometheus_url,
246
- params={"query": "aws_resources_exporter_rds_engineversion"},
247
- token=token,
248
- timeout=timeout,
249
- )
250
- ]
251
- # ElastiCache resources
252
- metrics += [
253
- ExternalResource(
254
- provider="aws",
255
- provisioner=ExternalResourceProvisioner(
256
- uid=m["aws_account_id"]
257
- ),
258
- resource_provider=SupportedResourceProvider.ELASTICACHE,
259
- # replication_group_id != resource_identifier!
260
- resource_identifier=elasticache_replication_group_id_to_identifier.get(
261
- (
262
- m["aws_account_id"],
263
- m["replication_group_id"],
264
- ),
265
- m["replication_group_id"],
266
- ),
267
- resource_engine=m["engine"],
268
- resource_engine_version=m["engine_version"],
269
- )
270
- for m in prom_get_func(
271
- url=cluster.prometheus_url,
272
- params={
273
- "query": "aws_resources_exporter_elasticache_redisversion"
274
- },
275
- token=token,
276
- timeout=timeout,
277
- )
278
- ]
236
+ rds_metrics = prom_get_func(
237
+ url=cluster.prometheus_url,
238
+ params={"query": "aws_resources_exporter_rds_engineversion"},
239
+ token=token,
240
+ timeout=timeout,
241
+ )
242
+
243
+ for m in rds_metrics:
244
+ try:
245
+ metrics.append(
246
+ ExternalResource(
247
+ provider="aws",
248
+ provisioner=ExternalResourceProvisioner(
249
+ uid=m["aws_account_id"]
250
+ ),
251
+ resource_provider=SupportedResourceProvider.RDS,
252
+ resource_identifier=m["dbinstance_identifier"],
253
+ resource_engine=m["engine"],
254
+ resource_engine_version=m["engine_version"],
255
+ )
256
+ )
257
+ except ValidationError:
258
+ # don't try to parse AWS extended support version numbers
259
+ # See https://aws.amazon.com/about-aws/whats-new/2025/04/amazon-rds-postgresql-extended-support-11-22-rds-20250220-12-22-rds-20250220/ for more info
260
+ if (
261
+ EXTENDED_SUPPORT_VERSION_INDICATOR
262
+ not in m["engine_version"]
263
+ ):
264
+ raise
265
+ except Exception as e:
266
+ logging.error(
267
+ f"Failed to parse RDS metric for {m['dbinstance_identifier']}: {e}"
268
+ )
279
269
  except Exception as e:
280
- logging.error(f"Failed to get metrics for cluster {cluster.name}: {e}")
270
+ logging.error(
271
+ f"Failed to get 'aws_resources_exporter_rds_engineversion' metrics for cluster {cluster.name}: {e}"
272
+ )
273
+
274
+ # ElastiCache resources
275
+ try:
276
+ elasticache_metrics = prom_get_func(
277
+ url=cluster.prometheus_url,
278
+ params={"query": "aws_resources_exporter_elasticache_redisversion"},
279
+ token=token,
280
+ timeout=timeout,
281
+ )
282
+ for m in elasticache_metrics:
283
+ try:
284
+ metrics.append(
285
+ ExternalResource(
286
+ provider="aws",
287
+ provisioner=ExternalResourceProvisioner(
288
+ uid=m["aws_account_id"]
289
+ ),
290
+ resource_provider=SupportedResourceProvider.ELASTICACHE,
291
+ # replication_group_id != resource_identifier!
292
+ resource_identifier=elasticache_replication_group_id_to_identifier.get(
293
+ (
294
+ m["aws_account_id"],
295
+ m["replication_group_id"],
296
+ ),
297
+ m["replication_group_id"],
298
+ ),
299
+ resource_engine=m["engine"],
300
+ resource_engine_version=m["engine_version"],
301
+ )
302
+ )
303
+ except Exception as e:
304
+ logging.error(
305
+ f"Failed to parse ElastiCache metrics for {m['replication_group_id']}: {e}"
306
+ )
307
+ except Exception as e:
308
+ logging.error(
309
+ f"Failed to get 'aws_resources_exporter_elasticache_redisversion' metrics for cluster {cluster.name}: {e}"
310
+ )
311
+
281
312
  return metrics
282
313
 
283
314
  def get_external_resource_specs(