qontract-reconcile 0.10.1rc548__py3-none-any.whl → 0.10.1rc550__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.1rc548
3
+ Version: 0.10.1rc550
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
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=NwErtrqgBiXr7eGCAHdtGGOx0S7-4JnSc29Ie
9
9
  reconcile/aws_support_cases_sos.py,sha256=Jk6_XjDeJSYxgRGqcEAOcynt9qJF2r5HPIPcSKmoBv8,2974
10
10
  reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=W_VJagnsJR1v5oqjlI3RJJE0_nhtJ0m81RS8zWA5u5c,3538
11
11
  reconcile/checkpoint.py,sha256=R2WFXUXLTB4sWMi4GeA4eegsuf_1-Q4vH8M0Toh3Ij4,5036
12
- reconcile/cli.py,sha256=glH6d_cL8D8Bd2Wl_iYiV5H39o74nElXQjck_HjUkpY,85765
12
+ reconcile/cli.py,sha256=H28wYQd623XEfcEYODG15elir-fvW4BBhjNznc0JJFs,87169
13
13
  reconcile/closedbox_endpoint_monitoring_base.py,sha256=SMhkcQqprWvThrIJa3U_3uh5w1h-alleW1QnCJFY4Qw,4909
14
14
  reconcile/cluster_deployment_mapper.py,sha256=2Ah-nu-Mdig0pjuiZl_XLrmVAjYzFjORR3dMlCgkmw0,2352
15
15
  reconcile/dashdotdb_base.py,sha256=a5aPLVxyqPSbjdB0Ty-uliOtxwvEbbEljHJKxdK3-Zk,4813
@@ -70,7 +70,7 @@ reconcile/openshift_namespaces.py,sha256=DboMc6t0vXD54lL9ZP9P9fQnCRo2g_0z5FWubtW
70
70
  reconcile/openshift_network_policies.py,sha256=_qqv7yj17OM1J8KJPsFmzFZ85gzESJeBocC672z4_WU,4231
71
71
  reconcile/openshift_resourcequotas.py,sha256=yUi56PiOn3inMMfq_x_FEHmaW-reGipzoorjdar372g,2415
72
72
  reconcile/openshift_resources.py,sha256=kwsY5cko7udEKNlhL2oKiKv_5wzEw9wmmwROE016ng8,1400
73
- reconcile/openshift_resources_base.py,sha256=XSctdE3pD4BI-91tlV5rdXIhvdtymZYeOKiCad8ZJl4,45839
73
+ reconcile/openshift_resources_base.py,sha256=rlzHO9mIQ2RGtlma-KHjtzkWirge6nZy-NP6cXlXeo0,45952
74
74
  reconcile/openshift_rolebindings.py,sha256=0sEKajdqVuBSzlagyPbLxtNXQdI2vyabmbIRifs0des,6629
75
75
  reconcile/openshift_routes.py,sha256=fXvuPSjcjVw1X3j2EQvUAdbOepmIFdKk-M3qP8QzPiw,1075
76
76
  reconcile/openshift_saas_deploy.py,sha256=NFiNrk7055vunzzJmI7cVBubFj6JPDlEpJqDwpG_t9g,12706
@@ -132,6 +132,8 @@ reconcile/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
132
132
  reconcile/aws_ami_cleanup/integration.py,sha256=IW95cpMj2P5ffs-AxsR_TDQCJnYFBhLIfP2de7dz_8A,10109
133
133
  reconcile/aws_cloudwatch_log_retention/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
134
134
  reconcile/aws_cloudwatch_log_retention/integration.py,sha256=0UcSZIrGvnGY4m9fj87oejIolIP_qTxtJInpmW9jrQ0,7772
135
+ reconcile/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
+ reconcile/aws_saml_idp/integration.py,sha256=k14YqAIE2w4P7s_3zX1astJNim9E0bZEPv95UpO79gA,4841
135
137
  reconcile/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
138
  reconcile/aws_version_sync/integration.py,sha256=dN_lZIeM5i0p6-yHYadGg65QgDs0nVWYJkPzU-KGwuo,15196
