qontract-reconcile 0.10.1rc879__py3-none-any.whl → 0.10.1rc881__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.
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/RECORD +17 -16
- reconcile/aws_account_manager/integration.py +7 -12
- reconcile/aws_account_manager/reconciler.py +51 -1
- reconcile/aws_account_manager/utils.py +3 -0
- reconcile/glitchtip/integration.py +3 -3
- reconcile/glitchtip_project_alerts/integration.py +4 -4
- reconcile/glitchtip_project_dsn/integration.py +4 -4
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +6 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +8 -0
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +4 -4
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +2 -2
- reconcile/utils/aws_api_typed/account.py +23 -0
- reconcile/utils/aws_api_typed/api.py +20 -9
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
3
|
+
Version: 0.10.1rc881
|
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
|
{qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/RECORD
RENAMED
@@ -138,11 +138,11 @@ reconcile/aus/version_gates/ingress_gate_handler.py,sha256=ZCtyggBzzcb0prtdbMpJs
|
|
138
138
|
reconcile/aus/version_gates/ocp_gate_handler.py,sha256=RW1ppDaCZXVegV9AzzqYXxDUu_Z_7d43Z5h2Pk_piKc,716
|
139
139
|
reconcile/aus/version_gates/sts_version_gate_handler.py,sha256=PhJ7yBh2q-rv9CJcfFhc0H11nyDyG7NAryNS3F74xdY,3697
|
140
140
|
reconcile/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
141
|
-
reconcile/aws_account_manager/integration.py,sha256=
|
141
|
+
reconcile/aws_account_manager/integration.py,sha256=60tMmQNAsc5BGqJh3v3sOrnIjfTPRG2rgPxwAbCsPP4,15005
|
142
142
|
reconcile/aws_account_manager/merge_request_manager.py,sha256=zZct3NxWMBQupl4QfD7ULxnt4ipt_2FBoH_NusboIuw,3781
|
143
143
|
reconcile/aws_account_manager/metrics.py,sha256=YB10ea4kIGwJfs5N14RF-RoXPb-QQWaDBz1jLZ3YWE0,917
|
144
|
-
reconcile/aws_account_manager/reconciler.py,sha256=
|
145
|
-
reconcile/aws_account_manager/utils.py,sha256=
|
144
|
+
reconcile/aws_account_manager/reconciler.py,sha256=5YG7nZ4GG1SY2Pe_OxetdtzOnl37MllZMu_ca22vRSo,15025
|
145
|
+
reconcile/aws_account_manager/utils.py,sha256=iYPPOtbZ7FiKkz9v5f1YXRIHw5YFOtSavUkF8oMwfJY,1439
|
146
146
|
reconcile/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
147
147
|
reconcile/aws_ami_cleanup/integration.py,sha256=IW95cpMj2P5ffs-AxsR_TDQCJnYFBhLIfP2de7dz_8A,10109
|
148
148
|
reconcile/aws_cloudwatch_log_retention/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -194,12 +194,12 @@ reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYj
|
|
194
194
|
reconcile/external_resources/secrets_sync.py,sha256=xFQ_ObWl29btbxzEJSkndvHBPcsVpSTkmUlWcUGzZ70,15132
|
195
195
|
reconcile/external_resources/state.py,sha256=fA_CzT4oNie4wnaImwW-W1duWEOKFyS1omcnMyYwx2Q,9644
|
196
196
|
reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
197
|
-
reconcile/glitchtip/integration.py,sha256=
|
197
|
+
reconcile/glitchtip/integration.py,sha256=SCfdllg0cywCyLKCA66yUm9Z_Sb8t5E0jDEKdwRk6HI,8372
|
198
198
|
reconcile/glitchtip/reconciler.py,sha256=nUvDv7qG1ly0cA16MmlL6NV71yl1mJYLT2mui7lmi0Y,12402
|
199
199
|
reconcile/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
200
|
-
reconcile/glitchtip_project_alerts/integration.py,sha256=
|
200
|
+
reconcile/glitchtip_project_alerts/integration.py,sha256=HI_HgvTTc2K-8Md0SpEBs6tOZ3CQm-AbOatbw_NrKqg,12425
|
201
201
|
reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
202
|
-
reconcile/glitchtip_project_dsn/integration.py,sha256=
|
202
|
+
reconcile/glitchtip_project_dsn/integration.py,sha256=5c8RVIO3Wjz2kBfB52EmxZ6VP2JQ1rLGMM9lybNhdAE,8109
|
203
203
|
reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
204
204
|
reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
205
205
|
reconcile/gql_definitions/acs/acs_instances.py,sha256=L91WW9LbhJbBSrECqShQpFtjoBOsmNIYLRpMbx1io5o,2181
|
@@ -211,7 +211,7 @@ reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py,sha256=zU
|
|
211
211
|
reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
212
212
|
reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py,sha256=uVEEqU6YYmKsNTo6EWlFnoVmqha2rvBDx-wiD64VmG0,1679
|
213
213
|
reconcile/gql_definitions/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
214
|
-
reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=
|
214
|
+
reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=R-Au5ZErdKSWqANtpiayLikvMSj3ha9muWoX5FI7-AE,4718
|
215
215
|
reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
216
216
|
reconcile/gql_definitions/aws_ami_cleanup/asg_namespaces.py,sha256=OJmeTu7uirLGAysZ3IQTtRXqMyL8noi_QZxPuWYxxmI,3678
|
217
217
|
reconcile/gql_definitions/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -281,7 +281,7 @@ reconcile/gql_definitions/external_resources/external_resources_settings.py,sha2
|
|
281
281
|
reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
282
282
|
reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
|
283
283
|
reconcile/gql_definitions/fragments/aws_account_common.py,sha256=3-7ZAP6GSff7Z2Syz2VQCLY4IySqBOSVmceaRiVNQpw,2385
|
284
|
-
reconcile/gql_definitions/fragments/aws_account_managed.py,sha256=
|
284
|
+
reconcile/gql_definitions/fragments/aws_account_managed.py,sha256=sM5J4TczyqpzhBFkX0IIQifRYvYpDIMY7pOhEDOUXCY,1789
|
285
285
|
reconcile/gql_definitions/fragments/aws_account_sso.py,sha256=ITR3PLz4Iq1SiWAoYGWPDuHJnAmTyZ0QQqs2Zsi8pxA,979
|
286
286
|
reconcile/gql_definitions/fragments/aws_infra_management_account.py,sha256=uAmALVRF2gBM3p_Dmez_ew6KVAtetamwOPkRIPZAlGc,1254
|
287
287
|
reconcile/gql_definitions/fragments/aws_vpc.py,sha256=T2egTwi2Rb0IRBBmsyag8xKpu_m6GbIAy80fhZNZwk8,1434
|
@@ -309,9 +309,9 @@ reconcile/gql_definitions/gitlab_members/gitlab_instances.py,sha256=oYPvfiOsPTGH
|
|
309
309
|
reconcile/gql_definitions/gitlab_members/permissions.py,sha256=Qzj3Fpv7xj8v9eygeP312nHRNg8er8XMRBveynPIyQM,3302
|
310
310
|
reconcile/gql_definitions/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
311
311
|
reconcile/gql_definitions/glitchtip/glitchtip_instance.py,sha256=QUfLhRkdE_-SorWgLBB8LHFD6kihbFwEoVByCLax3yM,2781
|
312
|
-
reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=
|
312
|
+
reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=AojrkCDGbVjY0TOkfookz-9tqLA9txY7_xNdsWe174c,6004
|
313
313
|
reconcile/gql_definitions/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
314
|
-
reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=
|
314
|
+
reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=pnkysdaQtdiVVxz9s7V8qttFygqcXOuXREd4LF7tCW8,4466
|
315
315
|
reconcile/gql_definitions/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
316
316
|
reconcile/gql_definitions/integrations/integrations.py,sha256=LfpgVbCCCk20ohwP5pDea5fwxMFGrcgE6J_WHBuGqek,11595
|
317
317
|
reconcile/gql_definitions/jenkins_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -715,7 +715,8 @@ reconcile/utils/acs/notifiers.py,sha256=2n5blP9N1FdGLZuy3do9bpjd8NKg88kmLNNqhAGn
|
|
715
715
|
reconcile/utils/acs/policies.py,sha256=_jAz6cv8KRYtDsXjGoJgNbD8_9PUa5LSwwVlpK4A_cQ,5505
|
716
716
|
reconcile/utils/acs/rbac.py,sha256=ugsLM9Pb7FbUbdq85E3VzXGMaB9ZovXob7tdWCxwqZ8,8808
|
717
717
|
reconcile/utils/aws_api_typed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
718
|
-
reconcile/utils/aws_api_typed/
|
718
|
+
reconcile/utils/aws_api_typed/account.py,sha256=puYfDsWF1E1Ub5e8yh0Hqz-whqERGn819N08i-g4zgY,626
|
719
|
+
reconcile/utils/aws_api_typed/api.py,sha256=1h_dQXnE7FUAZi4RRgBEU7nbyAz8awRo0cpuilXyhHE,9239
|
719
720
|
reconcile/utils/aws_api_typed/dynamodb.py,sha256=AKUbz8HGzmSq4cnpjJe7PgqsikMkjbpbzUD2UJv2b58,383
|
720
721
|
reconcile/utils/aws_api_typed/iam.py,sha256=ka46H2-SzTCgy6EJYapKTzyZK9vR1bkfD0wF8bDdy1Q,2201
|
721
722
|
reconcile/utils/aws_api_typed/organization.py,sha256=oXftcLVuSs9qej6efdssl38FvjeZaQC5R2Wj3NzxX4U,5529
|
@@ -837,8 +838,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
837
838
|
tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jrss,4941
|
838
839
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
839
840
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
840
|
-
qontract_reconcile-0.10.
|
841
|
-
qontract_reconcile-0.10.
|
842
|
-
qontract_reconcile-0.10.
|
843
|
-
qontract_reconcile-0.10.
|
844
|
-
qontract_reconcile-0.10.
|
841
|
+
qontract_reconcile-0.10.1rc881.dist-info/METADATA,sha256=aWt-wXRL72DWuJYJh5aKEqNiw9lbIpToGNsTP6zL8tI,2273
|
842
|
+
qontract_reconcile-0.10.1rc881.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
843
|
+
qontract_reconcile-0.10.1rc881.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
844
|
+
qontract_reconcile-0.10.1rc881.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
845
|
+
qontract_reconcile-0.10.1rc881.dist-info/RECORD,,
|
@@ -114,10 +114,8 @@ class AwsAccountMgmtIntegration(
|
|
114
114
|
for account in data.accounts or []
|
115
115
|
if integration_is_enabled(self.name, account)
|
116
116
|
and (not account_name or account.name == account_name)
|
117
|
+
and validate(account)
|
117
118
|
]
|
118
|
-
for account in all_aws_accounts:
|
119
|
-
validate(account)
|
120
|
-
|
121
119
|
payer_accounts = [
|
122
120
|
account
|
123
121
|
for account in all_aws_accounts
|
@@ -219,18 +217,16 @@ class AwsAccountMgmtIntegration(
|
|
219
217
|
self.reconcile_account(account_role_api, reconciler, account)
|
220
218
|
|
221
219
|
def reconcile_account(
|
222
|
-
self,
|
223
|
-
aws_api: AWSApi,
|
224
|
-
reconciler: AWSReconciler,
|
225
|
-
account: AWSAccountManaged,
|
226
|
-
create_initial_user: bool = True,
|
220
|
+
self, aws_api: AWSApi, reconciler: AWSReconciler, account: AWSAccountManaged
|
227
221
|
) -> None:
|
228
222
|
"""Reconcile an AWS account."""
|
223
|
+
assert account.security_contact # mypy
|
229
224
|
reconciler.reconcile_account(
|
230
225
|
aws_api=aws_api,
|
231
226
|
name=account.name,
|
232
227
|
alias=account.alias,
|
233
228
|
quotas=[q for ql in account.quota_limits or [] for q in ql.quotas],
|
229
|
+
security_contact=account.security_contact,
|
234
230
|
)
|
235
231
|
|
236
232
|
def reconcile_payer_accounts(
|
@@ -245,8 +241,7 @@ class AwsAccountMgmtIntegration(
|
|
245
241
|
# reconcile accounts within payer accounts, aka organization accounts
|
246
242
|
for payer_account in payer_accounts:
|
247
243
|
# having a state per flavor and payer account makes it easier in a shared environment
|
248
|
-
reconciler.state.state_path = default_state_path
|
249
|
-
reconciler.state.state_path += f"/{payer_account.name}"
|
244
|
+
reconciler.state.state_path = f"{default_state_path}/{payer_account.name}"
|
250
245
|
aws_account_manager_role = (
|
251
246
|
payer_account.automation_role.aws_account_manager
|
252
247
|
if payer_account.automation_role
|
@@ -290,8 +285,8 @@ class AwsAccountMgmtIntegration(
|
|
290
285
|
) -> None:
|
291
286
|
"""Reconcile accounts not part of an organization via a payer account (e.g. payer accounts themselves)"""
|
292
287
|
for account in non_organization_accounts:
|
293
|
-
|
294
|
-
reconciler.state.state_path
|
288
|
+
# the state must be account specific
|
289
|
+
reconciler.state.state_path = f"{default_state_path}/{account.name}"
|
295
290
|
secret = self.secret_reader.read_all_secret(account.automation_token)
|
296
291
|
with AWSApi(
|
297
292
|
AWSStaticCredentials(
|
@@ -25,6 +25,7 @@ TASK_REQUEST_SERVICE_QUOTA = "request-service-quota"
|
|
25
25
|
TASK_CHECK_SERVICE_QUOTA_STATUS = "check-service-quota-status"
|
26
26
|
TASK_ENABLE_ENTERPRISE_SUPPORT = "enable-enterprise-support"
|
27
27
|
TASK_CHECK_ENTERPRISE_SUPPORT_STATUS = "check-enterprise-support-status"
|
28
|
+
TASK_SET_SECURITY_CONTACT = "set-security-contact"
|
28
29
|
|
29
30
|
|
30
31
|
class Quota(Protocol):
|
@@ -35,6 +36,15 @@ class Quota(Protocol):
|
|
35
36
|
def dict(self) -> dict[str, Any]: ...
|
36
37
|
|
37
38
|
|
39
|
+
class Contact(Protocol):
|
40
|
+
name: str
|
41
|
+
title: str | None
|
42
|
+
email: str
|
43
|
+
phone_number: str
|
44
|
+
|
45
|
+
def dict(self) -> dict[str, Any]: ...
|
46
|
+
|
47
|
+
|
38
48
|
class AWSReconciler:
|
39
49
|
def __init__(self, state: State, dry_run: bool) -> None:
|
40
50
|
self.state = state
|
@@ -288,6 +298,33 @@ class AWSReconciler:
|
|
288
298
|
)
|
289
299
|
raise AbortStateTransaction("Enterprise support case still open")
|
290
300
|
|
301
|
+
def _set_security_contact(
|
302
|
+
self,
|
303
|
+
aws_api: AWSApi,
|
304
|
+
account: str,
|
305
|
+
name: str,
|
306
|
+
title: str | None,
|
307
|
+
email: str,
|
308
|
+
phone_number: str,
|
309
|
+
) -> None:
|
310
|
+
"""Set the security contact for the account."""
|
311
|
+
title = title or name
|
312
|
+
security_contact = f"{name} {title} {email} {phone_number}"
|
313
|
+
with self.state.transaction(
|
314
|
+
state_key(account, TASK_SET_SECURITY_CONTACT)
|
315
|
+
) as _state:
|
316
|
+
if _state.exists and _state.value == security_contact:
|
317
|
+
return
|
318
|
+
|
319
|
+
logging.info(f"Setting security contact for {account}")
|
320
|
+
if self.dry_run:
|
321
|
+
raise AbortStateTransaction("Dry run")
|
322
|
+
|
323
|
+
aws_api.account.set_security_contact(
|
324
|
+
name=name, title=title, email=email, phone_number=phone_number
|
325
|
+
)
|
326
|
+
_state.value = security_contact
|
327
|
+
|
291
328
|
#
|
292
329
|
# Public methods
|
293
330
|
#
|
@@ -345,9 +382,22 @@ class AWSReconciler:
|
|
345
382
|
self._check_enterprise_support_status(aws_api, case_id)
|
346
383
|
|
347
384
|
def reconcile_account(
|
348
|
-
self,
|
385
|
+
self,
|
386
|
+
aws_api: AWSApi,
|
387
|
+
name: str,
|
388
|
+
alias: str | None,
|
389
|
+
quotas: Iterable[Quota],
|
390
|
+
security_contact: Contact,
|
349
391
|
) -> None:
|
350
392
|
"""Reconcile/update the AWS account. Return the initial user access key if a new user was created."""
|
351
393
|
self._set_account_alias(aws_api, name, alias)
|
352
394
|
if request_ids := self._request_quotas(aws_api, name, quotas):
|
353
395
|
self._check_quota_change_requests(aws_api, name, request_ids)
|
396
|
+
self._set_security_contact(
|
397
|
+
aws_api,
|
398
|
+
account=name,
|
399
|
+
name=security_contact.name,
|
400
|
+
title=security_contact.title,
|
401
|
+
email=security_contact.email,
|
402
|
+
phone_number=security_contact.phone_number,
|
403
|
+
)
|
@@ -30,6 +30,9 @@ def validate(account: AWSAccountV1) -> bool:
|
|
30
30
|
f"Premium support is required for payer account {account.name}"
|
31
31
|
)
|
32
32
|
|
33
|
+
# security contact is mandatory for all accounts since June 2024
|
34
|
+
if not account.security_contact:
|
35
|
+
raise ValueError(f"Security contact is required for account {account.name}")
|
33
36
|
return True
|
34
37
|
|
35
38
|
|
@@ -19,7 +19,7 @@ from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
|
19
19
|
DEFINITION as GLITCHTIP_PROJECT_DEFINITION,
|
20
20
|
)
|
21
21
|
from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
22
|
-
|
22
|
+
GlitchtipProjectV1,
|
23
23
|
RoleV1,
|
24
24
|
)
|
25
25
|
from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
@@ -87,7 +87,7 @@ def fetch_current_state(
|
|
87
87
|
|
88
88
|
|
89
89
|
def fetch_desired_state(
|
90
|
-
glitchtip_projects: Sequence[
|
90
|
+
glitchtip_projects: Sequence[GlitchtipProjectV1],
|
91
91
|
mail_domain: str,
|
92
92
|
internal_groups_client: InternalGroupsClient,
|
93
93
|
) -> list[Organization]:
|
@@ -143,7 +143,7 @@ def fetch_desired_state(
|
|
143
143
|
return list(organizations.values())
|
144
144
|
|
145
145
|
|
146
|
-
def get_glitchtip_projects(query_func: Callable) -> list[
|
146
|
+
def get_glitchtip_projects(query_func: Callable) -> list[GlitchtipProjectV1]:
|
147
147
|
glitchtip_projects = (
|
148
148
|
glitchtip_project_query(query_func=query_func).glitchtip_projects or []
|
149
149
|
)
|
@@ -18,7 +18,7 @@ from reconcile.gql_definitions.glitchtip_project_alerts.glitchtip_project import
|
|
18
18
|
GlitchtipProjectAlertRecipientEmailV1,
|
19
19
|
GlitchtipProjectAlertRecipientV1,
|
20
20
|
GlitchtipProjectAlertRecipientWebhookV1,
|
21
|
-
|
21
|
+
GlitchtipProjectV1,
|
22
22
|
)
|
23
23
|
from reconcile.gql_definitions.glitchtip_project_alerts.glitchtip_project import (
|
24
24
|
query as glitchtip_project_query,
|
@@ -73,7 +73,7 @@ class GlitchtipProjectAlertsIntegration(
|
|
73
73
|
def get_early_exit_desired_state(self) -> Optional[dict[str, Any]]:
|
74
74
|
return {"projects": [c.dict() for c in self.get_projects(gql.get_api().query)]}
|
75
75
|
|
76
|
-
def get_projects(self, query_func: Callable) -> list[
|
76
|
+
def get_projects(self, query_func: Callable) -> list[GlitchtipProjectV1]:
|
77
77
|
return glitchtip_project_query(query_func=query_func).glitchtip_projects or []
|
78
78
|
|
79
79
|
def _build_project_alert_recipient(
|
@@ -95,7 +95,7 @@ class GlitchtipProjectAlertsIntegration(
|
|
95
95
|
|
96
96
|
def fetch_desired_state(
|
97
97
|
self,
|
98
|
-
glitchtip_projects: Iterable[
|
98
|
+
glitchtip_projects: Iterable[GlitchtipProjectV1],
|
99
99
|
gjb_alert_url: str | None,
|
100
100
|
gjb_token: str | None,
|
101
101
|
) -> list[Organization]:
|
@@ -264,7 +264,7 @@ class GlitchtipProjectAlertsIntegration(
|
|
264
264
|
glitchtip_instances = glitchtip_instance_query(
|
265
265
|
query_func=gqlapi.query
|
266
266
|
).instances
|
267
|
-
glitchtip_projects_by_instance: dict[str, list[
|
267
|
+
glitchtip_projects_by_instance: dict[str, list[GlitchtipProjectV1]] = (
|
268
268
|
defaultdict(list)
|
269
269
|
)
|
270
270
|
for glitchtip_project in self.get_projects(query_func=gqlapi.query):
|
@@ -20,7 +20,7 @@ from reconcile.gql_definitions.glitchtip.glitchtip_instance import (
|
|
20
20
|
from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
21
21
|
DEFINITION as GLITCHTIP_PROJECT_DEFINITION,
|
22
22
|
)
|
23
|
-
from reconcile.gql_definitions.glitchtip.glitchtip_project import
|
23
|
+
from reconcile.gql_definitions.glitchtip.glitchtip_project import GlitchtipProjectV1
|
24
24
|
from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
25
25
|
query as glitchtip_project_query,
|
26
26
|
)
|
@@ -73,7 +73,7 @@ def glitchtip_project_dsn_secret(project: Project, key: ProjectKey) -> dict[str,
|
|
73
73
|
|
74
74
|
|
75
75
|
def fetch_current_state(
|
76
|
-
project:
|
76
|
+
project: GlitchtipProjectV1,
|
77
77
|
oc_map: OCMap,
|
78
78
|
ri: ResourceInventory,
|
79
79
|
) -> None:
|
@@ -110,7 +110,7 @@ def fetch_current_state(
|
|
110
110
|
|
111
111
|
|
112
112
|
def fetch_desired_state(
|
113
|
-
glitchtip_projects: Iterable[
|
113
|
+
glitchtip_projects: Iterable[GlitchtipProjectV1],
|
114
114
|
ri: ResourceInventory,
|
115
115
|
glitchtip_client: GlitchtipClient,
|
116
116
|
) -> None:
|
@@ -145,7 +145,7 @@ def fetch_desired_state(
|
|
145
145
|
)
|
146
146
|
|
147
147
|
|
148
|
-
def projects_query(query_func: Callable) -> list[
|
148
|
+
def projects_query(query_func: Callable) -> list[GlitchtipProjectV1]:
|
149
149
|
glitchtip_projects = []
|
150
150
|
for project in (
|
151
151
|
glitchtip_project_query(query_func=query_func).glitchtip_projects or []
|
@@ -40,6 +40,13 @@ class AWSQuotaLimitsV1(ConfiguredBaseModel):
|
|
40
40
|
quotas: list[AWSQuotaV1] = Field(..., alias="quotas")
|
41
41
|
|
42
42
|
|
43
|
+
class AWSContactV1(ConfiguredBaseModel):
|
44
|
+
name: str = Field(..., alias="name")
|
45
|
+
title: Optional[str] = Field(..., alias="title")
|
46
|
+
email: str = Field(..., alias="email")
|
47
|
+
phone_number: str = Field(..., alias="phoneNumber")
|
48
|
+
|
49
|
+
|
43
50
|
class AWSAccountManaged(ConfiguredBaseModel):
|
44
51
|
name: str = Field(..., alias="name")
|
45
52
|
uid: str = Field(..., alias="uid")
|
@@ -47,3 +54,4 @@ class AWSAccountManaged(ConfiguredBaseModel):
|
|
47
54
|
premium_support: bool = Field(..., alias="premiumSupport")
|
48
55
|
organization: Optional[AWSOrganizationV1] = Field(..., alias="organization")
|
49
56
|
quota_limits: Optional[list[AWSQuotaLimitsV1]] = Field(..., alias="quotaLimits")
|
57
|
+
security_contact: Optional[AWSContactV1] = Field(..., alias="securityContact")
|
@@ -143,7 +143,7 @@ class GlitchtipInstanceV1(ConfiguredBaseModel):
|
|
143
143
|
name: str = Field(..., alias="name")
|
144
144
|
|
145
145
|
|
146
|
-
class
|
146
|
+
class GlitchtipProjectV1_GlitchtipOrganizationV1(ConfiguredBaseModel):
|
147
147
|
name: str = Field(..., alias="name")
|
148
148
|
instance: GlitchtipInstanceV1 = Field(..., alias="instance")
|
149
149
|
owners: Optional[list[str]] = Field(..., alias="owners")
|
@@ -180,19 +180,19 @@ class AppV1(ConfiguredBaseModel):
|
|
180
180
|
path: str = Field(..., alias="path")
|
181
181
|
|
182
182
|
|
183
|
-
class
|
183
|
+
class GlitchtipProjectV1(ConfiguredBaseModel):
|
184
184
|
name: str = Field(..., alias="name")
|
185
185
|
platform: str = Field(..., alias="platform")
|
186
186
|
project_id: Optional[str] = Field(..., alias="projectId")
|
187
187
|
event_throttle_rate: Optional[int] = Field(..., alias="eventThrottleRate")
|
188
188
|
teams: list[GlitchtipTeamV1] = Field(..., alias="teams")
|
189
|
-
organization:
|
189
|
+
organization: GlitchtipProjectV1_GlitchtipOrganizationV1 = Field(..., alias="organization")
|
190
190
|
namespaces: list[NamespaceV1] = Field(..., alias="namespaces")
|
191
191
|
app: Optional[AppV1] = Field(..., alias="app")
|
192
192
|
|
193
193
|
|
194
194
|
class ProjectsQueryData(ConfiguredBaseModel):
|
195
|
-
glitchtip_projects: Optional[list[
|
195
|
+
glitchtip_projects: Optional[list[GlitchtipProjectV1]] = Field(..., alias="glitchtip_projects")
|
196
196
|
|
197
197
|
|
198
198
|
def query(query_func: Callable, **kwargs: Any) -> ProjectsQueryData:
|
@@ -122,7 +122,7 @@ class GlitchtipProjectJiraV1(ConfiguredBaseModel):
|
|
122
122
|
labels: Optional[list[str]] = Field(..., alias="labels")
|
123
123
|
|
124
124
|
|
125
|
-
class
|
125
|
+
class GlitchtipProjectV1(ConfiguredBaseModel):
|
126
126
|
name: str = Field(..., alias="name")
|
127
127
|
project_id: Optional[str] = Field(..., alias="projectId")
|
128
128
|
organization: GlitchtipOrganizationV1 = Field(..., alias="organization")
|
@@ -131,7 +131,7 @@ class GlitchtipProjectsV1(ConfiguredBaseModel):
|
|
131
131
|
|
132
132
|
|
133
133
|
class GlitchtipProjectsWithAlertsQueryData(ConfiguredBaseModel):
|
134
|
-
glitchtip_projects: Optional[list[
|
134
|
+
glitchtip_projects: Optional[list[GlitchtipProjectV1]] = Field(..., alias="glitchtip_projects")
|
135
135
|
|
136
136
|
|
137
137
|
def query(query_func: Callable, **kwargs: Any) -> GlitchtipProjectsWithAlertsQueryData:
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from mypy_boto3_account import AccountClient
|
5
|
+
else:
|
6
|
+
AccountClient = object
|
7
|
+
|
8
|
+
|
9
|
+
class AWSApiAccount:
|
10
|
+
def __init__(self, client: AccountClient) -> None:
|
11
|
+
self.client = client
|
12
|
+
|
13
|
+
def set_security_contact(
|
14
|
+
self, name: str, title: str, email: str, phone_number: str
|
15
|
+
) -> None:
|
16
|
+
"""Set the security contact for the account."""
|
17
|
+
self.client.put_alternate_contact(
|
18
|
+
AlternateContactType="SECURITY",
|
19
|
+
EmailAddress=email,
|
20
|
+
Name=name,
|
21
|
+
Title=title,
|
22
|
+
PhoneNumber=phone_number,
|
23
|
+
)
|
@@ -9,6 +9,7 @@ from boto3 import Session
|
|
9
9
|
from botocore.client import BaseClient
|
10
10
|
from pydantic import BaseModel
|
11
11
|
|
12
|
+
import reconcile.utils.aws_api_typed.account
|
12
13
|
import reconcile.utils.aws_api_typed.dynamodb
|
13
14
|
import reconcile.utils.aws_api_typed.iam
|
14
15
|
import reconcile.utils.aws_api_typed.organization
|
@@ -16,6 +17,7 @@ import reconcile.utils.aws_api_typed.s3
|
|
16
17
|
import reconcile.utils.aws_api_typed.service_quotas
|
17
18
|
import reconcile.utils.aws_api_typed.sts
|
18
19
|
import reconcile.utils.aws_api_typed.support
|
20
|
+
from reconcile.utils.aws_api_typed.account import AWSApiAccount
|
19
21
|
from reconcile.utils.aws_api_typed.dynamodb import AWSApiDynamoDB
|
20
22
|
from reconcile.utils.aws_api_typed.iam import AWSApiIam
|
21
23
|
from reconcile.utils.aws_api_typed.organization import AWSApiOrganizations
|
@@ -26,13 +28,14 @@ from reconcile.utils.aws_api_typed.support import AWSApiSupport
|
|
26
28
|
|
27
29
|
SubApi = TypeVar(
|
28
30
|
"SubApi",
|
31
|
+
AWSApiAccount,
|
32
|
+
AWSApiDynamoDB,
|
29
33
|
AWSApiIam,
|
30
34
|
AWSApiOrganizations,
|
31
35
|
AWSApiS3,
|
32
36
|
AWSApiServiceQuotas,
|
33
37
|
AWSApiSts,
|
34
38
|
AWSApiSupport,
|
35
|
-
AWSApiDynamoDB,
|
36
39
|
)
|
37
40
|
|
38
41
|
|
@@ -168,6 +171,12 @@ class AWSApi:
|
|
168
171
|
def _init_sub_api(self, api_cls: type[SubApi]) -> SubApi:
|
169
172
|
"""Return a new or cached sub api client."""
|
170
173
|
match api_cls:
|
174
|
+
case reconcile.utils.aws_api_typed.account.AWSApiAccount:
|
175
|
+
client = self.session.client("account")
|
176
|
+
api = api_cls(client)
|
177
|
+
case reconcile.utils.aws_api_typed.dynamodb.AWSApiDynamoDB:
|
178
|
+
client = self.session.client("dynamodb")
|
179
|
+
api = api_cls(client)
|
171
180
|
case reconcile.utils.aws_api_typed.iam.AWSApiIam:
|
172
181
|
client = self.session.client("iam")
|
173
182
|
api = api_cls(client)
|
@@ -186,15 +195,22 @@ class AWSApi:
|
|
186
195
|
case reconcile.utils.aws_api_typed.support.AWSApiSupport:
|
187
196
|
client = self.session.client("support")
|
188
197
|
api = api_cls(client)
|
189
|
-
case reconcile.utils.aws_api_typed.dynamodb.AWSApiDynamoDB:
|
190
|
-
client = self.session.client("dynamodb")
|
191
|
-
api = api_cls(client)
|
192
198
|
case _:
|
193
199
|
raise ValueError(f"Unknown API class: {api_cls}")
|
194
200
|
|
195
201
|
self._session_clients.append(client)
|
196
202
|
return api
|
197
203
|
|
204
|
+
@cached_property
|
205
|
+
def account(self) -> AWSApiAccount:
|
206
|
+
"""Return an AWS Acount Api client"""
|
207
|
+
return self._init_sub_api(AWSApiAccount)
|
208
|
+
|
209
|
+
@cached_property
|
210
|
+
def dynamodb(self) -> AWSApiDynamoDB:
|
211
|
+
"""Return an AWS DynamoDB Api client"""
|
212
|
+
return self._init_sub_api(AWSApiDynamoDB)
|
213
|
+
|
198
214
|
@cached_property
|
199
215
|
def iam(self) -> AWSApiIam:
|
200
216
|
"""Return an AWS IAM Api client."""
|
@@ -225,11 +241,6 @@ class AWSApi:
|
|
225
241
|
"""Return an AWS Support Api client."""
|
226
242
|
return self._init_sub_api(AWSApiSupport)
|
227
243
|
|
228
|
-
@cached_property
|
229
|
-
def dynamodb(self) -> AWSApiDynamoDB:
|
230
|
-
"""Return an AWS DynamoDB Api client"""
|
231
|
-
return self._init_sub_api(AWSApiDynamoDB)
|
232
|
-
|
233
244
|
def assume_role(self, account_id: str, role: str) -> AWSApi:
|
234
245
|
"""Return a new AWSApi with the assumed role."""
|
235
246
|
credentials = self.sts.assume_role(account_id=account_id, role=role)
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/top_level.txt
RENAMED
File without changes
|