qontract-reconcile 0.10.1rc999__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.1rc999
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
@@ -778,7 +779,7 @@ reconcile/utils/ocm/__init__.py,sha256=xv7CJp7K9LCQfa4gL_W0MMCOD1P4qOy8t5aZj1xXN
778
779
  reconcile/utils/ocm/addons.py,sha256=_LDdJ-gapM3s5exKlIUt-MlXZTAUoHezbYBU0QmvfWQ,7335
779
780
  reconcile/utils/ocm/base.py,sha256=iL_uMN03URDisWHpsaGGto_pLx652epUkuld_9ctx5o,14555
780
781
  reconcile/utils/ocm/cluster_groups.py,sha256=F8oqVqN_4QUnGL0K61zZhoYIzJeP57EcmZpwmoV0mr4,1751
781
- reconcile/utils/ocm/clusters.py,sha256=Fn4swizm1qq-XiNlIZ9SvahkftWAyNT8hF4kqRBpK4g,8287
782
+ reconcile/utils/ocm/clusters.py,sha256=VwFucqOtXfHZABZLsMLxvAhBTwVg6h9L7WDDdJUaB1w,7962
782
783
  reconcile/utils/ocm/identity_providers.py,sha256=dKed09N8iWmn39tI_MpwgVe47x23eLsknGbjMUxtwr4,2175
783
784
  reconcile/utils/ocm/label_sources.py,sha256=ES_5VP4X6gsRxMFZ95WgbwE_HqqIUo_JRjHjdGYw6Ss,1846
784
785
  reconcile/utils/ocm/labels.py,sha256=aCsL5QkRk32hZeJwsSJuCCT9sbojWMn8LL5Zo-aoFb4,5916
@@ -856,8 +857,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
856
857
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
857
858
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
858
859
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
859
- qontract_reconcile-0.10.1rc999.dist-info/METADATA,sha256=enfD2JTSaUoouoeieJwg_fjf-OzHHSLEBR7icP_Nk1Y,2262
860
- qontract_reconcile-0.10.1rc999.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
861
- qontract_reconcile-0.10.1rc999.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
862
- qontract_reconcile-0.10.1rc999.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
863
- qontract_reconcile-0.10.1rc999.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
  ]
@@ -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