Skip to content

Commit 2b4d9ec

Browse files
committed
✨ feat(scripts): Improve generate_versions.py
Make the tool work with more providers/Cluster Stacks. AI-assisted: OpenCode.ai Signed-off-by: Jan Schoone <jan.schoone@uhurutec.com>
1 parent b663197 commit 2b4d9ec

1 file changed

Lines changed: 94 additions & 42 deletions

File tree

hack/generate_version.py

Lines changed: 94 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,30 @@
44
Generate version-specific hierarchy of the cluster-stacks repo.
55
66
This is a helper script to generate a version-specific folder structure
7-
of the base cluster-stacks implementation. The source directory is in
8-
`cluster-stacks/providers/openstack/scs` and supported versions are maintained
9-
in a file `versions.yaml` within the source directory. The source directory is a
10-
valid variant of this repo, pinned to the smallest supported version.
7+
of the base cluster-stacks implementation. The source directory is provider
8+
and stack specific (e.g., providers/openstack/scs2). Supported versions are
9+
maintained in a file `versions.yaml` within the source directory.
1110
"""
1211

1312

1413
import argparse
1514
import logging
15+
import os
1616
import shutil
1717
import subprocess
1818
import sys
19-
from pathlib import Path, PosixPath
19+
from pathlib import Path
2020

2121
import yaml
2222
import requests
2323

2424
BASE_PATH = Path(__file__).parent.parent
25-
SOURCE_PATH = BASE_PATH.joinpath("providers", "openstack", "scs")
26-
DEFAULT_TARGET_PATH = BASE_PATH.joinpath("providers", "openstack", "out")
25+
26+
# These will be set by command-line arguments in __main__
27+
SOURCE_PATH: Path
28+
DEFAULT_TARGET_PATH: Path
29+
PROVIDER: str
30+
STACK: str
2731

2832
logger = logging.getLogger(__name__)
2933

@@ -61,7 +65,7 @@ def get_dash_version(version: str) -> str:
6165
return "-".join(version.split(".")[0:2])
6266

6367

64-
def create_output_dir(version: str) -> PosixPath:
68+
def create_output_dir(version: str) -> Path:
6569
"""
6670
Prepare output directory by creating it and copying the source files over.
6771
This overwrites files existing inside the output directory, as those
@@ -94,7 +98,7 @@ def create_output_dir(version: str) -> PosixPath:
9498
return out_dir
9599

96100

97-
def readfile(path: PosixPath):
101+
def readfile(path: Path):
98102
"""
99103
Helper function to read yaml configuration files.
100104
@@ -104,18 +108,19 @@ def readfile(path: PosixPath):
104108
Returns:
105109
Content of the yaml configuration file.
106110
"""
107-
# TODO: yaml.safe_load either returns a list or dict,
108-
# depending on the structure of the yaml file. This can be improved / refactored.
111+
# TODO: yaml.safe_load either returns a list or dict,
112+
# depending on the structure of yaml file. This can be improved / refactored.
109113
with open(path, encoding="utf-8") as stream:
110114
try:
111115
content = yaml.safe_load(stream)
112116
except yaml.YAMLError as exc:
113117
print(exc)
118+
return content
114119

115120
return content
116121

117122

