qontract-reconcile 0.10.2.dev125__py3-none-any.whl → 0.10.2.dev127__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.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/RECORD +11 -11
- reconcile/aws_account_manager/integration.py +1 -0
- reconcile/aws_account_manager/reconciler.py +70 -15
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +1 -0
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +2 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +1 -0
- reconcile/gql_definitions/introspection.json +12 -0
- reconcile/utils/aws_api_typed/account.py +42 -0
- {qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev127
|
4
4
|
Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
|
5
5
|
Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
|
6
6
|
Project-URL: repository, https://github.com/app-sre/qontract-reconcile
|
{qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/RECORD
RENAMED
@@ -144,10 +144,10 @@ reconcile/automated_actions/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
144
144
|
reconcile/automated_actions/config/integration.py,sha256=cf1VxolcjlGP-xO7IIH5A00Qr4znNJTT7a_sU18ABig,10755
|
145
145
|
reconcile/aws_account_manager/README.md,sha256=_XFM3GZNHUzv--e_navqJuaUWpjC6QrHfulreHynFf0,262
|
146
146
|
reconcile/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
147
|
-
reconcile/aws_account_manager/integration.py,sha256=
|
147
|
+
reconcile/aws_account_manager/integration.py,sha256=o-6NCzub7apFgpCGaH4uIg5wJKMT3flBEfFlq45G1AQ,15207
|
148
148
|
reconcile/aws_account_manager/merge_request_manager.py,sha256=q8t-YwD4y_4UpxdoG9TQrEbDpjlzasOQIynFoCjP2OE,3947
|
149
149
|
reconcile/aws_account_manager/metrics.py,sha256=YB10ea4kIGwJfs5N14RF-RoXPb-QQWaDBz1jLZ3YWE0,917
|
150
|
-
reconcile/aws_account_manager/reconciler.py,sha256=
|
150
|
+
reconcile/aws_account_manager/reconciler.py,sha256=A3pYZiLX8QZTyGqQLuVvTCL1AmVQvNpor5qPIE-npiA,17025
|
151
151
|
reconcile/aws_account_manager/utils.py,sha256=iYPPOtbZ7FiKkz9v5f1YXRIHw5YFOtSavUkF8oMwfJY,1439
|
152
152
|
reconcile/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
153
153
|
reconcile/aws_ami_cleanup/integration.py,sha256=KG7g9NpbKmoaveDD3oi9SinqUE29NaM-4lGo-6YuHlM,9302
|
@@ -227,7 +227,7 @@ reconcile/glitchtip_project_alerts/integration.py,sha256=BgMx-NyV9mTuv7Sotb2OioC
|
|
227
227
|
reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
228
228
|
reconcile/glitchtip_project_dsn/integration.py,sha256=2iugub-kHYkHNK33n0v9_TeWonuxCPah_VkoTPvaajE,8077
|
229
229
|
reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
230
|
-
reconcile/gql_definitions/introspection.json,sha256=
|
230
|
+
reconcile/gql_definitions/introspection.json,sha256=AK7hGfvHjHL6Nqg3KNL4dmOiy4rOPkDSZ8zAWeA5kqU,2283098
|
231
231
|
reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
reconcile/gql_definitions/acs/acs_instances.py,sha256=L91WW9LbhJbBSrECqShQpFtjoBOsmNIYLRpMbx1io5o,2181
|
233
233
|
reconcile/gql_definitions/acs/acs_policies.py,sha256=bN5i4mks10Z23KJSj7jqp966Osq2dps4d-sPH9gjxEA,7008
|
@@ -243,7 +243,7 @@ reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py,sha256=XdV
|
|
243
243
|
reconcile/gql_definitions/automated_actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
244
244
|
reconcile/gql_definitions/automated_actions/instance.py,sha256=D50v0exLeK5hvjQKvxQ5V-6DnYZo_L6cX_Gaf3PGREs,5491
|
245
245
|
reconcile/gql_definitions/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
246
|
-
reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=
|
246
|
+
reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=vF51KrY2gwX0J9vESiaRMPQqdAMEtz9f_tBq52bInp0,5148
|
247
247
|
reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
248
248
|
reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py,sha256=jIgOa888MYLLvVsn1ir3nbkhWLG5T6dBg7oDnp1q8BI,4108
|
249
249
|
reconcile/gql_definitions/aws_saml_idp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -314,7 +314,7 @@ reconcile/gql_definitions/endpoints_discovery/apps.py,sha256=aBWRAwDUJQ32ghJS4cP
|
|
314
314
|
reconcile/gql_definitions/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
315
315
|
reconcile/gql_definitions/external_resources/aws_accounts.py,sha256=XR69j9dpTQ0gv8y-AZN7AJ0dPvO-wbHscyCDgrax6Bk,2046
|
316
316
|
reconcile/gql_definitions/external_resources/external_resources_modules.py,sha256=JViHtDWEBwjStBUo_bUdm_sxdpjCHcoATeFvwFRLQpU,3009
|
317
|
-
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=
|
317
|
+
reconcile/gql_definitions/external_resources/external_resources_namespaces.py,sha256=4omzQPYGofq1HgCrmh_ToouVCIX_Cz967H_8wpZjOBc,44740
|
318
318
|
reconcile/gql_definitions/external_resources/external_resources_settings.py,sha256=WBkJqnoyYCe1Vimwbp_Pa0RdyTdmWNf6oEWyA749QzA,3589
|
319
319
|
reconcile/gql_definitions/external_resources/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
320
320
|
reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py,sha256=T_qWCRtzU8F9frebBXG9TkeQdrKGt3R9YinSngPoFqM,1262
|
@@ -323,7 +323,7 @@ reconcile/gql_definitions/fleet_labeler/fleet_labels.py,sha256=XPk1YFmiCtGlwrldx
|
|
323
323
|
reconcile/gql_definitions/fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
324
324
|
reconcile/gql_definitions/fragments/aus_organization.py,sha256=uBKbTuBa3CZmTXR5HOcGhRcu2U9kM93KbYmoWTxcpB0,4767
|
325
325
|
reconcile/gql_definitions/fragments/aws_account_common.py,sha256=3-7ZAP6GSff7Z2Syz2VQCLY4IySqBOSVmceaRiVNQpw,2385
|
326
|
-
reconcile/gql_definitions/fragments/aws_account_managed.py,sha256=
|
326
|
+
reconcile/gql_definitions/fragments/aws_account_managed.py,sha256=V_9pH0wVza2sPyq8ckkabNMYIRZt6VW4Nixw_jAxaMc,1892
|
327
327
|
reconcile/gql_definitions/fragments/aws_account_sso.py,sha256=ITR3PLz4Iq1SiWAoYGWPDuHJnAmTyZ0QQqs2Zsi8pxA,979
|
328
328
|
reconcile/gql_definitions/fragments/aws_infra_management_account.py,sha256=uAmALVRF2gBM3p_Dmez_ew6KVAtetamwOPkRIPZAlGc,1254
|
329
329
|
reconcile/gql_definitions/fragments/aws_vpc.py,sha256=T2egTwi2Rb0IRBBmsyag8xKpu_m6GbIAy80fhZNZwk8,1434
|
@@ -663,7 +663,7 @@ reconcile/utils/acs/notifiers.py,sha256=nHVw9C_2-K4nv5zq26jlOTSw1roY6TKlovi1sOfp
|
|
663
663
|
reconcile/utils/acs/policies.py,sha256=jpbi3qpGkBD_X6MfzsX12dPajUbmACmhIOz_0rDvYzs,5489
|
664
664
|
reconcile/utils/acs/rbac.py,sha256=ugsLM9Pb7FbUbdq85E3VzXGMaB9ZovXob7tdWCxwqZ8,8808
|
665
665
|
reconcile/utils/aws_api_typed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
666
|
-
reconcile/utils/aws_api_typed/account.py,sha256=
|
666
|
+
reconcile/utils/aws_api_typed/account.py,sha256=f1UQul336_9rC_iCdzkbTQkhcFh5BjIZsf3X18SACfY,2048
|
667
667
|
reconcile/utils/aws_api_typed/api.py,sha256=1h_dQXnE7FUAZi4RRgBEU7nbyAz8awRo0cpuilXyhHE,9239
|
668
668
|
reconcile/utils/aws_api_typed/dynamodb.py,sha256=AKUbz8HGzmSq4cnpjJe7PgqsikMkjbpbzUD2UJv2b58,383
|
669
669
|
reconcile/utils/aws_api_typed/iam.py,sha256=a9lFtwqj6YJM1_W4fi2U3y7N0fX8TTPg08JjQwWPTio,2251
|
@@ -791,7 +791,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
791
791
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
792
792
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
793
793
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
794
|
-
qontract_reconcile-0.10.2.
|
795
|
-
qontract_reconcile-0.10.2.
|
796
|
-
qontract_reconcile-0.10.2.
|
797
|
-
qontract_reconcile-0.10.2.
|
794
|
+
qontract_reconcile-0.10.2.dev127.dist-info/METADATA,sha256=MZa1Z75ScJTRAg6c6E1GS6exq7gFyWYwIoxaIk8m5A0,24566
|
795
|
+
qontract_reconcile-0.10.2.dev127.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
796
|
+
qontract_reconcile-0.10.2.dev127.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
797
|
+
qontract_reconcile-0.10.2.dev127.dist-info/RECORD,,
|
@@ -227,6 +227,7 @@ class AwsAccountMgmtIntegration(
|
|
227
227
|
alias=account.alias,
|
228
228
|
quotas=[q for ql in account.quota_limits or [] for q in ql.quotas],
|
229
229
|
security_contact=account.security_contact,
|
230
|
+
regions=account.supported_deployment_regions or [],
|
230
231
|
)
|
231
232
|
|
232
233
|
def reconcile_payer_accounts(
|
@@ -4,6 +4,7 @@ from textwrap import dedent
|
|
4
4
|
from typing import Any, Protocol
|
5
5
|
|
6
6
|
from reconcile.aws_account_manager.utils import state_key
|
7
|
+
from reconcile.utils.aws_api_typed.account import OptStatus
|
7
8
|
from reconcile.utils.aws_api_typed.api import AWSApi
|
8
9
|
from reconcile.utils.aws_api_typed.iam import (
|
9
10
|
AWSAccessKey,
|
@@ -26,6 +27,7 @@ TASK_CHECK_SERVICE_QUOTA_STATUS = "check-service-quota-status"
|
|
26
27
|
TASK_ENABLE_ENTERPRISE_SUPPORT = "enable-enterprise-support"
|
27
28
|
TASK_CHECK_ENTERPRISE_SUPPORT_STATUS = "check-enterprise-support-status"
|
28
29
|
TASK_SET_SECURITY_CONTACT = "set-security-contact"
|
30
|
+
TASK_SET_SUPPORTED_REGIONS = "set-supported-regions"
|
29
31
|
|
30
32
|
|
31
33
|
class Quota(Protocol):
|
@@ -62,7 +64,7 @@ class AWSReconciler:
|
|
62
64
|
# account already exists, nothing to do
|
63
65
|
return _state.value
|
64
66
|
|
65
|
-
logging.info(f"Creating account
|
67
|
+
logging.info(f"{name}: Creating account")
|
66
68
|
if self.dry_run:
|
67
69
|
raise AbortStateTransaction("Dry run")
|
68
70
|
|
@@ -83,7 +85,7 @@ class AWSReconciler:
|
|
83
85
|
# account checked and exists, nothing to do
|
84
86
|
return _state.value
|
85
87
|
|
86
|
-
logging.info(f"Checking account creation status
|
88
|
+
logging.info(f"{name}: Checking account creation status")
|
87
89
|
status = aws_api.organizations.describe_create_account_status(
|
88
90
|
create_account_request_id=create_account_request_id
|
89
91
|
)
|
@@ -110,7 +112,7 @@ class AWSReconciler:
|
|
110
112
|
# account already tagged, nothing to do
|
111
113
|
return
|
112
114
|
|
113
|
-
logging.info(f"
|
115
|
+
logging.info(f"{name}: Setting tags {tags}")
|
114
116
|
_state.value = tags
|
115
117
|
if self.dry_run:
|
116
118
|
raise AbortStateTransaction("Dry run")
|
@@ -133,7 +135,7 @@ class AWSReconciler:
|
|
133
135
|
# account already moved, nothing to do
|
134
136
|
return
|
135
137
|
|
136
|
-
logging.info(f"Moving account
|
138
|
+
logging.info(f"{name}: Moving account to OU {ou}")
|
137
139
|
destination = self._get_destination_ou(aws_api, destination_path=ou)
|
138
140
|
if self.dry_run:
|
139
141
|
raise AbortStateTransaction("Dry run")
|
@@ -153,7 +155,7 @@ class AWSReconciler:
|
|
153
155
|
if _state.exists and _state.value == new_alias:
|
154
156
|
return
|
155
157
|
|
156
|
-
logging.info(f"Set account alias '{new_alias}'
|
158
|
+
logging.info(f"{name}: Set account alias '{new_alias}'")
|
157
159
|
if self.dry_run:
|
158
160
|
raise AbortStateTransaction("Dry run")
|
159
161
|
|
@@ -179,7 +181,7 @@ class AWSReconciler:
|
|
179
181
|
if quota.value > q.value:
|
180
182
|
# a quota can be already higher than requested, because it was may set manually or enforced by the payer account
|
181
183
|
logging.info(
|
182
|
-
f"Cannot lower quota {q.service_code=}, {q.quota_code=}: {quota.value} -> {q.value}. Skipping."
|
184
|
+
f"{name}: Cannot lower quota {q.service_code=}, {q.quota_code=}: {quota.value} -> {q.value}. Skipping."
|
183
185
|
)
|
184
186
|
elif quota.value < q.value:
|
185
187
|
quota.value = q.value
|
@@ -187,7 +189,7 @@ class AWSReconciler:
|
|
187
189
|
|
188
190
|
for q in new_quotas:
|
189
191
|
logging.info(
|
190
|
-
f"
|
192
|
+
f"{name}: Setting quota: {q.service_name}/{q.quota_name} ({q.service_code}/{q.quota_code}) -> {q.value}"
|
191
193
|
)
|
192
194
|
|
193
195
|
if self.dry_run:
|
@@ -203,7 +205,7 @@ class AWSReconciler:
|
|
203
205
|
)
|
204
206
|
except AWSResourceAlreadyExistsException:
|
205
207
|
raise AbortStateTransaction(
|
206
|
-
f"A quota increase for this {new_quota.service_code}/{new_quota.quota_code} already exists. Try it again later."
|
208
|
+
f"{name}: A quota increase for this {new_quota.service_code}/{new_quota.quota_code} already exists. Try it again later."
|
207
209
|
) from None
|
208
210
|
ids.append(req.id)
|
209
211
|
|
@@ -223,7 +225,7 @@ class AWSReconciler:
|
|
223
225
|
if _state.exists and _state.value == request_ids:
|
224
226
|
return
|
225
227
|
|
226
|
-
logging.info(f"Checking quota change requests
|
228
|
+
logging.info(f"{name}: Checking quota change requests")
|
227
229
|
if self.dry_run:
|
228
230
|
raise AbortStateTransaction("Dry run")
|
229
231
|
|
@@ -258,7 +260,7 @@ class AWSReconciler:
|
|
258
260
|
raise AbortStateTransaction("Dry run")
|
259
261
|
return None
|
260
262
|
|
261
|
-
logging.info(f"Enabling enterprise support
|
263
|
+
logging.info(f"{name}: Enabling enterprise support")
|
262
264
|
if self.dry_run:
|
263
265
|
raise AbortStateTransaction("Dry run")
|
264
266
|
|
@@ -277,7 +279,9 @@ class AWSReconciler:
|
|
277
279
|
_state.value = case_id
|
278
280
|
return case_id
|
279
281
|
|
280
|
-
def _check_enterprise_support_status(
|
282
|
+
def _check_enterprise_support_status(
|
283
|
+
self, aws_api: AWSApi, name: str, case_id: str
|
284
|
+
) -> None:
|
281
285
|
"""Check the status of the enterprise support case."""
|
282
286
|
with self.state.transaction(
|
283
287
|
state_key(case_id, TASK_CHECK_ENTERPRISE_SUPPORT_STATUS), True
|
@@ -285,7 +289,7 @@ class AWSReconciler:
|
|
285
289
|
if _state.exists:
|
286
290
|
return
|
287
291
|
|
288
|
-
logging.info(f"Checking enterprise support case {case_id}")
|
292
|
+
logging.info(f"{name}: Checking enterprise support case {case_id}")
|
289
293
|
if self.dry_run:
|
290
294
|
raise AbortStateTransaction("Dry run")
|
291
295
|
|
@@ -316,7 +320,7 @@ class AWSReconciler:
|
|
316
320
|
if _state.exists and _state.value == security_contact:
|
317
321
|
return
|
318
322
|
|
319
|
-
logging.info(f"Setting security contact
|
323
|
+
logging.info(f"{name}: Setting security contact")
|
320
324
|
if self.dry_run:
|
321
325
|
raise AbortStateTransaction("Dry run")
|
322
326
|
|
@@ -325,6 +329,55 @@ class AWSReconciler:
|
|
325
329
|
)
|
326
330
|
_state.value = security_contact
|
327
331
|
|
332
|
+
def _set_supported_regions(
|
333
|
+
self,
|
334
|
+
aws_api: AWSApi,
|
335
|
+
name: str,
|
336
|
+
regions: Iterable[str],
|
337
|
+
) -> None:
|
338
|
+
"""Set the supported regions for the account."""
|
339
|
+
with self.state.transaction(
|
340
|
+
state_key(name, TASK_SET_SUPPORTED_REGIONS)
|
341
|
+
) as _state:
|
342
|
+
if _state.exists and _state.value == regions:
|
343
|
+
return
|
344
|
+
|
345
|
+
aws_regions = aws_api.account.list_regions()
|
346
|
+
if invalid_regions := set(regions) - {r.name for r in aws_regions}:
|
347
|
+
raise RuntimeError(
|
348
|
+
f"{name}: Regions {invalid_regions} are not available"
|
349
|
+
)
|
350
|
+
|
351
|
+
# ATTENTION: Regions can be "enabled by default".
|
352
|
+
# That means we cannot enable or disable them manually. We just gently ignore them!
|
353
|
+
to_enable_regions = [
|
354
|
+
r.name
|
355
|
+
for r in aws_regions
|
356
|
+
if r.status == OptStatus.DISABLED and r.name in regions
|
357
|
+
]
|
358
|
+
|
359
|
+
to_disable_regions = [
|
360
|
+
r.name
|
361
|
+
for r in aws_regions
|
362
|
+
if r.status == OptStatus.ENABLED and r.name not in regions
|
363
|
+
]
|
364
|
+
|
365
|
+
if to_enable_regions:
|
366
|
+
logging.info(f"{name}: Enabling regions {to_enable_regions}")
|
367
|
+
|
368
|
+
if to_disable_regions:
|
369
|
+
logging.info(f"{name}: Disabling regions {to_disable_regions}")
|
370
|
+
|
371
|
+
if self.dry_run:
|
372
|
+
raise AbortStateTransaction("Dry run")
|
373
|
+
|
374
|
+
for aws_region in to_enable_regions:
|
375
|
+
aws_api.account.enable_region(aws_region)
|
376
|
+
for aws_region in to_disable_regions:
|
377
|
+
aws_api.account.disable_region(aws_region)
|
378
|
+
|
379
|
+
_state.value = regions
|
380
|
+
|
328
381
|
#
|
329
382
|
# Public methods
|
330
383
|
#
|
@@ -353,7 +406,7 @@ class AWSReconciler:
|
|
353
406
|
if _state.exists and _state.value == user_name:
|
354
407
|
return None
|
355
408
|
|
356
|
-
logging.info(f"Creating IAM user '{user_name}'
|
409
|
+
logging.info(f"{name}: Creating IAM user '{user_name}'")
|
357
410
|
if self.dry_run:
|
358
411
|
raise AbortStateTransaction("Dry run")
|
359
412
|
|
@@ -379,7 +432,7 @@ class AWSReconciler:
|
|
379
432
|
if enterprise_support and (
|
380
433
|
case_id := self._enable_enterprise_support(aws_api, name, uid)
|
381
434
|
):
|
382
|
-
self._check_enterprise_support_status(aws_api, case_id)
|
435
|
+
self._check_enterprise_support_status(aws_api, name, case_id)
|
383
436
|
|
384
437
|
def reconcile_account(
|
385
438
|
self,
|
@@ -388,6 +441,7 @@ class AWSReconciler:
|
|
388
441
|
alias: str | None,
|
389
442
|
quotas: Iterable[Quota],
|
390
443
|
security_contact: Contact,
|
444
|
+
regions: Iterable[str],
|
391
445
|
) -> None:
|
392
446
|
"""Reconcile/update the AWS account. Return the initial user access key if a new user was created."""
|
393
447
|
self._set_account_alias(aws_api, name, alias)
|
@@ -401,3 +455,4 @@ class AWSReconciler:
|
|
401
455
|
email=security_contact.email,
|
402
456
|
phone_number=security_contact.phone_number,
|
403
457
|
)
|
458
|
+
self._set_supported_regions(aws_api, name, regions)
|
@@ -117,6 +117,7 @@ query ExternalResourcesNamespaces {
|
|
117
117
|
blue_green_deployment {
|
118
118
|
enabled
|
119
119
|
switchover
|
120
|
+
switchover_timeout
|
120
121
|
delete
|
121
122
|
target {
|
122
123
|
allocated_storage
|
@@ -598,6 +599,7 @@ class RDSBlueGreenDeploymentTargetV1(ConfiguredBaseModel):
|
|
598
599
|
class RDSBlueGreenDeploymentV1(ConfiguredBaseModel):
|
599
600
|
enabled: Optional[bool] = Field(..., alias="enabled")
|
600
601
|
switchover: Optional[bool] = Field(..., alias="switchover")
|
602
|
+
switchover_timeout: Optional[int] = Field(..., alias="switchover_timeout")
|
601
603
|
delete: Optional[bool] = Field(..., alias="delete")
|
602
604
|
target: Optional[RDSBlueGreenDeploymentTargetV1] = Field(..., alias="target")
|
603
605
|
|
@@ -55,3 +55,4 @@ class AWSAccountManaged(ConfiguredBaseModel):
|
|
55
55
|
organization: Optional[AWSOrganizationV1] = Field(..., alias="organization")
|
56
56
|
quota_limits: Optional[list[AWSQuotaLimitsV1]] = Field(..., alias="quotaLimits")
|
57
57
|
security_contact: Optional[AWSContactV1] = Field(..., alias="securityContact")
|
58
|
+
supported_deployment_regions: Optional[list[str]] = Field(..., alias="supportedDeploymentRegions")
|
@@ -44387,6 +44387,18 @@
|
|
44387
44387
|
"isDeprecated": false,
|
44388
44388
|
"deprecationReason": null
|
44389
44389
|
},
|
44390
|
+
{
|
44391
|
+
"name": "switchover_timeout",
|
44392
|
+
"description": null,
|
44393
|
+
"args": [],
|
44394
|
+
"type": {
|
44395
|
+
"kind": "SCALAR",
|
44396
|
+
"name": "Int",
|
44397
|
+
"ofType": null
|
44398
|
+
},
|
44399
|
+
"isDeprecated": false,
|
44400
|
+
"deprecationReason": null
|
44401
|
+
},
|
44390
44402
|
{
|
44391
44403
|
"name": "delete",
|
44392
44404
|
"description": null,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from enum import StrEnum
|
1
2
|
from typing import TYPE_CHECKING
|
2
3
|
|
3
4
|
if TYPE_CHECKING:
|
@@ -5,6 +6,21 @@ if TYPE_CHECKING:
|
|
5
6
|
else:
|
6
7
|
AccountClient = object
|
7
8
|
|
9
|
+
from pydantic import BaseModel
|
10
|
+
|
11
|
+
|
12
|
+
class OptStatus(StrEnum):
|
13
|
+
"""Optional status enum."""
|
14
|
+
|
15
|
+
ENABLED = "ENABLED"
|
16
|
+
DISABLED = "DISABLED"
|
17
|
+
ENABLED_BY_DEFAULT = "ENABLED_BY_DEFAULT"
|
18
|
+
|
19
|
+
|
20
|
+
class Region(BaseModel):
|
21
|
+
name: str
|
22
|
+
status: OptStatus
|
23
|
+
|
8
24
|
|
9
25
|
class AWSApiAccount:
|
10
26
|
def __init__(self, client: AccountClient) -> None:
|
@@ -21,3 +37,29 @@ class AWSApiAccount:
|
|
21
37
|
Title=title,
|
22
38
|
PhoneNumber=phone_number,
|
23
39
|
)
|
40
|
+
|
41
|
+
def list_regions(self) -> list[Region]:
|
42
|
+
"""List all regions in the account."""
|
43
|
+
regions = []
|
44
|
+
paginator = self.client.get_paginator("list_regions")
|
45
|
+
for page in paginator.paginate():
|
46
|
+
for region in page["Regions"]:
|
47
|
+
match region["RegionOptStatus"]:
|
48
|
+
case "DISABLED" | "DISABLING":
|
49
|
+
status = OptStatus.DISABLED
|
50
|
+
case "ENABLED" | "ENABLING":
|
51
|
+
status = OptStatus.ENABLED
|
52
|
+
case "ENABLED_BY_DEFAULT":
|
53
|
+
status = OptStatus.ENABLED_BY_DEFAULT
|
54
|
+
case _:
|
55
|
+
raise ValueError(f"Unknown status: {region['RegionOptStatus']}")
|
56
|
+
regions.append(Region(name=region["RegionName"], status=status))
|
57
|
+
return regions
|
58
|
+
|
59
|
+
def enable_region(self, region: str) -> None:
|
60
|
+
"""Enable a region in the account."""
|
61
|
+
self.client.enable_region(RegionName=region)
|
62
|
+
|
63
|
+
def disable_region(self, region: str) -> None:
|
64
|
+
"""Disable a region in the account."""
|
65
|
+
self.client.disable_region(RegionName=region)
|
{qontract_reconcile-0.10.2.dev125.dist-info → qontract_reconcile-0.10.2.dev127.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|