qontract-reconcile 0.10.1rc1010__py3-none-any.whl → 0.10.1rc1012__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.1rc1010
3
+ Version: 0.10.1rc1012
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
@@ -190,13 +190,13 @@ reconcile/external_resources/aws.py,sha256=JvjKaABy2Pg8u8Lq82Acv4zMvpE3_qGKes7OG
190
190
  reconcile/external_resources/factories.py,sha256=DXgaLxoO87zZ76VOpRpu2GeYGhsbfOnOx5mrzgo4Gf4,4767
191
191
  reconcile/external_resources/integration.py,sha256=y1gJ16woMBC3J9qniMmS5y3lCkAs7V_ETZRUwjKqaO0,6628
192
192
  reconcile/external_resources/integration_secrets_sync.py,sha256=cMEZhgCvABAMf-DWF051L6CRnJQdfbsISA_b1xuS940,1670
193
- reconcile/external_resources/manager.py,sha256=8lHOFyA_xF8thQXbmJp8zzA2-oJ0MUhfnCcFpkexwjU,15089
193
+ reconcile/external_resources/manager.py,sha256=xVwcFAPFG0HyMl_uzj8D6XXdH-Zmcw541DX0IHs57Jc,15278
194
194
  reconcile/external_resources/meta.py,sha256=cMT9OsKcUY26qwEjlQ02EkorvOBNqWj0JVMwfJa3Mg0,634
195
195
  reconcile/external_resources/metrics.py,sha256=m2TIOao2N7pD6k45driFbBGVCC_N7ai44m-lLPfa5qk,454
196
196
  reconcile/external_resources/model.py,sha256=oXxJkjhV53lwwAuxUCBrjJ8aCJmQdgcKWv68ugJPK4k,7229
197
197
  reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYjHGyICWff9bxlc,9323
198
198
  reconcile/external_resources/secrets_sync.py,sha256=6n0oDPLjd9Ql0lf6zsr1AZw8A6EEe3yCzl20XodtgkE,16229
199
- reconcile/external_resources/state.py,sha256=bWq51xPK4-BHVXWsRu6Y-vn69yg9Dse4x1RNNF7qw84,9614
199
+ reconcile/external_resources/state.py,sha256=fKU6PLYOZ2ZTaIwvt1BNlNOnIqcewLijOyT3Lgcd1NE,9677
200
200
  reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
201
201
  reconcile/glitchtip/integration.py,sha256=XtewM9nfTPLnPSpYebP50GrveYOnhTvKNq3seSvL6u8,8343
202
202
  reconcile/glitchtip/reconciler.py,sha256=nUvDv7qG1ly0cA16MmlL6NV71yl1mJYLT2mui7lmi0Y,12402
@@ -644,7 +644,7 @@ reconcile/unleash_feature_toggles/integration.py,sha256=nx7BhtzCsTfPbOp60vI5MkNw
644
644
  reconcile/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
645
645
  reconcile/utils/aggregated_list.py,sha256=km0xadW0jO4G_CqZPsXmoBURQ8c90FaTu5x4X1K1cZs,3357
646
646
  reconcile/utils/amtool.py,sha256=ngtBuVPETH6oAy5RnKzvreVbjwQCaATS_PYYwBprzjQ,2288
647
- reconcile/utils/aws_api.py,sha256=TJ0cgOBg9djdL9U_8HqSxf4aWm-NvwBCIGqP7YMcOZA,66126
647
+ reconcile/utils/aws_api.py,sha256=C90pODy5UB2YRV2Yd9Z4J5aTnMZk1CZv9YxbCN0I1-4,66822
648
648
  reconcile/utils/aws_helper.py,sha256=MDbv5jrNdqqJ5pfBxniGdJXBBO_EYc2_Uf2w9ZzeMNs,2854
649
649
  reconcile/utils/batches.py,sha256=TtEm64a8lWhFuNbUVpFEmXVdU2Q0sTBrP_I0Cjbgh7g,320