118-
def writefile(path: PosixPath, content):
123+
def writefile(path: Path, content):
119124
"""
120125
Helper function to write content to a yaml configuration file.
121126
@@ -131,7 +136,7 @@ def writefile(path: PosixPath, content):
131136

132137

133138
def update_cluster_addon(
134-
target: PosixPath, build: bool, build_verbose: bool, **versions
139+
target: Path, build: bool, build_verbose: bool, **versions
135140
):
136141
"""
137142
Update relevant files inside the cluster-stacks/<path>/cluster-addon subdirectory
@@ -148,16 +153,22 @@ def update_cluster_addon(
148153
logger.info("Updating %s", target)
149154
content = readfile(target)
150155

151-
for dep in content["dependencies"]:
152-
if dep["name"] == "openstack-cinder-csi":
153-
dep["version"] = versions["cinder_csi"]
154-
155-
if dep["name"] == "openstack-cloud-controller-manager":
156-
dep["version"] = versions["occm"]
157-
158-
content["name"] = (
159-
f"openstack-scs-{get_dash_version(versions['kubernetes'])}-cluster-addon"
160-
)
156+
# Update provider-specific dependencies
157+
if PROVIDER == "openstack":
158+
for dep in content["dependencies"]:
159+
if dep["name"] == "openstack-cinder-csi":
160+
dep["version"] = versions.get("cinder_csi", dep["version"])
161+
if dep["name"] == "openstack-cloud-controller-manager":
162+
dep["version"] = versions.get("occm", dep["version"])
163+
# Add other provider-specific logic here as needed
164+
165+
# Update chart name with provider/stack info
166+
k8s_ver = get_dash_version(versions['kubernetes'])
167+
content["name"] = f"{PROVIDER}-{STACK}-{k8s_ver}-cluster-addon"
168+
169+
# Update chart name with provider/stack info
170+
k8s_ver = get_dash_version(versions['kubernetes'])
171+
content["name"] = f"{PROVIDER}-{STACK}-{k8s_ver}-cluster-addon"
161172

162173
writefile(target, content)
163174

@@ -172,7 +183,7 @@ def update_cluster_addon(
172183
)
173184

174185

175-
def update_csctl_conf(target: PosixPath, **versions):
186+
def update_csctl_conf(target: Path, **versions):
176187
"""
177188
Function to update csctl configuration file.
178189
@@ -191,7 +202,7 @@ def update_csctl_conf(target: PosixPath, **versions):
191202
writefile(target, content)
192203

193204

194-
def update_cluster_class(target: PosixPath, **kwargs):
205+
def update_cluster_class(target: Path, **kwargs):
195206
"""
196207
Update relevant files inside the cluster-stacks/<path>/cluster-class subdirectory.
197208
@@ -208,22 +219,26 @@ def update_cluster_class(target: PosixPath, **kwargs):
208219
logger.info("Updating %s", chart_file)
209220
content = readfile(chart_file)
210221
version = get_dash_version(kwargs["kubernetes"])
211-
content["name"] = f"openstack-scs-{version}-cluster-class"
222+
content["name"] = f"{PROVIDER}-{STACK}-{version}-cluster-class"
212223

213224
writefile(chart_file, content)
214225

215-
logger.info("Updating %s", values_file)
216-
content = readfile(values_file)
217-
218-
content["images"]["controlPlane"][
219-
"name"
220-
] = f"ubuntu-capi-image-v{kwargs['kubernetes']}"
221-
content["images"]["worker"]["name"] = f"ubuntu-capi-image-v{kwargs['kubernetes']}"
222-
223-
writefile(values_file, content)
224-
225-
226-
def update_node_images(target: PosixPath, **kwargs):
226+
# Update values.yaml (provider-specific)
227+
if values_file.exists():
228+
logger.info("Updating %s", values_file)
229+
content = readfile(values_file)
230+
231+
# OpenStack-specific image updates (only if content exists and has images)
232+
if content and PROVIDER == "openstack" and "images" in content:
233+
if "controlPlane" in content["images"]:
234+
content["images"]["controlPlane"]["name"] = f"ubuntu-capi-image-v{kwargs['kubernetes']}"
235+
if "worker" in content["images"]:
236+
content["images"]["worker"]["name"] = f"ubuntu-capi-image-v{kwargs['kubernetes']}"
237+
238+
writefile(values_file, content)
239+
240+
241+
def update_node_images(target: Path, **kwargs):
227242
"""
228243
Update relevant files inside the cluster-stacks/<path>/node-images subdirectory.
229244
@@ -258,8 +273,26 @@ def update_node_images(target: PosixPath, **kwargs):
258273
if __name__ == "__main__":
259274
LOGFORMAT = "%(asctime)s - %(levelname)s: %(message)s"
260275
logging.basicConfig(level=logging.INFO, encoding="utf-8", format=LOGFORMAT)
276+
261277
# Initialize arg parser
262-
parser = argparse.ArgumentParser()
278+
parser = argparse.ArgumentParser(
279+
description="Generate version-specific cluster stack manifests"
280+
)
281+
parser.add_argument(
282+
"--provider",
283+
type=str,
284+
default=os.environ.get("PROVIDER", "openstack"),
285+
help="Provider name (e.g., openstack, docker). Can be set via PROVIDER env var.",
286+
)
287+
parser.add_argument(
288+
"--cluster-stack",
289+
"--cs-name",
290+
"--stack", # Keep --stack for backwards compatibility
291+
dest="stack",
292+
type=str,
293+
default=os.environ.get("CLUSTER_STACK", os.environ.get("STACK", "scs2")),
294+
help="Cluster stack name (e.g., scs2, scs, ferrol). Can be set via CLUSTER_STACK or STACK env var.",
295+
)
263296
parser.add_argument(
264297
"-t",
265298
"--target-version",
@@ -274,6 +307,23 @@ def update_node_images(target: PosixPath, **kwargs):
274307
"--build-verbose", action="store_false", help="Show output of helm build"
275308
)
276309
args = parser.parse_args()
310+
311+
# Set global provider/stack paths
312+
PROVIDER = args.provider
313+
STACK = args.stack
314+
SOURCE_PATH = BASE_PATH / "providers" / PROVIDER / STACK
315+
DEFAULT_TARGET_PATH = BASE_PATH / "providers" / PROVIDER / "out"
316+
317+
# Validate source path exists
318+
if not SOURCE_PATH.exists():
319+
print(f"❌ Source directory not found: {SOURCE_PATH}")
320+
print(f" Available stacks for {PROVIDER}:")
321+
provider_path = BASE_PATH.joinpath("providers", PROVIDER)
322+
if provider_path.exists():
323+
for stack_dir in provider_path.iterdir():
324+
if stack_dir.is_dir() and stack_dir.name != "out":
325+
print(f" - {stack_dir.name}")
326+
sys.exit(1)
277327

278328
# Load supported target versions
279329
sup_versions = load_supported_versions()
@@ -304,6 +354,8 @@ def update_node_images(target: PosixPath, **kwargs):
304354
)
305355
update_csctl_conf(output_dir.joinpath("csctl.yaml"), **tv)
306356
update_cluster_class(output_dir.joinpath("cluster-class"), **tv)
307-
update_node_images(
308-
output_dir.joinpath("cluster-class", "templates", "image.yaml"), **tv
309-
)
357+
358+
# Update node images only if image.yaml exists (OpenStack-specific)
359+
image_yaml = output_dir.joinpath("cluster-class", "templates", "image.yaml")
360+
if image_yaml.exists():
361+
update_node_images(image_yaml, **tv)

0 commit comments

Comments
 (0)