Skip to content

Commit 5cebb93

Browse files
committed
adapt check pertaining to scs-0102-image-metadata
Signed-off-by: Matthias Büchse <[email protected]>
1 parent 0a822e8 commit 5cebb93

File tree

8 files changed

+493
-446
lines changed

8 files changed

+493
-446
lines changed

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

Lines changed: 0 additions & 424 deletions
This file was deleted.

Tests/iaas/openstack_test.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,20 @@
1515
import openstack
1616

1717
from scs_0100_flavor_naming.flavor_names_check import \
18-
compute_scs_flavors, compute_scs_0100_syntax_check, compute_scs_0100_semantics_check, compute_flavor_name_check
18+
compute_scs_flavors, compute_scs_0100_syntax_check, compute_scs_0100_semantics_check
1919
from scs_0101_entropy.entropy_check import \
2020
compute_scs_0101_image_property, compute_scs_0101_flavor_property, compute_canonical_image, \
2121
compute_collected_vm_output, compute_scs_0101_entropy_avail, compute_scs_0101_rngd, \
22-
compute_scs_0101_fips_test, compute_scs_0101_entropy_check
22+
compute_scs_0101_fips_test
23+
from scs_0102_image_metadata.image_metadata import \
24+
compute_scs_0102_prop_architecture, compute_scs_0102_prop_hash_algo, compute_scs_0102_prop_min_disk, \
25+
compute_scs_0102_prop_min_ram, compute_scs_0102_prop_os_version, compute_scs_0102_prop_os_distro, \
26+
compute_scs_0102_prop_hw_disk_bus, compute_scs_0102_prop_hypervisor_type, compute_scs_0102_prop_hw_rng_model, \
27+
compute_scs_0102_prop_image_build_date, compute_scs_0102_prop_image_original_user, \
28+
compute_scs_0102_prop_image_source, compute_scs_0102_prop_image_description, \
29+
compute_scs_0102_prop_replace_frequency, compute_scs_0102_prop_provided_until, \
30+
compute_scs_0102_prop_uuid_validity, compute_scs_0102_prop_hotfix_hours, \
31+
compute_scs_0102_image_recency
2332

2433

2534
logger = logging.getLogger(__name__)
@@ -36,22 +45,54 @@ def usage(rcode=1, file=sys.stderr):
3645