137
139
  reconcile/aws_version_sync/utils.py,sha256=sVv-48PKi2VITlqqvmpbjnFDOPeGqfKzgkpIszlmjL0,1708
@@ -176,6 +178,8 @@ reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py,sha256=47DE
176
178
  reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py,sha256=uVEEqU6YYmKsNTo6EWlFnoVmqha2rvBDx-wiD64VmG0,1679
177
179
  reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
180
  reconcile/gql_definitions/aws_ami_cleanup/asg_namespaces.py,sha256=OJmeTu7uirLGAysZ3IQTtRXqMyL8noi_QZxPuWYxxmI,3678
181
+ reconcile/gql_definitions/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
+ reconcile/gql_definitions/aws_saml_idp/aws_accounts.py,sha256=ZhsTyUmR-i-0eDXEEl2qZV64bIHMK25KrvlkqpzwO8Y,2652
179
183
  reconcile/gql_definitions/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
184
  reconcile/gql_definitions/aws_version_sync/clusters.py,sha256=2TOJOFxpTkZ2HKuqAGUo6tQkzOINSfO-bYDINVpJeL0,2295
181
185
  reconcile/gql_definitions/aws_version_sync/namespaces.py,sha256=eBLyXlSjWdmEE-jY9M2Ocgk7JGi2OsWisTkjHLfgU_A,4311
@@ -583,7 +587,7 @@ reconcile/utils/state.py,sha256=SAa6QLHu9lr0yqLCBy2AypNx1IPCJWlrRBrvlzAKsOU,1450
583
587
  reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
584
588
  reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
585
589
  reconcile/utils/terraform_client.py,sha256=_jBriLBwU005bDxWlq7CRByOkVCfiH47oBzB0ArNAY8,31901
586
- reconcile/utils/terrascript_aws_client.py,sha256=3jtFVmL0O10yvx-Lo8Qj63BKiM9jLMGSbdonJaTWb14,266082
590
+ reconcile/utils/terrascript_aws_client.py,sha256=j3DzUROG_oP2Q-YnG3Lc4DazTyQV7MRAVZIkU53FhBk,266379
587
591
  reconcile/utils/three_way_diff_strategy.py,sha256=nyqeQsLCoPI6e16k2CF3b9KNgQLU-rPf5RtfdUfVMwE,4468
588
592
  reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
589
593
  reconcile/utils/unleash.py,sha256=1D56CsZfE3ShDtN3IErE1T2eeIwNmxhK-yYbCotJ99E,3601
@@ -670,8 +674,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
670
674
  tools/test/test_qontract_cli.py,sha256=se-YG_YVCWRFrnCPvBVHDBT_59CkbIoEni-4SJa8_MU,2755
