qontract-reconcile 0.10.1rc880__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.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/RECORD +12 -11
- 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/gql_definitions/aws_account_manager/aws_accounts.py +6 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +8 -0
- reconcile/utils/aws_api_typed/account.py +23 -0
- reconcile/utils/aws_api_typed/api.py +20 -9
- {qontract_reconcile-0.10.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc880.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.1rc880.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
|
@@ -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
|
@@ -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
|
|
@@ -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")
|
@@ -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.1rc880.dist-info → qontract_reconcile-0.10.1rc881.dist-info}/top_level.txt
RENAMED
File without changes
|