qontract-reconcile 0.10.1rc762__py3-none-any.whl → 0.10.1rc764__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.1rc762
3
+ Version: 0.10.1rc764
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
@@ -176,6 +176,17 @@ reconcile/cna/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
176
176
  reconcile/cna/assets/asset.py,sha256=1v51uYSaD1NOc9cI_YxG7h0NOcR1ng-mkmD2UzQ8PXE,866
177
177
  reconcile/cna/assets/asset_factory.py,sha256=7T7X_J6xIsoGETqBRI45_EyIKEdQcnRPt_GAuVuLQcc,785
178
178
  reconcile/cna/assets/null.py,sha256=Fby1Fbn7oNRIGNasdyhRDvXJ0ktpxv-pUAPN0lZWSzk,1684
179
+ reconcile/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
+ reconcile/external_resources/aws.py,sha256=JvjKaABy2Pg8u8Lq82Acv4zMvpE3_qGKes7OG-zlHOM,2956
181
+ reconcile/external_resources/factories.py,sha256=bLboXX5Dq0xN60mtDGNjCOLC6HlKofXMWQxVbRwMMwo,4485
182
+ reconcile/external_resources/integration.py,sha256=QQZdKTeHoUD7afUTNKh878u-KWovYptAFZwjUBTIbCg,3317
183
+ reconcile/external_resources/manager.py,sha256=APszaw9PRIiHnFyCffHZjIFseIwhlYROIPLt18pHUTQ,13685
184
+ reconcile/external_resources/meta.py,sha256=SA4Km1r7ePdcNqHn2GA4ByQp4ZnIeo_n8qOOd-11IEg,151
185
+ reconcile/external_resources/metrics.py,sha256=m2TIOao2N7pD6k45driFbBGVCC_N7ai44m-lLPfa5qk,454
186
+ reconcile/external_resources/model.py,sha256=FJUb7rHU2l7YSAv-t4QaacL9pqheFBxhPydWSPqu3vY,7413
187
+ reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYjHGyICWff9bxlc,9323
188
+ reconcile/external_resources/secrets_sync.py,sha256=g-ksvzmTlCTwo3PM3FgYXm0LUBcnwfAxcvisuR1jAMY,7982
189
+ reconcile/external_resources/state.py,sha256=rRePQdA3A6U9oFDDs9aaL5Ja7nSIXpOC1wHwY8R47_8,9197
179
190
  reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
191
  reconcile/glitchtip/integration.py,sha256=Y7ofQg_xCt3dOln3pjeXp7rAnwohCgD2zcUAb-Hciis,8375
181
192
  reconcile/glitchtip/reconciler.py,sha256=nUvDv7qG1ly0cA16MmlL6NV71yl1mJYLT2mui7lmi0Y,12402
@@ -194,7 +205,7 @@ reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py,sha256=uF
194
205
  reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
195
206
  reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py,sha256=uVEEqU6YYmKsNTo6EWlFnoVmqha2rvBDx-wiD64VmG0,1679
196
207
  reconcile/gql_definitions/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=c3RmQwbHa9UlfGwruufkA8PUfeiRJZ-lXEDInAREZqE,4405
208
+ reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=jJfIzTtDiW6rasv3PFEbyVHA0d8bfRYSVYP5HxslYnY,4649
198
209
  reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
199
210
  reconcile/gql_definitions/aws_ami_cleanup/asg_namespaces.py,sha256=OJmeTu7uirLGAysZ3IQTtRXqMyL8noi_QZxPuWYxxmI,3678
200
211
  reconcile/gql_definitions/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -786,8 +797,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
786
797
  tools/test/test_qontract_cli.py,sha256=w2l4BHB09k1d-BGJ1jBUNCqDv7zkqYrMHojQXg-21kQ,4155