671
675
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
672
676
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
673
- qontract_reconcile-0.10.1rc548.dist-info/METADATA,sha256=96wIaY6LGAn5tRcG1TNghKvMbpgGEqj3Wep8MMnC7gA,2349
674
- qontract_reconcile-0.10.1rc548.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
675
- qontract_reconcile-0.10.1rc548.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
676
- qontract_reconcile-0.10.1rc548.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
677
- qontract_reconcile-0.10.1rc548.dist-info/RECORD,,
677
+ qontract_reconcile-0.10.1rc550.dist-info/METADATA,sha256=UCdLxw5-f02snUpWCllNiE-3f5PuEWHyyCqVJm7jBpw,2349
678
+ qontract_reconcile-0.10.1rc550.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
679
+ qontract_reconcile-0.10.1rc550.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
680
+ qontract_reconcile-0.10.1rc550.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
681
+ qontract_reconcile-0.10.1rc550.dist-info/RECORD,,
File without changes
@@ -0,0 +1,158 @@
1
+ import sys
2
+ from collections.abc import (
3
+ Callable,
4
+ Iterable,
5
+ )
6
+ from typing import (
7
+ Any,
8
+ )
9
+
10
+ import requests
11
+ from pydantic import BaseModel, HttpUrl
12
+
13
+ from reconcile import queries
14
+ from reconcile.gql_definitions.aws_saml_idp.aws_accounts import (
15
+ AWSAccountV1,
16
+ )
17
+ from reconcile.gql_definitions.aws_saml_idp.aws_accounts import (
18
+ query as aws_accounts_query,
19
+ )
20
+ from reconcile.status import ExitCodes
21
+ from reconcile.utils import gql
22
+ from reconcile.utils.aws_api import AWSApi
23
+ from reconcile.utils.defer import defer
24
+ from reconcile.utils.disabled_integrations import integration_is_enabled
25
+ from reconcile.utils.runtime.integration import (
26
+ PydanticRunParams,
27
+ QontractReconcileIntegration,
28
+ )
29
+ from reconcile.utils.semver_helper import make_semver
30
+ from reconcile.utils.terraform_client import TerraformClient
31
+ from reconcile.utils.terrascript_aws_client import TerrascriptClient
32
+
33
+ QONTRACT_INTEGRATION = "aws-saml-idp"
34
+ QONTRACT_INTEGRATION_VERSION = make_semver(1, 0, 0)
35
+
36
+
37
+ class AwsSamlIdpIntegrationParams(PydanticRunParams):
38
+ thread_pool_size: int = 10
39
+ print_to_file: str | None = None
40
+ enable_deletion: bool = False
41
+ # integration specific parameters
42
+ saml_idp_name: str
43
+ saml_metadata_url: HttpUrl
44
+ account_name: str | None = None
45
+
46
+
47
+ class SamlIdpConfig(BaseModel):
48
+ account_name: str
49
+ name: str
50
+ metadata: str
51
+
52
+
53
+ class AwsSamlIdpIntegration(QontractReconcileIntegration[AwsSamlIdpIntegrationParams]):
54
+ """Manage the SAML IDP config for all AWS accounts."""
55
+
56
+ @property
57
+ def name(self) -> str:
58
+ return QONTRACT_INTEGRATION
59
+
60
+ def get_early_exit_desired_state(
61
+ self, query_func: Callable | None = None
62
+ ) -> dict[str, Any]:
63
+ """Return the desired state for early exit."""
64
+ if not query_func:
65
+ query_func = gql.get_api().query
66
+ return {
67
+ "accounts": [c.dict() for c in self.get_aws_accounts(query_func)],
68
+ }
69
+
70
+ def get_aws_accounts(
71
+ self, query_func: Callable, account_name: str | None = None
72
+ ) -> list[AWSAccountV1]:
73
+ """Get all AWS accounts."""
74
+ data = aws_accounts_query(query_func)
75
+ return [
76
+ account
77
+ for account in data.accounts or []
78
+ if integration_is_enabled(self.name, account)
79
+ and (not account_name or account.name == account_name)
80
+ ]
81
+
82
+ def build_saml_idp_config(
83
+ self,
84
+ aws_accounts: Iterable[AWSAccountV1],
85
+ saml_idp_name: str,
86
+ saml_metadata: str,
87
+ ) -> list[SamlIdpConfig]:
88
+ """Build the desired state."""
89
+ return [
90
+ SamlIdpConfig(
91
+ account_name=account.name, name=saml_idp_name, metadata=saml_metadata
92
+ )
93
+ for account in aws_accounts
94
+ if account.sso
95
+ ]
96
+
97
+ def get_saml_metadata(self, saml_metadata_url: str) -> str:
98
+ """Get the SAML metadata from the given URL."""
99
+ response = requests.get(saml_metadata_url)
100
+ response.raise_for_status()
101
+ return response.text
102
+
103
+ @defer
104
+ def run(self, dry_run: bool, defer: Callable | None = None) -> None:
105
+ """Run the integration."""
106
+ gql_api = gql.get_api()
107
+ settings = queries.get_app_interface_settings()
108
+ aws_accounts = self.get_aws_accounts(
109
+ gql_api.query, account_name=self.params.account_name
110
+ )
111
+ aws_accounts_dict = [account.dict(by_alias=True) for account in aws_accounts]
112
+
113
+ ts = TerrascriptClient(
114
+ self.name.replace("-", "_"),
115
+ "",
116
+ self.params.thread_pool_size,
117
+ aws_accounts_dict,
118
+ settings=settings,
119
+ )
120
+
121
+ for saml_idp_config in self.build_saml_idp_config(
122
+ aws_accounts,
123
+ saml_idp_name=self.params.saml_idp_name,
124
+ saml_metadata=self.get_saml_metadata(self.params.saml_metadata_url),
125
+ ):
126
+ ts.populate_saml_idp(
127
+ account_name=saml_idp_config.account_name,
128
+ name=saml_idp_config.name,
129
+ metadata=saml_idp_config.metadata,
130
+ )
131
+ working_dirs = ts.dump(print_to_file=self.params.print_to_file)
132
+
133
+ if self.params.print_to_file:
134
+ sys.exit(ExitCodes.SUCCESS)
135
+
136
+ aws_api = AWSApi(1, aws_accounts_dict, settings=settings, init_users=False)
137
+ tf = TerraformClient(
138
+ self.name,
139
+ QONTRACT_INTEGRATION_VERSION,
140
+ "",
141
+ aws_accounts_dict,
142
+ working_dirs,
143
+ self.params.thread_pool_size,
144
+ aws_api,
145
+ )
146
+ if defer:
147
+ defer(tf.cleanup)
148
+
149
+ _, err = tf.plan(self.params.enable_deletion)
150
+ if err:
151
+ sys.exit(ExitCodes.ERROR)
152
+
153
+ if dry_run:
154
+ return
155
+
156
+ err = tf.apply()
157
+ if err:
158
+ sys.exit(ExitCodes.ERROR)
reconcile/cli.py CHANGED
@@ -698,6 +698,55 @@ def terraform_aws_route53(
698
698
  )
