def test_get_glance_image_service(self, glance_service_mock, session_mock): image_href = 'image-uuid' self.context.auth_token = 'fake' image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(session_mock.called)
def test_get_glance_image_service(self, glance_service_mock, token_mock): image_href = 'image-uuid' self.context.auth_token = 'fake' image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(token_mock.called)
def test_get_glance_image_service_default_v1(self, glance_service_mock, session_mock): self.config(glance_api_version=1, group='glance') image_href = 'image-uuid' self.context.auth_token = 'fake' image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(session_mock.called)
def test_get_glance_image_service_no_token(self, glance_service_mock, token_mock): image_href = 'image-uuid' self.context.auth_token = None token_mock.return_value = 'admin-token' image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) token_mock.assert_called_once_with() self.assertEqual('admin-token', self.context.auth_token)
def test_get_glance_image_service_token_not_needed(self, glance_service_mock, session_mock): image_href = 'image-uuid' self.context.auth_token = None self.config(auth_strategy='noauth', group='glance') image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(session_mock.called) self.assertIsNone(self.context.auth_token)
def test_get_glance_image_service_token_not_needed(self, glance_service_mock, token_mock): image_href = 'image-uuid' self.context.auth_token = None self.config(auth_strategy='noauth', group='glance') image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context) self.assertFalse(token_mock.called) self.assertIsNone(self.context.auth_token)
def _delete_master_path_if_stale(master_path, href, ctx): """Delete image from cache if it is not up to date with href contents. :param master_path: path to an image in master cache :param href: image href :param ctx: context to use :returns: True if master_path is up to date with href contents, False if master_path was stale and was deleted or it didn't exist """ if service_utils.is_glance_image(href): # Glance image contents cannot be updated without changing image's UUID return os.path.exists(master_path) if os.path.exists(master_path): img_service = image_service.get_image_service(href, context=ctx) img_mtime = img_service.show(href).get('updated_at') if not img_mtime: # This means that href is not a glance image and doesn't have an # updated_at attribute LOG.warning("Image service couldn't determine last " "modification time of %(href)s, considering " "cached image up to date.", {'href': href}) return True master_mtime = utils.unix_file_modification_datetime(master_path) if img_mtime <= master_mtime: return True # Delete image from cache as it is outdated LOG.info('Image %(href)s was last modified at %(remote_time)s. ' 'Deleting the cached copy "%(cached_file)s since it was ' 'last modified at %(local_time)s and may be outdated.', {'href': href, 'remote_time': img_mtime, 'local_time': master_mtime, 'cached_file': master_path}) os.unlink(master_path) return False
def _delete_master_path_if_stale(master_path, href, ctx): """Delete image from cache if it is not up to date with href contents. :param master_path: path to an image in master cache :param href: image href :param ctx: context to use :returns: True if master_path is up to date with href contents, False if master_path was stale and was deleted or it didn't exist """ if service_utils.is_glance_image(href): # Glance image contents cannot be updated without changing image's UUID return os.path.exists(master_path) if os.path.exists(master_path): img_service = image_service.get_image_service(href, context=ctx) img_mtime = img_service.show(href).get('updated_at') if not img_mtime: # This means that href is not a glance image and doesn't have an # updated_at attribute LOG.warn(_LW("Image service couldn't determine last " "modification time of %(href)s, considering " "cached image up to date."), {'href': href}) return True master_mtime = utils.unix_file_modification_datetime(master_path) if img_mtime <= master_mtime: return True # Delete image from cache as it is outdated LOG.info(_LI('Image %(href)s was last modified at %(remote_time)s. ' 'Deleting the cached copy "%(cached_file)s since it was ' 'last modified at %(local_time)s and may be outdated.'), {'href': href, 'remote_time': img_mtime, 'local_time': master_mtime, 'cached_file': master_path}) os.unlink(master_path) return False
def fetch_into(context, image_href, image_file): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. image_service = service.get_image_service(image_href, context=context) LOG.debug("Using %(image_service)s to download image %(image_href)s.", { 'image_service': image_service.__class__, 'image_href': image_href }) image_service.download(image_href, image_file)
def validate_image_properties(ctx, deploy_info, properties): """Validate the image. For Glance images it checks that the image exists in Glance and its properties or deployment info contain the properties passed. If it's not a Glance image, it checks that deployment info contains needed properties. :param ctx: security context :param deploy_info: the deploy_info to be validated :param properties: the list of image meta-properties to be validated. :raises: InvalidParameterValue if: * connection to glance failed; * authorization for accessing image failed; * HEAD request to image URL failed or returned response code != 200; * HEAD request response does not contain Content-Length header; * the protocol specified in image URL is not supported. :raises: MissingParameterValue if the image doesn't contain the mentioned properties. """ image_href = deploy_info['image_source'] try: img_service = image_service.get_image_service(image_href, context=ctx) image_props = img_service.show(image_href)['properties'] except (exception.GlanceConnectionFailed, exception.ImageNotAuthorized, exception.Invalid): raise exception.InvalidParameterValue( _("Failed to connect to Glance to get the properties " "of the image %s") % image_href) except exception.ImageNotFound: raise exception.InvalidParameterValue( _("Image %s can not be found.") % image_href) except exception.ImageRefValidationFailed as e: raise exception.InvalidParameterValue(e) missing_props = [] for prop in properties: if not (deploy_info.get(prop) or image_props.get(prop)): missing_props.append(prop) if missing_props: props = ', '.join(missing_props) raise exception.MissingParameterValue( _("Image %(image)s is missing the following properties: " "%(properties)s") % { 'image': image_href, 'properties': props })
def fetch(context, image_href, path, force_raw=False): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. image_service = service.get_image_service(image_href, context=context) LOG.debug("Using %(image_service)s to download image %(image_href)s." % {'image_service': image_service.__class__, 'image_href': image_href}) with fileutils.remove_path_on_error(path): with open(path, "wb") as image_file: image_service.download(image_href, image_file) if force_raw: image_to_raw(image_href, path, "%s.part" % path)
def fetch(context, image_href, path, force_raw=False): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. image_service = service.get_image_service(image_href, context=context) LOG.debug("Using %(image_service)s to download image %(image_href)s.", { 'image_service': image_service.__class__, 'image_href': image_href }) with fileutils.remove_path_on_error(path): with open(path, "wb") as image_file: image_service.download(image_href, image_file) if force_raw: image_to_raw(image_href, path, "%s.part" % path)
def validate_image_properties(ctx, deploy_info, properties): """Validate the image. For Glance images it checks that the image exists in Glance and its properties or deployment info contain the properties passed. If it's not a Glance image, it checks that deployment info contains needed properties. :param ctx: security context :param deploy_info: the deploy_info to be validated :param properties: the list of image meta-properties to be validated. :raises: InvalidParameterValue if: * connection to glance failed; * authorization for accessing image failed; * HEAD request to image URL failed or returned response code != 200; * HEAD request response does not contain Content-Length header; * the protocol specified in image URL is not supported. :raises: MissingParameterValue if the image doesn't contain the mentioned properties. """ image_href = deploy_info['image_source'] try: img_service = image_service.get_image_service(image_href, context=ctx) image_props = img_service.show(image_href)['properties'] except (exception.GlanceConnectionFailed, exception.ImageNotAuthorized, exception.Invalid): raise exception.InvalidParameterValue(_( "Failed to connect to Glance to get the properties " "of the image %s") % image_href) except exception.ImageNotFound: raise exception.InvalidParameterValue(_( "Image %s can not be found.") % image_href) except exception.ImageRefValidationFailed as e: raise exception.InvalidParameterValue(e) missing_props = [] for prop in properties: if not (deploy_info.get(prop) or image_props.get(prop)): missing_props.append(prop) if missing_props: props = ', '.join(missing_props) raise exception.MissingParameterValue(_( "Image %(image)s is missing the following properties: " "%(properties)s") % {'image': image_href, 'properties': props})
def get_image_properties(context, image_href, properties="all"): """Returns the values of several properties of an image :param context: context :param image_href: href of the image :param properties: the properties whose values are required. This argument is optional, default value is "all", so if not specified all properties will be returned. :returns: a dict of the values of the properties. A property not on the glance metadata will have a value of None. """ img_service = service.get_image_service(image_href, context=context) iproperties = img_service.show(image_href)['properties'] if properties == "all": return iproperties return {p: iproperties.get(p) for p in properties}
def test_get_glance_image_service_url(self, glance_service_mock): image_href = 'glance://image-uuid' image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context)
def test_get_glance_image_service_url(self, glance_service_mock): image_href = 'glance://%s' % uuidutils.generate_uuid() image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, self.context)
def download_size(context, image_href, image_service=None): if not image_service: image_service = service.get_image_service(image_href, context=context) return image_service.show(image_href)['size']
def image_show(context, image_href, image_service=None): if image_service is None: image_service = service.get_image_service(image_href, context=context) return image_service.show(image_href)
def test_get_https_image_service(self, http_service_mock): image_href = 'https://127.0.0.1/image.qcow2' image_service.get_image_service(image_href) http_service_mock.assert_called_once_with()
def test_get_file_image_service(self, local_service_mock): image_href = 'file:///home/user/image.qcow2' image_service.get_image_service(image_href) local_service_mock.assert_called_once_with()
def download_size(context, image_href, image_service=None): if not image_service: image_service = service.get_image_service(image_href, context=context) return image_service.show(image_href)["size"]
def test_get_glance_image_service_default_v1(self, glance_service_mock): self.config(glance_api_version=1, group='glance') image_href = uuidutils.generate_uuid() image_service.get_image_service(image_href, context=self.context) glance_service_mock.assert_called_once_with(mock.ANY, None, 1, self.context)