Skip to content

Commit 648300f

Browse files
committed
Add os_purpose field and output info.
I had to do some improvements how we check mandatory and non-mandatory properties. - We had no way to count warnings for properties. Address this by having a Property.check() function that returns a pair (ok, nowarn) and then wrappers is_ok() and is_nowarn(). - Prefix missing mandatory images with ERROR (as they are counted as such). - When in verbose mode, still report no of errors and warns of img. Signed-off-by: Kurt Garloff <[email protected]>
1 parent 63901e6 commit 648300f

File tree

1 file changed

+46
-18
lines changed

1 file changed

+46
-18
lines changed

Tests/iaas/image-metadata/image-md-check.py

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,38 +91,56 @@ def __init__(self, name, mand, values, desc = ""):
9191
else:
9292
self.desc = name
9393

94-
def is_ok(self, props, warn = ""):
94+
def check(self, props, warn):
9595
"Check validity of properties"
9696
if self.name in props:
97+
# Property exists but is not in allowed value list => ERROR
9798
if self.values and not props[self.name] in self.values:
9899
if warn:
99100
print(f'ERROR: Image "{warn}": value "{props[self.name]}" for property '
100101
f'"{self.name}" not allowed', file=sys.stderr)
101-
return False
102-
if not props[self.name] and not self.values:
103-
err = "ERROR"
104-
ret = False
102+
return (False, True)
103+
# Non-empty: OK
104+
if props[self.name]:
105+
return (True, True)
106+
# Empty property without an allowed value list => ERROR
107+
if not self.values:
108+
ok = True
105109
else:
106-
err = "WARNING"
107-
ret = True
108-
if not props[self.name] and (verbose or not self.values) and warn:
109-
print(f'{err}: Image "{warn}": empty value for property "{self.name}" not recommended',
110+
ok = False
111+
# Property empty => WARN (or ERROR if no allowed value list)
112+
if (verbose or not self.values) and warn:
113+
errstr = "WARNING" if ok else "ERROR"
114+
print(f'{errstr}: Image "{warn}": empty value for property "{self.name}" not recommended',
110115
file=sys.stderr)
111-
return ret
116+
return (ok, not ok)
117+
# Property does not exist but is mandatory => ERROR
112118
if self.ismand:
113119
if warn:
114120
print(f'ERROR: Image "{warn}": Mandatory property "{self.name}" is missing',
115121
file=sys.stderr)
116-
return False
122+
return (False, True)
123+
# Property does not exist => WARN/INFO
117124
if warn and verbose:
118125
print(f'INFO: Image "{warn}": Optional property "{self.name}" is missing') # , file=sys.stderr)
119-
return True
126+
return (True, False)
127+
128+
def is_ok(self, props, warn = ""):
129+
"Return True if no hard error is found"
130+
ok, nowarn = self.check(props, warn)
131+
return ok
132+
133+
def is_nowarn(self, props, warn = ""):
134+
"Return True if nothing to warn about is found"
135+
ok, nowarn = self.check(props, warn)
136+
return nowarn
120137

121138

122139
# From the image metadata specification
123140
# https://github.com/SovereignCloudStack/Docs/blob/main/Design-Docs/Image-Properties-Spec.md
124141
os_props = (Property("os_distro", True, ()),
125-
Property("os_version", True, ()))
142+
Property("os_version", True, ()),
143+
Property("os_purpose", False, ("generic", "minimal", "k8snode", "gpu", "network", "custom")))
126144
arch_props = (Property("architecture", True, ("x86_64", "aarch64", "risc-v"), "CPU architecture"),
127145
Property("hypervisor_type", True, ("qemu", "kvm", "xen", "hyper-v", "esxi", None)))
128146
hw_props = (Property("hw_rng_model", False, ("virtio", None), "Random Number Generator"),
@@ -204,16 +222,24 @@ def validate_imageMD(img, outd_list):
204222
# Now the hard work: Look at properties ....
205223
errors = 0
206224
warnings = 0
207-
# (1) recommended os_* and hw_*
225+
# (1) mandatory and recommended os_* and hw_*
208226
# (4) image_build_date, image_original_user, image_source (opt image_description)
209227
# (5) maintained_until, provided_until, uuid_validity, replace_frequency
210228
for prop in (*os_props, *arch_props, *hw_props):
211229
if not prop.is_ok(img, imgnm):
212230
errors += 1
231+
elif not prop.is_nowarn(img, ""):
232+
warnings += 1
233+
# We do not count missing optional fields in these
213234
for prop in (*build_props, *maint_props):
214235
if not prop.is_ok(img.properties, imgnm):
215236
errors += 1
237+
# Construct a name from os_distro and os_version
216238
constr_name = f"{img.os_distro} {img.os_version}"
239+
# TODO: Could add warnings for
240+
# - os_distro not being all-lowercase (they all should be acc. to
241+
# https://docs.openstack.org/glance/2025.1/admin/useful-image-properties.html
242+
# - os_version not matching regexp r'[0-9\.]*' (should be a numeric version no)
217243
# (3) os_hash
218244
if img.hash_algo not in ('sha256', 'sha512'):
219245
print(f'WARNING: Image "{imgnm}": no valid hash algorithm {img.hash_algo}', file=sys.stderr)
@@ -278,9 +304,9 @@ def validate_imageMD(img, outd_list):
278304
outd_list.append(imgnm)
279305
elif outd:
280306
outd_list.append(imgnm)
281-
# (2) sanity min_ram (>=64), min_disk (>= size)
282-
if img.min_ram < 64:
283-
print(f'WARNING: Image "{imgnm}": min_ram == {img.min_ram} MiB < 64 MiB', file=sys.stderr)
307+
# (2) sanity min_ram (>=32), min_disk (>= size)
308+
if img.min_ram < 32:
309+
print(f'WARNING: Image "{imgnm}": min_ram == {img.min_ram} MiB < 32 MiB', file=sys.stderr)
284310
warnings += 1
285311
if not img.min_ram:
286312
print(f'ERROR: Image "{imgnm}": min_ram == 0', file=sys.stderr)
@@ -304,6 +330,8 @@ def validate_imageMD(img, outd_list):
304330

305331
if not errors and verbose:
306332
print(f'Image "{imgnm}": All good ({warnings} warnings)')
333+
elif verbose:
334+
print(f'Image "{imgnm}": {errors} errors and {warnings} warnings')
307335
return errors
308336

309337

@@ -313,7 +341,7 @@ def report_stdimage_coverage(imgs):
313341
for inm in mand_images:
314342
if inm not in imgs:
315343
err += 1
316-
print(f'WARNING: Mandatory image "{inm}" is missing', file=sys.stderr)
344+
print(f'ERROR: Mandatory image "{inm}" is missing', file=sys.stderr)
317345
for inm in (*rec1_images, *rec2_images):
318346
if inm not in imgs:
319347
print(f'INFO: Recommended image "{inm}" is missing', file=sys.stderr)

0 commit comments

Comments
 (0)