qontract-reconcile 0.10.1rc1151__py3-none-any.whl → 0.10.1rc1153__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.1rc1151
3
+ Version: 0.10.1rc1153
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
@@ -192,14 +192,14 @@ reconcile/endpoints_discovery/integration.py,sha256=znfnlm8bZesfcNbQnaR2aaVM-DTB
192
192
  reconcile/endpoints_discovery/merge_request.py,sha256=_yLb4tnvoZMCko8rta2C_CvOInJa9pa3HzSmHNtjgGU,2978
193
193
  reconcile/endpoints_discovery/merge_request_manager.py,sha256=wUMsumxv8RnWaRattax4HfoRlhtVzmgro3GiJJ1C4Vc,6392
194
194
  reconcile/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
195
- reconcile/external_resources/aws.py,sha256=7W-6d-lXO6JGwaxtO1Uc3Lw0p8csJ1EVgz__O1YWUOc,4793
196
- reconcile/external_resources/factories.py,sha256=nhdTqf1WEfRfgd5-70KAUJVz0ZvZ19C3Pz7wmotSdrs,4857
195
+ reconcile/external_resources/aws.py,sha256=309Zui7rE8XFJA1ZBLupl55Vp8Y5KKgXdsKQWqKbg8I,7069
196
+ reconcile/external_resources/factories.py,sha256=KrJDh52_8PeCEVjwfeVr1jwAJDdhMXRQ_XcBETfnKY4,4988
197
197
  reconcile/external_resources/integration.py,sha256=gBVO5dE8JyZ3xYcYik-MTIp_18oU7_hpYc_oztyfElQ,6753
198
198
  reconcile/external_resources/integration_secrets_sync.py,sha256=dX09O3r6KURziUYYfiki10orNjOGVma-XojhVqd0ww4,1667
199
- reconcile/external_resources/manager.py,sha256=SRrx44silyaKv_P8EWNW9JxpJADYh_CRwBmSE8DO6cs,17671
199
+ reconcile/external_resources/manager.py,sha256=wcqTawNS4qoBHFVfyCfHtWXh4L3AlgcNYx_Ov_vEjNg,17914
200
200
  reconcile/external_resources/meta.py,sha256=noaytFzmShpzLA_ebGh7wuP45mOfHIOnnoUxivjDa1I,672
201
201
  reconcile/external_resources/metrics.py,sha256=nMbyonGZEJDD1lYzpQY2eR9TNwvxYC4ZCcpi6wrExcM,1037
202
- reconcile/external_resources/model.py,sha256=UuQgrnv-SSkvSEQQGeCE2IZkhXjLTCVkP_mw8zBZsIQ,8349
202
+ reconcile/external_resources/model.py,sha256=ibOd0pa6hyJX-MK3LGVxOa3ra_Xfq7mbd5T_9d3bfhM,8444
203
203
  reconcile/external_resources/reconciler.py,sha256=3KFmkHsN7YAwJUSBpN1Xd_D2zM9Ea5_c2uMGWsfruZo,9707
204
204
  reconcile/external_resources/secrets_sync.py,sha256=6n0oDPLjd9Ql0lf6zsr1AZw8A6EEe3yCzl20XodtgkE,16229
205
205
  reconcile/external_resources/state.py,sha256=UupSa6tl4-73_J6Fhisn-qHal3v3uAUS5s5sk85LGDs,9343
@@ -292,7 +292,7 @@ reconcile/gql_definitions/endpoints_discovery/namespaces.py,sha256=FqJ0H7NdsIm5B
292
292
  reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
293
293
  reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=XR69j9dpTQ0gv8y-AZN7AJ0dPvO-wbHscyCDgrax6Bk,2046
294
294
  reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=HFOQjmNbNxk0j5nChxppQeCnJjeDsqibJkPgA7R1zRw,2417
