qontract-reconcile 0.10.1rc998__py3-none-any.whl → 0.10.1rc1000__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.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/RECORD +14 -11
- reconcile/aus/advanced_upgrade_service.py +13 -0
- reconcile/aus/base.py +21 -27
- reconcile/aus/models.py +14 -0
- reconcile/aus/node_pool_spec.py +35 -0
- reconcile/aus/ocm_upgrade_scheduler_org.py +20 -3
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +112 -0
- reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
- reconcile/utils/ocm/clusters.py +0 -14
- tools/qontract_cli.py +30 -0
- {qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.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.1rc1000
|
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.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/RECORD
RENAMED
@@ -120,16 +120,17 @@ reconcile/terraform_vpc_peerings.py,sha256=VLSfuO7FvHN5McopRiKoKJDHCmIhYtlJEHv_h
|
|
120
120
|
reconcile/vault_replication.py,sha256=isfmNaqxl4AC90n8sVJffUt685sPBfhNSvjks6DoQXg,17339
|
121
121
|
reconcile/vpc_peerings_validator.py,sha256=-upvNg3ggKCxcJ4kqZcqJVsiltlhQ8MyyLZiWX8eYmE,7068
|
122
122
|
reconcile/aus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
123
|
-
reconcile/aus/advanced_upgrade_service.py,sha256=
|
123
|
+
reconcile/aus/advanced_upgrade_service.py,sha256=NF3UQ02MdUpVPup50EqnTbTn3dRHGoXoSfFLZxOjr8Q,23744
|
124
124
|
reconcile/aus/aus_label_source.py,sha256=2Rktyvs7ZvCwsRwmbGUhddycTBTq0jHq8wpBaiDHAMA,4165
|
125
|
-
reconcile/aus/base.py,sha256=
|
125
|
+
reconcile/aus/base.py,sha256=lrYqt-fUNM9gISbEgk93yewXf6a6bZfEFN2EL144JFs,49432
|
126
126
|
reconcile/aus/cluster_version_data.py,sha256=VZWbUEIbrDKO-sroMpQtiWCTqDraTMd8tssKV0HyTQ0,7140
|
127
127
|
reconcile/aus/healthchecks.py,sha256=jR9c-syh9impnkV0fd6XW3Bnk7iRN5zv8oCRYM-yIRY,2700
|
128
128
|
reconcile/aus/metrics.py,sha256=nKT4m2zGT-QOMR0c-z-npVNKWsNMubzdffpU_f9n4II,3927
|
129
|
-
reconcile/aus/models.py,sha256=
|
129
|
+
reconcile/aus/models.py,sha256=MSKX7SY0GDw7BgpIuKeLT3i_v8E1LFz4M0DQAL7JWUM,7783
|
130
|
+
reconcile/aus/node_pool_spec.py,sha256=FkMggklG-4BgQwud2Swp2m3AAAKzZmeaXgohl9uwxZ8,1138
|
130
131
|
reconcile/aus/ocm_addons_upgrade_scheduler_org.py,sha256=t2_J7CuovTm6FGvwWI6HsyiftPbt3ZRWEKjsGmIRcEI,10207
|
131
132
|
reconcile/aus/ocm_upgrade_scheduler.py,sha256=2uPn13y3QGCHLoKwCc1Z7q9wQsoQf_F1HATMYUbl53s,3695
|
132
|
-
reconcile/aus/ocm_upgrade_scheduler_org.py,sha256=
|
133
|
+
reconcile/aus/ocm_upgrade_scheduler_org.py,sha256=yXUNd-r_VVqcq_dkODap6dAN3S4Dk3F_WOc1C7xejyk,3914
|
133
134
|
reconcile/aus/upgrades.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
134
135
|
reconcile/aus/version_gate_approver.py,sha256=iZg7l-VgcgyVf7jV9mLZzXq3d22r8feAnl-1LDVUJR4,7358
|
135
136
|
reconcile/aus/version_gates/__init__.py,sha256=AlfmPhMbuuRnJloODTKTgPhM-iFSW3XKsJhbiewBT1s,454
|
@@ -243,6 +244,7 @@ reconcile/gql_definitions/common/app_interface_dms_settings.py,sha256=h-N7-XGpmH
|
|
243
244
|
reconcile/gql_definitions/common/app_interface_repo_settings.py,sha256=rud0rz9NIFF-h1fFdk3MnwGmx73rhwrn1taN_HefvyU,1754
|
244
245
|
reconcile/gql_definitions/common/app_interface_state_settings.py,sha256=VXIK0Hmyv6GTShI86IGkjxyHGwufqUBAh617XKUAKaI,2507
|
245
246
|
reconcile/gql_definitions/common/app_interface_vault_settings.py,sha256=w8quvdG0cSq71ZyJokPPp7MyMpoDb6-HLQ3o9JHVGRQ,1771
|
247
|
+
reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py,sha256=Nnl5ZSHukf0mux_Kfu_qSsTCQ6e9guytZTAApMRWz6Y,3050
|
246
248
|
reconcile/gql_definitions/common/aws_vpc_requests.py,sha256=2lpyy-QSfHPSTvV_zbnqzqUoFzVNl-CJDmoqd_zVSX4,2366
|
247
249
|
reconcile/gql_definitions/common/aws_vpcs.py,sha256=Dss9dQ3xagnz3Ltg1e9mtG2PAmQGBbUzKCmmzvuN28s,1892
|
248
250
|
reconcile/gql_definitions/common/clusters.py,sha256=Dr5AsSsTuqjAxkI9fU0fdiaP6u5qkmRpkkCcYDnU584,21868
|
@@ -592,6 +594,7 @@ reconcile/typed_queries/app_interface_deadmanssnitch_settings.py,sha256=_PpC3IM_
|
|
592
594
|
reconcile/typed_queries/app_interface_repo_url.py,sha256=9fhgWihjWNYOmK65irBWw9jdm7YPJNUWqZC1Ez__PFc,578
|
593
595
|
reconcile/typed_queries/app_interface_state_settings.py,sha256=GdtxrjKs6JONthBzXJO66wHx80v3YyHvbZScj0XFM1Q,447
|
594
596
|
reconcile/typed_queries/app_interface_vault_settings.py,sha256=ffkKVDD5cukQWOorUIrGvpcVr3lCbUHRIz0HWX_h7gI,715
|
597
|
+
reconcile/typed_queries/app_quay_repos_escalation_policies.py,sha256=qpO9z9ev2RSH8sdZprLxhhrrbI0kvzmliSPfIVnfPbE,397
|
595
598
|
reconcile/typed_queries/aws_vpc_requests.py,sha256=3LmBX9usfK8Uqr-pAux2oap01sXiMdGC_ihln6w4oV8,358
|
596
599
|
reconcile/typed_queries/aws_vpcs.py,sha256=Fd0QCwXOH46UHw3-Xo_1ghtGYgUVJDpKf5Q3r1GpJGI,339
|
597
600
|
reconcile/typed_queries/cloudflare.py,sha256=jOsqgCzMrjomPaIWc1isTcQAGONmMIJDTBcpmCheonA,308
|
@@ -776,7 +779,7 @@ reconcile/utils/ocm/__init__.py,sha256=xv7CJp7K9LCQfa4gL_W0MMCOD1P4qOy8t5aZj1xXN
|
|
776
779
|
reconcile/utils/ocm/addons.py,sha256=_LDdJ-gapM3s5exKlIUt-MlXZTAUoHezbYBU0QmvfWQ,7335
|
777
780
|
reconcile/utils/ocm/base.py,sha256=iL_uMN03URDisWHpsaGGto_pLx652epUkuld_9ctx5o,14555
|
778
781
|
reconcile/utils/ocm/cluster_groups.py,sha256=F8oqVqN_4QUnGL0K61zZhoYIzJeP57EcmZpwmoV0mr4,1751
|
779
|
-
reconcile/utils/ocm/clusters.py,sha256=
|
782
|
+
reconcile/utils/ocm/clusters.py,sha256=VwFucqOtXfHZABZLsMLxvAhBTwVg6h9L7WDDdJUaB1w,7962
|
780
783
|
reconcile/utils/ocm/identity_providers.py,sha256=dKed09N8iWmn39tI_MpwgVe47x23eLsknGbjMUxtwr4,2175
|
781
784
|
reconcile/utils/ocm/label_sources.py,sha256=ES_5VP4X6gsRxMFZ95WgbwE_HqqIUo_JRjHjdGYw6Ss,1846
|
782
785
|
reconcile/utils/ocm/labels.py,sha256=aCsL5QkRk32hZeJwsSJuCCT9sbojWMn8LL5Zo-aoFb4,5916
|
@@ -823,7 +826,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
823
826
|
tools/app_interface_reporter.py,sha256=1ZP58LYV6ww3XOLVxgy8NKasMb1jQmp4BNqzTEB0VBE,17723
|
824
827
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
825
828
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
826
|
-
tools/qontract_cli.py,sha256=
|
829
|
+
tools/qontract_cli.py,sha256=UC03zpZPnKu8M2CUmdaghhpN9ji4UYLQtr25hLnHAvg,126922
|
827
830
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
828
831
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
829
832
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -854,8 +857,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
|
|
854
857
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
855
858
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
856
859
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
857
|
-
qontract_reconcile-0.10.
|
858
|
-
qontract_reconcile-0.10.
|
859
|
-
qontract_reconcile-0.10.
|
860
|
-
qontract_reconcile-0.10.
|
861
|
-
qontract_reconcile-0.10.
|
860
|
+
qontract_reconcile-0.10.1rc1000.dist-info/METADATA,sha256=JStF4I4I3sYMBMP948ovqQ5qMT4zRymFFR6M6cdf-Qo,2263
|
861
|
+
qontract_reconcile-0.10.1rc1000.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
862
|
+
qontract_reconcile-0.10.1rc1000.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
863
|
+
qontract_reconcile-0.10.1rc1000.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
864
|
+
qontract_reconcile-0.10.1rc1000.dist-info/RECORD,,
|
@@ -18,8 +18,12 @@ from reconcile.aus.healthchecks import (
|
|
18
18
|
from reconcile.aus.metrics import AUSOCMEnvironmentError
|
19
19
|
from reconcile.aus.models import (
|
20
20
|
ClusterUpgradeSpec,
|
21
|
+
NodePoolSpec,
|
21
22
|
OrganizationUpgradeSpec,
|
22
23
|
)
|
24
|
+
from reconcile.aus.node_pool_spec import (
|
25
|
+
get_node_pool_specs_by_org_cluster,
|
26
|
+
)
|
23
27
|
from reconcile.aus.ocm_upgrade_scheduler_org import (
|
24
28
|
OCMClusterUpgradeSchedulerOrgIntegration,
|
25
29
|
)
|
@@ -148,6 +152,9 @@ class AdvancedUpgradeServiceIntegration(OCMClusterUpgradeSchedulerOrgIntegration
|
|
148
152
|
labels_by_org = _get_org_labels(
|
149
153
|
ocm_api=ocm_api, org_ids=set(organizations.keys())
|
150
154
|
)
|
155
|
+
node_pool_specs_by_org_cluster = get_node_pool_specs_by_org_cluster(
|
156
|
+
ocm_api, clusters_by_org
|
157
|
+
)
|
151
158
|
|
152
159
|
cluster_health_providers = self._health_check_providers_for_env(ocm_env.name)
|
153
160
|
|
@@ -159,6 +166,7 @@ class AdvancedUpgradeServiceIntegration(OCMClusterUpgradeSchedulerOrgIntegration
|
|
159
166
|
org_ref.org_id: vdi for org_ref, vdi in inheritance_network.items()
|
160
167
|
},
|
161
168
|
cluster_health_providers=cluster_health_providers,
|
169
|
+
node_pool_specs_by_org_cluster=node_pool_specs_by_org_cluster,
|
162
170
|
)
|
163
171
|
|
164
172
|
def signal_validation_issues(
|
@@ -243,6 +251,7 @@ def _build_org_upgrade_specs_for_ocm_env(
|
|
243
251
|
labels_by_org: dict[str, LabelContainer],
|
244
252
|
inheritance_network: dict[str, "VersionDataInheritance"],
|
245
253
|
cluster_health_providers: dict[str, ClusterHealthProvider],
|
254
|
+
node_pool_specs_by_org_cluster: dict[str, dict[str, list[NodePoolSpec]]],
|
246
255
|
) -> dict[str, OrganizationUpgradeSpec]:
|
247
256
|
"""
|
248
257
|
Builds the cluster upgrade specs for the given OCM environment.
|
@@ -258,6 +267,8 @@ def _build_org_upgrade_specs_for_ocm_env(
|
|
258
267
|
org=orgs[org_id],
|
259
268
|
providers=cluster_health_providers,
|
260
269
|
),
|
270
|
+
node_pool_specs_by_cluster_id=node_pool_specs_by_org_cluster.get(org_id)
|
271
|
+
or {},
|
261
272
|
)
|
262
273
|
for org_id, clusters in clusters_by_org.items()
|
263
274
|
}
|
@@ -315,6 +326,7 @@ def _build_org_upgrade_spec(
|
|
315
326
|
org_labels: LabelContainer,
|
316
327
|
version_data_inheritance: Optional["VersionDataInheritance"],
|
317
328
|
cluster_health_provider: AUSClusterHealthCheckProvider,
|
329
|
+
node_pool_specs_by_cluster_id: dict[str, list[NodePoolSpec]],
|
318
330
|
) -> OrganizationUpgradeSpec:
|
319
331
|
"""
|
320
332
|
Build a upgrade policy spec for each cluster in the organization that
|
@@ -359,6 +371,7 @@ def _build_org_upgrade_spec(
|
|
359
371
|
upgradePolicy=upgrade_policy,
|
360
372
|
cluster=c.ocm_cluster,
|
361
373
|
health=cluster_health,
|
374
|
+
nodePools=node_pool_specs_by_cluster_id.get(c.ocm_cluster.id) or [],
|
362
375
|
)
|
363
376
|
)
|
364
377
|
except ValidationError as validation_error:
|
reconcile/aus/base.py
CHANGED
@@ -74,8 +74,6 @@ from reconcile.utils.filtering import remove_none_values_from_dict
|
|
74
74
|
from reconcile.utils.ocm.addons import AddonService, AddonServiceV1, AddonServiceV2
|
75
75
|
from reconcile.utils.ocm.clusters import (
|
76
76
|
OCMCluster,
|
77
|
-
get_node_pools,
|
78
|
-
get_version,
|
79
77
|
)
|
80
78
|
from reconcile.utils.ocm.upgrades import (
|
81
79
|
OCMVersionGate,
|
@@ -296,7 +294,7 @@ class AdvancedUpgradeSchedulerBaseIntegration(
|
|
296
294
|
org_id=cluster_upgrade_spec.org.org_id,
|
297
295
|
org_name=org_upgrade_spec.org.name,
|
298
296
|
channel=cluster_upgrade_spec.cluster.version.channel_group,
|
299
|
-
current_version=cluster_upgrade_spec.
|
297
|
+
current_version=cluster_upgrade_spec.oldest_current_version,
|
300
298
|
cluster_name=cluster_upgrade_spec.name,
|
301
299
|
schedule=cluster_upgrade_spec.upgrade_policy.schedule,
|
302
300
|
sector=cluster_upgrade_spec.upgrade_policy.conditions.sector or "",
|
@@ -607,13 +605,13 @@ def fetch_current_state(
|
|
607
605
|
for upgrade_policy in upgrade_policies:
|
608
606
|
upgrade_policy["cluster"] = spec.cluster
|
609
607
|
current_state.append(ControlPlaneUpgradePolicy(**upgrade_policy))
|
610
|
-
for node_pool in
|
608
|
+
for node_pool in spec.node_pools:
|
611
609
|
node_upgrade_policies = get_node_pool_upgrade_policies(
|
612
|
-
ocm_api, spec.cluster.id, node_pool
|
610
|
+
ocm_api, spec.cluster.id, node_pool.id
|
613
611
|
)
|
614
612
|
for upgrade_policy in node_upgrade_policies:
|
615
613
|
upgrade_policy["cluster"] = spec.cluster
|
616
|
-
upgrade_policy["node_pool"] = node_pool
|
614
|
+
upgrade_policy["node_pool"] = node_pool.id
|
617
615
|
current_state.append(NodePoolUpgradePolicy(**upgrade_policy))
|
618
616
|
else:
|
619
617
|
upgrade_policies = get_upgrade_policies(ocm_api, spec.cluster.id)
|
@@ -1002,27 +1000,23 @@ def _create_upgrade_policy(
|
|
1002
1000
|
|
1003
1001
|
|
1004
1002
|
def _calculate_node_pool_diffs(
|
1005
|
-
|
1003
|
+
spec: ClusterUpgradeSpec, now: datetime
|
1006
1004
|
) -> UpgradePolicyHandler | None:
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
next_run=next_schedule,
|
1023
|
-
node_pool=pool["id"],
|
1024
|
-
),
|
1025
|
-
)
|
1005
|
+
for pool in spec.node_pools:
|
1006
|
+
if parse_semver(pool.version).match(f"<{spec.current_version}"):
|
1007
|
+
next_schedule = (now + timedelta(minutes=MIN_DELTA_MINUTES)).strftime(
|
1008
|
+
"%Y-%m-%dT%H:%M:%SZ"
|
1009
|
+
)
|
1010
|
+
return UpgradePolicyHandler(
|
1011
|
+
action="create",
|
1012
|
+
policy=NodePoolUpgradePolicy(
|
1013
|
+
cluster=spec.cluster,
|
1014
|
+
version=spec.current_version,
|
1015
|
+
schedule_type="manual",
|
1016
|
+
next_run=next_schedule,
|
1017
|
+
node_pool=pool.id,
|
1018
|
+
),
|
1019
|
+
)
|
1026
1020
|
return None
|
1027
1021
|
|
1028
1022
|
|
@@ -1072,7 +1066,7 @@ def calculate_diff(
|
|
1072
1066
|
if verify_lock_should_skip(spec, locked):
|
1073
1067
|
continue
|
1074
1068
|
|
1075
|
-
node_pool_update = _calculate_node_pool_diffs(
|
1069
|
+
node_pool_update = _calculate_node_pool_diffs(spec, now)
|
1076
1070
|
if node_pool_update: # node pool update policy not yet created
|
1077
1071
|
diffs.append(node_pool_update)
|
1078
1072
|
set_mutex(locked, spec.cluster.id, spec.effective_mutexes)
|
reconcile/aus/models.py
CHANGED
@@ -22,6 +22,11 @@ from reconcile.utils.ocm.clusters import OCMCluster
|
|
22
22
|
from reconcile.utils.semver_helper import parse_semver
|
23
23
|
|
24
24
|
|
25
|
+
class NodePoolSpec(BaseModel):
|
26
|
+
id: str
|
27
|
+
version: str
|
28
|
+
|
29
|
+
|
25
30
|
class ClusterUpgradeSpec(BaseModel):
|
26
31
|
"""
|
27
32
|
An upgrade spec for a cluster.
|
@@ -31,6 +36,7 @@ class ClusterUpgradeSpec(BaseModel):
|
|
31
36
|
cluster: OCMCluster
|
32
37
|
upgrade_policy: ClusterUpgradePolicyV1 = Field(..., alias="upgradePolicy")
|
33
38
|
health: AUSClusterHealth
|
39
|
+
node_pools: list[NodePoolSpec] = Field(default_factory=list, alias="nodePools")
|
34
40
|
|
35
41
|
@property
|
36
42
|
def name(self) -> str:
|
@@ -44,6 +50,14 @@ class ClusterUpgradeSpec(BaseModel):
|
|
44
50
|
def current_version(self) -> str:
|
45
51
|
return self.cluster.version.raw_id
|
46
52
|
|
53
|
+
@property
|
54
|
+
def oldest_current_version(self) -> str:
|
55
|
+
"""
|
56
|
+
Consider versions in node pools and the cluster itself, find the oldest one.
|
57
|
+
"""
|
58
|
+
versions = [np.version for np in self.node_pools] + [self.current_version]
|
59
|
+
return min(versions, key=parse_semver)
|
60
|
+
|
47
61
|
@property
|
48
62
|
def blocked_versions(self) -> set[str]:
|
49
63
|
return set(self.org.blocked_versions or []) | set(
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from collections.abc import Iterable, Mapping
|
2
|
+
|
3
|
+
from reconcile.aus.models import NodePoolSpec
|
4
|
+
from reconcile.utils.ocm import get_node_pools
|
5
|
+
from reconcile.utils.ocm.base import ClusterDetails
|
6
|
+
from reconcile.utils.ocm_base_client import OCMBaseClient
|
7
|
+
|
8
|
+
|
9
|
+
def get_node_pool_specs(ocm_api: OCMBaseClient, cluster_id: str) -> list[NodePoolSpec]:
|
10
|
+
node_pools = get_node_pools(ocm_api, cluster_id)
|
11
|
+
return [
|
12
|
+
NodePoolSpec(
|
13
|
+
id=p["id"],
|
14
|
+
version=p["version"]["raw_id"],
|
15
|
+
)
|
16
|
+
for p in node_pools
|
17
|
+
]
|
18
|
+
|
19
|
+
|
20
|
+
def get_node_pool_specs_by_org_cluster(
|
21
|
+
ocm_api: OCMBaseClient,
|
22
|
+
clusters_by_org: Mapping[str, Iterable[ClusterDetails]],
|
23
|
+
) -> dict[str, dict[str, list[NodePoolSpec]]]:
|
24
|
+
"""
|
25
|
+
Fetch node pool specs for all rosa hypershift clusters
|
26
|
+
Returns a dict with org IDs as keys, the values are dicts with cluster id as key
|
27
|
+
"""
|
28
|
+
return {
|
29
|
+
org_id: {
|
30
|
+
c.ocm_cluster.id: get_node_pool_specs(ocm_api, c.ocm_cluster.id)
|
31
|
+
for c in clusters
|
32
|
+
if c.ocm_cluster.is_rosa_hypershift()
|
33
|
+
}
|
34
|
+
for org_id, clusters in clusters_by_org.items()
|
35
|
+
}
|
@@ -1,11 +1,15 @@
|
|
1
|
+
from collections import defaultdict
|
2
|
+
|
1
3
|
from reconcile.aus.healthchecks import (
|
2
4
|
AUSClusterHealthCheckProvider,
|
3
5
|
build_cluster_health_providers_for_organization,
|
4
6
|
)
|
5
7
|
from reconcile.aus.models import (
|
6
8
|
ClusterUpgradeSpec,
|
9
|
+
NodePoolSpec,
|
7
10
|
OrganizationUpgradeSpec,
|
8
11
|
)
|
12
|
+
from reconcile.aus.node_pool_spec import get_node_pool_specs_by_org_cluster
|
9
13
|
from reconcile.aus.ocm_upgrade_scheduler import OCMClusterUpgradeSchedulerIntegration
|
10
14
|
from reconcile.gql_definitions.fragments.aus_organization import AUSOCMOrganization
|
11
15
|
from reconcile.gql_definitions.fragments.ocm_environment import OCMEnvironment
|
@@ -41,6 +45,15 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
|
|
41
45
|
ocm_env.name
|
42
46
|
)
|
43
47
|
|
48
|
+
clusters_by_org = defaultdict(list)
|
49
|
+
for cluster in clusters:
|
50
|
+
clusters_by_org[cluster.organization_id].append(cluster)
|
51
|
+
|
52
|
+
node_pool_specs_by_org_cluster = get_node_pool_specs_by_org_cluster(
|
53
|
+
ocm_api,
|
54
|
+
clusters_by_org,
|
55
|
+
)
|
56
|
+
|
44
57
|
return {
|
45
58
|
org.name: OrganizationUpgradeSpec(
|
46
59
|
org=org,
|
@@ -48,13 +61,15 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
|
|
48
61
|
org=org,
|
49
62
|
clusters_by_name={
|
50
63
|
c.ocm_cluster.name: c.ocm_cluster
|
51
|
-
for c in
|
52
|
-
if c.organization_id == org.org_id
|
64
|
+
for c in clusters_by_org[org.org_id]
|
53
65
|
},
|
54
66
|
cluster_health_provider=build_cluster_health_providers_for_organization(
|
55
67
|
org=org,
|
56
68
|
providers=cluster_health_providers,
|
57
69
|
),
|
70
|
+
node_pool_specs_by_cluster_id=node_pool_specs_by_org_cluster[
|
71
|
+
org.org_id
|
72
|
+
],
|
58
73
|
),
|
59
74
|
)
|
60
75
|
for org in organizations
|
@@ -65,6 +80,7 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
|
|
65
80
|
org: AUSOCMOrganization,
|
66
81
|
clusters_by_name: dict[str, OCMCluster],
|
67
82
|
cluster_health_provider: AUSClusterHealthCheckProvider,
|
83
|
+
node_pool_specs_by_cluster_id: dict[str, list[NodePoolSpec]],
|
68
84
|
) -> list[ClusterUpgradeSpec]:
|
69
85
|
return [
|
70
86
|
ClusterUpgradeSpec(
|
@@ -75,9 +91,10 @@ class OCMClusterUpgradeSchedulerOrgIntegration(OCMClusterUpgradeSchedulerIntegra
|
|
75
91
|
cluster_external_id=clusters_by_name[cluster.name].external_id,
|
76
92
|
org_id=org.org_id,
|
77
93
|
),
|
94
|
+
nodePools=node_pool_specs_by_cluster_id.get(ocm_cluster.id) or [],
|
78
95
|
)
|
79
96
|
for cluster in org.upgrade_policy_clusters or []
|
80
97
|
# clusters that are not in the UUID dict will be ignored because
|
81
98
|
# they don't exist in the OCM organization (or have been deprovisioned)
|
82
|
-
if cluster.name
|
99
|
+
if (ocm_cluster := clusters_by_name.get(cluster.name))
|
83
100
|
]
|
@@ -0,0 +1,112 @@
|
|
1
|
+
"""
|
2
|
+
Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
|
3
|
+
"""
|
4
|
+
from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
|
5
|
+
from datetime import datetime # noqa: F401 # pylint: disable=W0611
|
6
|
+
from enum import Enum # noqa: F401 # pylint: disable=W0611
|
7
|
+
from typing import ( # noqa: F401 # pylint: disable=W0611
|
8
|
+
Any,
|
9
|
+
Optional,
|
10
|
+
Union,
|
11
|
+
)
|
12
|
+
|
13
|
+
from pydantic import ( # noqa: F401 # pylint: disable=W0611
|
14
|
+
BaseModel,
|
15
|
+
Extra,
|
16
|
+
Field,
|
17
|
+
Json,
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
DEFINITION = """
|
22
|
+
query AppQuayReposEscalationPolicies {
|
23
|
+
apps: apps_v1 {
|
24
|
+
name
|
25
|
+
escalationPolicy {
|
26
|
+
channels {
|
27
|
+
email
|
28
|
+
slackUserGroup {
|
29
|
+
handle
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
quayRepos {
|
34
|
+
org {
|
35
|
+
name
|
36
|
+
}
|
37
|
+
items {
|
38
|
+
name
|
39
|
+
mirror {
|
40
|
+
path
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
"""
|
47
|
+
|
48
|
+
|
49
|
+
class ConfiguredBaseModel(BaseModel):
|
50
|
+
class Config:
|
51
|
+
smart_union=True
|
52
|
+
extra=Extra.forbid
|
53
|
+
|
54
|
+
|
55
|
+
class PermissionSlackUsergroupV1(ConfiguredBaseModel):
|
56
|
+
handle: str = Field(..., alias="handle")
|
57
|
+
|
58
|
+
|
59
|
+
class AppEscalationPolicyChannelsV1(ConfiguredBaseModel):
|
60
|
+
email: list[str] = Field(..., alias="email")
|
61
|
+
slack_user_group: list[PermissionSlackUsergroupV1] = Field(..., alias="slackUserGroup")
|
62
|
+
|
63
|
+
|
64
|
+
class AppEscalationPolicyV1(ConfiguredBaseModel):
|
65
|
+
channels: AppEscalationPolicyChannelsV1 = Field(..., alias="channels")
|
66
|
+
|
67
|
+
|
68
|
+
class QuayOrgV1(ConfiguredBaseModel):
|
69
|
+
name: str = Field(..., alias="name")
|
70
|
+
|
71
|
+
|
72
|
+
class ContainerImageMirrorV1(ConfiguredBaseModel):
|
73
|
+
path: str = Field(..., alias="path")
|
74
|
+
|
75
|
+
|
76
|
+
class AppQuayReposItemsV1(ConfiguredBaseModel):
|
77
|
+
name: str = Field(..., alias="name")
|
78
|
+
mirror: Optional[ContainerImageMirrorV1] = Field(..., alias="mirror")
|
79
|
+
|
80
|
+
|
81
|
+
class AppQuayReposV1(ConfiguredBaseModel):
|
82
|
+
org: QuayOrgV1 = Field(..., alias="org")
|
83
|
+
items: list[AppQuayReposItemsV1] = Field(..., alias="items")
|
84
|
+
|
85
|
+
|
86
|
+
class AppV1(ConfiguredBaseModel):
|
87
|
+
name: str = Field(..., alias="name")
|
88
|
+
escalation_policy: AppEscalationPolicyV1 = Field(..., alias="escalationPolicy")
|
89
|
+
quay_repos: Optional[list[AppQuayReposV1]] = Field(..., alias="quayRepos")
|
90
|
+
|
91
|
+
|
92
|
+
class AppQuayReposEscalationPoliciesQueryData(ConfiguredBaseModel):
|
93
|
+
apps: Optional[list[AppV1]] = Field(..., alias="apps")
|
94
|
+
|
95
|
+
|
96
|
+
def query(query_func: Callable, **kwargs: Any) -> AppQuayReposEscalationPoliciesQueryData:
|
97
|
+
"""
|
98
|
+
This is a convenience function which queries and parses the data into
|
99
|
+
concrete types. It should be compatible with most GQL clients.
|
100
|
+
You do not have to use it to consume the generated data classes.
|
101
|
+
Alternatively, you can also mime and alternate the behavior
|
102
|
+
of this function in the caller.
|
103
|
+
|
104
|
+
Parameters:
|
105
|
+
query_func (Callable): Function which queries your GQL Server
|
106
|
+
kwargs: optional arguments that will be passed to the query function
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
AppQuayReposEscalationPoliciesQueryData: queried data parsed into generated classes
|
110
|
+
"""
|
111
|
+
raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
|
112
|
+
return AppQuayReposEscalationPoliciesQueryData(**raw_data)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from reconcile.gql_definitions.common.app_quay_repos_escalation_policies import (
|
2
|
+
AppV1,
|
3
|
+
query,
|
4
|
+
)
|
5
|
+
from reconcile.utils import gql
|
6
|
+
from reconcile.utils.gql import GqlApi
|
7
|
+
|
8
|
+
|
9
|
+
def get_apps_quay_repos_escalation_policies(
|
10
|
+
gql_api: GqlApi | None = None,
|
11
|
+
) -> list[AppV1]:
|
12
|
+
api = gql_api if gql_api else gql.get_api()
|
13
|
+
data = query(query_func=api.query)
|
14
|
+
return list(data.apps or [])
|
reconcile/utils/ocm/clusters.py
CHANGED
@@ -3,7 +3,6 @@ from collections.abc import (
|
|
3
3
|
Generator,
|
4
4
|
Iterable,
|
5
5
|
)
|
6
|
-
from functools import lru_cache
|
7
6
|
from typing import Any
|
8
7
|
|
9
8
|
from reconcile.utils.ocm.base import (
|
@@ -42,11 +41,6 @@ NODE_POOL_DESIRED_KEYS = {
|
|
42
41
|
"version",
|
43
42
|
}
|
44
43
|
|
45
|
-
VERSION_DESIRED_KEYS = {
|
46
|
-
"id",
|
47
|
-
"raw_id",
|
48
|
-
}
|
49
|
-
|
50
44
|
|
51
45
|
def discover_clusters_by_labels(
|
52
46
|
ocm_api: OCMBaseClient, label_filter: Filter
|
@@ -246,14 +240,6 @@ def get_node_pools(ocm_api: OCMBaseClient, cluster_id: str) -> list[dict[str, An
|
|
246
240
|
return results
|
247
241
|
|
248
242
|
|
249
|
-
@lru_cache
|
250
|
-
def get_version(ocm_api: OCMBaseClient, version: str) -> dict[str, Any]:
|
251
|
-
api = f"/api/clusters_mgmt/v1/versions/{version}"
|
252
|
-
|
253
|
-
item = ocm_api.get(api)
|
254
|
-
return {k: v for k, v in item.items() if k in VERSION_DESIRED_KEYS}
|
255
|
-
|
256
|
-
|
257
243
|
def get_provisioning_shard_id(ocm_api: OCMBaseClient, cluster_id: str) -> str:
|
258
244
|
api = f"/api/clusters_mgmt/v1/clusters/{cluster_id}/provision_shard"
|
259
245
|
|
tools/qontract_cli.py
CHANGED
@@ -80,6 +80,9 @@ from reconcile.typed_queries.alerting_services_settings import get_alerting_serv
|
|
80
80
|
from reconcile.typed_queries.app_interface_vault_settings import (
|
81
81
|
get_app_interface_vault_settings,
|
82
82
|
)
|
83
|
+
from reconcile.typed_queries.app_quay_repos_escalation_policies import (
|
84
|
+
get_apps_quay_repos_escalation_policies,
|
85
|
+
)
|
83
86
|
from reconcile.typed_queries.clusters import get_clusters
|
84
87
|
from reconcile.typed_queries.external_resources import (
|
85
88
|
get_modules,
|
@@ -2843,6 +2846,33 @@ You can view the source of this Markdown to extract the JSON data.
|
|
2843
2846
|
print_output(ctx.obj["options"], results, columns)
|
2844
2847
|
|
2845
2848
|
|
2849
|
+
@get.command
|
2850
|
+
@click.pass_context
|
2851
|
+
def container_image_details(ctx):
|
2852
|
+
apps = get_apps_quay_repos_escalation_policies()
|
2853
|
+
data: list[dict[str, str]] = []
|
2854
|
+
for app in apps:
|
2855
|
+
app_name = app.name
|
2856
|
+
ep_channels = app.escalation_policy.channels
|
2857
|
+
email = ep_channels.email
|
2858
|
+
slack = ep_channels.slack_user_group[0].handle
|
2859
|
+
for org_items in app.quay_repos or []:
|
2860
|
+
org_name = org_items.org.name
|
2861
|
+
for repo in org_items.items or []:
|
2862
|
+
if repo.mirror:
|
2863
|
+
continue
|
2864
|
+
repository = f"quay.io/{org_name}/{repo.name}"
|
2865
|
+
item = {
|
2866
|
+
"app": app_name,
|
2867
|
+
"repository": repository,
|
2868
|
+
"email": email,
|
2869
|
+
"slack": slack,
|
2870
|
+
}
|
2871
|
+
data.append(item)
|
2872
|
+
columns = ["app", "repository", "email", "slack"]
|
2873
|
+
print_output(ctx.obj["options"], data, columns)
|
2874
|
+
|
2875
|
+
|
2846
2876
|
@root.group(name="set")
|
2847
2877
|
@output
|
2848
2878
|
@click.pass_context
|
{qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc998.dist-info → qontract_reconcile-0.10.1rc1000.dist-info}/top_level.txt
RENAMED
File without changes
|