@@ -326,59 +326,88 @@ def download(self, context, image_id, data=None, dst_path=None,
326326 raise exception .ImageUnacceptable (image_id = image_id ,
327327 reason = 'Image has no associated data' )
328328
329- # Retrieve properties for verification of Glance image signature
330- verifier = self ._get_verifier (context , image_id , trusted_certs )
329+ return self ._verify_and_write (context , image_id , trusted_certs ,
330+ image_chunks , data , dst_path )
331+
332+ def _verify_and_write (self , context , image_id , trusted_certs ,
333+ image_chunks , data , dst_path ):
334+ """Perform image signature verification and save the image file if needed.
335+
336+ This function writes the content of the image_chunks iterator either to
337+ a file object provided by the data parameter or to a filepath provided
338+ by dst_path parameter. If none of them are provided then no data will
339+ be written out but instead image_chunks iterator is returned.
340+
341+ :param image_id: The UUID of the image
342+ :param trusted_certs: A 'nova.objects.trusted_certs.TrustedCerts'
343+ object with a list of trusted image certificate
344+ IDs.
345+ :param image_chunks An iterator pointing to the image data
346+ :param data: File object to use when writing the image.
347+ If passed as None and dst_path is provided, new file is opened.
348+ :param dst_path: Filepath to transfer the image file to.
349+ :returns an iterable with image data, or nothing. Iterable is returned
350+ only when data param is None and dst_path is not provided (assuming
351+ the caller wants to process the data by itself).
352+
353+ """
331354
332355 close_file = False
333356 if data is None and dst_path :
334357 data = open (dst_path , 'wb' )
335358 close_file = True
336359
360+ write_image = True
337361 if data is None :
362+ write_image = False
338363
339- # Perform image signature verification
340- if verifier :
341- try :
342- for chunk in image_chunks :
343- verifier .update (chunk )
344- verifier .verify ()
345-
346- LOG .info ('Image signature verification succeeded '
347- 'for image: %s' , image_id )
348-
349- except cryptography .exceptions .InvalidSignature :
350- with excutils .save_and_reraise_exception ():
351- LOG .error ('Image signature verification failed '
352- 'for image: %s' , image_id )
353- return image_chunks
354- else :
355- try :
356- for chunk in image_chunks :
357- if verifier :
358- verifier .update (chunk )
359- data .write (chunk )
364+ # Retrieve properties for verification of Glance image signature
365+ verifier = self ._get_verifier (context , image_id , trusted_certs )
366+
367+ # Exit early if we do not need write nor verify
368+ if verifier is None and write_image is False :
369+ if data is None :
370+ return image_chunks
371+ else :
372+ return
373+
374+ try :
375+ for chunk in image_chunks :
360376 if verifier :
361- verifier .verify ()
362- LOG .info ('Image signature verification succeeded '
363- 'for image %s' , image_id )
364- except cryptography .exceptions .InvalidSignature :
377+ verifier .update (chunk )
378+ if write_image :
379+ data .write (chunk )
380+ if verifier :
381+ verifier .verify ()
382+ LOG .info ('Image signature verification succeeded '
383+ 'for image %s' , image_id )
384+ except cryptography .exceptions .InvalidSignature :
385+ if write_image :
365386 data .truncate (0 )
366- with excutils .save_and_reraise_exception ():
367- LOG .error ('Image signature verification failed '
368- 'for image: %s' , image_id )
369- except Exception as ex :
387+ with excutils .save_and_reraise_exception ():
388+ LOG .error ('Image signature verification failed '
389+ 'for image %s' , image_id )
390+ except Exception as ex :
391+ if write_image :
370392 with excutils .save_and_reraise_exception ():
371393 LOG .error ("Error writing to %(path)s: %(exception)s" ,
372394 {'path' : dst_path , 'exception' : ex })
373- finally :
374- if close_file :
375- # Ensure that the data is pushed all the way down to
376- # persistent storage. This ensures that in the event of a
377- # subsequent host crash we don't have running instances
378- # using a corrupt backing file.
379- data .flush ()
380- self ._safe_fsync (data )
381- data .close ()
395+ else :
396+ with excutils .save_and_reraise_exception ():
397+ LOG .error ("Error during image verification: %s" , ex )
398+
399+ finally :
400+ if close_file :
401+ # Ensure that the data is pushed all the way down to
402+ # persistent storage. This ensures that in the event of a
403+ # subsequent host crash we don't have running instances
404+ # using a corrupt backing file.
405+ data .flush ()
406+ self ._safe_fsync (data )
407+ data .close ()
408+
409+ if data is None :
410+ return image_chunks
382411
383412 def _get_verifier (self , context , image_id , trusted_certs ):
384413 verifier = None
0 commit comments