3746
def make_container(cloud):
3847
c = Container()
39-
# scs_0100_flavor_naming
48+
# basic support attributes shared by multiple testcases
4049
c.add_function('conn', lambda _: openstack.connect(cloud=cloud, timeout=32))
4150
c.add_function('flavors', lambda c: list(c.conn.list_flavors(get_extra=True)))
4251
c.add_function('images', lambda c: [img for img in c.conn.list_images() if img.visibility in ('public', 'community')])
52+
# scs_0100_flavor_naming
4353
c.add_function('scs_flavors', lambda c: compute_scs_flavors(c.flavors))
4454
c.add_function('scs_0100_syntax_check', lambda c: compute_scs_0100_syntax_check(c.scs_flavors))
4555
c.add_function('scs_0100_semantics_check', lambda c: compute_scs_0100_semantics_check(c.scs_flavors))
46-
c.add_function('flavor_name_check', lambda c: compute_flavor_name_check(c.scs_0100_syntax_check, c.scs_0100_semantics_check))
47-
c.add_function('scs_0101_image_property', lambda c: compute_scs_0101_image_property(c.images))
48-
c.add_function('scs_0101_flavor_property', lambda c: compute_scs_0101_flavor_property(c.flavors))
56+
c.add_function('flavor_name_check', lambda c: all((
57+
c.scs_0100_syntax_check, c.scs_0100_semantics_check,
58+
)))
59+
# scs_0101_entropy
4960
c.add_function('canonical_image', lambda c: compute_canonical_image(c.images))
5061
c.add_function('collected_vm_output', lambda c: compute_collected_vm_output(c.conn, c.flavors, c.canonical_image))
62+
c.add_function('scs_0101_image_property', lambda c: compute_scs_0101_image_property(c.images))
63+
c.add_function('scs_0101_flavor_property', lambda c: compute_scs_0101_flavor_property(c.flavors))
5164
c.add_function('scs_0101_entropy_avail', lambda c: compute_scs_0101_entropy_avail(c.collected_vm_output, c.canonical_image.name))
5265
c.add_function('scs_0101_rngd', lambda c: compute_scs_0101_rngd(c.collected_vm_output, c.canonical_image.name))
5366
c.add_function('scs_0101_fips_test', lambda c: compute_scs_0101_fips_test(c.collected_vm_output, c.canonical_image.name))
54-
c.add_function('entropy_check', lambda c: compute_scs_0101_entropy_check(c.scs_0101_entropy_avail, c.scs_0101_fips_test))
67+
c.add_function('entropy_check', lambda c: all((
68+
c.scs_0101_entropy_avail, c.scs_0101_fips_test,
69+
)))
70+
# scs_0102_image_metadata
71+
c.add_function('scs_0102_prop_architecture', lambda c: compute_scs_0102_prop_architecture(c.images))
72+
c.add_function('scs_0102_prop_hash_algo', lambda c: compute_scs_0102_prop_hash_algo(c.images))
73+
c.add_function('scs_0102_prop_min_disk', lambda c: compute_scs_0102_prop_min_disk(c.images))
74+
c.add_function('scs_0102_prop_min_ram', lambda c: compute_scs_0102_prop_min_ram(c.images))
75+
c.add_function('scs_0102_prop_os_version', lambda c: compute_scs_0102_prop_os_version(c.images))
76+
c.add_function('scs_0102_prop_os_distro', lambda c: compute_scs_0102_prop_os_distro(c.images))
77+
c.add_function('scs_0102_prop_hw_disk_bus', lambda c: compute_scs_0102_prop_hw_disk_bus(c.images))
78+
c.add_function('scs_0102_prop_hypervisor_type', lambda c: compute_scs_0102_prop_hypervisor_type(c.images))
79+
c.add_function('scs_0102_prop_hw_rng_model', lambda c: compute_scs_0102_prop_hw_rng_model(c.images))
80+
c.add_function('scs_0102_prop_image_build_date', lambda c: compute_scs_0102_prop_image_build_date(c.images))
81+
c.add_function('scs_0102_prop_image_original_user', lambda c: compute_scs_0102_prop_image_original_user(c.images))
82+
c.add_function('scs_0102_prop_image_source', lambda c: compute_scs_0102_prop_image_source(c.images))
83+
c.add_function('scs_0102_prop_image_description', lambda c: compute_scs_0102_prop_image_description(c.images))
84+
c.add_function('scs_0102_prop_replace_frequency', lambda c: compute_scs_0102_prop_replace_frequency(c.images))
85+
c.add_function('scs_0102_prop_provided_until', lambda c: compute_scs_0102_prop_provided_until(c.images))
86+
c.add_function('scs_0102_prop_uuid_validity', lambda c: compute_scs_0102_prop_uuid_validity(c.images))
87+
c.add_function('scs_0102_prop_hotfix_hours', lambda c: compute_scs_0102_prop_hotfix_hours(c.images))
88+
c.add_function('scs_0102_image_recency', lambda c: compute_scs_0102_image_recency(c.images))
89+
c.add_function('image_metadata_check', lambda c: all((
90+
c.scs_0102_prop_architecture, c.scs_0102_prop_min_disk, c.scs_0102_prop_min_ram, c.scs_0102_prop_os_version,
91+
c.scs_0102_prop_os_distro, c.scs_0102_prop_hw_disk_bus, c.scs_0102_prop_image_build_date,
92+
c.scs_0102_prop_image_original_user, c.scs_0102_prop_image_source, c.scs_0102_prop_image_description,
93+
c.scs_0102_prop_replace_frequency, c.scs_0102_prop_provided_until, c.scs_0102_prop_uuid_validity,
94+
c.scs_0102_image_recency,
95+
)))
5596
return c
5697

5798

@@ -82,6 +123,7 @@ def __init__(self):
82123
def __getattr__(self, key):
83124
val = self._values.get(key)
84125
if val is None:
126+
logger.debug(f'... {key}')
85127
try:
86128
ret = self._functions[key](self)
87129
except BaseException as e:

Tests/iaas/scs_0100_flavor_naming/flavor_names_check.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,3 @@ def compute_scs_0100_semantics_check(scs_flavors: list) -> bool:
7676
if problems:
7777
logger.error(f"scs-100-semantics-check: flavor(s) failed: {', '.join(sorted(problems))}")
7878
return not problems
79-
80-
81-
def compute_flavor_name_check(syntax_check_result, semantics_check_result):
82-
return syntax_check_result and semantics_check_result

Tests/iaas/scs_0101_entropy/entropy-check.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222
import openstack.cloud
2323

2424

25-
try:
26-
from . import entropy_check
27-
except ImportError:
28-
import entropy_check
25+
import entropy_check
2926

3027

3128
logger = logging.getLogger(__name__)

Tests/iaas/scs_0101_entropy/entropy_check.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,6 @@ def compute_scs_0101_virtio_rng(collected_vm_output, image_name):
149149
logger.critical(f"Couldn't check VM '{image_name}' recommends", exc_info=True)
150150

151151

152-
def compute_scs_0101_entropy_check(scs_0101_entropy_avail_result, scs_0101_fips_test_result):
153-
# note: this is about the mandatory things
154-
return scs_0101_entropy_avail_result and scs_0101_fips_test_result
155-
156-
157152
class TestEnvironment:
158153
def __init__(self, conn):
159154
self.conn = conn
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python3
2+
# vim: set ts=4 sw=4 et:
3+
#
4+
# SCS/Docs/tools/image-md-check.py
5+
6+
"""
7+
Retrieve metadata from (public) images and check for compliance
8+
with SCS specifications.
9+
10+
(c) Kurt Garloff <[email protected]>, 09/2022
11+
SPDX-License-Identifier: CC-BY-SA-4.0
12+
"""
13+
14+
from collections import Counter
15+
import getopt
16+
import logging
17+
import os
18+
import sys
19+
20+
import openstack
21+
22+
23+
from image_metadata import \
24+
compute_scs_0102_prop_architecture, compute_scs_0102_prop_hash_algo, compute_scs_0102_prop_min_disk, \
25+
compute_scs_0102_prop_min_ram, compute_scs_0102_prop_os_version, compute_scs_0102_prop_os_distro, \
26+
compute_scs_0102_prop_hw_disk_bus, compute_scs_0102_prop_hypervisor_type, compute_scs_0102_prop_hw_rng_model, \
27+
compute_scs_0102_prop_image_build_date, compute_scs_0102_prop_image_original_user, \
28+
compute_scs_0102_prop_image_source, compute_scs_0102_prop_image_description, \
29+
compute_scs_0102_prop_replace_frequency, compute_scs_0102_prop_provided_until, \
30+
compute_scs_0102_prop_uuid_validity, compute_scs_0102_prop_hotfix_hours, \
31+
compute_scs_0102_image_recency
32+
33+
34+
logger = logging.getLogger(__name__)
35+
36+
37+
def usage(ret):
38+
"Usage information"
39+
print("Usage: image-md-check.py [options] [images]")
40+
print("image-md-check.py will create a report on public images by retrieving")
41+
print(" the image metadata (properties) and comparing this against the image")
42+
print(" metadata spec from SCS.")
43+
print("Options: --os-cloud CLOUDNAME: Use this cloud config, default is $OS_CLOUD")
44+
print(" -p/--private : Also consider private images")
45+
print(" -v/--verbose : Be more verbose")
46+
print(" -h/--help : Print this usage information")
47+
print(" [-V/--image-visibility VIS_LIST] : filters images by visibility")
48+
print(" (default: 'public,community'; use '*' to disable)")
49+
print("If you pass images, only these will be validated, otherwise all images")
50+
print("(filtered according to -p, -V) from the catalog will be processed.")
51+
sys.exit(ret)
52+
53+
54+
def main(argv):
55+
"Main entry point"
56+
# configure logging, disable verbose library logging
57+
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
58+
openstack.enable_logging(debug=False)
59+
image_visibility = set()
60+
private = False
61+
cloud = os.environ.get("OS_CLOUD")
62+
err = 0
63+
try:
64+
opts, args = getopt.gnu_getopt(argv[1:], "phvc:sV:",
65+
("private", "help", "os-cloud=", "verbose", "skip-completeness", "image-visibility="))
66+
except getopt.GetoptError: # as exc:
67+
print("CRITICAL: Command-line syntax error", file=sys.stderr)
68+
usage(1)
69+
for opt in opts:
70+
if opt[0] == "-h" or opt[0] == "--help":
71+
usage(0)
72+
elif opt[0] == "-p" or opt[0] == "--private":
73+
private = True # only keep this for backwards compatibility (we have -V now)
74+
elif opt[0] == "-v" or opt[0] == "--verbose":
75+
logging.getLogger().setLevel(logging.DEBUG)
76+
elif opt[0] == "-s" or opt[0] == "--skip-completeness":
77+
logger.info("ignoring obsolete command-line option -s")
78+
elif opt[0] == "-c" or opt[0] == "--os-cloud":
79+
cloud = opt[1]
80+
if opt[0] == "-V" or opt[0] == "--image-visibility":
81+
image_visibility.update([v.strip() for v in opt[1].split(',')])
82+
image_names = args
83+
if not cloud:
84+
print("CRITICAL: Need to specify --os-cloud or set OS_CLOUD environment.", file=sys.stderr)
85+
usage(1)
86+
if not image_visibility:
87+
image_visibility.update(("public", "community"))
88+
if private:
89+
image_visibility.add("private")
90+
try:
91+
conn = openstack.connect(cloud=cloud, timeout=24)
92+
all_images = list(conn.image.images())
93+
if '*' not in image_visibility:
94+
logger.debug(f"Images: filter for visibility {', '.join(sorted(image_visibility))}")
95+
all_images = [img for img in all_images if img.visibility in image_visibility]
96+
all_image_names = [f"{img.name} ({img.visibility})" for img in all_images]
97+
logger.debug(f"Images: {', '.join(all_image_names) or '(NONE)'}")
98+
by_name = {img.name: img for img in all_images}
99+
if len(by_name) != len(all_images):
100+
counter = Counter([img.name for img in all_images])
101+
duplicates = [name for name, count in counter.items() if count > 1]
102+
print(f'WARNING: duplicate names detected: {", ".join(duplicates)}', file=sys.stderr)
103+
if image_names:
104+
images = [by_name[nm] for nm in image_names]
105+
else:
106+
images = all_images
107+
result = all((
108+
compute_scs_0102_prop_architecture(images),
109+
compute_scs_0102_prop_min_disk(images),
110+
compute_scs_0102_prop_min_ram(images),
111+
compute_scs_0102_prop_os_version(images),
112+
compute_scs_0102_prop_os_distro(images),
113+
compute_scs_0102_prop_hw_disk_bus(images),
114+
compute_scs_0102_prop_image_build_date(images),
115+
compute_scs_0102_prop_image_original_user(images),
116+
compute_scs_0102_prop_image_source(images),
117+
compute_scs_0102_prop_image_description(images),
118+
compute_scs_0102_prop_replace_frequency(images),
119+
compute_scs_0102_prop_provided_until(images),
120+
compute_scs_0102_prop_uuid_validity(images),
121+
compute_scs_0102_prop_hotfix_hours(images),
122+
compute_scs_0102_image_recency(images),
123+
))
124+
print("image-metadata-check: " + ('FAIL', 'PASS')[min(1, result)])
125+
# recommended stuff
126+
_ = all((
127+
compute_scs_0102_prop_hash_algo(images),
128+
compute_scs_0102_prop_hypervisor_type(images),
129+
compute_scs_0102_prop_hw_rng_model(images),
130+
))
131+
except BaseException as exc:
132+
print(f"CRITICAL: {exc!r}", file=sys.stderr)
133+
return 1 + err
134+
return err
135+
136+
137+
if __name__ == "__main__":
138+
sys.exit(main(sys.argv))

0 commit comments

Comments
 (0)