699
699
 
700
700
 
701
+ @integration.command(short_help="Manage the SAML IDP config for all AWS accounts.")
702
+ @print_to_file
703
+ @threaded()
704
+ @binary(["terraform", "git"])
705
+ @binary_version("terraform", ["version"], TERRAFORM_VERSION_REGEX, TERRAFORM_VERSION)
706
+ @enable_deletion(default=True)
707
+ @account_name
708
+ @click.option(
709
+ "--saml-idp-name",
710
+ help="Name of the SAML IDP. Must match the name the SAML response!",
711
+ required=True,
712
+ default="RedHatInternal",
713
+ )
714
+ @click.option(
715
+ "--saml-metadata-url",
716
+ help="URL of the SAML metadata xml file. Must be a valid URL!",
717
+ required=True,
718
+ default="https://auth.redhat.com/auth/realms/EmployeeIDP/protocol/saml/descriptor",
719
+ )
720
+ @click.pass_context
721
+ def aws_saml_idp(
722
+ ctx,
723
+ print_to_file,
724
+ enable_deletion,
725
+ thread_pool_size,
726
+ account_name,
727
+ saml_idp_name,
728
+ saml_metadata_url,
729
+ ):
730
+ from reconcile.aws_saml_idp.integration import (
731
+ AwsSamlIdpIntegration,
732
+ AwsSamlIdpIntegrationParams,
733
+ )
734
+
735
+ run_class_integration(
736
+ integration=AwsSamlIdpIntegration(
737
+ AwsSamlIdpIntegrationParams(
738
+ thread_pool_size=thread_pool_size,
739
+ print_to_file=print_to_file,
740
+ enable_deletion=enable_deletion,
741
+ saml_idp_name=saml_idp_name,
742
+ saml_metadata_url=saml_metadata_url,
743
+ account_name=account_name,
744
+ )
745
+ ),
746
+ ctx=ctx.obj,
747
+ )
748
+
749
+
701
750
  @integration.command(short_help="Configures the teams and members in a GitHub org.")
702
751
  @click.pass_context
703
752
  def github(ctx):