787
798
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
788
799
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
789
- qontract_reconcile-0.10.1rc762.dist-info/METADATA,sha256=f9qo3Mn92aMIw-oLh-t9rMXsdX6CkqcfJOP14BamQ3M,2382
790
- qontract_reconcile-0.10.1rc762.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
791
- qontract_reconcile-0.10.1rc762.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
792
- qontract_reconcile-0.10.1rc762.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
793
- qontract_reconcile-0.10.1rc762.dist-info/RECORD,,
800
+ qontract_reconcile-0.10.1rc764.dist-info/METADATA,sha256=Eov5cvApy_dlSvDlyNdI1Uk8pAO7tJZfv4cOMjUfeEA,2382
801
+ qontract_reconcile-0.10.1rc764.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
802
+ qontract_reconcile-0.10.1rc764.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
803
+ qontract_reconcile-0.10.1rc764.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
804
+ qontract_reconcile-0.10.1rc764.dist-info/RECORD,,
File without changes
@@ -0,0 +1,85 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
3
+
4
+ from reconcile.external_resources.model import (
5
+ ExternalResource,
6
+ ExternalResourcesInventory,
7
+ )
8
+ from reconcile.utils.external_resource_spec import (
9
+ ExternalResourceSpec,
10
+ )
11
+ from reconcile.utils.external_resources import ResourceValueResolver
12
+ from reconcile.utils.secret_reader import SecretReaderBase
13
+
14
+
15
+ class AWSResourceFactory(ABC):
16
+ def __init__(
17
+ self, er_inventory: ExternalResourcesInventory, secrets_reader: SecretReaderBase
18
+ ):
19
+ self.er_inventory = er_inventory
20
+ self.secrets_reader = secrets_reader
21
+
22
+ @abstractmethod
23
+ def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]: ...
24
+
25
+ @abstractmethod
26
+ def validate(self, resource: ExternalResource) -> None: ...
27
+
28
+
29
+ class AWSDefaultResourceFactory(AWSResourceFactory):
30
+ def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
31
+ return ResourceValueResolver(spec=spec, identifier_as_value=True).resolve()
32
+
33
+ def validate(self, resource: ExternalResource) -> None: ...
34
+
35
+
36
+ class AWSRdsFactory(AWSDefaultResourceFactory):
37
+ def _get_source_db_spec(
38
+ self, provisioner: str, identifier: str
39
+ ) -> ExternalResourceSpec:
40
+ return self.er_inventory.get_inventory_spec(
41
+ "aws", provisioner, "rds", identifier
42
+ )
43
+
44
+ def _get_kms_key_spec(
45
+ self, provisioner: str, identifier: str
46
+ ) -> ExternalResourceSpec:
47
+ return self.er_inventory.get_inventory_spec(
48
+ "aws", provisioner, "kms", identifier
49
+ )
50
+
51
+ def resolve(self, spec: ExternalResourceSpec) -> dict[str, Any]:
52
+ rvr = ResourceValueResolver(spec=spec, identifier_as_value=True)
53
+ data = rvr.resolve()
54
+
55
+ data["output_prefix"] = spec.output_prefix
56
+
57
+ if "parameter_group" in data:
58
+ pg_data = rvr._get_values(data["parameter_group"])
59
+ data["parameter_group"] = pg_data
60
+ if "old_parameter_group" in data:
61
+ old_pg_data = rvr._get_values(data["old_parameter_group"])
62
+ data["old_parameter_group"] = old_pg_data
63
+ if "replica_source" in data:
64
+ sourcedb_spec = self._get_source_db_spec(
65
+ spec.provisioner_name, data["replica_source"]
66
+ )
67
+ sourcedb = self.resolve(sourcedb_spec)
68
+ sourcedb_region = (
69
+ sourcedb.get("region", None)
70
+ or sourcedb_spec.provisioner["resources_default_region"]
71
+ )
72
+ data["replica_source"] = {
73
+ "identifier": sourcedb["identifier"],
74
+ "region": sourcedb_region,
75
+ }
76
+
77
+ kms_key_id: str = data.get("kms_key_id", None)
78
+ if kms_key_id and not kms_key_id.startswith("arn:"):
79
+ data["kms_key_id"] = self._get_kms_key_spec(
80
+ spec.provisioner_name, kms_key_id
81
+ ).identifier
82
+
83
+ return data
84
+
85
+ def validate(self, resource: ExternalResource) -> None: ...
@@ -0,0 +1,133 @@
1
+ from abc import (
2
+ ABC,
3
+ abstractmethod,
4
+ )
5
+ from typing import Generic, TypeVar
6
+
7
+ from reconcile.external_resources.aws import (
8
+ AWSDefaultResourceFactory,
9
+ AWSRdsFactory,
10
+ AWSResourceFactory,
11
+ )
12
+ from reconcile.external_resources.model import (
13
+ ExternalResource,
14
+ ExternalResourceKey,
15
+ ExternalResourceProvision,
16
+ ExternalResourcesInventory,
17
+ ModuleInventory,
18
+ ModuleProvisionData,
19
+ TerraformModuleProvisionData,
20
+ )
21
+ from reconcile.gql_definitions.external_resources.external_resources_settings import (
22
+ ExternalResourcesSettingsV1,
23
+ )
24
+ from reconcile.utils.external_resource_spec import (
25
+ ExternalResourceSpec,
26
+ )
27
+ from reconcile.utils.secret_reader import SecretReaderBase
28
+
29
+ T = TypeVar("T")
30
+
31
+
32
+ class ObjectFactory(Generic[T]):
33
+ def __init__(self) -> None:
34
+ self._factories: dict[str, T] = {}
35
+
36
+ def register_factory(self, id: str, t: T) -> None:
37
+ self._factories[id] = t
38
+
39
+ def get_factory(self, id: str) -> T:
40
+ return self._factories[id]
41
+
42
+
43
+ class ExternalResourceFactory(ABC):
44
+ @abstractmethod
45
+ def create_external_resource(self, spec: ExternalResourceSpec) -> ExternalResource:
46
+ pass
47
+
48
+ @abstractmethod
49
+ def validate_external_resource(self, resource: ExternalResource) -> None:
50
+ pass
51
+
52
+
53
+ class ModuleProvisionDataFactory(ABC):
54
+ @abstractmethod
55
+ def create_provision_data(self, ers: ExternalResourceSpec) -> ModuleProvisionData:
56
+ pass
57
+
58
+
59
+ class TerraformModuleProvisionDataFactory(ModuleProvisionDataFactory):
60
+ def __init__(self, settings: ExternalResourcesSettingsV1):
61
+ self.settings = settings
62
+
63
+ def create_provision_data(
64
+ self, spec: ExternalResourceSpec
65
+ ) -> TerraformModuleProvisionData:
66
+ key = ExternalResourceKey.from_spec(spec)
67
+
68
+ return TerraformModuleProvisionData(
69
+ tf_state_bucket=self.settings.tf_state_bucket,
70
+ tf_state_region=self.settings.tf_state_region,
71
+ tf_state_dynamodb_table=self.settings.tf_state_dynamodb_table,
72
+ tf_state_key=key.state_path + "/terraform.tfstate",
73
+ )
74
+
75
+
76
+ def setup_aws_resource_factories(
77
+ er_inventory: ExternalResourcesInventory, secrets_reader: SecretReaderBase
78
+ ) -> ObjectFactory[AWSResourceFactory]:
79
+ f = ObjectFactory[AWSResourceFactory]()
80
+ f.register_factory("rds", AWSRdsFactory(er_inventory, secrets_reader))
81
+ f.register_factory(
82
+ "default", AWSDefaultResourceFactory(er_inventory, secrets_reader)
83
+ )
84
+ return f
85
+
86
+
87
+ class AWSExternalResourceFactory(ExternalResourceFactory):
88
+ def __init__(
89
+ self,
90
+ module_inventory: ModuleInventory,
91
+ er_inventory: ExternalResourcesInventory,
92
+ secret_reader: SecretReaderBase,
93
+ provision_factories: ObjectFactory[ModuleProvisionDataFactory],
94
+ resource_factories: ObjectFactory[AWSResourceFactory],
95
+ ):
96
+ self.provision_factories = provision_factories
97
+ self.resource_factories = resource_factories
98
+ self.module_inventory = module_inventory
99
+ self.er_inventory = er_inventory
100
+ self.secret_reader = secret_reader
101
+
102
+ def create_external_resource(self, spec: ExternalResourceSpec) -> ExternalResource:
103
+ f = self.resource_factories.get_factory(spec.provider)
104
+ data = f.resolve(spec)
105
+
106
+ region = data.get("region")
107
+ if region:
108
+ if region not in spec.provisioner["supported_deployment_regions"]:
109
+ raise ValueError(region)
110
+ else:
111
+ region = spec.provisioner["resources_default_region"]
112
+ data["region"] = region
113
+
114
+ module_type = self.module_inventory.get_from_spec(spec).module_type
115
+ provision_factory = self.provision_factories.get_factory(module_type)
116
+ module_provision_data = provision_factory.create_provision_data(spec)
117
+
118
+ provision = ExternalResourceProvision(
119
+ provision_provider=spec.provision_provider,
120
+ provisioner=spec.provisioner_name,
121
+ provider=spec.provider,
122
+ identifier=spec.identifier,
123
+ target_cluster=spec.cluster_name,
124
+ target_namespace=spec.namespace_name,
125
+ target_secret_name=spec.output_resource_name,
126
+ module_provision_data=module_provision_data,
127
+ )
128
+
129
+ return ExternalResource(data=data, provision=provision)
130
+
131
+ def validate_external_resource(self, resource: ExternalResource) -> None:
132
+ f = self.resource_factories.get_factory(resource.provision.provider)
133
+ f.validate(resource)
@@ -0,0 +1,95 @@
1
+ import logging
2
+
3
+ from reconcile.external_resources.manager import (
4
+ ExternalResourcesInventory,
5
+ ExternalResourcesManager,
6
+ setup_factories,
7
+ )
8
+ from reconcile.external_resources.meta import (
9
+ QONTRACT_INTEGRATION,
10
+ QONTRACT_INTEGRATION_VERSION,
11
+ )
12
+ from reconcile.external_resources.model import load_module_inventory
13
+ from reconcile.external_resources.reconciler import K8sExternalResourcesReconciler
14
+ from reconcile.external_resources.secrets_sync import (
15
+ build_incluster_secrets_reconciler,
16
+ )
17
+ from reconcile.external_resources.state import ExternalResourcesStateDynamoDB
18
+ from reconcile.typed_queries.app_interface_vault_settings import (
19
+ get_app_interface_vault_settings,
20
+ )
21
+ from reconcile.typed_queries.external_resources import (
22
+ get_modules,
23
+ get_namespaces,
24
+ get_settings,
25
+ )
26
+ from reconcile.utils.jobcontroller.controller import (
27
+ build_job_controller,
28
+ )
29
+ from reconcile.utils.oc import (
30
+ OCCli,
31
+ )
32
+ from reconcile.utils.openshift_resource import OpenshiftResource, ResourceInventory
33
+ from reconcile.utils.secret_reader import create_secret_reader
34
+
35
+
36
+ def fetch_current_state(
37
+ ri: ResourceInventory, oc: OCCli, cluster: str, namespace: str
38
+ ) -> None:
39
+ for item in oc.get_items("Job", namespace=namespace):
40
+ r = OpenshiftResource(item, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION)
41
+ ri.add_current(cluster, namespace, "Job", r.name, r)
42
+
43
+
44
+ def run(
45
+ dry_run: bool,
46
+ cluster: str,
47
+ namespace: str,
48
+ dry_run_job_suffix: str,
49
+ thread_pool_size: int,
50
+ ) -> None:
51
+ vault_settings = get_app_interface_vault_settings()
52
+ secret_reader = create_secret_reader(use_vault=vault_settings.vault)
53
+ er_settings = get_settings()[0]
54
+ m_inventory = load_module_inventory(get_modules())
55
+ namespaces = [ns for ns in get_namespaces() if ns.external_resources]
56
+ er_inventory = ExternalResourcesInventory(namespaces)
57
+
58
+ er_mgr = ExternalResourcesManager(
59
+ thread_pool_size=thread_pool_size,
60
+ settings=er_settings,
61
+ secret_reader=secret_reader,
62
+ factories=setup_factories(
63
+ er_settings, m_inventory, er_inventory, secret_reader
64
+ ),
65
+ er_inventory=er_inventory,
66
+ module_inventory=m_inventory,
67
+ state_manager=ExternalResourcesStateDynamoDB(
68
+ table_name=er_settings.state_dynamodb_table,
69
+ region_name=er_settings.state_dynamodb_region,
70
+ ),
71
+ reconciler=K8sExternalResourcesReconciler(
72
+ controller=build_job_controller(
73
+ integration=QONTRACT_INTEGRATION,
74
+ integration_version=QONTRACT_INTEGRATION_VERSION,
75
+ cluster=cluster,
76
+ namespace=namespace,
77
+ secret_reader=secret_reader,
78
+ dry_run=dry_run,
79
+ ),
80
+ dry_run=dry_run,
81
+ dry_run_job_suffix=dry_run_job_suffix,
82
+ ),
83
+ secrets_reconciler=build_incluster_secrets_reconciler(
84
+ cluster, namespace, secret_reader, vault_path="app-sre"
85
+ ),
86
+ )
87
+
88
+ if dry_run:
89
+ er_mgr.handle_dry_run_resources()
90
+ if er_mgr.errors:
91
+ logging.error("Validation Errors:")
92
+ for k, e in er_mgr.errors.items():
93
+ logging.error("ExternalResourceKey: %s, Error: %s" % (k, e))
94
+ else:
95
+ er_mgr.handle_resources()