295
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=-ehru0zFyTGOmhh3YB1nHVBd480Iq3rlOnPM3PEA20A,42585
295
+ reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=KSASnKycr-e5kCUSOkqnS8w7Gvo_nXA_5NQcS8vGeLY,43466
296
296
  reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=Hw9n_90BPG6Lnt2PT3mHc6p0KEm2CxKxvSGRFc_Dhus,2982
297
297
  reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
298
298
  reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
@@ -683,7 +683,7 @@ reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
683
683
  reconcile/utils/gql.py,sha256=C0thIm_k9MBldfqwHzyqtYZk9sIvMdm9IbbnXLGwjD8,14158
684
684
  reconcile/utils/grouping.py,sha256=vr9SFHZ7bqmHYrvYcEZt-Er3-yQYfAAdq5sHLZVmXPY,456
685
685
  reconcile/utils/helm.py,sha256=hr4J_9mBZwbc1FDNfFh4QKAj0h3eLxyTN2Y3UxIRp8U,3893
686
- reconcile/utils/helpers.py,sha256=k9svgFFZG7H5FvHYY0g5jJyvgvh2UDZxf0Ib221teag,1179
686
+ reconcile/utils/helpers.py,sha256=1PK_6gTzg2kJ8Ac8zZHB2yEubewDWtVspTl5bVbvbEY,1462
687
687
  reconcile/utils/imap_client.py,sha256=h8YDiCSCvroErhpH_-KGYI7Y2WU2Q2oSpuxDFbOkSbY,1989
688
688
  reconcile/utils/instrumented_wrappers.py,sha256=eVwMoa6FCrYxLv3RML3WpZF9qKVfCTjMxphgVXG03OM,1073
689
689
  reconcile/utils/jenkins_api.py,sha256=RaKuZmO7_lbI-hE6c_Pq2a6CQdmBVj7BcP2jR68cIbI,7081
@@ -880,8 +880,8 @@ tools/test/test_qontract_cli.py,sha256=iuzKbQ6ahinvjoQmQLBrG4shey0z-1rB6qCgS8T6d
880
880
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
881
881
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
882
882
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
883
- qontract_reconcile-0.10.1rc1151.dist-info/METADATA,sha256=kIbyRbeEHOgr_be8cLvc2kZ_5psU6e_Hltp8zQvbkMA,2213
884
- qontract_reconcile-0.10.1rc1151.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
885
- qontract_reconcile-0.10.1rc1151.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
886
- qontract_reconcile-0.10.1rc1151.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
887
- qontract_reconcile-0.10.1rc1151.dist-info/RECORD,,
883
+ qontract_reconcile-0.10.1rc1153.dist-info/METADATA,sha256=W7PsNpp1_srAAOioGMxIeZNzgmkrmBV5ra6opFDI-58,2213
884
+ qontract_reconcile-0.10.1rc1153.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
885
+ qontract_reconcile-0.10.1rc1153.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
886
+ qontract_reconcile-0.10.1rc1153.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
887
+ qontract_reconcile-0.10.1rc1153.dist-info/RECORD,,
@@ -9,6 +9,7 @@ from reconcile.utils.external_resource_spec import (
9
9
  ExternalResourceSpec,
10
10
  )
11
11
  from reconcile.utils.external_resources import ResourceValueResolver
12
+ from reconcile.utils.helpers import generate_random_password
12
13
  from reconcile.utils.secret_reader import SecretReaderBase
13
14
 
14
15
 
@@ -33,6 +34,57 @@ class AWSDefaultResourceFactory(AWSResourceFactory):
33
34
  def validate(self, resource: ExternalResource) -> None: ...
34
35
 
35
36
 
