qontract-reconcile 0.10.2.dev402__py3-none-any.whl → 0.10.2.dev404__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.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/RECORD +9 -9
- reconcile/aws_ami_share.py +69 -62
- reconcile/external_resources/reconciler.py +5 -2
- reconcile/queries.py +6 -0
- reconcile/utils/aws_api.py +51 -20
- reconcile/utils/jobcontroller/models.py +17 -1
- {qontract_reconcile-0.10.2.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev402.dist-info → qontract_reconcile-0.10.2.dev404.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.dev404
|
|
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.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/RECORD
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
reconcile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
reconcile/acs_policies.py,sha256=1LKnRRPa6h3QewsDhv0epINi9RJtQmT88mPgcU2LhDM,8667
|
|
3
3
|
reconcile/acs_rbac.py,sha256=15vNfNzdG_DeXaJ-f5m8DSaJh__LUK766_xAECqyTsg,22657
|
|
4
|
-
reconcile/aws_ami_share.py,sha256=
|
|
4
|
+
reconcile/aws_ami_share.py,sha256=JqevGzjLKlktRDeL01ukBko5ope5Xhl_0NvdjfGdENA,3503
|
|
5
5
|
reconcile/aws_ecr_image_pull_secrets.py,sha256=r9Dy01w4kNPWh3LO2tSGH_x4rQg3B2FJc5sVjPJxZdI,2622
|
|
6
6
|
reconcile/aws_iam_keys.py,sha256=YHp-K8K8Dqm7vVKzry0RyhM6Egmpp7eCWMNdKk0vbME,4118
|
|
7
7
|
reconcile/aws_iam_password_reset.py,sha256=5oajSspJVAvpGd445hKsxtEGYb75dM4l1_PJTzrfHk0,3253
|
|
@@ -88,7 +88,7 @@ reconcile/quay_mirror.py,sha256=pA1_OujRduwQ6dYljoWXU_VJgAwlv7DzThk26ymKmGs,1432
|
|
|
88
88
|
reconcile/quay_mirror_org.py,sha256=ltPbHuWUI8Wnl8gV4aeYmvoYFA1uXLWqlXqEPpw7Hi0,11065
|
|
89
89
|
reconcile/quay_permissions.py,sha256=BF539lRxjpgwm88WzazklzgaCF_ipRALwbO2AdpqUqE,4388
|
|
90
90
|
reconcile/quay_repos.py,sha256=fBleLzMtfDmTidpzbrTt8kGCy-Bk3J06EO4hhyghGnQ,7570
|
|
91
|
-
reconcile/queries.py,sha256=
|
|
91
|
+
reconcile/queries.py,sha256=L0NbIr6-M12P7xqU2s_2-tgi5BOC5QEo6Otu33WG5tI,56598
|
|
92
92
|
reconcile/query_validator.py,sha256=csOSkKxcf6ZlpchJu4ck2jLYKUN6y1l-UmSQUFHgssY,1618
|
|
93
93
|
reconcile/requests_sender.py,sha256=g-tlrudvIqhneQPDMrfYF0Xsq7BSW2QcBPirl7hFM6I,4058
|
|
94
94
|
reconcile/resource_scraper.py,sha256=TcMhXga7konX9x97NhpoijnDGWA-ZjdpiiXjm5qCmPk,2249
|
|
@@ -192,7 +192,7 @@ reconcile/external_resources/manager.py,sha256=4UxcrJzgIDiVBClIhIbIAZ11yZ5a6YQW7
|
|
|
192
192
|
reconcile/external_resources/meta.py,sha256=RM8qGE6UoJR58nLqABReIJrrdmx4Tqt_OcdlT-QygGs,620
|
|
193
193
|
reconcile/external_resources/metrics.py,sha256=KiBjMUaN_z0cSkF_7Ar_a8RiuiwVqjyMcVdISlxhzXE,3898
|
|
194
194
|
reconcile/external_resources/model.py,sha256=dDYTlMNL8vy07lquPnj_QXTGDK5punKSmP4fvbz83Uc,15021
|
|
195
|
-
reconcile/external_resources/reconciler.py,sha256=
|
|
195
|
+
reconcile/external_resources/reconciler.py,sha256=Ip84k-yL4-eHDkdT7BMwmou5jd5berIEkthqJWyWX_Q,9720
|
|
196
196
|
reconcile/external_resources/secrets_sync.py,sha256=iz5qoyxFCCQ66EwiCy20ZiIurq8FEDHKOPpUhIkkMxk,16177
|
|
197
197
|
reconcile/external_resources/state.py,sha256=6GTwsmEqDuKz8mSPJtVzGtzgwAWJgBiotH_2hfTYZHo,13451
|
|
198
198
|
reconcile/fleet_labeler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -584,7 +584,7 @@ reconcile/unleash_feature_toggles/integration.py,sha256=Etp6D-UPkGy16IGHMsWBJscg
|
|
|
584
584
|
reconcile/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
585
585
|
reconcile/utils/aggregated_list.py,sha256=IxQoMpKV2HHuZOxRmVIew2WQ7SutuLJ_VxlewieK3nY,4036
|
|
586
586
|
reconcile/utils/amtool.py,sha256=Ng5VVNCiPYEK67eDjIwfuuTLs5JsfltCwt6w5UfXbcY,2289
|
|
587
|
-
reconcile/utils/aws_api.py,sha256=
|
|
587
|
+
reconcile/utils/aws_api.py,sha256=M2EQfDg2Aa8gKDh5aZDL8-Zd0vBXD7FQSySv-ivmYE4,62002
|
|
588
588
|
reconcile/utils/aws_helper.py,sha256=9u4m94bnc3chFIDDEXwYXRXj5b--D6CTRy6g234jhNY,2972
|
|
589
589
|
reconcile/utils/batches.py,sha256=TtEm64a8lWhFuNbUVpFEmXVdU2Q0sTBrP_I0Cjbgh7g,320
|
|
590
590
|
reconcile/utils/binary.py,sha256=lSIevhilMeoGMePPHD7A-pxe45LVpBT0LksecYbM-EA,2477
|
|
@@ -700,7 +700,7 @@ reconcile/utils/jinja2/filters.py,sha256=JfO_14APySBPidsMvHXG-8dULNPddZCE15Umjk_
|
|
|
700
700
|
reconcile/utils/jinja2/utils.py,sha256=ScFapI-Qh9uUklMYoMSr_AKhzyMuMhF558RSUGBTaxE,9253
|
|
701
701
|
reconcile/utils/jobcontroller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
702
702
|
reconcile/utils/jobcontroller/controller.py,sha256=NBsmH8kKGrGIcQFtJI77kP2yYoYZiCmGY4AhbqBx1Es,15379
|
|
703
|
-
reconcile/utils/jobcontroller/models.py,sha256=
|
|
703
|
+
reconcile/utils/jobcontroller/models.py,sha256=okj1zGdharGTJYW-f1XyvmWfp4F2ESTkvhYvrmzSGGE,6936
|
|
704
704
|
reconcile/utils/membershipsources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
705
705
|
reconcile/utils/membershipsources/app_interface_resolver.py,sha256=MqDFvK3aXhmmMuMiIygC-onFVrrIopKHriaYJQ5jnuY,1988
|
|
706
706
|
reconcile/utils/membershipsources/models.py,sha256=yuEbG4HJ3NOEpSS9EH7OAx1U-uiRW-QmNMAZJe1Rb-U,1898
|
|
@@ -800,7 +800,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
800
800
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
|
|
801
801
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
|
802
802
|
tools/sre_checkpoints/util.py,sha256=KcYVfa3UmJHVP_ocgrKe8NkrO5IDB9aWEDydSokPcRk,975
|
|
803
|
-
qontract_reconcile-0.10.2.
|
|
804
|
-
qontract_reconcile-0.10.2.
|
|
805
|
-
qontract_reconcile-0.10.2.
|
|
806
|
-
qontract_reconcile-0.10.2.
|
|
803
|
+
qontract_reconcile-0.10.2.dev404.dist-info/METADATA,sha256=8yOHo8P888-GRCR1xE6xEJZyxETTQeIpsDS3cSlKIlc,24946
|
|
804
|
+
qontract_reconcile-0.10.2.dev404.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
805
|
+
qontract_reconcile-0.10.2.dev404.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
|
806
|
+
qontract_reconcile-0.10.2.dev404.dist-info/RECORD,,
|
reconcile/aws_ami_share.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import re
|
|
2
3
|
from collections.abc import (
|
|
3
|
-
Callable,
|
|
4
4
|
Iterable,
|
|
5
5
|
Mapping,
|
|
6
6
|
)
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
from reconcile import queries
|
|
10
|
+
from reconcile.typed_queries.aws_account_tags import get_aws_account_tags
|
|
11
|
+
from reconcile.typed_queries.external_resources import get_settings
|
|
10
12
|
from reconcile.utils.aws_api import AWSApi
|
|
11
|
-
from reconcile.utils.defer import defer
|
|
12
13
|
|
|
13
14
|
QONTRACT_INTEGRATION = "aws-ami-share"
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
MANAGED_TAG = {"managed_by_integration": QONTRACT_INTEGRATION}
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def filter_accounts(accounts: Iterable[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
@@ -37,65 +39,70 @@ def get_region(
|
|
|
37
39
|
return region
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
def share_ami(
|
|
43
|
+
dry_run: bool,
|
|
44
|
+
src_account: Mapping[str, Any],
|
|
45
|
+
share: Mapping[str, Any],
|
|
46
|
+
default_tags: dict[str, str],
|
|
47
|
+
aws_api: AWSApi,
|
|
48
|
+
) -> None:
|
|
49
|
+
dst_account = share["account"]
|
|
50
|
+
regex = re.compile(share["regex"])
|
|
51
|
+
region = get_region(share, src_account, dst_account)
|
|
52
|
+
src_amis = aws_api.get_amis_details(src_account, src_account, regex, region)
|
|
53
|
+
dst_amis = aws_api.get_amis_details(dst_account, src_account, regex, region)
|
|
54
|
+
|
|
55
|
+
for ami_id, src_ami_tags in src_amis.items():
|
|
56
|
+
dst_ami_tags = dst_amis.get(ami_id)
|
|
57
|
+
if dst_ami_tags is None:
|
|
58
|
+
logging.info([
|
|
59
|
+
"share_ami",
|
|
60
|
+
src_account["name"],
|
|
61
|
+
dst_account["name"],
|
|
62
|
+
ami_id,
|
|
63
|
+
])
|
|
64
|
+
if not dry_run:
|
|
65
|
+
aws_api.share_ami(src_account, dst_account["uid"], ami_id, region)
|
|
66
|
+
dst_account_tags = default_tags | get_aws_account_tags(
|
|
67
|
+
dst_account.get("organization", None)
|
|
68
|
+
)
|
|
69
|
+
desired_tags = src_ami_tags | dst_account_tags | MANAGED_TAG
|
|
70
|
+
current_tags = dst_ami_tags or {}
|
|
71
|
+
|
|
72
|
+
if desired_tags != current_tags:
|
|
73
|
+
logging.info([
|
|
74
|
+
"tag_shared_ami",
|
|
75
|
+
dst_account["name"],
|
|
76
|
+
ami_id,
|
|
77
|
+
desired_tags,
|
|
78
|
+
])
|
|
79
|
+
if not dry_run:
|
|
80
|
+
aws_api.create_tags(dst_account, ami_id, desired_tags)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def run(dry_run: bool) -> None:
|
|
42
84
|
accounts = queries.get_aws_accounts(sharing=True)
|
|
43
85
|
sharing_accounts = filter_accounts(accounts)
|
|
44
86
|
settings = queries.get_app_interface_settings()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"share_ami",
|
|
68
|
-
src_account["name"],
|
|
69
|
-
dst_account["name"],
|
|
70
|
-
src_ami_id,
|
|
71
|
-
])
|
|
72
|
-
if not dry_run:
|
|
73
|
-
aws_api.share_ami(
|
|
74
|
-
src_account, dst_account["uid"], src_ami_id, region
|
|
75
|
-
)
|
|
76
|
-
# we assume an unshared ami does not have tags
|
|
77
|
-
found_dst_amis = [{"image_id": src_ami_id, "tags": []}]
|
|
78
|
-
|
|
79
|
-
dst_ami = found_dst_amis[0]
|
|
80
|
-
dst_ami_id = dst_ami["image_id"]
|
|
81
|
-
dst_ami_tags = dst_ami["tags"]
|
|
82
|
-
if MANAGED_TAG not in dst_ami_tags:
|
|
83
|
-
logging.info([
|
|
84
|
-
"tag_shared_ami",
|
|
85
|
-
dst_account["name"],
|
|
86
|
-
dst_ami_id,
|
|
87
|
-
MANAGED_TAG,
|
|
88
|
-
])
|
|
89
|
-
if not dry_run:
|
|
90
|
-
aws_api.create_tag(dst_account, dst_ami_id, MANAGED_TAG)
|
|
91
|
-
src_ami_tags = src_ami["tags"]
|
|
92
|
-
for src_tag in src_ami_tags:
|
|
93
|
-
if src_tag not in dst_ami_tags:
|
|
94
|
-
logging.info([
|
|
95
|
-
"tag_shared_ami",
|
|
96
|
-
dst_account["name"],
|
|
97
|
-
dst_ami_id,
|
|
98
|
-
src_tag,
|
|
99
|
-
])
|
|
100
|
-
if not dry_run:
|
|
101
|
-
aws_api.create_tag(dst_account, dst_ami_id, src_tag)
|
|
87
|
+
try:
|
|
88
|
+
default_tags = get_settings().default_tags
|
|
89
|
+
except ValueError:
|
|
90
|
+
# no external resources settings found
|
|
91
|
+
default_tags = {}
|
|
92
|
+
|
|
93
|
+
with AWSApi(
|
|
94
|
+
1,
|
|
95
|
+
sharing_accounts,
|
|
96
|
+
settings=settings,
|
|
97
|
+
init_users=False,
|
|
98
|
+
) as aws_api:
|
|
99
|
+
for src_account in sharing_accounts:
|
|
100
|
+
for share in src_account.get("sharing") or []:
|
|
101
|
+
if share["provider"] == "ami":
|
|
102
|
+
share_ami(
|
|
103
|
+
dry_run=dry_run,
|
|
104
|
+
src_account=src_account,
|
|
105
|
+
share=share,
|
|
106
|
+
default_tags=default_tags,
|
|
107
|
+
aws_api=aws_api,
|
|
108
|
+
)
|
|
@@ -70,10 +70,13 @@ class ReconciliationK8sJob(K8sJob, BaseModel, frozen=True):
|
|
|
70
70
|
dry_run_suffix: str = ""
|
|
71
71
|
|
|
72
72
|
def name_prefix(self) -> str:
|
|
73
|
+
identifier = (
|
|
74
|
+
f"{self.reconciliation.key.provider}-{self.reconciliation.key.identifier}"
|
|
75
|
+
)
|
|
73
76
|
if self.is_dry_run:
|
|
74
|
-
return f"er-dry-run-mr-{self.dry_run_suffix}"
|
|
77
|
+
return f"er-dry-run-mr-{self.dry_run_suffix}-{identifier}"
|
|
75
78
|
else:
|
|
76
|
-
return "er"
|
|
79
|
+
return f"er-{identifier}"
|
|
77
80
|
|
|
78
81
|
def unit_of_work_identity(self) -> Any:
|
|
79
82
|
return self.reconciliation.key
|
reconcile/queries.py
CHANGED
reconcile/utils/aws_api.py
CHANGED
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
import operator
|
|
5
5
|
import os
|
|
6
|
-
import re
|
|
7
6
|
from functools import lru_cache
|
|
8
7
|
from threading import Lock
|
|
9
8
|
from typing import (
|
|
@@ -25,6 +24,7 @@ import reconcile.utils.lean_terraform_client as terraform
|
|
|
25
24
|
from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
|
|
26
25
|
|
|
27
26
|
if TYPE_CHECKING:
|
|
27
|
+
import re
|
|
28
28
|
from collections.abc import (
|
|
29
29
|
Iterable,
|
|
30
30
|
Iterator,
|
|
@@ -1074,28 +1074,40 @@ class AWSApi:
|
|
|
1074
1074
|
return [rt["RouteTableId"] for rt in vpc_route_tables]
|
|
1075
1075
|
|
|
1076
1076
|
@staticmethod
|
|
1077
|
-
def
|
|
1078
|
-
|
|
1079
|
-
) -> list[dict[str, Any]]:
|
|
1080
|
-
results = []
|
|
1081
|
-
pattern = re.compile(regex)
|
|
1082
|
-
for i in images:
|
|
1083
|
-
if not re.search(pattern, i["Name"]):
|
|
1084
|
-
continue
|
|
1085
|
-
if i["State"] != "available":
|
|
1086
|
-
continue
|
|
1087
|
-
item = {"image_id": i["ImageId"], "tags": i.get("Tags", [])}
|
|
1088
|
-
results.append(item)
|
|
1077
|
+
def normalize_tags(tags: Iterable[TagTypeDef]) -> dict[str, str]:
|
|
1078
|
+
return {tag["Key"]: tag["Value"] for tag in tags}
|
|
1089
1079
|
|
|
1090
|
-
|
|
1080
|
+
@staticmethod
|
|
1081
|
+
def _filter_amis(
|
|
1082
|
+
images: Iterable[ImageTypeDef],
|
|
1083
|
+
regex: re.Pattern,
|
|
1084
|
+
) -> dict[str, dict[str, str]]:
|
|
1085
|
+
return {
|
|
1086
|
+
image["ImageId"]: AWSApi.normalize_tags(image.get("Tags", []))
|
|
1087
|
+
for image in images
|
|
1088
|
+
if regex.search(image["Name"]) and image["State"] == "available"
|
|
1089
|
+
}
|
|
1091
1090
|
|
|
1092
1091
|
def get_amis_details(
|
|
1093
1092
|
self,
|
|
1094
1093
|
account: Mapping[str, Any],
|
|
1095
1094
|
owner_account: Mapping[str, Any],
|
|
1096
|
-
regex:
|
|
1095
|
+
regex: re.Pattern,
|
|
1097
1096
|
region: str | None = None,
|
|
1098
|
-
) ->
|
|
1097
|
+
) -> dict[str, dict[str, str]]:
|
|
1098
|
+
"""
|
|
1099
|
+
Get AMI details for an account, find AMI name matches regex and state is available.
|
|
1100
|
+
Return ImageId and normalized tags.
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
account: AWS account
|
|
1104
|
+
owner_account: AMI owner AWS account uid
|
|
1105
|
+
regex: regex to filter AMI name
|
|
1106
|
+
region: AWS account region
|
|
1107
|
+
|
|
1108
|
+
Returns:
|
|
1109
|
+
dict[str, dict[str, str]]: Key is AMI ImageId, value is AMI normalized tags.
|
|
1110
|
+
"""
|
|
1099
1111
|
ec2 = self._account_ec2_client(account["name"], region_name=region)
|
|
1100
1112
|
images = self.get_account_amis(ec2, owner=owner_account["uid"])
|
|
1101
1113
|
return self._filter_amis(images, regex)
|
|
@@ -1175,12 +1187,31 @@ class AWSApi:
|
|
|
1175
1187
|
client = self._account_cloudwatch_client(account_name, region_name=region_name)
|
|
1176
1188
|
client.delete_log_group(logGroupName=group_name)
|
|
1177
1189
|
|
|
1178
|
-
def
|
|
1179
|
-
self,
|
|
1190
|
+
def create_tags(
|
|
1191
|
+
self,
|
|
1192
|
+
account: Mapping[str, Any],
|
|
1193
|
+
resource_id: str,
|
|
1194
|
+
tags: Mapping[str, str],
|
|
1180
1195
|
) -> None:
|
|
1196
|
+
"""
|
|
1197
|
+
Create tags on EC2 resources (AMI)
|
|
1198
|
+
|
|
1199
|
+
Args:
|
|
1200
|
+
account: AWS account
|
|
1201
|
+
resource_id: AWS resource id
|
|
1202
|
+
tags: tags to update
|
|
1203
|
+
|
|
1204
|
+
Returns:
|
|
1205
|
+
None
|
|
1206
|
+
"""
|
|
1181
1207
|
ec2 = self._account_ec2_client(account["name"])
|
|
1182
|
-
|
|
1183
|
-
|
|
1208
|
+
formatted_tags: list[TagTypeDef] = [
|
|
1209
|
+
{"Key": k, "Value": v} for k, v in tags.items()
|
|
1210
|
+
]
|
|
1211
|
+
ec2.create_tags(
|
|
1212
|
+
Resources=[resource_id],
|
|
1213
|
+
Tags=formatted_tags,
|
|
1214
|
+
)
|
|
1184
1215
|
|
|
1185
1216
|
def get_alb_network_interface_ips(
|
|
1186
1217
|
self, account: awsh.Account, service_name: str
|
|
@@ -38,6 +38,8 @@ class JobValidationError(Exception):
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
JOB_GENERATION_ANNOTATION = "qontract-reconcile/job.generation"
|
|
41
|
+
MAX_JOB_NAME_LENGTH = 63
|
|
42
|
+
UNIT_OF_WORK_DIGEST_LENGTH = 10
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
class K8sJob(ABC):
|
|
@@ -72,7 +74,21 @@ class K8sJob(ABC):
|
|
|
72
74
|
"""
|
|
73
75
|
|
|
74
76
|
def name(self) -> str:
|
|
75
|
-
|
|
77
|
+
"""
|
|
78
|
+
Generate the full job name by combining the name prefix with a digest.
|
|
79
|
+
|
|
80
|
+
The name is constructed from the name_prefix (truncated to ensure total
|
|
81
|
+
length compliance) and the unit_of_work_digest. The total length is
|
|
82
|
+
limited to MAX_JOB_NAME_LENGTH (63 characters) to comply with Kubernetes
|
|
83
|
+
naming constraints.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
A unique job name in the format: {name_prefix}-{digest}
|
|
87
|
+
"""
|
|
88
|
+
prefix = self.name_prefix()[
|
|
89
|
+
: MAX_JOB_NAME_LENGTH - UNIT_OF_WORK_DIGEST_LENGTH - 1
|
|
90
|
+
]
|
|
91
|
+
return f"{prefix}-{self.unit_of_work_digest(UNIT_OF_WORK_DIGEST_LENGTH)}"
|
|
76
92
|
|
|
77
93
|
@abstractmethod
|
|
78
94
|
def name_prefix(self) -> str:
|
{qontract_reconcile-0.10.2.dev402.dist-info → qontract_reconcile-0.10.2.dev404.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|