qontract-reconcile 0.10.2.dev262__py3-none-any.whl → 0.10.2.dev264__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.dev262.dist-info → qontract_reconcile-0.10.2.dev264.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev262.dist-info → qontract_reconcile-0.10.2.dev264.dist-info}/RECORD +14 -14
- reconcile/cli.py +2 -3
- reconcile/mr_client_gateway.py +7 -2
- reconcile/ocm_additional_routers.py +28 -21
- reconcile/ocm_addons.py +14 -7
- reconcile/ocm_aws_infrastructure_access.py +14 -7
- reconcile/ocm_clusters.py +3 -4
- reconcile/ocm_external_configuration_labels.py +32 -20
- reconcile/ocm_groups.py +31 -10
- reconcile/ocm_machine_pools.py +29 -24
- reconcile/openshift_groups.py +7 -11
- {qontract_reconcile-0.10.2.dev262.dist-info → qontract_reconcile-0.10.2.dev264.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev262.dist-info → qontract_reconcile-0.10.2.dev264.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev262.dist-info → qontract_reconcile-0.10.2.dev264.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.dev264
|
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.dev262.dist-info → qontract_reconcile-0.10.2.dev264.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=C4x30JxgSmKfqhOliWlJaBMsJjtLkd7UpWC9c5wjB4A,112236
|
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
|
@@ -43,21 +43,21 @@ reconcile/jenkins_webhooks_cleaner.py,sha256=tFbAzsFGvJ6UrHRZFdIuLdqG-Ocd5_Oknfs
|
|
43
43
|
reconcile/jenkins_worker_fleets.py,sha256=azjrrZ2mJyheuh96Cpv8eGkKO_86uKVlQzcSq0NQ2TI,5382
|
44
44
|
reconcile/jira_permissions_validator.py,sha256=nVHZg7kNn04Q-ryNM20wthMrhXos28g3O9b0ahzxAKc,14690
|
45
45
|
reconcile/ldap_users.py,sha256=oP1CAxmgSi3zDJ3vKTPySjap6WmEX1U469FmFrov5l4,4599
|
46
|
-
reconcile/mr_client_gateway.py,sha256=
|
47
|
-
reconcile/ocm_additional_routers.py,sha256=
|
48
|
-
reconcile/ocm_addons.py,sha256=
|
46
|
+
reconcile/mr_client_gateway.py,sha256=3L21YncbetuUI3HYvDAEb5JX5HO5KG2CfUyjapX3w8E,2063
|
47
|
+
reconcile/ocm_additional_routers.py,sha256=e5P_OJAaV0jp0626dJ0Hp1-xUsEKXRCnrJzFTIQBdJg,3854
|
48
|
+
reconcile/ocm_addons.py,sha256=b59NWAMmd_zW4pxAH7hm8jzAkis0VZrUBmPYgduVlJc,3684
|
49
49
|
reconcile/ocm_addons_upgrade_tests_trigger.py,sha256=A9zXeYG-_52DsS1dz47yDSnHz62du5XpPBlaeRa6zxY,3975
|
50
|
-
reconcile/ocm_aws_infrastructure_access.py,sha256=
|
51
|
-
reconcile/ocm_clusters.py,sha256=
|
52
|
-
reconcile/ocm_external_configuration_labels.py,sha256=
|
53
|
-
reconcile/ocm_groups.py,sha256=
|
54
|
-
reconcile/ocm_machine_pools.py,sha256=
|
50
|
+
reconcile/ocm_aws_infrastructure_access.py,sha256=f-zVCEf0ucdslhWvfeLcXxQ6Y4xtfCXUG6pxswGgWnU,7251
|
51
|
+
reconcile/ocm_clusters.py,sha256=_nfrI9EeJ4PtLt7RWCHODqaA3G23sKkHMRCQK13twTA,17045
|
52
|
+
reconcile/ocm_external_configuration_labels.py,sha256=dGE2-WeuLdz9kmkuRLmpbHlOkwI3GyY6Jd_cvRpsyJo,4342
|
53
|
+
reconcile/ocm_groups.py,sha256=m-1-ho_pYadaldULF3ogCmC5GZ6nxEbbaLuME4UsMKw,4089
|
54
|
+
reconcile/ocm_machine_pools.py,sha256=KnTYAOw25N-QRb3Y7zbNY8w8xCR55WyqVjycYz24Yxk,17243
|
55
55
|
reconcile/ocm_update_recommended_version.py,sha256=Vi3Y2sX-OQxx1mv_xiPQXnmrpsZzGIE38No0yBcTaD4,4204
|
56
56
|
reconcile/ocm_upgrade_scheduler_org_updater.py,sha256=aLgyInt9oIWAg0XtCiwJRUSwdPx3masKV8kHzkyEEOQ,4282
|
57
57
|
reconcile/openshift_base.py,sha256=S9CUvTaJhO_ibfqiIJ11ezMfSxiji-CEaMvCwK48OFk,52831
|
58
58
|
reconcile/openshift_cluster_bots.py,sha256=Dgh7QhmPn1OKAHnzvmRI9kAvzdmuW7INNj11VmcT4Os,10934
|
59
59
|
reconcile/openshift_clusterrolebindings.py,sha256=sDgHi_t2ayE3O6zZ5CLao7uBmihxRK8K70w2GSADz-w,5822
|
60
|
-
reconcile/openshift_groups.py,sha256=
|
60
|
+
reconcile/openshift_groups.py,sha256=zAXAF2Eej-TsUcOZqPe-dmlfXDlM8MD3AUsOC1-7Ltg,9188
|
61
61
|
reconcile/openshift_limitranges.py,sha256=UvCGo_OQ4XoDK55TJmn55qEhhlkhLzhU12tX8nT5kPQ,3442
|
62
62
|
reconcile/openshift_namespace_labels.py,sha256=4pC6uZICldzID0L2-cUUTC7UQawfmVXf8AEa2p24RZo,15588
|
63
63
|
reconcile/openshift_namespaces.py,sha256=xG2scrmsi7VFeGv1Kc1d5kPY_r_JO6s5P85Ty4rRoys,5806
|
@@ -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.dev264.dist-info/METADATA,sha256=6PUt4AX0OmDwYV7hjsuzytGQngumyFCkFFozm3YiFyw,24501
|
801
|
+
qontract_reconcile-0.10.2.dev264.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
802
|
+
qontract_reconcile-0.10.2.dev264.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
803
|
+
qontract_reconcile-0.10.2.dev264.dist-info/RECORD,,
|
reconcile/cli.py
CHANGED
@@ -2944,12 +2944,11 @@ def ocm_update_recommended_version(
|
|
2944
2944
|
|
2945
2945
|
|
2946
2946
|
@integration.command(short_help="Manages cluster Addons in OCM.")
|
2947
|
-
@threaded()
|
2948
2947
|
@click.pass_context
|
2949
|
-
def ocm_addons(ctx: click.Context
|
2948
|
+
def ocm_addons(ctx: click.Context) -> None:
|
2950
2949
|
import reconcile.ocm_addons
|
2951
2950
|
|
2952
|
-
run_integration(reconcile.ocm_addons, ctx
|
2951
|
+
run_integration(reconcile.ocm_addons, ctx)
|
2953
2952
|
|
2954
2953
|
|
2955
2954
|
@integration.command(
|
reconcile/mr_client_gateway.py
CHANGED
@@ -27,14 +27,19 @@ MR_GW_QUERY = """
|
|
27
27
|
def get_mr_gateway_settings() -> Mapping[str, Any]:
|
28
28
|
"""Returns SecretReader settings"""
|
29
29
|
gqlapi = gql.get_api()
|
30
|
-
|
30
|
+
data = gqlapi.query(MR_GW_QUERY)
|
31
|
+
if not data:
|
32
|
+
raise ValueError("no app-interface-settings found from gql query")
|
33
|
+
settings = data.get("settings")
|
31
34
|
if settings:
|
32
35
|
# assuming a single settings file for now
|
33
36
|
return settings[0]
|
34
37
|
raise ValueError("no app-interface-settings found")
|
35
38
|
|
36
39
|
|
37
|
-
def init(
|
40
|
+
def init(
|
41
|
+
gitlab_project_id: str | int | None = None, sqs_or_gitlab: str | None = None
|
42
|
+
) -> GitLabApi | SQSGateway:
|
38
43
|
"""
|
39
44
|
Creates the Merge Request client to of a given type.
|
40
45
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
3
|
import sys
|
4
|
-
from collections.abc import Mapping
|
4
|
+
from collections.abc import Iterable, Mapping, MutableMapping
|
5
5
|
from typing import Any
|
6
6
|
|
7
7
|
from reconcile import queries
|
@@ -17,7 +17,9 @@ QONTRACT_INTEGRATION = "ocm-additional-routers"
|
|
17
17
|
SUPPORTED_OCM_PRODUCTS = [OCM_PRODUCT_OSD]
|
18
18
|
|
19
19
|
|
20
|
-
def fetch_current_state(
|
20
|
+
def fetch_current_state(
|
21
|
+
clusters: list[Mapping[str, Any]],
|
22
|
+
) -> tuple[OCMMap, list[dict[str, Any]]]:
|
21
23
|
settings = queries.get_app_interface_settings()
|
22
24
|
ocm_map = OCMMap(
|
23
25
|
clusters=clusters, integration=QONTRACT_INTEGRATION, settings=settings
|
@@ -35,13 +37,13 @@ def fetch_current_state(clusters):
|
|
35
37
|
return ocm_map, current_state
|
36
38
|
|
37
39
|
|
38
|
-
def fetch_desired_state(clusters):
|
40
|
+
def fetch_desired_state(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
39
41
|
desired_state = []
|
40
42
|
for cluster in clusters:
|
41
43
|
cluster_name = cluster["name"]
|
42
44
|
for router in cluster["additionalRouters"]:
|
43
45
|
listening = "internal" if router["private"] else "external"
|
44
|
-
item = {"listening": listening, "cluster": cluster_name}
|
46
|
+
item: dict[str, Any] = {"listening": listening, "cluster": cluster_name}
|
45
47
|
selectors = router.get("route_selectors", None)
|
46
48
|
if selectors:
|
47
49
|
item["route_selectors"] = json.loads(selectors)
|
@@ -50,31 +52,34 @@ def fetch_desired_state(clusters):
|
|
50
52
|
return desired_state
|
51
53
|
|
52
54
|
|
53
|
-
def calculate_diff(
|
55
|
+
def calculate_diff(
|
56
|
+
current_state: Iterable[MutableMapping[str, Any]],
|
57
|
+
desired_state: Iterable[MutableMapping[str, Any]],
|
58
|
+
) -> list[MutableMapping[str, Any]]:
|
54
59
|
diffs = []
|
55
|
-
for
|
56
|
-
|
57
|
-
if not
|
58
|
-
|
59
|
-
diffs.append(
|
60
|
-
|
61
|
-
for
|
62
|
-
|
63
|
-
if not
|
64
|
-
|
65
|
-
diffs.append(
|
60
|
+
for d_item in desired_state:
|
61
|
+
c_items = [c for c in current_state if d_item.items() <= c.items()]
|
62
|
+
if not c_items:
|
63
|
+
d_item["action"] = "create"
|
64
|
+
diffs.append(d_item)
|
65
|
+
|
66
|
+
for c_item in current_state:
|
67
|
+
d_items = [d for d in desired_state if d.items() <= c_item.items()]
|
68
|
+
if not d_items:
|
69
|
+
c_item["action"] = "delete"
|
70
|
+
diffs.append(c_item)
|
66
71
|
|
67
72
|
return diffs
|
68
73
|
|
69
74
|
|
70
|
-
def sort_diffs(diff):
|
75
|
+
def sort_diffs(diff: Mapping[str, Any]) -> int:
|
71
76
|
"""Sort diffs so we delete first and create later"""
|
72
77
|
if diff["action"] == "delete":
|
73
78
|
return 1
|
74
79
|
return 2
|
75
80
|
|
76
81
|
|
77
|
-
def act(dry_run, diffs, ocm_map):
|
82
|
+
def act(dry_run: bool, diffs: list[MutableMapping[str, Any]], ocm_map: OCMMap) -> None:
|
78
83
|
diffs.sort(key=sort_diffs)
|
79
84
|
for diff in diffs:
|
80
85
|
action = diff.pop("action")
|
@@ -82,6 +87,9 @@ def act(dry_run, diffs, ocm_map):
|
|
82
87
|
logging.info([action, cluster])
|
83
88
|
if not dry_run:
|
84
89
|
ocm = ocm_map.get(cluster)
|
90
|
+
if ocm is None:
|
91
|
+
logging.error(f"OCM client for cluster {cluster} not found.")
|
92
|
+
continue
|
85
93
|
if action == "create":
|
86
94
|
ocm.create_additional_router(cluster, diff)
|
87
95
|
elif action == "delete":
|
@@ -96,11 +104,10 @@ def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
|
96
104
|
)
|
97
105
|
|
98
106
|
|
99
|
-
def run(dry_run):
|
100
|
-
clusters = queries.get_clusters()
|
107
|
+
def run(dry_run: bool) -> None:
|
101
108
|
clusters = [
|
102
109
|
c
|
103
|
-
for c in
|
110
|
+
for c in queries.get_clusters()
|
104
111
|
if integration_is_enabled(QONTRACT_INTEGRATION, c) and _cluster_is_compatible(c)
|
105
112
|
]
|
106
113
|
if not clusters:
|
reconcile/ocm_addons.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import sys
|
3
|
-
from collections.abc import Mapping
|
3
|
+
from collections.abc import Iterable, Mapping, MutableMapping
|
4
4
|
from operator import itemgetter
|
5
5
|
from typing import Any
|
6
6
|
|
@@ -12,7 +12,9 @@ from reconcile.utils.ocm import OCMMap
|
|
12
12
|
QONTRACT_INTEGRATION = "ocm-addons"
|
13
13
|
|
14
14
|
|
15
|
-
def fetch_current_state(
|
15
|
+
def fetch_current_state(
|
16
|
+
clusters: Iterable[Mapping[str, Any]],
|
17
|
+
) -> tuple[OCMMap, list[dict[str, Any]]]:
|
16
18
|
settings = queries.get_app_interface_settings()
|
17
19
|
ocm_map = OCMMap(
|
18
20
|
clusters=clusters,
|
@@ -35,7 +37,7 @@ def fetch_current_state(clusters):
|
|
35
37
|
return ocm_map, current_state
|
36
38
|
|
37
39
|
|
38
|
-
def fetch_desired_state(clusters):
|
40
|
+
def fetch_desired_state(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
39
41
|
desired_state = []
|
40
42
|
for cluster in clusters:
|
41
43
|
cluster_name = cluster["name"]
|
@@ -49,13 +51,16 @@ def fetch_desired_state(clusters):
|
|
49
51
|
return desired_state
|
50
52
|
|
51
53
|
|
52
|
-
def sort_parameters(addon):
|
54
|
+
def sort_parameters(addon: MutableMapping[str, Any]) -> None:
|
53
55
|
addon_parameters = addon.get("parameters")
|
54
56
|
if addon_parameters:
|
55
57
|
addon["parameters"] = sorted(addon_parameters, key=itemgetter("id"))
|
56
58
|
|
57
59
|
|
58
|
-
def calculate_diff(
|
60
|
+
def calculate_diff(
|
61
|
+
current_state: Iterable[Mapping[str, Any]],
|
62
|
+
desired_state: Iterable[MutableMapping[str, Any]],
|
63
|
+
) -> list[MutableMapping[str, Any]]:
|
59
64
|
diffs = []
|
60
65
|
for d in desired_state:
|
61
66
|
c = [c for c in current_state if d.items() <= c.items()]
|
@@ -66,7 +71,9 @@ def calculate_diff(current_state, desired_state):
|
|
66
71
|
return diffs
|
67
72
|
|
68
73
|
|
69
|
-
def act(
|
74
|
+
def act(
|
75
|
+
dry_run: bool, diffs: Iterable[MutableMapping[str, Any]], ocm_map: OCMMap
|
76
|
+
) -> bool:
|
70
77
|
err = False
|
71
78
|
for diff in diffs:
|
72
79
|
action = diff.pop("action")
|
@@ -95,7 +102,7 @@ def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
|
95
102
|
return cluster.get("ocm") is not None and cluster.get("addons") is not None
|
96
103
|
|
97
104
|
|
98
|
-
def run(dry_run
|
105
|
+
def run(dry_run: bool) -> None:
|
99
106
|
clusters = queries.get_clusters()
|
100
107
|
clusters = [
|
101
108
|
c
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import sys
|
3
|
-
from collections.abc import Mapping
|
3
|
+
from collections.abc import Iterable, Mapping
|
4
4
|
from typing import Any
|
5
5
|
|
6
6
|
from reconcile import queries
|
@@ -22,7 +22,9 @@ QONTRACT_INTEGRATION = "ocm-aws-infrastructure-access"
|
|
22
22
|
SUPPORTED_OCM_PRODUCTS = [OCM_PRODUCT_OSD]
|
23
23
|
|
24
24
|
|
25
|
-
def fetch_current_state(
|
25
|
+
def fetch_current_state(
|
26
|
+
clusters: Iterable[Mapping[str, Any]],
|
27
|
+
) -> tuple[OCMMap, list[dict[str, Any]], list[dict[str, Any]], list[dict[str, Any]]]:
|
26
28
|
current_state = []
|
27
29
|
current_failed = []
|
28
30
|
current_deleting = []
|
@@ -52,7 +54,7 @@ def fetch_current_state(clusters):
|
|
52
54
|
return ocm_map, current_state, current_failed, current_deleting
|
53
55
|
|
54
56
|
|
55
|
-
def fetch_desired_state(clusters):
|
57
|
+
def fetch_desired_state(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
56
58
|
desired_state = []
|
57
59
|
|
58
60
|
for cluster_info in clusters:
|
@@ -129,8 +131,13 @@ def fetch_desired_state(clusters):
|
|
129
131
|
|
130
132
|
|
131
133
|
def act(
|
132
|
-
dry_run
|
133
|
-
|
134
|
+
dry_run: bool,
|
135
|
+
ocm_map: OCMMap,
|
136
|
+
current_state: list[dict[str, Any]],
|
137
|
+
current_failed: Iterable[dict[str, Any]],
|
138
|
+
desired_state: Iterable[dict[str, Any]],
|
139
|
+
current_deleting: list[dict[str, Any]],
|
140
|
+
) -> None:
|
134
141
|
to_delete = [c for c in current_state if c not in desired_state]
|
135
142
|
to_delete += current_failed
|
136
143
|
for item in to_delete:
|
@@ -173,7 +180,7 @@ def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
|
173
180
|
)
|
174
181
|
|
175
182
|
|
176
|
-
def get_clusters():
|
183
|
+
def get_clusters() -> list[dict[str, Any]]:
|
177
184
|
return [
|
178
185
|
c
|
179
186
|
for c in queries.get_clusters(aws_infrastructure_access=True)
|
@@ -181,7 +188,7 @@ def get_clusters():
|
|
181
188
|
]
|
182
189
|
|
183
190
|
|
184
|
-
def run(dry_run):
|
191
|
+
def run(dry_run: bool) -> None:
|
185
192
|
clusters = get_clusters()
|
186
193
|
if not clusters:
|
187
194
|
logging.debug(
|
reconcile/ocm_clusters.py
CHANGED
@@ -40,7 +40,7 @@ QONTRACT_INTEGRATION = "ocm-clusters"
|
|
40
40
|
QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
|
41
41
|
|
42
42
|
|
43
|
-
def _set_rosa_ocm_attrs(cluster: Mapping[str, Any]):
|
43
|
+
def _set_rosa_ocm_attrs(cluster: Mapping[str, Any]) -> None:
|
44
44
|
"""Cluster account (aws) attribute from app-interface differs from the OCMSpec.
|
45
45
|
app-interface's account includes the details for all the OCM environments
|
46
46
|
but the cluster only needs the target OCM environment where it belongs.
|
@@ -78,8 +78,7 @@ def _set_rosa_ocm_attrs(cluster: Mapping[str, Any]):
|
|
78
78
|
|
79
79
|
# doing this allows to exclude account fields which can be queried in graphql
|
80
80
|
rosa_cluster_aws_account = ROSAClusterAWSAccount(
|
81
|
-
uid=uid,
|
82
|
-
rosa=rosa,
|
81
|
+
uid=uid, rosa=rosa, billing_account_id=None
|
83
82
|
)
|
84
83
|
if billing_account := account.get("billingAccount"):
|
85
84
|
rosa_cluster_aws_account.billing_account_id = billing_account["uid"]
|
@@ -293,7 +292,7 @@ def get_cluster_ocm_update_spec(
|
|
293
292
|
|
294
293
|
def _app_interface_updates_mr(
|
295
294
|
clusters_updates: Mapping[str, Any], gitlab_project_id: str | None, dry_run: bool
|
296
|
-
):
|
295
|
+
) -> None:
|
297
296
|
"""Creates an MR to app-interface with the necessary cluster manifest updates
|
298
297
|
|
299
298
|
:param clusters_updates: Updates to perform. Format required by the MR utils code
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
3
|
import sys
|
4
|
-
from collections.abc import Mapping
|
4
|
+
from collections.abc import Iterable, Mapping
|
5
5
|
from typing import Any
|
6
6
|
|
7
7
|
from reconcile import queries
|
@@ -12,14 +12,16 @@ from reconcile.utils.ocm import OCMMap
|
|
12
12
|
QONTRACT_INTEGRATION = "ocm-external-configuration-labels"
|
13
13
|
|
14
14
|
|
15
|
-
def get_allowed_labels_for_cluster(cluster:
|
15
|
+
def get_allowed_labels_for_cluster(cluster: Mapping[str, Any]) -> set[str]:
|
16
16
|
allowed_labels = cluster.get("ocm", {}).get(
|
17
17
|
"allowedClusterExternalConfigLabels", []
|
18
18
|
)
|
19
19
|
return set(allowed_labels)
|
20
20
|
|
21
21
|
|
22
|
-
def fetch_current_state(
|
22
|
+
def fetch_current_state(
|
23
|
+
clusters: Iterable[Mapping[str, Any]],
|
24
|
+
) -> tuple[OCMMap, list[dict[str, Any]]]:
|
23
25
|
settings = queries.get_app_interface_settings()
|
24
26
|
ocm_map = OCMMap(
|
25
27
|
clusters=clusters, integration=QONTRACT_INTEGRATION, settings=settings
|
@@ -34,13 +36,16 @@ def fetch_current_state(clusters):
|
|
34
36
|
for key, value in labels.items():
|
35
37
|
if key not in allowed_labels:
|
36
38
|
continue
|
37
|
-
item = {
|
39
|
+
item = {
|
40
|
+
"label": {"key": key, "value": value},
|
41
|
+
"cluster": cluster_name,
|
42
|
+
}
|
38
43
|
current_state.append(item)
|
39
44
|
|
40
45
|
return ocm_map, current_state
|
41
46
|
|
42
47
|
|
43
|
-
def fetch_desired_state(clusters):
|
48
|
+
def fetch_desired_state(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str, Any]]:
|
44
49
|
desired_state = []
|
45
50
|
for cluster in clusters:
|
46
51
|
cluster_name = cluster["name"]
|
@@ -57,32 +62,35 @@ def fetch_desired_state(clusters):
|
|
57
62
|
return desired_state
|
58
63
|
|
59
64
|
|
60
|
-
def calculate_diff(
|
65
|
+
def calculate_diff(
|
66
|
+
current_state: Iterable[dict[str, Any]],
|
67
|
+
desired_state: Iterable[dict[str, Any]],
|
68
|
+
) -> tuple[list[dict[str, Any]], bool]:
|
61
69
|
diffs = []
|
62
70
|
err = False
|
63
|
-
for
|
64
|
-
|
65
|
-
if not
|
66
|
-
|
67
|
-
diffs.append(
|
68
|
-
|
69
|
-
for
|
70
|
-
|
71
|
-
if not
|
72
|
-
|
73
|
-
diffs.append(
|
71
|
+
for d_item in desired_state:
|
72
|
+
c_items = [c for c in current_state if d_item == c]
|
73
|
+
if not c_items:
|
74
|
+
d_item["action"] = "create"
|
75
|
+
diffs.append(d_item)
|
76
|
+
|
77
|
+
for c_item in current_state:
|
78
|
+
d_items = [d for d in desired_state if c_item == d]
|
79
|
+
if not d_items:
|
80
|
+
c_item["action"] = "delete"
|
81
|
+
diffs.append(c_item)
|
74
82
|
|
75
83
|
return diffs, err
|
76
84
|
|
77
85
|
|
78
|
-
def sort_diffs(diff):
|
86
|
+
def sort_diffs(diff: Mapping[str, Any]) -> int:
|
79
87
|
"""Sort diffs so we delete first and create later"""
|
80
88
|
if diff["action"] == "delete":
|
81
89
|
return 1
|
82
90
|
return 2
|
83
91
|
|
84
92
|
|
85
|
-
def act(dry_run, diffs, ocm_map):
|
93
|
+
def act(dry_run: bool, diffs: list[dict[str, Any]], ocm_map: OCMMap) -> None:
|
86
94
|
diffs.sort(key=sort_diffs)
|
87
95
|
for diff in diffs:
|
88
96
|
action = diff["action"]
|
@@ -104,7 +112,11 @@ def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
|
104
112
|
)
|
105
113
|
|
106
114
|
|
107
|
-
def run(
|
115
|
+
def run(
|
116
|
+
dry_run: bool,
|
117
|
+
gitlab_project_id: str | None = None,
|
118
|
+
thread_pool_size: int = 10,
|
119
|
+
) -> None:
|
108
120
|
clusters = queries.get_clusters()
|
109
121
|
clusters = [
|
110
122
|
c
|
reconcile/ocm_groups.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
import itertools
|
2
2
|
import logging
|
3
3
|
import sys
|
4
|
-
from collections.abc import
|
4
|
+
from collections.abc import (
|
5
|
+
Iterable,
|
6
|
+
Mapping,
|
7
|
+
)
|
5
8
|
from typing import Any
|
6
9
|
|
7
10
|
from sretoolbox.utils import threaded
|
@@ -18,7 +21,20 @@ from reconcile.utils.ocm.base import OCMClusterGroupId
|
|
18
21
|
QONTRACT_INTEGRATION = "ocm-groups"
|
19
22
|
|
20
23
|
|
21
|
-
def
|
24
|
+
def create_groups_list(clusters: Iterable[Mapping[str, Any]]) -> list[dict[str, str]]:
|
25
|
+
groups_list: list[dict[str, str]] = []
|
26
|
+
for cluster_info in clusters:
|
27
|
+
cluster = cluster_info["name"]
|
28
|
+
groups = cluster_info["managedGroups"] or []
|
29
|
+
groups_list.extend(
|
30
|
+
{"cluster": cluster, "group_name": group_name} for group_name in groups
|
31
|
+
)
|
32
|
+
return groups_list
|
33
|
+
|
34
|
+
|
35
|
+
def get_cluster_state(
|
36
|
+
group_items: Mapping[str, str], ocm_map: OCMMap
|
37
|
+
) -> list[dict[str, str]]:
|
22
38
|
cluster = group_items["cluster"]
|
23
39
|
ocm = ocm_map.get(cluster)
|
24
40
|
group_name = group_items["group_name"]
|
@@ -27,17 +43,18 @@ def get_cluster_state(group_items, ocm_map):
|
|
27
43
|
return []
|
28
44
|
return [
|
29
45
|
{"cluster": cluster, "group": group_name, "user": user}
|
30
|
-
for user in group
|
46
|
+
for user in group.get("users") or []
|
31
47
|
]
|
32
48
|
|
33
49
|
|
34
|
-
def fetch_current_state(
|
35
|
-
|
50
|
+
def fetch_current_state(
|
51
|
+
clusters: Iterable[Mapping[str, Any]], thread_pool_size: int
|
52
|
+
) -> tuple[OCMMap, list[dict[str, str]]]:
|
36
53
|
settings = queries.get_app_interface_settings()
|
37
54
|
ocm_map = OCMMap(
|
38
55
|
clusters=clusters, integration=QONTRACT_INTEGRATION, settings=settings
|
39
56
|
)
|
40
|
-
groups_list =
|
57
|
+
groups_list = create_groups_list(clusters)
|
41
58
|
results = threaded.run(
|
42
59
|
get_cluster_state, groups_list, thread_pool_size, ocm_map=ocm_map
|
43
60
|
)
|
@@ -46,7 +63,7 @@ def fetch_current_state(clusters, thread_pool_size):
|
|
46
63
|
return ocm_map, current_state
|
47
64
|
|
48
65
|
|
49
|
-
def act(diff, ocm_map):
|
66
|
+
def act(diff: Mapping[str, Any], ocm_map: OCMMap) -> None:
|
50
67
|
cluster = diff["cluster"]
|
51
68
|
group = diff["group"]
|
52
69
|
user = diff["user"]
|
@@ -63,8 +80,12 @@ def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
|
63
80
|
return cluster.get("ocm") is not None
|
64
81
|
|
65
82
|
|
66
|
-
def run(dry_run, thread_pool_size=10):
|
83
|
+
def run(dry_run: bool, thread_pool_size: int = 10) -> None:
|
67
84
|
clusters = queries.get_clusters()
|
85
|
+
if not clusters:
|
86
|
+
logging.debug("No clusters found in app-interface")
|
87
|
+
sys.exit(ExitCodes.SUCCESS)
|
88
|
+
|
68
89
|
clusters = [
|
69
90
|
c
|
70
91
|
for c in clusters
|
@@ -97,10 +118,10 @@ def run(dry_run, thread_pool_size=10):
|
|
97
118
|
act(diff, ocm_map)
|
98
119
|
|
99
120
|
|
100
|
-
def early_exit_desired_state(*args, **kwargs) -> dict[str, Any]:
|
121
|
+
def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
|
101
122
|
clusters = [
|
102
123
|
c["name"]
|
103
|
-
for c in queries.get_clusters()
|
124
|
+
for c in queries.get_clusters() or []
|
104
125
|
if integration_is_enabled(QONTRACT_INTEGRATION, c) and _cluster_is_compatible(c)
|
105
126
|
]
|
106
127
|
desired_state = openshift_groups.fetch_desired_state(clusters=clusters)
|
reconcile/ocm_machine_pools.py
CHANGED
@@ -5,6 +5,7 @@ from abc import (
|
|
5
5
|
)
|
6
6
|
from collections.abc import Iterable, Mapping
|
7
7
|
from enum import Enum
|
8
|
+
from typing import Any, Self
|
8
9
|
|
9
10
|
from pydantic import (
|
10
11
|
BaseModel,
|
@@ -48,11 +49,11 @@ class AbstractAutoscaling(BaseModel):
|
|
48
49
|
)
|
49
50
|
|
50
51
|
@abstractmethod
|
51
|
-
def get_min(self):
|
52
|
+
def get_min(self) -> int:
|
52
53
|
pass
|
53
54
|
|
54
55
|
@abstractmethod
|
55
|
-
def get_max(self):
|
56
|
+
def get_max(self) -> int:
|
56
57
|
pass
|
57
58
|
|
58
59
|
|
@@ -61,9 +62,12 @@ class MachinePoolAutoscaling(AbstractAutoscaling):
|
|
61
62
|
max_replicas: int
|
62
63
|
|
63
64
|
@root_validator()
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
def max_greater_min(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
|
66
|
+
min_replicas = field_values.get("min_replicas")
|
67
|
+
max_replicas = field_values.get("max_replicas")
|
68
|
+
if min_replicas is None or max_replicas is None:
|
69
|
+
raise ValueError("min_replicas and max_replicas must be set")
|
70
|
+
if min_replicas > max_replicas:
|
67
71
|
raise ValueError("max_replicas must be greater than min_replicas")
|
68
72
|
return field_values
|
69
73
|
|
@@ -79,10 +83,13 @@ class NodePoolAutoscaling(AbstractAutoscaling):
|
|
79
83
|
max_replica: int
|
80
84
|
|
81
85
|
@root_validator()
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
def max_greater_min(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
|
87
|
+
min_replica = field_values.get("min_replica")
|
88
|
+
max_replica = field_values.get("max_replica")
|
89
|
+
if min_replica is None or max_replica is None:
|
90
|
+
raise ValueError("min_replica and max_replica must be set")
|
91
|
+
if min_replica > max_replica:
|
92
|
+
raise ValueError("max_replica must be greater than min_replica")
|
86
93
|
return field_values
|
87
94
|
|
88
95
|
def get_min(self) -> int:
|
@@ -104,8 +111,7 @@ class AbstractPool(ABC, BaseModel):
|
|
104
111
|
autoscaling: AbstractAutoscaling | None
|
105
112
|
|
106
113
|
@root_validator()
|
107
|
-
|
108
|
-
def validate_scaling(cls, field_values):
|
114
|
+
def validate_scaling(cls, field_values: Mapping[str, Any]) -> Mapping[str, Any]:
|
109
115
|
if field_values.get("autoscaling") and field_values.get("replicas"):
|
110
116
|
raise ValueError("autoscaling and replicas are mutually exclusive")
|
111
117
|
return field_values
|
@@ -134,14 +140,12 @@ class AbstractPool(ABC, BaseModel):
|
|
134
140
|
def deletable(self) -> bool:
|
135
141
|
pass
|
136
142
|
|
137
|
-
def _has_diff_autoscale(self, pool):
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
case _:
|
144
|
-
return self.autoscaling.has_diff(pool.autoscale)
|
143
|
+
def _has_diff_autoscale(self, pool: ClusterMachinePoolV1) -> bool:
|
144
|
+
if self.autoscaling is None and pool.autoscale is None:
|
145
|
+
return False
|
146
|
+
if self.autoscaling is None or pool.autoscale is None:
|
147
|
+
return True
|
148
|
+
return self.autoscaling.has_diff(pool.autoscale)
|
145
149
|
|
146
150
|
|
147
151
|
class MachinePool(AbstractPool):
|
@@ -198,7 +202,7 @@ class MachinePool(AbstractPool):
|
|
198
202
|
pool: ClusterMachinePoolV1,
|
199
203
|
cluster: str,
|
200
204
|
cluster_type: ClusterType,
|
201
|
-
):
|
205
|
+
) -> Self:
|
202
206
|
autoscaling: MachinePoolAutoscaling | None = None
|
203
207
|
if pool.autoscale:
|
204
208
|
autoscaling = MachinePoolAutoscaling(
|
@@ -278,7 +282,7 @@ class NodePool(AbstractPool):
|
|
278
282
|
pool: ClusterMachinePoolV1,
|
279
283
|
cluster: str,
|
280
284
|
cluster_type: ClusterType,
|
281
|
-
):
|
285
|
+
) -> Self:
|
282
286
|
autoscaling: NodePoolAutoscaling | None = None
|
283
287
|
if pool.autoscale:
|
284
288
|
autoscaling = NodePoolAutoscaling(
|
@@ -369,7 +373,7 @@ def _classify_cluster_type(cluster: ClusterV1) -> ClusterType:
|
|
369
373
|
raise ValueError(f"unknown cluster type for cluster {cluster.name}")
|
370
374
|
|
371
375
|
|
372
|
-
def fetch_current_state_for_cluster(cluster, ocm):
|
376
|
+
def fetch_current_state_for_cluster(cluster: ClusterV1, ocm: OCM) -> list[AbstractPool]:
|
373
377
|
cluster_type = _classify_cluster_type(cluster)
|
374
378
|
if cluster_type == ClusterType.ROSA_HCP:
|
375
379
|
return [
|
@@ -505,14 +509,15 @@ def act(dry_run: bool, diffs: Iterable[PoolHandler], ocm_map: OCMMap) -> None:
|
|
505
509
|
logging.info([diff.action, diff.pool.cluster, diff.pool.id])
|
506
510
|
if not dry_run:
|
507
511
|
ocm = ocm_map.get(diff.pool.cluster)
|
508
|
-
|
512
|
+
if ocm is not None:
|
513
|
+
diff.act(dry_run, ocm)
|
509
514
|
|
510
515
|
|
511
516
|
def _cluster_is_compatible(cluster: ClusterV1) -> bool:
|
512
517
|
return cluster.ocm is not None and cluster.machine_pools is not None
|
513
518
|
|
514
519
|
|
515
|
-
def run(dry_run: bool):
|
520
|
+
def run(dry_run: bool) -> None:
|
516
521
|
clusters = get_clusters()
|
517
522
|
|
518
523
|
filtered_clusters = [
|
reconcile/openshift_groups.py
CHANGED
@@ -5,11 +5,11 @@ from collections.abc import (
|
|
5
5
|
Iterable,
|
6
6
|
Mapping,
|
7
7
|
)
|
8
|
-
from typing import Any
|
9
8
|
|
10
9
|
from sretoolbox.utils import threaded
|
11
10
|
|
12
11
|
import reconcile.openshift_base as ob
|
12
|
+
from reconcile.gql_definitions.common.clusters import ClusterV1
|
13
13
|
from reconcile.gql_definitions.openshift_groups.managed_groups import (
|
14
14
|
query as query_managed_groups,
|
15
15
|
)
|
@@ -62,20 +62,16 @@ def get_cluster_state(
|
|
62
62
|
|
63
63
|
|
64
64
|
def create_groups_list(
|
65
|
-
clusters: Iterable[
|
65
|
+
clusters: Iterable[ClusterV1], oc_map: ClusterMap
|
66
66
|
) -> list[dict[str, str]]:
|
67
|
-
"""
|
68
|
-
Also used by ocm-groups integration and thus requires to work with dict for now
|
69
|
-
"""
|
70
67
|
groups_list: list[dict[str, str]] = []
|
71
|
-
for
|
72
|
-
|
73
|
-
oc = oc_map.get(cluster)
|
68
|
+
for cluster in clusters:
|
69
|
+
oc = oc_map.get(cluster.name)
|
74
70
|
if isinstance(oc, OCLogMsg):
|
75
71
|
logging.log(level=oc.log_level, msg=oc.message)
|
76
|
-
groups =
|
72
|
+
groups = cluster.managed_groups or []
|
77
73
|
groups_list.extend(
|
78
|
-
{"cluster": cluster, "group_name": group_name} for group_name in groups
|
74
|
+
{"cluster": cluster.name, "group_name": group_name} for group_name in groups
|
79
75
|
)
|
80
76
|
return groups_list
|
81
77
|
|
@@ -97,7 +93,7 @@ def fetch_current_state(
|
|
97
93
|
thread_pool_size=thread_pool_size,
|
98
94
|
)
|
99
95
|
|
100
|
-
groups_list = create_groups_list(
|
96
|
+
groups_list = create_groups_list(clusters, oc_map)
|
101
97
|
results = threaded.run(
|
102
98
|
get_cluster_state, groups_list, thread_pool_size, oc_map=oc_map
|
103
99
|
)
|
{qontract_reconcile-0.10.2.dev262.dist-info → qontract_reconcile-0.10.2.dev264.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|