650
650
  reconcile/utils/binary.py,sha256=7MaAFBpzuBUTJ_aA6G6-eult_BPMVyiXbBLD0Y6F-DM,2301
@@ -716,7 +716,7 @@ reconcile/utils/sqs_gateway.py,sha256=XNIf3PY4UCPNufP2Ul0UJj3fKlt5larBba-VTT-41F
716
716
  reconcile/utils/state.py,sha256=a_EO5u7__Pqd0_E3MqzUttJ-0xRtuxcNx5oQi5WIahI,16392
717
717
  reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
718
718
  reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
719
- reconcile/utils/terraform_client.py,sha256=tCDVrfmFCB6lGfGhJt13VRkHxGy7Psw88KIze0r-JLo,31787
719
+ reconcile/utils/terraform_client.py,sha256=QTLRB33dWOlf2AmZPntx3WWBV8d_-cwMZyLKd7eqclk,34176
720
720
  reconcile/utils/terrascript_aws_client.py,sha256=1JgXcCF_-xbaAg7V9qihL1Xz5okQlSSrT1DeXGducHc,278037
721
721
  reconcile/utils/three_way_diff_strategy.py,sha256=oQcHXd9LVhirJfoaOBoHUYuZVGfyL2voKr6KVI34zZE,4833
722
722
  reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
@@ -828,7 +828,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
828
828
  tools/app_interface_reporter.py,sha256=1ZP58LYV6ww3XOLVxgy8NKasMb1jQmp4BNqzTEB0VBE,17723
829
829
  tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
830
830
  tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
831
- tools/qontract_cli.py,sha256=iY_ORJiPBF2CShM33AtPdRPX-1f8PFM4Kfbe4M5TlPQ,126959
831
+ tools/qontract_cli.py,sha256=bFTYOymVksNKp_ntG2l9GoA40tODuxeRDU3rO4J-CjA,128875
832
832
  tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
833
833
  tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
834
834
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -859,8 +859,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
859
859
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
860
860
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
861
861
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
862
- qontract_reconcile-0.10.1rc1010.dist-info/METADATA,sha256=7cFnKb9RaHgWUrwtmYqUUsZ2MHpPoQNg5MZJ6U8U8Qg,2263
863
- qontract_reconcile-0.10.1rc1010.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
864
- qontract_reconcile-0.10.1rc1010.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
865
- qontract_reconcile-0.10.1rc1010.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
866
- qontract_reconcile-0.10.1rc1010.dist-info/RECORD,,
862
+ qontract_reconcile-0.10.1rc1012.dist-info/METADATA,sha256=mF7VTRaqvqomAcDgHl1erECgIQ54KoxAT6lFU0Sv690,2263
863
+ qontract_reconcile-0.10.1rc1012.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
864
+ qontract_reconcile-0.10.1rc1012.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
865
+ qontract_reconcile-0.10.1rc1012.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
866
+ qontract_reconcile-0.10.1rc1012.dist-info/RECORD,,
@@ -79,6 +79,7 @@ class ReconcileAction(StrEnum):
79
79
  APPLY_ERROR = "Resource status in ERROR state"
80
80
  APPLY_SPEC_CHANGED = "Resource spec has changed"
81
81
  APPLY_DRIFT_DETECTION = "Resource drift detection run"
82
+ APPLY_USER_REQUESTED = "Resource reconciliation requested"
82
83
  DESTROY_CREATED = "Resource no longer exists in the configuration"
83
84
  DESTROY_ERROR = "Resource status in ERROR state"
84
85
 
@@ -112,6 +113,8 @@ class ExternalResourcesManager:
112
113
  ) -> ReconcileAction:
113
114
  if reconciliation.action == Action.APPLY:
114
115
  match state.resource_status:
116
+ case ResourceStatus.RECONCILIATION_REQUESTED:
117
+ return ReconcileAction.APPLY_USER_REQUESTED
115
118
  case ResourceStatus.NOT_EXISTS:
116
119
  return ReconcileAction.APPLY_NOT_EXISTS
117
120
  case ResourceStatus.ERROR:
@@ -36,6 +36,7 @@ class ResourceStatus(StrEnum):
36
36
  DELETE_IN_PROGRESS: str = "DELETE_IN_PROGRESS"
37
37
  ERROR: str = "ERROR"
38
38
  PENDING_SECRET_SYNC: str = "PENDING_SECRET_SYNC"
39
+ RECONCILIATION_REQUESTED: str = "RECONCILIATION_REQUESTED"
39
40
 
40
41
 
41
42
  class ExternalResourceState(BaseModel):
@@ -1630,6 +1630,25 @@ class AWSApi: # pylint: disable=too-many-public-methods
1630
1630
  return versions[0]["ValidUpgradeTarget"]
1631
1631
  return []
1632
1632
 
1633
+ def describe_db_parameter_group(
1634
+ self,
1635
+ account_name: str,
1636
+ db_parameter_group_name: str,
1637
+ region_name: str | None = None,
1638
+ ) -> dict[str, str]:
1639
+ optional_kwargs = {}
1640
+
1641
+ if region_name:
1642
+ optional_kwargs["region_name"] = region_name
1643
+
1644
+ rds = self._account_rds_client(account_name, **optional_kwargs)
1645
+ paginator = rds.get_paginator("describe_db_parameters")
1646
+ parameters = {}
1647
+ for page in paginator.paginate(DBParameterGroupName=db_parameter_group_name):
1648
+ for param in page.get("Parameters", []):
1649
+ parameters[param["ParameterName"]] = param["ParameterValue"]
1650
+ return parameters
1651
+
1633
1652
  def get_organization_billing_account(self, account_name: str) -> str:
1634
1653
  org = self._account_organizations_client(account_name)
1635
1654
  return org.describe_organization()["Organization"]["MasterAccountId"]
@@ -24,6 +24,7 @@ from typing import (
24
24
  )
25
25
 
26
26
  from botocore.errorfactory import ClientError
27
+ from packaging import version as pkg_version
27
28
  from sretoolbox.utils import (
28
29
  retry,
29
30
  threaded,
@@ -785,6 +786,71 @@ class TerraformClient: # pylint: disable=too-many-public-methods
785
786
  f"{resource_name} to a new major version."
786
787
  )
787
788
 
789
+ blue_green_update = after.get("blue_green_update", {}).get("enabled", False)
790
+ if blue_green_update:
791
+ self.validate_blue_green_update_requirements(
792
+ account_name,
793
+ engine,
794
+ after_version,
795
+ before["db_parameter_group_name"],
796
+ before.get("replica_source"),
797
+ region_name,
798
+ )
799
+
800
+ def validate_blue_green_update_requirements(
801
+ self,
802
+ account_name,
803
+ engine,
804
+ version,
805
+ parameter_group,
806
+ replica_source,
807
+ region_name,
808
+ ):
809
+ min_supported_versions = {
810
+ "mysql": [pkg_version.parse("5.7"), pkg_version.parse("8.0.15")],
811
+ "postgres": [
812
+ pkg_version.parse("11.21"),
813
+ pkg_version.parse("12.16"),
814
+ pkg_version.parse("13.12"),
815
+ pkg_version.parse("14.9"),
816
+ pkg_version.parse("15.4"),
817
+ pkg_version.parse("16.1"),
818
+ ],
819
+ }
820
+
821
+ def is_supported(engine, version):
822
+ parsed_version = pkg_version.parse(version)
823
+ if engine == "mysql":
824
+ return any(
825
+ parsed_version >= min_version
826
+ for min_version in min_supported_versions["mysql"]
827
+ )
828
+ elif engine == "postgres":
829
+ return any(
830
+ parsed_version >= min_version
831
+ for min_version in min_supported_versions["postgres"]
832
+ )
833
+ return False
834
+
835
+ if not is_supported(engine, version):
836
+ raise ValueError(
837
+ f"Engine version {version} is not supported for blue/green updates."
838
+ )
839
+
840
+ if replica_source:
841
+ raise ValueError(
842
+ "Blue/green updates are not supported for instances with read replicas."
843
+ )
844
+
845
+ if engine == "postgres" and parameter_group:
846
+ pg_details = self._aws_api.describe_db_parameter_group(
847
+ account_name, parameter_group, region_name
848
+ )
849
+ if pg_details.get("rds.logical_replication") != "1":
850
+ raise ValueError(
851
+ f"Parameter group {parameter_group} does not have logical replication enabled."
852
+ )
853
+
788
854
 
