Skip to content

Commit f930e54

Browse files
committed
Enforce one platform policy for GardenLinux canonical names
Signed-off-by: Tobias Wolf <[email protected]> On-behalf-of: SAP <[email protected]>
1 parent 64b1404 commit f930e54

File tree

4 files changed

+53
-79
lines changed

4 files changed

+53
-79
lines changed

src/gardenlinux/features/__main__.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"container_tag",
2424
"commit_id",
2525
"features",
26-
"platforms",
26+
"platform",
2727
"flags",
2828
"flavor",
2929
"elements",
@@ -147,7 +147,7 @@ def main() -> None:
147147
"flags",
148148
"flavor",
149149
"graph",
150-
"platforms",
150+
"platform",
151151
):
152152
if args.type == "graph" or len(args.ignore) > 0:
153153
features_parser = Parser(gardenlinux_root, feature_dir_name)
@@ -270,13 +270,13 @@ def print_output_from_features_parser(
270270
flavor, additional_filter_func=additional_filter_func
271271
)
272272
)
273-
elif (output_type in "platforms", "elements", "flags"):
273+
elif (output_type in "platform", "elements", "flags"):
274274
features_by_type = parser.filter_as_dict(
275275
flavor, additional_filter_func=additional_filter_func
276276
)
277277

278-
if output_type == "platforms":
279-
print(",".join(features_by_type["platform"]))
278+
if output_type == "platform":
279+
print(features_by_type["platform"][0])
280280
elif output_type == "elements":
281281
print(",".join(features_by_type["element"]))
282282
elif output_type == "flags":
@@ -305,8 +305,8 @@ def print_output_from_features_parser(
305305
print(cname)
306306
elif output_type == "container_name":
307307
print(RE_CAMEL_CASE_SPLITTER.sub("\\1_\\2", cname_base).lower())
308-
elif output_type == "platforms":
309-
print(",".join(features_by_type["platform"]))
308+
elif output_type == "platform":
309+
print(features_by_type["platform"][0])
310310
elif output_type == "elements":
311311
print(",".join(features_by_type["element"]))
312312
elif output_type == "flags":
@@ -331,7 +331,7 @@ def print_output_from_cname(output_type: str, cname_instance: CName) -> None:
331331
print(cname_instance.cname)
332332
elif output_type == "container_name":
333333
print(RE_CAMEL_CASE_SPLITTER.sub("\\1-\\2", cname_instance.flavor).lower())
334-
elif output_type == "platforms":
334+
elif output_type == "platform":
335335
print(cname_instance.feature_set_platform)
336336
elif output_type == "elements":
337337
print(cname_instance.feature_set_element)

src/gardenlinux/features/cname.py

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import re
88
from configparser import UNNAMED_SECTION, ConfigParser
9-
from os import PathLike
9+
from os import environ, PathLike
1010
from pathlib import Path
1111
from typing import List, Optional
1212

@@ -51,8 +51,9 @@ def __init__(self, cname, arch=None, commit_hash=None, version=None):
5151
self._commit_id = None
5252
self._feature_elements_cached = None
5353
self._feature_flags_cached = None
54-
self._feature_platforms_cached = None
54+
self._feature_platform_cached = None
5555
self._feature_set_cached = None
56+
self._flag_multiple_platforms = bool(environ.get("GL_ALLOW_FRANKENSTEIN", False))
5657
self._flavor = None
5758
self._version = None
5859

@@ -117,7 +118,7 @@ def cname(self) -> str:
117118
:return: (str) CName
118119
:since: 0.7.0
119120
"""
120-
assert self._flavor is not None, "CName flavor is not set!"
121+
121122
cname = self._flavor
122123

123124
if self._arch is not None:
@@ -229,14 +230,20 @@ def feature_set_platform(self) -> str:
229230
"""
230231
Returns the feature set of type "platform" for the cname parsed.
231232
232-
:return: (str) Feature set platforms
233+
:return: (str) Feature set platform
233234
:since: 0.11.0
234235
"""
235236

236-
if self._feature_platforms_cached is not None:
237-
return ",".join(self._feature_platforms_cached)
237+
if self._feature_platform_cached is not None:
238+
return self._feature_platform_cached
239+
240+
platforms = Parser().filter_as_dict(self.flavor)["platform"]
241+
242+
if self._flag_multiple_platforms:
243+
return ",".join(platforms)
238244

239-
return ",".join(Parser().filter_as_dict(self.flavor)["platform"])
245+
assert len(platforms) < 2; "Only one platform is supported"
246+
return platforms[0]
240247

241248
@property
242249
def release_metadata_string(self) -> str:
@@ -249,9 +256,12 @@ def release_metadata_string(self) -> str:
249256

250257
features = Parser().filter_as_dict(self.flavor)
251258

259+
if not self._flag_multiple_platforms:
260+
assert len(features["platform"]) < 2; "Only one platform is supported"
261+
252262
elements = ",".join(features["element"])
253263
flags = ",".join(features["flag"])
254-
platforms = ",".join(features["platform"])
264+
platform = ",".join(features["platform"])
255265

256266
metadata = f"""
257267
ID={GL_RELEASE_ID}
@@ -264,7 +274,7 @@ def release_metadata_string(self) -> str:
264274
BUG_REPORT_URL="{GL_BUG_REPORT_URL}"
265275
GARDENLINUX_CNAME="{self.cname}"
266276
GARDENLINUX_FEATURES="{self.feature_set}"
267-
GARDENLINUX_FEATURES_PLATFORMS="{platforms}"
277+
GARDENLINUX_FEATURES_PLATFORM="{platform}"
268278
GARDENLINUX_FEATURES_ELEMENTS="{elements}"
269279
GARDENLINUX_FEATURES_FLAGS="{flags}"
270280
GARDENLINUX_VERSION="{self.version}"
@@ -282,24 +292,9 @@ def platform(self) -> str:
282292
:return: (str) Feature set platforms
283293
:since: 0.7.0
284294
"""
285-
assert self._flavor is not None, "Flavor not set!"
286295

287296
return self.feature_set_platform
288297

289-
@property
290-
def platforms(self) -> List[str]:
291-
"""
292-
Returns the platforms for the cname parsed.
293-
294-
:return: (str) Platforms
295-
:since: 0.11.0
296-
"""
297-
298-
if self._feature_platforms_cached is not None:
299-
return self._feature_platforms_cached
300-
301-
return Parser().filter_as_dict(self.flavor)["platform"]
302-
303298
@property
304299
def version(self) -> Optional[str]:
305300
"""
@@ -350,7 +345,7 @@ def load_from_release_file(self, release_file: PathLike | str) -> None:
350345
"GARDENLINUX_FEATURES",
351346
"GARDENLINUX_FEATURES_ELEMENTS",
352347
"GARDENLINUX_FEATURES_FLAGS",
353-
"GARDENLINUX_FEATURES_PLATFORMS",
348+
"GARDENLINUX_FEATURES_PLATFORM",
354349
"GARDENLINUX_VERSION",
355350
):
356351
if not release_config.has_option(UNNAMED_SECTION, release_field):
@@ -395,9 +390,9 @@ def load_from_release_file(self, release_file: PathLike | str) -> None:
395390
UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS"
396391
).split(",")
397392

