qontract-reconcile 0.10.2.dev268__py3-none-any.whl → 0.10.2.dev269__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.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/RECORD +8 -8
- reconcile/aws_account_manager/integration.py +1 -1
- reconcile/cli.py +1 -1
- reconcile/utils/aws_api_typed/account.py +40 -8
- reconcile/utils/aws_api_typed/iam.py +19 -9
- {qontract_reconcile-0.10.2.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev268.dist-info → qontract_reconcile-0.10.2.dev269.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.dev269
|
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.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/RECORD
RENAMED
@@ -8,7 +8,7 @@ reconcile/aws_iam_password_reset.py,sha256=FpAqAXngmLFqkOtOjrz_i90qteUyLHJL0GMjo
|
|
8
8
|
reconcile/aws_support_cases_sos.py,sha256=PDhilxQ4TBxVnxUPIUdTbKEaNUI0wzPiEsB91oHT2fY,3384
|
9
9
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
|
10
10
|
reconcile/checkpoint.py,sha256=gjtS8g6KIyKFYlHMSZjAqDUOlVh83nh4go-9yNrhWZU,5016
|
11
|
-
reconcile/cli.py,sha256=
|
11
|
+
reconcile/cli.py,sha256=ysDzZ-LRzO5D2FfderoNFx_NmYbxfd2iCYaGOhz6Z90,112239
|
12
12
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=_OKz7K7HHw0-gzxeEma8PcUCtd70pRBy7JMoaAm8IVU,4940
|
13
13
|
reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
|
14
14
|
reconcile/dashdotdb_base.py,sha256=83ZWIf5JJk3P_D69y2TmXRcQr6ELJGlv10OM0h7fJVs,4767
|
@@ -138,7 +138,7 @@ reconcile/automated_actions/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
138
138
|
reconcile/automated_actions/config/integration.py,sha256=EbVJGyEAFf91dHiIlnwbetbqZ3Y7HJOez2Fnexzd550,13853
|
139
139
|
reconcile/aws_account_manager/README.md,sha256=_XFM3GZNHUzv--e_navqJuaUWpjC6QrHfulreHynFf0,262
|
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=WEbcvF8GocFHJrlz3mmXSOyYHIUrrHxq_SKaImgJQ2c,15346
|
142
142
|
reconcile/aws_account_manager/merge_request_manager.py,sha256=q8t-YwD4y_4UpxdoG9TQrEbDpjlzasOQIynFoCjP2OE,3947
|
143
143
|
reconcile/aws_account_manager/metrics.py,sha256=YB10ea4kIGwJfs5N14RF-RoXPb-QQWaDBz1jLZ3YWE0,917
|
144
144
|
reconcile/aws_account_manager/reconciler.py,sha256=oSuR3xrN6fihmJUl79HSDxH5-MsR7Sfpf7eqiMlwwRg,17141
|
@@ -669,10 +669,10 @@ reconcile/utils/acs/base.py,sha256=4UsDrCpAOuddL3PKNuIQYoJP1BtZQNNB8_KEX0lXneg,2
|
|
669
669
|
reconcile/utils/acs/policies.py,sha256=jpbi3qpGkBD_X6MfzsX12dPajUbmACmhIOz_0rDvYzs,5489
|
670
670
|
reconcile/utils/acs/rbac.py,sha256=ugsLM9Pb7FbUbdq85E3VzXGMaB9ZovXob7tdWCxwqZ8,8808
|
671
671
|
reconcile/utils/aws_api_typed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
672
|
-
reconcile/utils/aws_api_typed/account.py,sha256=
|
672
|
+
reconcile/utils/aws_api_typed/account.py,sha256=4UfsVcOKIkR1b6bYlr6lcnYk5A6T-KZWUi1mZoLL40c,3376
|
673
673
|
reconcile/utils/aws_api_typed/api.py,sha256=1h_dQXnE7FUAZi4RRgBEU7nbyAz8awRo0cpuilXyhHE,9239
|
674
674
|
reconcile/utils/aws_api_typed/dynamodb.py,sha256=AKUbz8HGzmSq4cnpjJe7PgqsikMkjbpbzUD2UJv2b58,383
|
675
|
-
reconcile/utils/aws_api_typed/iam.py,sha256=
|
675
|
+
reconcile/utils/aws_api_typed/iam.py,sha256=uuK5JzVmlWpokyixhd_Oy2pBr_31z_d4Gz7bPeDK71E,2864
|
676
676
|
reconcile/utils/aws_api_typed/organization.py,sha256=rmZkm14t30Bm0ctMTtCNzcDrTjOFkal1TO0pHncNxcg,5513
|
677
677
|
reconcile/utils/aws_api_typed/s3.py,sha256=J2uOTtEFgMyKT22pa4DbFnV7zfg575m2DeidQaeselM,1034
|
678
678
|
reconcile/utils/aws_api_typed/service_quotas.py,sha256=ywPligZTxGgDhJ4TjWzXg5MbQ4j1iGUxonngII_KOHo,3022
|
@@ -797,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
797
797
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=oF7C4hpIgyMTwTRm3Aun3cDCHIjVar65JoLp6NcJHlU,3909
|
798
798
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
799
799
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
800
|
-
qontract_reconcile-0.10.2.
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
803
|
-
qontract_reconcile-0.10.2.
|
800
|
+
qontract_reconcile-0.10.2.dev269.dist-info/METADATA,sha256=Wzl-5Z8F3fPHuNHeOahSh8r4e1Nk-KKbpKlVrcaRheI,24501
|
801
|
+
qontract_reconcile-0.10.2.dev269.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
802
|
+
qontract_reconcile-0.10.2.dev269.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
803
|
+
qontract_reconcile-0.10.2.dev269.dist-info/RECORD,,
|
@@ -53,7 +53,7 @@ class AwsAccountMgmtIntegrationParams(PydanticRunParams):
|
|
53
53
|
)
|
54
54
|
# To avoid the accidental deletion of the resource file, explicitly set the
|
55
55
|
# qontract.cli option in the integration extraArgs!
|
56
|
-
account_tmpl_resource: str = "/aws-account-manager/account-tmpl.yml"
|
56
|
+
account_tmpl_resource: str = "/aws-account-manager/account-tmpl.yml.j2"
|
57
57
|
template_collection_root_path: str = "data/templating/collections/aws-account"
|
58
58
|
|
59
59
|
|
reconcile/cli.py
CHANGED
@@ -969,7 +969,7 @@ def aws_saml_roles(
|
|
969
969
|
"--account-tmpl-resource",
|
970
970
|
help="Resource name of the account template-collection template in the app-interface.",
|
971
971
|
required=True,
|
972
|
-
default="/aws-account-manager/account-tmpl.yml",
|
972
|
+
default="/aws-account-manager/account-tmpl.yml.j2",
|
973
973
|
)
|
974
974
|
@click.option(
|
975
975
|
"--template-collection-root-path",
|
@@ -1,11 +1,14 @@
|
|
1
|
+
import logging
|
1
2
|
from enum import StrEnum
|
2
3
|
from typing import TYPE_CHECKING
|
3
4
|
|
4
5
|
if TYPE_CHECKING:
|
5
6
|
from mypy_boto3_account import AccountClient
|
7
|
+
from mypy_boto3_account.type_defs import AlternateContactTypeDef
|
6
8
|
else:
|
7
|
-
AccountClient = object
|
9
|
+
AccountClient = AlternateContactTypeDef = object
|
8
10
|
|
11
|
+
import botocore
|
9
12
|
from pydantic import BaseModel
|
10
13
|
|
11
14
|
|
@@ -22,6 +25,9 @@ class Region(BaseModel):
|
|
22
25
|
status: OptStatus
|
23
26
|
|
24
27
|
|
28
|
+
log = logging.getLogger(__name__)
|
29
|
+
|
30
|
+
|
25
31
|
class AWSApiAccount:
|
26
32
|
def __init__(self, client: AccountClient) -> None:
|
27
33
|
self.client = client
|
@@ -30,13 +36,39 @@ class AWSApiAccount:
|
|
30
36
|
self, name: str, title: str, email: str, phone_number: str
|
31
37
|
) -> None:
|
32
38
|
"""Set the security contact for the account."""
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
try:
|
40
|
+
self.client.put_alternate_contact(
|
41
|
+
AlternateContactType="SECURITY",
|
42
|
+
EmailAddress=email,
|
43
|
+
Name=name,
|
44
|
+
Title=title,
|
45
|
+
PhoneNumber=phone_number,
|
46
|
+
)
|
47
|
+
except botocore.exceptions.ClientError as e:
|
48
|
+
if e.response["Error"]["Code"] != "AccessDenied":
|
49
|
+
raise
|
50
|
+
|
51
|
+
# This exception is raised if the user does not have permission to perform this action.
|
52
|
+
# Let's see if the current security contact is already set to the same values.
|
53
|
+
current_contact = self.get_security_contact()
|
54
|
+
if (
|
55
|
+
not current_contact
|
56
|
+
or current_contact["EmailAddress"] != email
|
57
|
+
or current_contact["Name"] != name
|
58
|
+
or current_contact["Title"] != title
|
59
|
+
or current_contact["PhoneNumber"] != phone_number
|
60
|
+
):
|
61
|
+
raise
|
62
|
+
|
63
|
+
def get_security_contact(self) -> AlternateContactTypeDef | None:
|
64
|
+
"""Get the security contact for the account."""
|
65
|
+
try:
|
66
|
+
return self.client.get_alternate_contact(AlternateContactType="SECURITY")[
|
67
|
+
"AlternateContact"
|
68
|
+
]
|
69
|
+
except self.client.exceptions.ResourceNotFoundException:
|
70
|
+
log.warning("Security contact not set.")
|
71
|
+
return None
|
40
72
|
|
41
73
|
def list_regions(self) -> list[Region]:
|
42
74
|
"""List all regions in the account."""
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from typing import TYPE_CHECKING
|
2
2
|
|
3
|
+
import botocore
|
3
4
|
from pydantic import BaseModel, Field
|
4
5
|
|
5
6
|
if TYPE_CHECKING:
|
@@ -40,10 +41,12 @@ class AWSApiIam:
|
|
40
41
|
try:
|
41
42
|
user = self.client.create_user(UserName=user_name)
|
42
43
|
return AWSUser(**user["User"])
|
43
|
-
except
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
except botocore.exceptions.ClientError as e:
|
45
|
+
if e.response["Error"]["Code"] == "EntityAlreadyExists":
|
46
|
+
raise AWSEntityAlreadyExistsError(
|
47
|
+
f"User {user_name} already exists"
|
48
|
+
) from e
|
49
|
+
raise
|
47
50
|
|
48
51
|
def attach_user_policy(self, user_name: str, policy_arn: str) -> None:
|
49
52
|
"""Attach a policy to a user."""
|
@@ -60,8 +63,15 @@ class AWSApiIam:
|
|
60
63
|
"""Set the account alias."""
|
61
64
|
try:
|
62
65
|
self.client.create_account_alias(AccountAlias=account_alias)
|
63
|
-
except
|
64
|
-
if
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
except botocore.exceptions.ClientError as e:
|
67
|
+
if e.response["Error"]["Code"] == "EntityAlreadyExists":
|
68
|
+
if self.get_account_alias() != account_alias:
|
69
|
+
raise ValueError(
|
70
|
+
"Account alias already exists for another AWS account. Choose another one!"
|
71
|
+
) from e
|
72
|
+
elif e.response["Error"]["Code"] == "AccessDenied":
|
73
|
+
# AccessDeniedException can occur if the user does not have permission to create an account alias.
|
74
|
+
# This can happen if the alias is already set and we don't have permission to change it.
|
75
|
+
# If the existing alias is the one we want, we can ignore the error.
|
76
|
+
if self.get_account_alias() != account_alias:
|
77
|
+
raise
|
{qontract_reconcile-0.10.2.dev268.dist-info → qontract_reconcile-0.10.2.dev269.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|