@@ -100,6 +100,7 @@ def is_outdated(img, now=time.time()):
100100
101101
102102def _log_error (cause , offenders , channel = logging .ERROR ):
103+ """helper function to construct report messages"""
103104 if not offenders :
104105 return []
105106 names = [img .name for img in offenders ]
@@ -111,36 +112,34 @@ def _log_error(cause, offenders, channel=logging.ERROR):
111112def compute_scs_0102_prop_architecture (images , architectures = ARCHITECTURES ):
112113 """This test ensures that each image has a proper value for the property `architecture`."""
113114 offenders = [img for img in images if img .architecture not in architectures ]
114- _log_error ('property architecture not correct' , offenders )
115- return not offenders
115+ return _log_error ('property architecture not correct' , offenders )
116116
117117
118118# NOTE I think this is a recommendation
119119def compute_scs_0102_prop_hash_algo (images ):
120120 """This test ensures that each image has a proper value for the property `hash_algo`."""
121121 offenders = [img for img in images if img .hash_algo not in ('sha256' , 'sha512' )]
122- _log_error ('property hash_algo invalid' , offenders )
123- return not offenders
122+ return _log_error ('property hash_algo invalid' , offenders )
124123
125124
126125def compute_scs_0102_prop_min_disk (images ):
127126 """This test ensures that each image has a proper value for the property `min_disk`."""
128127 offenders1 = [img for img in images if not img .min_disk ]
129- _log_error ('property min_disk not set' , offenders1 )
130128 offenders2 = [img for img in images if img .min_disk and img .min_disk * GIB < img .size ]
131- _log_error ('property min_disk smaller than size' , offenders2 )
132- return not offenders1 and not offenders2
129+ return (
130+ _log_error ('property min_disk not set' , offenders1 ) +
131+ _log_error ('property min_disk smaller than size' , offenders2 )
132+ )
133133
134134
135135def compute_scs_0102_prop_min_ram (images ):
136136 """This test ensures that each image has a proper value for the property `min_ram`."""
137- offenders1 = [img for img in images if not img .min_ram ]
138- _log_error ('property min_ram not set' , offenders1 )
139137 # emit a warning im RAM really low
140138 # NOTE this will probably only get noticed if an error occurs as well
141139 offenders2 = [img for img in images if img .min_ram and img .min_ram < 64 ]
142140 _log_error ('property min_ram < 64 MiB' , offenders2 , channel = logging .WARNING )
143- return not offenders1
141+ offenders1 = [img for img in images if not img .min_ram ]
142+ return _log_error ('property min_ram not set' , offenders1 )
144143
145144
146145def compute_scs_0102_prop_os_version (images ):
@@ -150,8 +149,7 @@ def compute_scs_0102_prop_os_version(images):
150149 # certain values for common operating systems.
151150 # - os_version not matching regexp r'[0-9\.]*' (should be a numeric version no)
152151 offenders = [img for img in images if not img .os_version ]
153- _log_error ('property os_version not set' , offenders )
154- return not offenders
152+ return _log_error ('property os_version not set' , offenders )
155153
156154
157155def compute_scs_0102_prop_os_distro (images ):
@@ -160,8 +158,7 @@ def compute_scs_0102_prop_os_distro(images):
160158 # - os_distro not being all-lowercase (they all should be acc. to
161159 # https://docs.openstack.org/glance/2025.1/admin/useful-image-properties.html
162160 offenders = [img for img in images if not img .os_distro ]
163- _log_error ('property os_distro not set' , offenders )
164- return not offenders
161+ return _log_error ('property os_distro not set' , offenders )
165162
166163
167164def compute_scs_0102_prop_os_purpose (images , os_purposes = OS_PURPOSES ):
@@ -173,41 +170,44 @@ def compute_scs_0102_prop_os_purpose(images, os_purposes=OS_PURPOSES):
173170def compute_scs_0102_prop_hw_disk_bus (images , hw_disk_buses = HW_DISK_BUSES ):
174171 """This test ensures that each image has a proper value for the property `hw_disk_bus`."""
175172 offenders = [img for img in images if img .hw_disk_bus not in hw_disk_buses ]
176- _log_error ('property hw_disk_bus not correct' , offenders )
177- return not offenders
173+ return _log_error ('property hw_disk_bus not correct' , offenders )
178174
179175
180176def compute_scs_0102_prop_hypervisor_type (images , hypervisor_types = HYPERVISOR_TYPES ):
181177 """This test ensures that each image has a proper value for the property `hypervisor_type`."""
182178 offenders = [img for img in images if img .hypervisor_type not in hypervisor_types ]
183- _log_error ('property hypervisor_type not correct' , offenders )
184- return not offenders
179+ return _log_error ('property hypervisor_type not correct' , offenders )
185180
186181
187182def compute_scs_0102_prop_hw_rng_model (images , hw_rng_models = HW_RNG_MODELS ):
188183 """This test ensures that each image has a proper value for the property `hw_rng_model`."""
189184 offenders = [img for img in images if img .hw_rng_model not in hw_rng_models ]
190- _log_error ('property hw_rng_model not correct' , offenders )
191- return not offenders
185+ return _log_error ('property hw_rng_model not correct' , offenders )
192186
193187
194188def compute_scs_0102_prop_image_build_date (images , now = time .time ()):
195189 """This test ensures that each image has a proper value for the property `image_build_date`."""
196- errors = 0
190+ offenders1 = []
191+ offenders2 = []
192+ offenders3 = []
197193 for img in images :
198194 rdate = parse_date (img .created_at , formats = STRICT_FORMATS )
199195 bdate_str = img .properties .get ('image_build_date' , '' )
200196 bdate = parse_date (bdate_str )
201197 if not bdate :
202198 logger .error (f'Image "{ img .name } ": image_build_date "{ bdate_str } " INVALID' )
203- errors += 1
199+ offenders1 . append ( img )
204200 elif bdate > rdate :
205201 logger .error (f'Image "{ img .name } ": image_build_date { bdate_str } AFTER registration date { img .created_at } ' )
206- errors += 1
202+ offenders3 . append ( img )
207203 if (bdate or rdate ) > now :
208204 logger .error (f'Image "{ img .name } " has build time in the future: { bdate } ' )
209- errors += 1
210- return not errors
205+ offenders3 .append (img )
206+ return (
207+ _log_error ('image_build_date INVALID' , offenders1 , channel = logging .DEBUG ) +
208+ _log_error ('image_build_date AFTER registration date' , offenders2 , channel = logging .DEBUG ) +
209+ _log_error ('image build time in the future' , offenders3 , channel = logging .DEBUG )
210+ )
211211
212212
213213# FIXME this is completely optional
@@ -218,8 +218,7 @@ def compute_scs_0102_prop_image_build_date(images, now=time.time()):
218218def compute_scs_0102_prop_image_original_user (images ):
219219 """This test ensures that each image has a proper value for the property `image_original_user`."""
220220 offenders = [img for img in images if not img .properties .get ('image_original_user' )]
221- _log_error ('property image_original_user not set' , offenders )
222- return not offenders
221+ return _log_error ('property image_original_user not set' , offenders )
223222
224223
225224def compute_scs_0102_prop_image_source (images ):
@@ -230,34 +229,30 @@ def compute_scs_0102_prop_image_source(images):
230229 if img .properties .get ('image_source' ) != 'private'
231230 if not is_url (img .properties .get ('image_source' , '' ))
232231 ]
233- _log_error ('property image_source INVALID (url or "private")' , offenders )
234- return not offenders
232+ return _log_error ('property image_source INVALID (url or "private")' , offenders )
235233
236234
237235def compute_scs_0102_prop_image_description (images ):
238236 """This test ensures that each image has a proper value for the property `image_description`."""
239237 offenders = [img for img in images if not img .properties .get ('image_description' )]
240- _log_error ('property image_description not set' , offenders )
241- return not offenders
238+ return _log_error ('property image_description not set' , offenders )
242239
243240
244241def compute_scs_0102_prop_replace_frequency (images , replace_frequencies = FREQ_TO_SEC ):
245242 """This test ensures that each image has a proper value for the property `replace_frequency`."""
246243 offenders = [img for img in images if img .properties .get ('replace_frequency' ) not in replace_frequencies ]
247- _log_error ('property replace_frequency not correct' , offenders )
248- return not offenders
244+ return _log_error ('property replace_frequency not correct' , offenders )
249245
250246
251247def compute_scs_0102_prop_provided_until (images ):
252248 """This test ensures that each image has a proper value for the property `provided_until`."""
253249 offenders = [img for img in images if not img .properties .get ('provided_until' )]
254- _log_error ('property provided_until not set' , offenders )
255- return not offenders
250+ return _log_error ('property provided_until not set' , offenders )
256251
257252
258253def compute_scs_0102_prop_uuid_validity (images ):
259254 """This test ensures that each image has a proper value for the property `uuid_validity`."""
260- errors = 0
255+ offenders = []
261256 for img in images :
262257 img_uuid_val = img .properties .get ("uuid_validity" )
263258 if img_uuid_val in (None , "none" , "notice" , "forever" ):
@@ -268,20 +263,20 @@ def compute_scs_0102_prop_uuid_validity(images):
268263 pass
269264 else :
270265 logger .error (f'Image "{ img .name } ": property uuid_validity INVALID: { img_uuid_val } ' )
271- errors += 1
272- return not errors
266+ offenders . append ( img )
267+ return _log_error ( 'uuid_validity INVALID' , offenders , channel = logging . DEBUG )
273268
274269
275270def compute_scs_0102_prop_hotfix_hours (images ):
276271 """This test ensures that each image has a proper value for the property `hotfix_hours`."""
277- errors = 0
272+ offenders = []
278273 for img in images :
279274 hotfix_hours = img .properties .get ("hotfix_hours" , '' )
280275 if not hotfix_hours or hotfix_hours .isdecimal ():
281276 continue
282277 logger .error (f'Image "{ img .name } ": property hotfix_hours INVALID: { hotfix_hours } ' )
283- errors += 1
284- return not errors
278+ offenders . append ( img )
279+ return _log_error ( 'hotfix_hours INVALID' , offenders , channel = logging . DEBUG )
285280
286281
287282def _find_replacement_image (by_name , img_name ):
@@ -310,7 +305,8 @@ def compute_scs_0102_image_recency(images):
310305 counter = Counter ([img .name for img in images ])
311306 duplicates = [name for name , count in counter .items () if count > 1 ]
312307 logger .warning (f'duplicate names detected: { ", " .join (duplicates )} ' )
313- errors = 0
308+ offenders1 = []
309+ offenders2 = []
314310 for img in images :
315311 # This is a bit tricky: We need to disregard images that have been rotated out
316312 # - os_hidden = True is a safe sign for this
@@ -319,17 +315,18 @@ def compute_scs_0102_image_recency(images):
319315 if not outd :
320316 continue # fine
321317 if outd == 3 :
322- logger .error (f'Image "{ img .name } " does not provide a valid provided until date' )
323- errors += 1
318+ offenders1 .append (img )
324319 continue # hopeless
325320 # in case that outd in (1, 2) try to find a non-outdated version
326321 if outd == 2 :
327322 logger .warning (f'Image "{ img .name } " seems outdated (acc. to its repl freq) but is not hidden or otherwise marked' )
328323 # warnings += 1
329324 replacement = _find_replacement_image (by_name , img .name )
330325 if replacement is None :
331- logger .error (f'Image "{ img .name } " outdated without replacement' )
332- errors += 1
326+ offenders2 .append (img )
333327 else :
334328 logger .info (f'Image "{ replacement .name } " is a valid replacement for outdated "{ img .name } "' )
335- return not errors
329+ return (
330+ _log_error ('images w/o valid provided_until' , offenders1 , channel = logging .DEBUG ) +
331+ _log_error ('outdated images w/o replacement' , offenders2 , channel = logging .DEBUG )
332+ )
0 commit comments