37
+ class AWSElasticacheFactory(AWSDefaultResourceFactory):
38
+ def _get_source_db_spec(
39
+ self, provisioner: str, identifier: str
40
+ ) -> ExternalResourceSpec:
41
+ return self.er_inventory.get_inventory_spec(
42
+ "aws", provisioner, "elasticache", identifier
43
+ )
44
+
45
+ def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
46
+ """Resolve the elasticache resource specification and translate some attributes to AWS >= 5.60.0 provider format."""
47
+ rvr = ResourceValueResolver(spec=spec, identifier_as_value=True)
48
+ data = rvr.resolve()
49
+ data["output_prefix"] = spec.output_prefix
50
+
51
+ if "replication_group_id" not in data:
52
+ data["replication_group_id"] = spec.identifier
53
+
54
+ if cluster_mode := data.pop("cluster_mode", {}):
55
+ for k, v in cluster_mode.items():
56
+ data[k] = v
57
+
58
+ if "parameter_group" in data:
59
+ pg_data = rvr._get_values(data["parameter_group"])
60
+ data["parameter_group"] = pg_data
61
+
62
+ if data.get("transit_encryption_enabled", False):
63
+ data["auth_token"] = (
64
+ spec.get_secret_field("db.auth_token") or generate_random_password()
65
+ )
66
+ return data
67
+
68
+ def validate(self, resource: ExternalResource) -> None:
69
+ """Validate the elasticache resource specification."""
70
+ data = resource.data
71
+ if data.get("parameter_group"):
72
+ if not data["parameter_group"].get("name"):
73
+ data["parameter_group"]["name"] = f"{data['replication_group_id']}-pg"
74
+
75
+ if (
76
+ data.get("parameter_group_name")
77
+ and data["parameter_group"]["name"] != data["parameter_group_name"]
78
+ ):
79
+ raise ValueError(
80
+ "Custom parameter_group set and parameter_group_name given. Either remove parameter_group_name or set it to the same value as parameter_group.name."
81
+ )
82
+
83
+ if not data.get("parameter_group_name"):
84
+ # automatically set /aws/elasticache-defaults-1.yml/parameter_group_name to /aws/parameter-group-1.yml/name
85
+ data["parameter_group_name"] = data["parameter_group"]["name"]
86
+
87
+
36
88
  class AWSRdsFactory(AWSDefaultResourceFactory):