789
855
  class TerraformPlanFailed(Exception):
790
856
  pass
tools/qontract_cli.py CHANGED
@@ -56,14 +56,22 @@ from reconcile.cli import (
56
56
  config_file,
57
57
  use_jump_host,
58
58
  )
59
+ from reconcile.external_resources.integration import (
60
+ get_aws_api,
61
+ )
59
62
  from reconcile.external_resources.manager import (
60
63
  FLAG_RESOURCE_MANAGED_BY_ERV2,
61
64
  setup_factories,
62
65
  )
63
66
  from reconcile.external_resources.model import (
67
+ ExternalResourceKey,
64
68
  ExternalResourcesInventory,
65
69
  load_module_inventory,
66
70
  )
71
+ from reconcile.external_resources.state import (
72
+ ExternalResourcesStateDynamoDB,
73
+ ResourceStatus,
74
+ )
67
75
  from reconcile.gql_definitions.advanced_upgrade_service.aus_clusters import (
68
76
  query as aus_clusters_query,
69
77
  )
@@ -3942,5 +3950,47 @@ def get_input(
3942
3950
  print(resource.json(exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}}))
3943
3951
 
3944
3952
 
3953
+ @external_resources.command()
3954
+ @click.argument("provision-provider", required=True)
3955
+ @click.argument("provisioner", required=True)
3956
+ @click.argument("provider", required=True)
3957
+ @click.argument("identifier", required=True)
3958
+ @click.pass_context
3959
+ def request_reconciliation(
3960
+ ctx, provision_provider: str, provisioner: str, provider: str, identifier: str
3961
+ ):
3962
+ """Marks a resource as it needs to get reconciled. The itegration will reconcile the resource at
3963
+ its next iteration.
3964
+
3965
+ e.g: e.g: qontract-reconcile --config=<config> external-resources request-reconciliation aws app-sre-stage rds dashdotdb-stage
3966
+ """
3967
+ er_settings = get_settings()[0]
3968
+ vault_settings = get_app_interface_vault_settings()
3969
+ secret_reader = create_secret_reader(use_vault=vault_settings.vault)
3970
+ with get_aws_api(
3971
+ query_func=gql.get_api().query,
3972
+ account_name=er_settings.state_dynamodb_account.name,
3973
+ region=er_settings.state_dynamodb_region,
3974
+ secret_reader=secret_reader,
3975
+ ) as aws_api:
3976
+ state_manager = ExternalResourcesStateDynamoDB(
3977
+ aws_api=aws_api,
3978
+ table_name=er_settings.state_dynamodb_table,
3979
+ )
3980
+ key = ExternalResourceKey(
3981
+ provision_provider=provision_provider,
3982
+ provisioner_name=provisioner,
3983
+ provider=provider,
3984
+ identifier=identifier,
3985
+ )
3986
+ current_state = state_manager.get_external_resource_state(key)
3987
+ if current_state.resource_status != ResourceStatus.NOT_EXISTS:
3988
+ state_manager.update_resource_status(
3989
+ key, ResourceStatus.RECONCILIATION_REQUESTED
3990
+ )
3991
+ else:
3992
+ logging.info("External Resource does not exist")
3993
+
3994
+
3945
3995
  if __name__ == "__main__":
3946
3996
  root() # pylint: disable=no-value-for-parameter