File without changes
@@ -0,0 +1,116 @@
1
+ """
2
+ Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
+ """
4
+ from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
+ from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
+ from enum import Enum # noqa: F401 # pylint: disable=W0611
7
+ from typing import ( # noqa: F401 # pylint: disable=W0611
8
+ Any,
9
+ Optional,
10
+ Union,
11
+ )
12
+
13
+ from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
+ BaseModel,
15
+ Extra,
16
+ Field,
17
+ Json,
18
+ )
19
+
20
+ from reconcile.gql_definitions.fragments.aws_account_common import AWSAccountCommon
21
+ from reconcile.gql_definitions.fragments.terraform_state import TerraformState
22
+
23
+
24
+ DEFINITION = """
25
+ fragment AWSAccountCommon on AWSAccount_v1 {
26
+ path
27
+ name
28
+ uid
29
+ terraformUsername
30
+ consoleUrl
31
+ resourcesDefaultRegion
32
+ supportedDeploymentRegions
33
+ providerVersion
34
+ accountOwners {
35
+ name
36
+ email
37
+ }
38
+ automationToken {
39
+ ... VaultSecret
40
+ }
41
+ garbageCollection
42
+ enableDeletion
43
+ deletionApprovals {
44
+ type
45
+ name
46
+ expiration
47
+ }
48
+ disable {
49
+ integrations
50
+ }
51
+ deleteKeys
52
+ premiumSupport
53
+ partition
54
+ }
55
+
56
+ fragment TerraformState on TerraformStateAWS_v1 {
57
+ provider
58
+ bucket
59
+ region
60
+ integrations {
61
+ key
62
+ integration
63
+ }
64
+ }
65
+
66
+ fragment VaultSecret on VaultSecret_v1 {
67
+ path
68
+ field
69
+ version
70
+ format
71
+ }
72
+
73
+ query AWSAccountsSamlIdp {
74
+ accounts: awsaccounts_v1 {
75
+ sso
76
+ ...AWSAccountCommon
77
+ terraformState {
78
+ ...TerraformState
79
+ }
80
+ }
81
+ }
82
+ """
83
+
84
+
85
+ class ConfiguredBaseModel(BaseModel):
86
+ class Config:
87
+ smart_union=True
88
+ extra=Extra.forbid
89
+
90
+
91
+ class AWSAccountV1(AWSAccountCommon):
92
+ sso: Optional[bool] = Field(..., alias="sso")
93
+ terraform_state: Optional[TerraformState] = Field(..., alias="terraformState")
94
+
95
+
96
+ class AWSAccountsSamlIdpQueryData(ConfiguredBaseModel):
97
+ accounts: Optional[list[AWSAccountV1]] = Field(..., alias="accounts")
98
+
99
+
100
+ def query(query_func: Callable, **kwargs: Any) -> AWSAccountsSamlIdpQueryData:
101
+ """
102
+ This is a convenience function which queries and parses the data into
103
+ concrete types. It should be compatible with most GQL clients.
104
+ You do not have to use it to consume the generated data classes.
105
+ Alternatively, you can also mime and alternate the behavior
106
+ of this function in the caller.
107
+
108
+ Parameters:
109
+ query_func (Callable): Function which queries your GQL Server
110
+ kwargs: optional arguments that will be passed to the query function
111
+
112
+ Returns:
113
+ AWSAccountsSamlIdpQueryData: queried data parsed into generated classes
114
+ """
115
+ raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
116
+ return AWSAccountsSamlIdpQueryData(**raw_data)
@@ -194,8 +194,14 @@ NAMESPACES_QUERY = """
194
194
  %s
195
195
  }
196
196
  spec {
197
+ ... on ClusterSpecROSA_v1 {
198
+ account {
199
+ uid
200
+ }
201
+ }
197
202
  version
198
203
  region
204
+ hypershift
199
205
  }
200
206
  network {
201
207
  pod
@@ -90,6 +90,7 @@ from terrascript.resource import (
90
90
  aws_iam_role,
91
91
  aws_iam_role_policy,
92
92
  aws_iam_role_policy_attachment,
93
+ aws_iam_saml_provider,
93
94
  aws_iam_service_linked_role,
94
95
  aws_iam_user,
95
96
  aws_iam_user_group_membership,
@@ -6454,3 +6455,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
6454
6455
  )
6455
6456
  )
6456
6457
  self.add_resources(account, tf_resources)
6458
+
6459
+ def populate_saml_idp(self, account_name: str, name: str, metadata: str) -> None:
6460
+ saml_idp = aws_iam_saml_provider(
6461
+ f"{account_name}-{name}", name=name, saml_metadata_document=metadata
6462
+ )
6463
+ self.add_resource(account_name, saml_idp)