398-
self._feature_platforms_cached = release_config.get(
399-
UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS"
400-
).split(",")
393+
self._feature_platform_cached = release_config.get(
394+
UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORM"
395+
)
401396

402397
def save_to_release_file(
403398
self, release_file: PathLike | str, overwrite: Optional[bool] = False

src/gardenlinux/s3/__main__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ def main() -> None:
3636
if args.action == "download-artifacts-from-bucket":
3737
S3Artifacts(args.bucket).download_to_directory(args.cname, args.path)
3838
elif args.action == "upload-artifacts-to-bucket":
39-
S3Artifacts(args.bucket).upload_from_directory(args.cname, args.path, dry_run=args.dry_run)
39+
S3Artifacts(args.bucket).upload_from_directory(
40+
args.cname, args.path, dry_run=args.dry_run
41+
)

src/gardenlinux/s3/s3_artifacts.py

Lines changed: 19 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import yaml
2020

2121
from .bucket import Bucket
22+
from ..features import CName
2223

2324

2425
class S3Artifacts(object):
@@ -116,36 +117,20 @@ def upload_from_directory(
116117

117118
artifacts_dir = Path(artifacts_dir)
118119

120+
cname_object = CName(cname)
121+
119122
if not artifacts_dir.is_dir():
120123
raise RuntimeError(f"Artifacts directory given is invalid: {artifacts_dir}")
121124

122125
release_file = artifacts_dir.joinpath(f"{cname}.release")
123126
release_timestamp = stat(release_file).st_ctime
124127

125-
release_config = ConfigParser(allow_unnamed_section=True)
126-
release_config.read(release_file)
127-
128-
# Get architecture from the GARDENLINUX_CNAME (second to last element when split by -)
129-
release_cname = release_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME")
130-
cname_parts = release_cname.split("-")
131-
if len(cname_parts) < 2:
132-
raise RuntimeError(f"Invalid GARDENLINUX_CNAME format in release file: {release_cname}")
133-
arch = cname_parts[-2] # Second to last element is the architecture
128+
cname_object.load_from_release_file(release_file)
134129

135-
commit_id = release_config.get(UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID")
136-
expected_cname = f"{release_cname}-{commit_id}"
137-
138-
# Verify the provided cname matches the release file
139-
if cname != expected_cname:
140-
raise RuntimeError(
141-
f"Release file cname does not match provided cname: {expected_cname} != {cname}"
142-
)
143-
144-
commit_hash = release_config.get(UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG")
145-
146-
feature_set = release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES")
147-
feature_list = feature_set.split(",")
130+
if cname_object.arch is None:
131+
raise RuntimeError("Architecture could not be determined from cname")
148132

133+
feature_list = cname_object.feature_set
149134
requirements_file = artifacts_dir.joinpath(f"{cname}.requirements")
150135
require_uefi = None
151136
secureboot = None
@@ -168,33 +153,25 @@ def upload_from_directory(
168153
if secureboot is None:
169154
secureboot = "_trustedboot" in feature_list
170155

171-
version = release_config.get(UNNAMED_SECTION, "GARDENLINUX_VERSION")
172-
platform = release_config.get(UNNAMED_SECTION, "GARDENLINUX_PLATFORM")
173-
174156
metadata = {
175-
"platform": platform,
176-
"architecture": arch,
157+
"platform": cname_object.feature_set_platform,
158+
"architecture": cname_object.arch,
177159
"base_image": None,
178-
"build_committish": commit_hash,
160+
"build_committish": cname_object.commit_hash,
179161
"build_timestamp": datetime.fromtimestamp(release_timestamp).isoformat(),
180-
"gardenlinux_epoch": int(version.split(".", 1)[0]),
162+
"gardenlinux_epoch": int(cname_object.version.split(".", 1)[0]),
181163
"logs": None,
182-
"modifiers": feature_list,
164+
"modifiers": cname_object.feature_set,
183165
"require_uefi": require_uefi,
184166
"secureboot": secureboot,
185167
"published_image_metadata": None,
186168
"s3_bucket": self._bucket.name,
187169
"s3_key": f"meta/singles/{cname}",
188170
"test_result": None,
189-
"version": version,
171+
"version": cname_object.version,
190172
"paths": [],
191173
}
192174

193-
if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT"):
194-
metadata["platform_variant"] = release_config.get(
195-
UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT"
196-
)
197-
198175
re_object = re.compile("[^a-zA-Z0-9\\s+\\-=.\\_:/@]")
199176

200177
for artifact in artifacts_dir.iterdir():
@@ -224,16 +201,14 @@ def upload_from_directory(
224201
}
225202

226203
s3_tags = {
227-
"architecture": re_object.sub("+", arch),
228-
"platform": re_object.sub("+", platform),
229-
"version": re_object.sub("+", version),
230-
"committish": commit_hash,
204+
"architecture": re_object.sub("+", cname_object.arch),
205+
"platform": re_object.sub("+", cname_object.platform),
206+
"version": re_object.sub("+", cname_object.version),
207+
"committish": cname_object.commit_hash,
231208
"md5sum": md5sum,
232209
"sha256sum": sha256sum,
233210
}
234211

235-
metadata["paths"].append(artifact_metadata)
236-
237212
if not dry_run:
238213
if delete_before_push:
239214
self._bucket.delete_objects(Delete={"Objects": [{"Key": s3_key}]})
@@ -244,6 +219,8 @@ def upload_from_directory(
244219
ExtraArgs={"Tagging": urlencode(s3_tags)},
245220
)
246221

222+
metadata["paths"].append(artifact_metadata)
223+
247224
if dry_run:
248225
print(yaml.dump(metadata, sort_keys=False))
249226
else:

0 commit comments

Comments
 (0)