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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc998
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
@@ -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=KsXSIbuaNjg3r3iXEWPCosKEWNKq9MZDf9mwRFn9xdY,23093
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=_1y0gH_Z-WBVaAiNZogDwBymjLb7wcHS8eAuMJWZbZg,49800
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=zReascmYDZV-5sAlGm7SUMyp363etE8BM0qs-q2nfdk,7338
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=f7pE_XrX9695EMZpg-CFZiakZ9vZ9BoRpkE2I9UC0sI,3190
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=Fn4swizm1qq-XiNlIZ9SvahkftWAyNT8hF4kqRBpK4g,8287
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=w_z2WAfPxXRXm8jbrg-Vc95sIYbPxVu3lCR14lEK3J4,125855
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.1rc998.dist-info/METADATA,sha256=C-FKJi66DUTRsEPvxIam7tbqEn2MiaX4Of5mxG-eYhA,2262
858
- qontract_reconcile-0.10.1rc998.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
859
- qontract_reconcile-0.10.1rc998.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
860
- qontract_reconcile-0.10.1rc998.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
861
- qontract_reconcile-0.10.1rc998.dist-info/RECORD,,
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.current_version,
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 get_node_pools(ocm_api, spec.cluster.id):
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["id"]
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["id"]
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
- ocm_api: OCMBaseClient, spec: ClusterUpgradeSpec, now: datetime
1003
+ spec: ClusterUpgradeSpec, now: datetime
1006
1004
  ) -> UpgradePolicyHandler | None:
1007
- node_pools = get_node_pools(ocm_api, spec.cluster.id)
1008
- if node_pools:
1009
- for pool in node_pools:
1010
- pool_version_id = pool.get("version", {}).get("id")
1011
- pool_version = get_version(ocm_api, pool_version_id)["raw_id"]
1012
- if parse_semver(pool_version).match(f"<{spec.current_version}"):
1013
- next_schedule = (now + timedelta(minutes=MIN_DELTA_MINUTES)).strftime(
1014
- "%Y-%m-%dT%H:%M:%SZ"
1015
- )
1016
- return UpgradePolicyHandler(
1017
- action="create",
1018
- policy=NodePoolUpgradePolicy(
1019
- cluster=spec.cluster,
1020
- version=spec.current_version,
1021
- schedule_type="manual",
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(ocm_api, spec, now)
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 clusters
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 in clusters_by_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 [])
@@ -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