37
89
  def _get_source_db_spec(
38
90
  self, provisioner: str, identifier: str
@@ -6,6 +6,7 @@ from typing import Generic, TypeVar
6
6
 
7
7
  from reconcile.external_resources.aws import (
8
8
  AWSDefaultResourceFactory,
9
+ AWSElasticacheFactory,
9
10
  AWSMskFactory,
10
11
  AWSRdsFactory,
11
12
  AWSResourceFactory,
@@ -87,6 +88,9 @@ def setup_aws_resource_factories(
87
88
  er_inventory: ExternalResourcesInventory, secret_reader: SecretReaderBase
88
89
  ) -> ObjectFactory[AWSResourceFactory]:
89
90
  f = ObjectFactory[AWSResourceFactory]()
91
+ f.register_factory(
92
+ "elasticache", AWSElasticacheFactory(er_inventory, secret_reader)
93
+ )
90
94
  f.register_factory("rds", AWSRdsFactory(er_inventory, secret_reader))
91
95
  f.register_factory("msk", AWSMskFactory(er_inventory, secret_reader))
92
96
  f.register_factory(
@@ -104,19 +104,22 @@ class ReconciliationStatus(BaseModel):
104
104
  def publish_metrics(self, r: Reconciliation, spec: ExternalResourceSpec) -> None:
105
105
  job_name = ReconciliationK8sJob(reconciliation=r).name()
106
106
 
107
- metrics.set_gauge(
108
- ExternalResourcesResourceStatus(
109
- app=spec.namespace["app"]["name"],
110
- environment=spec.namespace["environment"]["name"],
111
- provision_provider=r.key.provision_provider,
112
- provisioner_name=r.key.provisioner_name,
113
- provider=r.key.provider,
114
- identifier=r.key.identifier,
115
- job_name=job_name,
116
- status=self.resource_status,
117
- ),
118
- 1,
119
- )
107
+ # Use transactional_metrics to remove old status, we just want to expose the latest status
108
+ with metrics.transactional_metrics(scope=job_name) as metrics_container:
109
+ metrics_container.set_gauge(
110
+ ExternalResourcesResourceStatus(
111
+ app=spec.namespace["app"]["name"],
112
+ environment=spec.namespace["environment"]["name"],
113
+ provision_provider=r.key.provision_provider,
114
+ provisioner_name=r.key.provisioner_name,
115
+ provider=r.key.provider,
116
+ identifier=r.key.identifier,
117
+ job_name=job_name,
118
+ status=self.resource_status,
119
+ ),
120
+ 1,
121
+ )
122
+
120
123
  metrics.set_gauge(
121
124
  ExternalResourcesReconcileTimeGauge(
122
125
  app=spec.namespace["app"]["name"],
@@ -24,6 +24,7 @@ from reconcile.gql_definitions.external_resources.external_resources_modules imp
24
24
  from reconcile.gql_definitions.external_resources.external_resources_namespaces import (
25
25
  ExternalResourcesModuleOverridesV1,
26
26
  NamespaceTerraformProviderResourceAWSV1,
27
+ NamespaceTerraformResourceElastiCacheV1,
27
28
  NamespaceTerraformResourceMskV1,
28
29
  NamespaceTerraformResourceRDSV1,
29
30
  NamespaceV1,
@@ -68,7 +69,9 @@ class ExternalResourceKey(BaseModel, frozen=True):
68
69
 
69
70
  SUPPORTED_RESOURCE_PROVIDERS = NamespaceTerraformProviderResourceAWSV1
70
71
  SUPPORTED_RESOURCE_TYPES = (
71
- NamespaceTerraformResourceRDSV1 | NamespaceTerraformResourceMskV1
72
+ NamespaceTerraformResourceRDSV1
73
+ | NamespaceTerraformResourceMskV1
74
+ | NamespaceTerraformResourceElastiCacheV1
72
75
  )
73
76
 
74
77
 
@@ -144,6 +144,14 @@ query ExternalResourcesNamespaces {
144
144
  overrides
145
145
  output_resource_name
146
146
  annotations
147
+ managed_by_erv2
148
+ delete
149
+ module_overrides {
150
+ module_type
151
+ image
152
+ version
153
+ reconcile_timeout_minutes
154
+ }
147
155
  }
148
156
  ... on NamespaceTerraformResourceServiceAccount_v1 {
149
157
  identifier
@@ -602,6 +610,13 @@ class NamespaceTerraformResourceS3V1(NamespaceTerraformResourceAWSV1):
602
610
  annotations: Optional[str] = Field(..., alias="annotations")
603
611
 
604
612
 
613
+ class NamespaceTerraformResourceElastiCacheV1_ExternalResourcesModuleOverridesV1(ConfiguredBaseModel):
614
+ module_type: Optional[str] = Field(..., alias="module_type")
615
+ image: Optional[str] = Field(..., alias="image")
616
+ version: Optional[str] = Field(..., alias="version")
617
+ reconcile_timeout_minutes: Optional[int] = Field(..., alias="reconcile_timeout_minutes")
618
+
619
+
605
620
  class NamespaceTerraformResourceElastiCacheV1(NamespaceTerraformResourceAWSV1):
606
621
  identifier: str = Field(..., alias="identifier")
607
622
  defaults: str = Field(..., alias="defaults")
@@ -610,6 +625,9 @@ class NamespaceTerraformResourceElastiCacheV1(NamespaceTerraformResourceAWSV1):
610
625
  overrides: Optional[str] = Field(..., alias="overrides")
611
626
  output_resource_name: Optional[str] = Field(..., alias="output_resource_name")
612
627
  annotations: Optional[str] = Field(..., alias="annotations")
628
+ managed_by_erv2: Optional[bool] = Field(..., alias="managed_by_erv2")
629
+ delete: Optional[bool] = Field(..., alias="delete")
630
+ module_overrides: Optional[NamespaceTerraformResourceElastiCacheV1_ExternalResourcesModuleOverridesV1] = Field(..., alias="module_overrides")
613
631
 
614
632
 
615
633
  class ClusterV1(ConfiguredBaseModel):
@@ -1014,7 +1032,7 @@ class NamespaceTerraformResourceMskV1(NamespaceTerraformResourceAWSV1):
1014
1032
 
1015
1033
  class NamespaceTerraformProviderResourceAWSV1(NamespaceExternalResourceV1):
1016
1034
  provisioner: AWSAccountV1 = Field(..., alias="provisioner")
1017
- resources: list[Union[NamespaceTerraformResourceRDSV1, NamespaceTerraformResourceRosaAuthenticatorV1, NamespaceTerraformResourceALBV1, NamespaceTerraformResourceS3V1, NamespaceTerraformResourceASGV1, NamespaceTerraformResourceMskV1, NamespaceTerraformResourceRoleV1, NamespaceTerraformResourceSNSTopicV1, NamespaceTerraformResourceElastiCacheV1, NamespaceTerraformResourceServiceAccountV1, NamespaceTerraformResourceS3SQSV1, NamespaceTerraformResourceCloudWatchV1, NamespaceTerraformResourceRosaAuthenticatorVPCEV1, NamespaceTerraformResourceS3CloudFrontV1, NamespaceTerraformResourceKMSV1, NamespaceTerraformResourceElasticSearchV1, NamespaceTerraformResourceACMV1, NamespaceTerraformResourceKinesisV1, NamespaceTerraformResourceRoute53ZoneV1, NamespaceTerraformResourceSQSV1, NamespaceTerraformResourceDynamoDBV1, NamespaceTerraformResourceECRV1, NamespaceTerraformResourceS3CloudFrontPublicKeyV1, NamespaceTerraformResourceSecretsManagerV1, NamespaceTerraformResourceSecretsManagerServiceAccountV1, NamespaceTerraformResourceAWSV1]] = Field(..., alias="resources")
1035
+ resources: list[Union[NamespaceTerraformResourceRDSV1, NamespaceTerraformResourceRosaAuthenticatorV1, NamespaceTerraformResourceALBV1, NamespaceTerraformResourceS3V1, NamespaceTerraformResourceElastiCacheV1, NamespaceTerraformResourceASGV1, NamespaceTerraformResourceMskV1, NamespaceTerraformResourceRoleV1, NamespaceTerraformResourceSNSTopicV1, NamespaceTerraformResourceServiceAccountV1, NamespaceTerraformResourceS3SQSV1, NamespaceTerraformResourceCloudWatchV1, NamespaceTerraformResourceRosaAuthenticatorVPCEV1, NamespaceTerraformResourceS3CloudFrontV1, NamespaceTerraformResourceKMSV1, NamespaceTerraformResourceElasticSearchV1, NamespaceTerraformResourceACMV1, NamespaceTerraformResourceKinesisV1, NamespaceTerraformResourceRoute53ZoneV1, NamespaceTerraformResourceSQSV1, NamespaceTerraformResourceDynamoDBV1, NamespaceTerraformResourceECRV1, NamespaceTerraformResourceS3CloudFrontPublicKeyV1, NamespaceTerraformResourceSecretsManagerV1, NamespaceTerraformResourceSecretsManagerServiceAccountV1, NamespaceTerraformResourceAWSV1]] = Field(..., alias="resources")
1018
1036
 
1019
1037
 
1020
1038
  class EnvironmentV1(ConfiguredBaseModel):
@@ -1,4 +1,6 @@
1
1
  import logging
2
+ import random
3
+ import string
2
4
  from collections import Counter
3
5
  from collections.abc import (
4
6
  Iterable,
@@ -44,3 +46,9 @@ Item = TypeVar("Item")
44
46
 
45
47
  def find_duplicates(items: Iterable[Item]) -> list[Item]:
46
48
  return [item for item, count in Counter(items).items() if count > 1]
49
+
50
+
51
+ def generate_random_password(string_length: int = 20) -> str:
52
+ """Generate a random string of letters and digits"""
53
+ letters_and_digits = string.ascii_letters + string.digits
54
+ return "".join(random.choices(letters_and_digits, k=string_length))