qontract-reconcile 0.10.1rc692__py3-none-any.whl → 0.10.1rc694__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.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/RECORD +12 -12
- reconcile/aus/base.py +67 -20
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +8 -4
- reconcile/cli.py +1 -0
- reconcile/queries.py +1 -0
- reconcile/utils/ocm/addons.py +205 -34
- reconcile/utils/ocm/upgrades.py +0 -66
- tools/qontract_cli.py +17 -9
- {qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.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.1rc694
|
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.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/RECORD
RENAMED
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=NwErtrqgBiXr7eGCAHdtGGOx0S7-4JnSc29Ie
|
|
9
9
|
reconcile/aws_support_cases_sos.py,sha256=Jk6_XjDeJSYxgRGqcEAOcynt9qJF2r5HPIPcSKmoBv8,2974
|
10
10
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=W_VJagnsJR1v5oqjlI3RJJE0_nhtJ0m81RS8zWA5u5c,3538
|
11
11
|
reconcile/checkpoint.py,sha256=R2WFXUXLTB4sWMi4GeA4eegsuf_1-Q4vH8M0Toh3Ij4,5036
|
12
|
-
reconcile/cli.py,sha256=
|
12
|
+
reconcile/cli.py,sha256=Xj_msd-518yR9r1hy39FI3Q9gBRZQsfM9HRA-Ep6CKY,93661
|
13
13
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=SMhkcQqprWvThrIJa3U_3uh5w1h-alleW1QnCJFY4Qw,4909
|
14
14
|
reconcile/cluster_deployment_mapper.py,sha256=2Ah-nu-Mdig0pjuiZl_XLrmVAjYzFjORR3dMlCgkmw0,2352
|
15
15
|
reconcile/dashdotdb_base.py,sha256=a5aPLVxyqPSbjdB0Ty-uliOtxwvEbbEljHJKxdK3-Zk,4813
|
@@ -92,7 +92,7 @@ reconcile/quay_mirror.py,sha256=9NzbNoxl-NdD8CwImcXNG5xTdHmUJxBfeVk5XHH41J8,1488
|
|
92
92
|
reconcile/quay_mirror_org.py,sha256=Oq-t3kSkgfeSAOUDjLCDRBeEvOIEBacfX38qrX_s0oc,10801
|
93
93
|
reconcile/quay_permissions.py,sha256=9KOutS1w4RFQqkvMSy54VtsKNx56-phzP6yI_rEW-B8,4244
|
94
94
|
reconcile/quay_repos.py,sha256=cuEYG0HUe0ut5yvLdEwOF5-CmccpXQHRb_wDazvDrvQ,6895
|
95
|
-
reconcile/queries.py,sha256=
|
95
|
+
reconcile/queries.py,sha256=hgQizeUT5_a1ZI9i8wH-ajr7e956u5ynIp90zKMeRCA,50560
|
96
96
|
reconcile/query_validator.py,sha256=BAjGrU8_VhzTOv5k0-uz0hY9ziZyconv8VAhgre1Auc,1497
|
97
97
|
reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
|
98
98
|
reconcile/resource_scraper.py,sha256=vo1N9vLJCYWvXlTwFRIpEuWjx_39ZV9zxJlpoPq4g3U,2330
|
@@ -120,12 +120,12 @@ reconcile/vpc_peerings_validator.py,sha256=Kv22HJVlTW9l9GB2eXwjPWqdDbr_VuvQBNPtt
|
|
120
120
|
reconcile/aus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
121
121
|
reconcile/aus/advanced_upgrade_service.py,sha256=MPqcWpq1QeYzBsB8rtTlo102h_cR_q83oOYtWAncuAk,22391
|
122
122
|
reconcile/aus/aus_label_source.py,sha256=qoP8Fgxuu1tCuhG6ixCWve7Ll-KD6a79E2uLAmC0ifw,4184
|
123
|
-
reconcile/aus/base.py,sha256=
|
123
|
+
reconcile/aus/base.py,sha256=4VTHqc22IW1xyLCgxhUrSBDRsaF99RW3uzoQafTQDN4,49410
|
124
124
|
reconcile/aus/cluster_version_data.py,sha256=j4UyEBi5mQuvPq5Lo7a_L_0blxvH790wJV07uAiikFU,7126
|
125
125
|
reconcile/aus/healthchecks.py,sha256=S8_KPn_zFiOo_wf5XlVmz-I3tUDYAim3EGSqiSPMvLQ,2707
|
126
126
|
reconcile/aus/metrics.py,sha256=nKT4m2zGT-QOMR0c-z-npVNKWsNMubzdffpU_f9n4II,3927
|
127
127
|
reconcile/aus/models.py,sha256=2e0IPHDJNSM4opqIJUGGxjXLF3zFyrBCAFWRJKjgEEQ,7371
|
128
|
-
reconcile/aus/ocm_addons_upgrade_scheduler_org.py,sha256=
|
128
|
+
reconcile/aus/ocm_addons_upgrade_scheduler_org.py,sha256=t2_J7CuovTm6FGvwWI6HsyiftPbt3ZRWEKjsGmIRcEI,10207
|
129
129
|
reconcile/aus/ocm_upgrade_scheduler.py,sha256=2uPn13y3QGCHLoKwCc1Z7q9wQsoQf_F1HATMYUbl53s,3695
|
130
130
|
reconcile/aus/ocm_upgrade_scheduler_org.py,sha256=f7pE_XrX9695EMZpg-CFZiakZ9vZ9BoRpkE2I9UC0sI,3190
|
131
131
|
reconcile/aus/upgrades.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -667,7 +667,7 @@ reconcile/utils/mr/ocm_update_recommended_version.py,sha256=p_aVP0TGrlKk9WBwgQnY
|
|
667
667
|
reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py,sha256=RzEKRT_BhvB2ud9pyNFZ1cNZFmDGBUah9vjpP0y9f9w,2810
|
668
668
|
reconcile/utils/mr/user_maintenance.py,sha256=cHPBn8zrReWLHalyk-EFdkFJe9zjVjRoZhT4t2zZfGE,3956
|
669
669
|
reconcile/utils/ocm/__init__.py,sha256=xv7CJp7K9LCQfa4gL_W0MMCOD1P4qOy8t5aZj1xXNUE,808
|
670
|
-
reconcile/utils/ocm/addons.py,sha256=
|
670
|
+
reconcile/utils/ocm/addons.py,sha256=cofEAtnoBGKbtShSe3oAz9YbEuql1z6w_2FoNiBcFwA,6887
|
671
671
|
reconcile/utils/ocm/base.py,sha256=GclZtCrPkPJmGP9HHvqIlV-8VXSKuaQTQJkA2pklN60,13817
|
672
672
|
reconcile/utils/ocm/cluster_groups.py,sha256=F8oqVqN_4QUnGL0K61zZhoYIzJeP57EcmZpwmoV0mr4,1751
|
673
673
|
reconcile/utils/ocm/clusters.py,sha256=Nw9m-jgN3GHHCh6w9UOBbMV4rtS24_-Ep09jAWQ-_fE,7653
|
@@ -681,7 +681,7 @@ reconcile/utils/ocm/sre_capability_labels.py,sha256=-TUmTzvK5yu7qY8SUMGj6-684wa8
|
|
681
681
|
reconcile/utils/ocm/status_board.py,sha256=fOuyzkykxU9Rr7zhW5VaY0Vkn8Ur-GxvElzb8No-DZg,2283
|
682
682
|
reconcile/utils/ocm/subscriptions.py,sha256=4qSH8uF9JvFxiecVSV1Kh8-mPcGSTfTTK7In5qHz_2w,2568
|
683
683
|
reconcile/utils/ocm/syncsets.py,sha256=zvji9qWvInIRTdoybMaM9-VUhq4L1VewWfWCQmp4urc,940
|
684
|
-
reconcile/utils/ocm/upgrades.py,sha256=
|
684
|
+
reconcile/utils/ocm/upgrades.py,sha256=zrr_J9X2WIgnnW4hz5NCqdLq22jmoIAX82xKhz-_LY8,4910
|
685
685
|
reconcile/utils/rosa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
686
686
|
reconcile/utils/rosa/rosa_cli.py,sha256=b7V3EgO4b4hOnvZzrxdn-bxRbkINQysOg_ecuB8l5GA,11364
|
687
687
|
reconcile/utils/rosa/session.py,sha256=jYJ0QsJv0mgV15MQIrfTuk2arscmgO4zkBhKcwyO5qo,6915
|
@@ -712,7 +712,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
712
712
|
tools/app_interface_reporter.py,sha256=upA-J-n-HXHKVDINRuMR7vTt-iJvQORKUVi9D3leQto,17738
|
713
713
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
714
714
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
715
|
-
tools/qontract_cli.py,sha256=
|
715
|
+
tools/qontract_cli.py,sha256=fxXsgjmLBzC1zDkmNnB5jfOnwL-kGci5xC_4BsoIe3M,111648
|
716
716
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
717
717
|
tools/template_validation.py,sha256=-U-lTGeLaci8yWPEblCJeev2DOlY1jM9QOOh-O1zts8,3376
|
718
718
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -724,8 +724,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
724
724
|
tools/test/test_qontract_cli.py,sha256=OvalpVRfY4pNmpMaWHHYqBjV68b1eGQjX8SCyTAXb1w,3501
|
725
725
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
726
726
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
727
|
-
qontract_reconcile-0.10.
|
728
|
-
qontract_reconcile-0.10.
|
729
|
-
qontract_reconcile-0.10.
|
730
|
-
qontract_reconcile-0.10.
|
731
|
-
qontract_reconcile-0.10.
|
727
|
+
qontract_reconcile-0.10.1rc694.dist-info/METADATA,sha256=cJGxg2IBbK-ByqiYdq5k4iFEqTyNRhmB3W8V5a1a_II,2382
|
728
|
+
qontract_reconcile-0.10.1rc694.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
729
|
+
qontract_reconcile-0.10.1rc694.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
|
730
|
+
qontract_reconcile-0.10.1rc694.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
731
|
+
qontract_reconcile-0.10.1rc694.dist-info/RECORD,,
|
reconcile/aus/base.py
CHANGED
@@ -8,6 +8,7 @@ from abc import (
|
|
8
8
|
from datetime import (
|
9
9
|
datetime,
|
10
10
|
timedelta,
|
11
|
+
timezone,
|
11
12
|
)
|
12
13
|
from typing import (
|
13
14
|
Callable,
|
@@ -74,6 +75,7 @@ from reconcile.utils.clusterhealth.telemeter import (
|
|
74
75
|
from reconcile.utils.defer import defer
|
75
76
|
from reconcile.utils.disabled_integrations import integration_is_enabled
|
76
77
|
from reconcile.utils.filtering import remove_none_values_from_dict
|
78
|
+
from reconcile.utils.ocm.addons import AddonService, AddonServiceV1, AddonServiceV2
|
77
79
|
from reconcile.utils.ocm.clusters import (
|
78
80
|
OCMCluster,
|
79
81
|
get_node_pools,
|
@@ -81,14 +83,11 @@ from reconcile.utils.ocm.clusters import (
|
|
81
83
|
)
|
82
84
|
from reconcile.utils.ocm.upgrades import (
|
83
85
|
OCMVersionGate,
|
84
|
-
create_addon_upgrade_policy,
|
85
86
|
create_control_plane_upgrade_policy,
|
86
87
|
create_node_pool_upgrade_policy,
|
87
88
|
create_upgrade_policy,
|
88
|
-
delete_addon_upgrade_policy,
|
89
89
|
delete_control_plane_upgrade_policy,
|
90
90
|
delete_upgrade_policy,
|
91
|
-
get_addon_upgrade_policies,
|
92
91
|
get_control_plane_upgrade_policies,
|
93
92
|
get_node_pool_upgrade_policies,
|
94
93
|
get_upgrade_policies,
|
@@ -365,6 +364,34 @@ class AdvancedUpgradeSchedulerBaseIntegration(
|
|
365
364
|
return None
|
366
365
|
|
367
366
|
|
367
|
+
def init_addon_service(ocm_env: OCMEnvironment) -> AddonService:
|
368
|
+
"""
|
369
|
+
Initialize the right version of addon-service for an OCM environment.
|
370
|
+
Since this is just temporary until all OCM environments are on v2, we
|
371
|
+
use a label on the OCM environmentschema to determine which version to use.
|
372
|
+
"""
|
373
|
+
addon_service_version = (ocm_env.labels or {}).get(
|
374
|
+
"feature_flag_addon_service_version"
|
375
|
+
) or "v2"
|
376
|
+
return init_addon_service_version(addon_service_version)
|
377
|
+
|
378
|
+
|
379
|
+
def init_addon_service_version(addon_service_version: str) -> AddonService:
|
380
|
+
"""
|
381
|
+
Initialize the right version of addon-service based on the version string.
|
382
|
+
Supported versions are:
|
383
|
+
- v1: part of CS
|
384
|
+
- v2: standalone service using upgrade-plans instead of upgrade-policies
|
385
|
+
"""
|
386
|
+
match addon_service_version:
|
387
|
+
case "v1":
|
388
|
+
return AddonServiceV1()
|
389
|
+
case "v2":
|
390
|
+
return AddonServiceV2()
|
391
|
+
case _:
|
392
|
+
raise ValueError(f"Unknown addon service version: {addon_service_version}")
|
393
|
+
|
394
|
+
|
368
395
|
class RemainingSoakDayMetricsBuilder(Protocol):
|
369
396
|
def __call__(
|
370
397
|
self, cluster_uuid: str, soaking_version: str
|
@@ -397,27 +424,39 @@ class AbstractUpgradePolicy(ABC, BaseModel):
|
|
397
424
|
pass
|
398
425
|
|
399
426
|
|
427
|
+
def addon_upgrade_policy_soonest_next_run() -> str:
|
428
|
+
now = datetime.now(tz=timezone.utc)
|
429
|
+
next_run = now + timedelta(minutes=MIN_DELTA_MINUTES)
|
430
|
+
return next_run.strftime("%Y-%m-%dT%H:%M:%SZ")
|
431
|
+
|
432
|
+
|
400
433
|
class AddonUpgradePolicy(AbstractUpgradePolicy):
|
401
434
|
"""Class to create and delete Addon upgrade policies in OCM"""
|
402
435
|
|
403
436
|
addon_id: str
|
437
|
+
addon_service: AddonService
|
438
|
+
|
439
|
+
class Config:
|
440
|
+
arbitrary_types_allowed = True
|
404
441
|
|
405
442
|
def create(self, ocm_api: OCMBaseClient) -> None:
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
"
|
411
|
-
|
412
|
-
|
413
|
-
|
443
|
+
self.addon_service.create_addon_upgrade_policy(
|
444
|
+
ocm_api=ocm_api,
|
445
|
+
cluster_id=self.cluster.id,
|
446
|
+
addon_id=self.addon_id,
|
447
|
+
schedule_type="manual",
|
448
|
+
version=self.version,
|
449
|
+
next_run=self.next_run or addon_upgrade_policy_soonest_next_run(),
|
450
|
+
)
|
414
451
|
|
415
452
|
def delete(self, ocm_api: OCMBaseClient) -> None:
|
416
453
|
if not self.id:
|
417
454
|
raise ValueError(
|
418
455
|
"Cannot delete addon upgrade policy without id (not created yet)"
|
419
456
|
)
|
420
|
-
|
457
|
+
self.addon_service.delete_addon_upgrade_policy(
|
458
|
+
ocm_api=ocm_api, cluster_id=self.cluster.id, policy_id=self.id
|
459
|
+
)
|
421
460
|
|
422
461
|
def summarize(self) -> str:
|
423
462
|
details = {
|
@@ -452,7 +491,8 @@ class ClusterUpgradePolicy(AbstractUpgradePolicy):
|
|
452
491
|
details = {
|
453
492
|
"cluster": self.cluster.name,
|
454
493
|
"cluster_id": self.cluster.id,
|
455
|
-
"
|
494
|
+
"from_version": self.cluster.version.raw_id,
|
495
|
+
"to_version": self.version,
|
456
496
|
"next_run": self.next_run,
|
457
497
|
}
|
458
498
|
return f"cluster upgrade policy - {remove_none_values_from_dict(details)}"
|
@@ -543,15 +583,18 @@ def fetch_current_state(
|
|
543
583
|
addons: bool = False,
|
544
584
|
) -> list[AbstractUpgradePolicy]:
|
545
585
|
current_state: list[AbstractUpgradePolicy] = []
|
586
|
+
addon_service = init_addon_service(org_upgrade_spec.org.environment)
|
546
587
|
for spec in org_upgrade_spec.specs:
|
547
588
|
if addons and isinstance(spec, ClusterAddonUpgradeSpec):
|
548
589
|
addon_spec = cast(ClusterAddonUpgradeSpec, spec)
|
549
|
-
upgrade_policies = get_addon_upgrade_policies(
|
590
|
+
upgrade_policies = addon_service.get_addon_upgrade_policies(
|
550
591
|
ocm_api, spec.cluster.id, addon_id=addon_spec.addon.addon.id
|
551
592
|
)
|
552
593
|
for upgrade_policy in upgrade_policies:
|
553
594
|
upgrade_policy["cluster"] = spec.cluster
|
554
|
-
current_state.append(
|
595
|
+
current_state.append(
|
596
|
+
AddonUpgradePolicy(**upgrade_policy, addon_service=addon_service)
|
597
|
+
)
|
555
598
|
elif spec.cluster.is_rosa_hypershift():
|
556
599
|
upgrade_policies = get_control_plane_upgrade_policies(
|
557
600
|
ocm_api, spec.cluster.id
|
@@ -1014,6 +1057,7 @@ def calculate_diff(
|
|
1014
1057
|
for mutex in spec.effective_mutexes:
|
1015
1058
|
locked[mutex] = spec.cluster.id
|
1016
1059
|
|
1060
|
+
addon_service = init_addon_service(desired_state.org.environment)
|
1017
1061
|
now = datetime.utcnow()
|
1018
1062
|
gates = get_version_gates(ocm_api)
|
1019
1063
|
for spec in desired_state.specs:
|
@@ -1062,6 +1106,7 @@ def calculate_diff(
|
|
1062
1106
|
schedule_type="manual",
|
1063
1107
|
addon_id=addon_id,
|
1064
1108
|
upgrade_type="ADDON",
|
1109
|
+
addon_service=addon_service,
|
1065
1110
|
),
|
1066
1111
|
)
|
1067
1112
|
)
|
@@ -1078,12 +1123,12 @@ def calculate_diff(
|
|
1078
1123
|
#
|
1079
1124
|
# this might change in the future - revisite for 4.16
|
1080
1125
|
if not minor_version_gates:
|
1081
|
-
logging.
|
1126
|
+
logging.info(
|
1082
1127
|
f"[{spec.org.org_id}/{spec.org.name}/{spec.cluster.name}] no gates found for {target_version_prefix}. "
|
1083
1128
|
"Skip creation of an upgrade policy."
|
1084
1129
|
)
|
1085
1130
|
continue
|
1086
|
-
|
1131
|
+
gates_with_missing_agreements = gates_to_agree(
|
1087
1132
|
gates=minor_version_gates,
|
1088
1133
|
cluster=spec.cluster,
|
1089
1134
|
acked_gate_ids={
|
@@ -1091,10 +1136,12 @@ def calculate_diff(
|
|
1091
1136
|
for agreement in get_version_agreement(ocm_api, spec.cluster.id)
|
1092
1137
|
},
|
1093
1138
|
)
|
1094
|
-
if
|
1095
|
-
|
1139
|
+
if gates_with_missing_agreements:
|
1140
|
+
missing_gate_ids = [
|
1141
|
+
gate.id for gate in gates_with_missing_agreements
|
1142
|
+
]
|
1096
1143
|
logging.info(
|
1097
|
-
f"[{spec.org.org_id}/{spec.org.name}/{spec.cluster.name}] found gates for {target_version_prefix} - {
|
1144
|
+
f"[{spec.org.org_id}/{spec.org.name}/{spec.cluster.name}] found gates with missing agreements for {target_version_prefix} - {missing_gate_ids} "
|
1098
1145
|
"Skip creation of an upgrade policy until all of them have been acked by the version-gate-approver integration or a user."
|
1099
1146
|
)
|
1100
1147
|
continue
|
@@ -6,6 +6,7 @@ from reconcile.aus import base as aus
|
|
6
6
|
from reconcile.aus.base import (
|
7
7
|
AbstractUpgradePolicy,
|
8
8
|
AddonUpgradePolicy,
|
9
|
+
init_addon_service,
|
9
10
|
)
|
10
11
|
from reconcile.aus.cluster_version_data import VersionData
|
11
12
|
from reconcile.aus.healthchecks import (
|
@@ -26,8 +27,6 @@ from reconcile.gql_definitions.fragments.ocm_environment import OCMEnvironment
|
|
26
27
|
from reconcile.utils import metrics
|
27
28
|
from reconcile.utils.ocm.addons import (
|
28
29
|
OCMAddonInstallation,
|
29
|
-
get_addon_latest_versions,
|
30
|
-
get_addons_for_cluster,
|
31
30
|
)
|
32
31
|
from reconcile.utils.ocm.clusters import (
|
33
32
|
OCMCluster,
|
@@ -137,15 +136,17 @@ class OCMAddonsUpgradeSchedulerOrgIntegration(
|
|
137
136
|
if not organizations:
|
138
137
|
return {}
|
139
138
|
|
139
|
+
addon_service = init_addon_service(ocm_env)
|
140
|
+
|
140
141
|
# lookup cluster in OCM to figure out if they exist
|
141
142
|
# and to get their UUID
|
142
143
|
with init_ocm_base_client(ocm_env, self.secret_reader) as ocm_api:
|
143
144
|
clusters = discover_clusters_for_organizations(
|
144
145
|
ocm_api, [org.org_id for org in organizations]
|
145
146
|
)
|
146
|
-
addon_latest_versions = get_addon_latest_versions(ocm_api)
|
147
|
+
addon_latest_versions = addon_service.get_addon_latest_versions(ocm_api)
|
147
148
|
addons_per_cluster: dict[str, list[OCMAddonInstallation]] = {
|
148
|
-
cluster.ocm_cluster.name: get_addons_for_cluster(
|
149
|
+
cluster.ocm_cluster.name: addon_service.get_addons_for_cluster(
|
149
150
|
ocm_api=ocm_api,
|
150
151
|
cluster_id=cluster.ocm_cluster.id,
|
151
152
|
addon_latest_versions=addon_latest_versions,
|
@@ -260,6 +261,9 @@ def calculate_diff(
|
|
260
261
|
id=current.id,
|
261
262
|
addon_id=current.addon_id,
|
262
263
|
schedule_type=current.schedule_type,
|
264
|
+
addon_service=init_addon_service(
|
265
|
+
org_upgrade_spec.org.environment
|
266
|
+
),
|
263
267
|
),
|
264
268
|
)
|
265
269
|
)
|
reconcile/cli.py
CHANGED
@@ -2469,6 +2469,7 @@ def ocm_addons_upgrade_scheduler_org(
|
|
2469
2469
|
run_class_integration(
|
2470
2470
|
integration=OCMAddonsUpgradeSchedulerOrgIntegration(
|
2471
2471
|
AdvancedUpgradeSchedulerBaseIntegrationParams(
|
2472
|
+
ocm_environment="ocm-integration",
|
2472
2473
|
ocm_organization_ids=set(org_id),
|
2473
2474
|
excluded_ocm_organization_ids=set(exclude_org_id),
|
2474
2475
|
)
|
reconcile/queries.py
CHANGED
reconcile/utils/ocm/addons.py
CHANGED
@@ -6,46 +6,217 @@ from typing import (
|
|
6
6
|
from reconcile.utils.ocm.base import OCMAddonInstallation
|
7
7
|
from reconcile.utils.ocm_base_client import OCMBaseClient
|
8
8
|
|
9
|
+
ADDON_UPGRADE_POLICY_DESIRED_KEYS = {
|
10
|
+
"id",
|
11
|
+
"addon_id",
|
12
|
+
"schedule_type",
|
13
|
+
"schedule",
|
14
|
+
"next_run",
|
15
|
+
"version",
|
16
|
+
}
|
9
17
|
|
10
|
-
def get_addons_for_cluster(
|
11
|
-
ocm_api: OCMBaseClient,
|
12
|
-
cluster_id: str,
|
13
|
-
addon_latest_versions: dict[str, str],
|
14
|
-
required_state: Optional[str],
|
15
|
-
) -> list[OCMAddonInstallation]:
|
16
|
-
"""
|
17
|
-
Returns a list of Addons installed on a cluster
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
class AddonService:
|
20
|
+
def get_addon_latest_versions(self, ocm_api: OCMBaseClient) -> dict[str, str]:
|
21
|
+
"""
|
22
|
+
Returns the latest version for each addon.
|
23
|
+
"""
|
24
|
+
latest_versions: dict[str, str] = {}
|
25
|
+
for addon in ocm_api.get_paginated(f"{self.addon_base_api_path()}/addons"):
|
26
|
+
addon_id = addon["id"]
|
27
|
+
latest_versions[addon_id] = addon["version"]["id"]
|
28
|
+
return latest_versions
|
29
|
+
|
30
|
+
def get_addons_for_cluster(
|
31
|
+
self,
|
32
|
+
ocm_api: OCMBaseClient,
|
33
|
+
cluster_id: str,
|
34
|
+
addon_latest_versions: dict[str, str],
|
35
|
+
required_state: Optional[str],
|
36
|
+
) -> list[OCMAddonInstallation]:
|
37
|
+
"""
|
38
|
+
Returns a list of Addons installed on a cluster
|
39
|
+
|
40
|
+
:param cluster_id: ID of the cluster
|
41
|
+
:param addon_latest_versions: dict of addon_id -> latest version. This allows us to
|
42
|
+
populate the addonsinstalation available upgrades in an efficient way.
|
43
|
+
:param required_state: only return addons with this state
|
44
|
+
"""
|
45
|
+
|
46
|
+
params: Optional[dict[str, Any]] = None
|
47
|
+
if required_state:
|
48
|
+
params = {"search": f"state='{required_state}'"}
|
49
|
+
|
50
|
+
addons = []
|
51
|
+
for addon in ocm_api.get_paginated(
|
52
|
+
api_path=f"{self.addon_base_api_path()}/clusters/{cluster_id}/addons",
|
53
|
+
params=params,
|
54
|
+
):
|
55
|
+
current_version = addon["addon_version"]["id"]
|
56
|
+
latest_version = addon_latest_versions.get(addon["id"])
|
57
|
+
addon["addon_version"]["available_upgrades"] = (
|
58
|
+
[latest_version] if latest_version != current_version else []
|
59
|
+
)
|
60
|
+
addons.append(OCMAddonInstallation(**addon))
|
61
|
+
return addons
|
62
|
+
|
63
|
+
def addon_base_api_path(self) -> str:
|
64
|
+
raise NotImplementedError()
|
65
|
+
|
66
|
+
def get_addon_upgrade_policies(
|
67
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, addon_id: Optional[str] = None
|
68
|
+
) -> list[dict[str, Any]]:
|
69
|
+
raise NotImplementedError()
|
70
|
+
|
71
|
+
def create_addon_upgrade_policy(
|
72
|
+
self,
|
73
|
+
ocm_api: OCMBaseClient,
|
74
|
+
cluster_id: str,
|
75
|
+
addon_id: str,
|
76
|
+
schedule_type: str,
|
77
|
+
version: str,
|
78
|
+
next_run: str,
|
79
|
+
) -> None:
|
80
|
+
raise NotImplementedError()
|
81
|
+
|
82
|
+
def delete_addon_upgrade_policy(
|
83
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, policy_id: str
|
84
|
+
) -> None:
|
85
|
+
raise NotImplementedError()
|
86
|
+
|
87
|
+
|
88
|
+
class AddonServiceV1(AddonService):
|
23
89
|
"""
|
90
|
+
The original addon-service API that is part of CS.
|
91
|
+
"""
|
92
|
+
|
93
|
+
def addon_base_api_path(self) -> str:
|
94
|
+
return "/api/clusters_mgmt/v1"
|
95
|
+
|
96
|
+
def get_addon_upgrade_policies(
|
97
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, addon_id: Optional[str] = None
|
98
|
+
) -> list[dict[str, Any]]:
|
99
|
+
results: list[dict[str, Any]] = []
|
24
100
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
101
|
+
for policy in ocm_api.get_paginated(
|
102
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/addon_upgrade_policies"
|
103
|
+
):
|
104
|
+
if addon_id and policy["addon_id"] != addon_id:
|
105
|
+
continue
|
106
|
+
policy_data = {
|
107
|
+
k: v
|
108
|
+
for k, v in policy.items()
|
109
|
+
if k in ADDON_UPGRADE_POLICY_DESIRED_KEYS
|
110
|
+
}
|
111
|
+
policy_data["state"] = self._get_addon_upgrade_policy_state(
|
112
|
+
ocm_api, cluster_id, policy["id"]
|
113
|
+
)
|
114
|
+
results.append(policy_data)
|
115
|
+
|
116
|
+
return results
|
117
|
+
|
118
|
+
def _get_addon_upgrade_policy_state(
|
119
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, addon_upgrade_policy_id: str
|
120
|
+
) -> Optional[str]:
|
121
|
+
try:
|
122
|
+
state_data = ocm_api.get(
|
123
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/addon_upgrade_policies/{addon_upgrade_policy_id}/state"
|
124
|
+
)
|
125
|
+
return state_data.get("value")
|
126
|
+
except Exception:
|
127
|
+
return None
|
128
|
+
|
129
|
+
def create_addon_upgrade_policy(
|
130
|
+
self,
|
131
|
+
ocm_api: OCMBaseClient,
|
132
|
+
cluster_id: str,
|
133
|
+
addon_id: str,
|
134
|
+
schedule_type: str,
|
135
|
+
version: str,
|
136
|
+
next_run: str,
|
137
|
+
) -> None:
|
138
|
+
"""
|
139
|
+
Creates a new Addon Upgrade Policy
|
140
|
+
"""
|
141
|
+
spec = {
|
142
|
+
"version": version,
|
143
|
+
"schedule_type": schedule_type,
|
144
|
+
"addon_id": addon_id,
|
145
|
+
"cluster_id": cluster_id,
|
146
|
+
"upgrade_type": "ADDON",
|
147
|
+
}
|
148
|
+
ocm_api.post(
|
149
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/addon_upgrade_policies",
|
150
|
+
spec,
|
38
151
|
)
|
39
|
-
addons.append(OCMAddonInstallation(**addon))
|
40
|
-
return addons
|
41
152
|
|
153
|
+
def delete_addon_upgrade_policy(
|
154
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, policy_id: str
|
155
|
+
) -> None:
|
156
|
+
"""
|
157
|
+
Deletes an existing Addon Upgrade Policy
|
158
|
+
"""
|
159
|
+
ocm_api.delete(
|
160
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/addon_upgrade_policies/{policy_id}"
|
161
|
+
)
|
42
162
|
|
43
|
-
|
163
|
+
|
164
|
+
class AddonServiceV2(AddonService):
|
44
165
|
"""
|
45
|
-
|
166
|
+
The dedicated addon-service API that is part of OCM.
|
46
167
|
"""
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
168
|
+
|
169
|
+
def addon_base_api_path(self) -> str:
|
170
|
+
return "/api/addons_mgmt/v1"
|
171
|
+
|
172
|
+
def get_addon_upgrade_policies(
|
173
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, addon_id: Optional[str] = None
|
174
|
+
) -> list[dict[str, Any]]:
|
175
|
+
results: list[dict[str, Any]] = []
|
176
|
+
|
177
|
+
for policy in ocm_api.get_paginated(
|
178
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/upgrade_plan"
|
179
|
+
):
|
180
|
+
if addon_id and policy["addon_id"] != addon_id:
|
181
|
+
continue
|
182
|
+
policy_data = {
|
183
|
+
k: v
|
184
|
+
for k, v in policy.items()
|
185
|
+
if k in ADDON_UPGRADE_POLICY_DESIRED_KEYS
|
186
|
+
}
|
187
|
+
results.append(policy_data)
|
188
|
+
|
189
|
+
return results
|
190
|
+
|
191
|
+
def create_addon_upgrade_policy(
|
192
|
+
self,
|
193
|
+
ocm_api: OCMBaseClient,
|
194
|
+
cluster_id: str,
|
195
|
+
addon_id: str,
|
196
|
+
schedule_type: str,
|
197
|
+
version: str,
|
198
|
+
next_run: str,
|
199
|
+
) -> None:
|
200
|
+
"""
|
201
|
+
Schedules an addon upgrade. Leverages addon-service upgrade plans behind the scene.
|
202
|
+
"""
|
203
|
+
spec = {
|
204
|
+
"version": version,
|
205
|
+
"type": schedule_type,
|
206
|
+
"addon_id": addon_id,
|
207
|
+
"cluster_id": cluster_id,
|
208
|
+
"next_run": next_run,
|
209
|
+
}
|
210
|
+
ocm_api.post(
|
211
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/upgrade_plan", spec
|
212
|
+
)
|
213
|
+
|
214
|
+
def delete_addon_upgrade_policy(
|
215
|
+
self, ocm_api: OCMBaseClient, cluster_id: str, policy_id: str
|
216
|
+
) -> None:
|
217
|
+
"""
|
218
|
+
Deletes an existing upgrade plan.
|
219
|
+
"""
|
220
|
+
ocm_api.delete(
|
221
|
+
f"{self.addon_base_api_path()}/clusters/{cluster_id}/upgrade_plan/{policy_id}"
|
222
|
+
)
|
reconcile/utils/ocm/upgrades.py
CHANGED
@@ -8,78 +8,12 @@ from reconcile.utils.ocm.base import OCMVersionGate
|
|
8
8
|
from reconcile.utils.ocm_base_client import OCMBaseClient
|
9
9
|
|
10
10
|
UPGRADE_POLICY_DESIRED_KEYS = {"id", "schedule_type", "schedule", "next_run", "version"}
|
11
|
-
ADDON_UPGRADE_POLICY_DESIRED_KEYS = {
|
12
|
-
"id",
|
13
|
-
"addon_id",
|
14
|
-
"schedule_type",
|
15
|
-
"schedule",
|
16
|
-
"next_run",
|
17
|
-
"version",
|
18
|
-
}
|
19
11
|
|
20
12
|
|
21
13
|
def build_cluster_url(cluster_id: str) -> str:
|
22
14
|
return f"/api/clusters_mgmt/v1/clusters/{cluster_id}"
|
23
15
|
|
24
16
|
|
25
|
-
#
|
26
|
-
# ADDON UPGRADE POLICIES
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
def get_addon_upgrade_policies(
|
31
|
-
ocm_api: OCMBaseClient, cluster_id: str, addon_id: Optional[str] = None
|
32
|
-
) -> list[dict[str, Any]]:
|
33
|
-
results: list[dict[str, Any]] = []
|
34
|
-
|
35
|
-
for policy in ocm_api.get_paginated(
|
36
|
-
f"{build_cluster_url(cluster_id)}/addon_upgrade_policies"
|
37
|
-
):
|
38
|
-
if addon_id and policy["addon_id"] != addon_id:
|
39
|
-
continue
|
40
|
-
policy_data = {
|
41
|
-
k: v for k, v in policy.items() if k in ADDON_UPGRADE_POLICY_DESIRED_KEYS
|
42
|
-
}
|
43
|
-
policy_data["state"] = get_addon_upgrade_policy_state(
|
44
|
-
ocm_api, cluster_id, policy["id"]
|
45
|
-
)
|
46
|
-
results.append(policy_data)
|
47
|
-
|
48
|
-
return results
|
49
|
-
|
50
|
-
|
51
|
-
def get_addon_upgrade_policy_state(
|
52
|
-
ocm_api: OCMBaseClient, cluster_id: str, addon_upgrade_policy_id: str
|
53
|
-
) -> Optional[str]:
|
54
|
-
try:
|
55
|
-
state_data = ocm_api.get(
|
56
|
-
f"{build_cluster_url(cluster_id)}/addon_upgrade_policies/{addon_upgrade_policy_id}/state"
|
57
|
-
)
|
58
|
-
return state_data.get("value")
|
59
|
-
except Exception:
|
60
|
-
return None
|
61
|
-
|
62
|
-
|
63
|
-
def create_addon_upgrade_policy(
|
64
|
-
ocm_api: OCMBaseClient, cluster_id: str, spec: dict
|
65
|
-
) -> None:
|
66
|
-
"""
|
67
|
-
Creates a new Addon Upgrade Policy
|
68
|
-
"""
|
69
|
-
ocm_api.post(f"{build_cluster_url(cluster_id)}/addon_upgrade_policies", spec)
|
70
|
-
|
71
|
-
|
72
|
-
def delete_addon_upgrade_policy(
|
73
|
-
ocm_api: OCMBaseClient, cluster_id: str, policy_id: str
|
74
|
-
) -> None:
|
75
|
-
"""
|
76
|
-
Deletes an existing Addon Upgrade Policy
|
77
|
-
"""
|
78
|
-
ocm_api.delete(
|
79
|
-
f"{build_cluster_url(cluster_id)}/addon_upgrade_policies/{policy_id}"
|
80
|
-
)
|
81
|
-
|
82
|
-
|
83
17
|
#
|
84
18
|
# UPGRADE POLICIES
|
85
19
|
#
|
tools/qontract_cli.py
CHANGED
@@ -46,6 +46,8 @@ from reconcile.aus.base import (
|
|
46
46
|
AbstractUpgradePolicy,
|
47
47
|
AdvancedUpgradeSchedulerBaseIntegration,
|
48
48
|
AdvancedUpgradeSchedulerBaseIntegrationParams,
|
49
|
+
addon_upgrade_policy_soonest_next_run,
|
50
|
+
init_addon_service_version,
|
49
51
|
)
|
50
52
|
from reconcile.aus.models import OrganizationUpgradeSpec
|
51
53
|
from reconcile.change_owners.bundle import NoOpFileDiffResolver
|
@@ -834,7 +836,6 @@ def upgrade_cluster_addon(
|
|
834
836
|
ocm_org: str, cluster: str, addon: str, dry_run: bool, force: bool
|
835
837
|
) -> None:
|
836
838
|
import reconcile.aus.ocm_addons_upgrade_scheduler_org as oauso
|
837
|
-
from reconcile.utils.ocm.upgrades import create_addon_upgrade_policy
|
838
839
|
|
839
840
|
settings = queries.get_app_interface_settings()
|
840
841
|
ocms = queries.get_openshift_cluster_managers()
|
@@ -886,14 +887,21 @@ def upgrade_cluster_addon(
|
|
886
887
|
)
|
887
888
|
print(["create", ocm_org, cluster, addon, ocm_addon_version])
|
888
889
|
if not dry_run:
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
"
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
create_addon_upgrade_policy(
|
890
|
+
# detection addon service version
|
891
|
+
ocm_env_labels = json.loads(ocm_info["environment"].get("labels") or "{}")
|
892
|
+
addon_service_version = (
|
893
|
+
ocm_env_labels.get("feature_flag_addon_service_version") or "v2"
|
894
|
+
)
|
895
|
+
addon_service = init_addon_service_version(addon_service_version)
|
896
|
+
|
897
|
+
addon_service.create_addon_upgrade_policy(
|
898
|
+
ocm_api=ocm._ocm_client,
|
899
|
+
cluster_id=ocm.cluster_ids[cluster],
|
900
|
+
addon_id=ocm_addon["id"],
|
901
|
+
schedule_type="manual",
|
902
|
+
version=ocm_addon_version,
|
903
|
+
next_run=addon_upgrade_policy_soonest_next_run(),
|
904
|
+
)
|
897
905
|
|
898
906
|
|
899
907
|
def has_cluster_account_access(cluster: dict[str, Any]):
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc692.dist-info → qontract_reconcile-0.10.1rc694.dist-info}/top_level.txt
RENAMED
File without changes
|