def get(self, context, image_id, data): """Get image and metadata.""" try: with open(self._path_to(image_id)) as metadata_file: metadata = json.load(metadata_file) with open(self._path_to(image_id, 'image')) as image_file: shutil.copyfileobj(image_file, data) except (IOError, ValueError): raise exception.ImageNotFound(image_id=image_id) return metadata
def _translate_image_exception(image_id, exc_value): if isinstance(exc_value, (glanceclient.exc.Forbidden, glanceclient.exc.Unauthorized)): return exception.ImageNotAuthorized(image_id=image_id) if isinstance(exc_value, glanceclient.exc.NotFound): return exception.ImageNotFound(image_id=image_id) if isinstance(exc_value, glanceclient.exc.BadRequest): return exception.ImageBadRequest(image_id=image_id, response=six.text_type(exc_value)) return exc_value
def fake_show(meh, context, id): if id: return {'id': id, 'min_disk': None, 'min_ram': None, 'name': 'fake_name', 'status': 'active', 'properties': {'kernel_id': 'fake_kernel_id', 'ramdisk_id': 'fake_ramdisk_id', 'something_else': 'meow'}} else: raise exception.ImageNotFound(image_id=id)
def _translate_image_exception(image_id, exc_type, exc_value): if exc_type in (glance_exception.Forbidden, glance_exception.NotAuthenticated, glance_exception.MissingCredentialError): return exception.ImageNotAuthorized(image_id=image_id) if exc_type is glance_exception.NotFound: return exception.ImageNotFound(image_id=image_id) if exc_type is glance_exception.Invalid: return exception.Invalid(exc_value) return exc_value
def show(self, context, image_id, include_locations=False, show_deleted=True): """Returns a dict with image data for the given opaque image id. :param context: The context object to pass to image client :param image_id: The UUID of the image :param include_locations: (Optional) include locations in the returned dict of information if the image service API supports it. If the image service API does not support the locations attribute, it will still be included in the returned dict, as an empty list. :param show_deleted: (Optional) show the image even the status of image is deleted. """ version = 1 if include_locations: version = 2 try: image = self._client.call(context, version, 'get', image_id) except Exception: _reraise_translated_image_exception(image_id) if not show_deleted and getattr(image, 'deleted', False): raise exception.ImageNotFound(image_id=image_id) if not _is_image_available(context, image): raise exception.ImageNotFound(image_id=image_id) image = _translate_from_glance(image, include_locations=include_locations) if include_locations: locations = image.get('locations', None) or [] du = image.get('direct_url', None) if du: locations.append({'url': du, 'metadata': {}}) image['locations'] = locations return image
def delete(self, context, image_id): """Delete the given image. :raises: ImageNotFound if the image does not exist. :raises: NotAuthorized if the user is not an owner. """ try: self._client.call(context, 1, 'delete', image_id) except glanceclient.exc.NotFound: raise exception.ImageNotFound(image_id=image_id) return True
def show(self, context, image_id): """Get data about specified image. Returns a dict containing image data for the given opaque image id. """ image = self.images.get(str(image_id)) if image: return copy.deepcopy(image) LOG.warn('Unable to find image id %s. Have images: %s', image_id, self.images) raise exception.ImageNotFound(image_id=image_id)
def describe_image_attribute(self, context, image_id, attribute, **kwargs): if attribute != 'launchPermission': raise exception.ApiError( _('attribute not supported: %s') % attribute) try: image = self._get_image(context, image_id) except exception.NotFound: raise exception.ImageNotFound(image_id=image_id) result = {'imageId': image_id, 'launchPermission': []} if image['is_public']: result['launchPermission'].append({'group': 'all'}) return result
def show(self, context, image_id): """Returns a dict with image data for the given opaque image id.""" try: image = self._client.call(context, 1, 'get', image_id) except Exception: _reraise_translated_image_exception(image_id) if not _is_image_available(context, image): raise exception.ImageNotFound(image_id=image_id) base_image_meta = _translate_from_glance(image) return base_image_meta
def delete(self, context, image_id): """Delete the given image. :raises: ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) try: shutil.rmtree(self._path_to(image_id, None)) except (IOError, ValueError): raise exception.ImageNotFound(image_id=image_id)
def get(self, context, image_id, data): """Calls out to Glance for metadata and data and writes data.""" try: image_meta, image_chunks = self.client.get_image(image_id) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) for chunk in image_chunks: data.write(chunk) base_image_meta = self._translate_to_base(image_meta) return base_image_meta
def test_get_image_meta_no_image(self): e = exception.ImageNotFound(image_id='fake-image') self.mock_image_api.get.side_effect = e image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) self.image['properties'] = 'DONTCARE' # NOTE(danms): The trip through system_metadata will stringify things for key in self.image: self.image[key] = str(self.image[key]) self.assertThat(self.image, matchers.DictMatches(image_meta))
def get_location(self, context, image_id): """Returns the direct url representing the backend storage location, or None if this attribute is not shown by Glance.""" try: client = GlanceClientWrapper() image_meta = client.call(context, 2, 'get', image_id) except Exception: _reraise_translated_image_exception(image_id) if not self._is_image_available(context, image_meta): raise exception.ImageNotFound(image_id=image_id) return getattr(image_meta, 'direct_url', None)
def show_by_name(self, context, name): """Returns a dict containing image data for the given name.""" # NOTE(vish): Not very efficient, but the local image service # is for testing so it should be fine. images = self.detail(context) image = None for cantidate in images: if name == cantidate.get('name'): image = cantidate break if image is None: raise exception.ImageNotFound(image_id=name) return image
def test_get_image_meta_no_image_no_image_system_meta(self): e = exception.ImageNotFound(image_id='fake-image') self.mock_image_api.get.side_effect = e for k in self.instance['system_metadata'].keys(): if k.startswith('image_'): del self.instance['system_metadata'][k] image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) expected = {'properties': 'DONTCARE'} self.assertThat(expected, matchers.DictMatches(image_meta))
def delete(self, context, image_id): """Delete the given image. :raises: ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) try: result = self.client.delete_image(image_id) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) return result
def return_image_meta(*args, **kwargs): image_meta_table = { '2': {'id': 2, 'status': 'active', 'container_format': 'ari'}, '155d900f-4e14-4e4c-a73d-069cbf4541e6': {'id': 3, 'status': 'active', 'container_format': 'raw', 'properties': {'kernel_id': 1, 'ramdisk_id': 2}}, } image_id = args[2] try: image_meta = image_meta_table[str(image_id)] except KeyError: raise exception.ImageNotFound(image_id=image_id) return image_meta
def describe_images(self, context, image_id=None, **kwargs): # NOTE: image_id is a list! if image_id: images = [] for ec2_id in image_id: try: image = self._get_image(context, ec2_id) except exception.NotFound: raise exception.ImageNotFound(image_id=ec2_id) images.append(image) else: images = self.image_service.detail(context) images = [self._format_image(i) for i in images] return {'imagesSet': images}
def update(self, context, image_id, image_meta, data=None): """Replace the contents of the given image with the new data. :raises: ImageNotFound if the image does not exist. """ # NOTE(vish): show is to check if image is available self.show(context, image_id) try: image_meta = self.client.update_image(image_id, image_meta, data) except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) base_image_meta = self._translate_to_base(image_meta) return base_image_meta
def _store(self, context, image_id, metadata, data=None): metadata['id'] = image_id try: if data: location = self._path_to(image_id, 'image') with open(location, 'w') as image_file: shutil.copyfileobj(data, image_file) # NOTE(vish): update metadata similarly to glance metadata['status'] = 'active' metadata['location'] = location with open(self._path_to(image_id), 'w') as metadata_file: json.dump(metadata, metadata_file) except (IOError, ValueError): raise exception.ImageNotFound(image_id=image_id) return metadata
def test_get_image_meta_no_image_no_image_system_meta(self): e = exception.ImageNotFound(image_id='fake-image') self.mock_image_api.get.side_effect = e for k in self.instance_obj.system_metadata.keys(): if k.startswith('image_'): del self.instance_obj.system_metadata[k] with mock.patch('nova.objects.Flavor.get_by_flavor_id') as get: get.return_value = objects.Flavor(extra_specs={}) image_meta = compute_utils.get_image_metadata( self.ctx, self.mock_image_api, 'fake-image', self.instance_obj) expected = {'properties': 'DONTCARE'} self.assertThat(expected, matchers.DictMatches(image_meta))
def _get_locations(client, context, image_id): """Returns the direct url representing the backend storage location, or None if this attribute is not shown by Glance. """ try: image_meta = client.call(context, 2, 'get', image_id) except Exception: _reraise_translated_image_exception(image_id) if not _is_image_available(context, image_meta): raise exception.ImageNotFound(image_id=image_id) locations = getattr(image_meta, 'locations', []) du = getattr(image_meta, 'direct_url', None) if du: locations.append({'url': du, 'metadata': {}}) return locations
def delete(self, context, image_id): """Delete the given image. :raises: ImageNotFound if the image does not exist. :raises: NotAuthorized if the user is not an owner. :raises: ImageNotAuthorized if the user is not authorized. :raises: ImageDeleteConflict if the image is conflicted to delete. """ try: self._client.call(context, 2, 'delete', image_id) except glanceclient.exc.NotFound: raise exception.ImageNotFound(image_id=image_id) except glanceclient.exc.HTTPForbidden: raise exception.ImageNotAuthorized(image_id=image_id) except glanceclient.exc.HTTPConflict as exc: raise exception.ImageDeleteConflict(reason=six.text_type(exc)) return True
def update(self, context, image_id, metadata, data=None, purge_props=False): """Replace the contents of the given image with the new data. :raises: ImageNotFound if the image does not exist. """ if not self.images.get(image_id): raise exception.ImageNotFound(image_id=image_id) if purge_props: self.images[image_id] = copy.deepcopy(metadata) else: image = self.images[image_id] try: image['properties'].update(metadata.pop('properties')) except KeyError: pass image.update(metadata) return self.images[image_id]
def test_resize_with_image_exceptions(self): body = dict(resize=dict(flavorRef="http://localhost/3")) self.resize_called = 0 image_id = 'fake_image_id' exceptions = [ (exception.ImageNotAuthorized(image_id=image_id), webob.exc.HTTPUnauthorized), (exception.ImageNotFound(image_id=image_id), webob.exc.HTTPBadRequest), (exception.Invalid, webob.exc.HTTPBadRequest), (exception.NoValidHost(reason='Bad host'), webob.exc.HTTPBadRequest), (exception.AutoDiskConfigDisabledByImage(image=image_id), webob.exc.HTTPBadRequest), ] raised, expected = map(iter, zip(*exceptions)) def _fake_resize(obj, context, instance, flavor_id): self.resize_called += 1 raise raised.next() self.stubs.Set(compute_api.API, 'resize', _fake_resize) for call_no in range(len(exceptions)): req = fakes.HTTPRequestV3.blank(self.url) next_exception = expected.next() actual = self.assertRaises(next_exception, self.controller._action_resize, req, FAKE_UUID, body=body) if (isinstance(exceptions[call_no][0], exception.NoValidHost)): self.assertEqual(actual.explanation, 'No valid host was found. Bad host') elif (isinstance(exceptions[call_no][0], exception.AutoDiskConfigDisabledByImage)): self.assertEqual( actual.explanation, 'Requested image fake_image_id has automatic' ' disk resize disabled.') self.assertEqual(self.resize_called, call_no + 1)
def get(self, context, image_id, data): """Calls out to Glance for metadata and data and writes data.""" num_retries = FLAGS.glance_num_retries for count in xrange(1 + num_retries): client = self._get_client(context) try: image_meta, image_chunks = client.get_image(image_id) break except glance_exception.NotFound: raise exception.ImageNotFound(image_id=image_id) except Exception: if count == num_retries: raise time.sleep(1) for chunk in image_chunks: data.write(chunk) base_image_meta = self._translate_from_glance(image_meta) return base_image_meta
def upload_image(self, context, session, instance, image_id, vdi_uuids): params = {'vdi_uuids': vdi_uuids} props = params['properties'] = {} props['auto_disk_config'] = instance['auto_disk_config'] props['os_type'] = instance.get( 'os_type', None) or (CONF.xenserver.default_os_type) compression_level = vm_utils.get_compression_level() if compression_level: props['xenapi_image_compression_level'] = compression_level auto_disk_config = utils.get_auto_disk_config_from_instance(instance) if utils.is_auto_disk_config_disabled(auto_disk_config): props["auto_disk_config"] = "disabled" try: self._call_glance_plugin(context, instance, session, host_glance.upload_vhd, image_id, params) except xenapi_exception.PluginRetriesExceeded: raise exception.CouldNotUploadImage(image_id=image_id) except xenapi_exception.PluginImageNotFound: raise exception.ImageNotFound(image_id=image_id)
def update(self, context, image_id, metadata, data=None, headers=None): """Replace the contents of the given image with the new data. :raises: ImageNotFound if the image does not exist. """ if not self.images.get(image_id): raise exception.ImageNotFound(image_id=image_id) try: purge = headers['x-glance-registry-purge-props'] except Exception: purge = True if purge: self.images[image_id] = copy.deepcopy(metadata) else: image = self.images[image_id] try: image['properties'].update(metadata.pop('properties')) except Exception: pass image.update(metadata) return self.images[image_id]
def modify_image_attribute(self, context, image_id, attribute, operation_type, **kwargs): # TODO(devcamcar): Support users and groups other than 'all'. if attribute != 'launchPermission': raise exception.ApiError( _('attribute not supported: %s') % attribute) if not 'user_group' in kwargs: raise exception.ApiError(_('user or group not specified')) if len(kwargs['user_group']) != 1 and kwargs['user_group'][0] != 'all': raise exception.ApiError(_('only group "all" is supported')) if not operation_type in ['add', 'remove']: raise exception.ApiError(_('operation_type must be add or remove')) LOG.audit(_("Updating image %s publicity"), image_id, context=context) try: image = self._get_image(context, image_id) except exception.NotFound: raise exception.ImageNotFound(image_id=image_id) internal_id = image['id'] del (image['id']) image['is_public'] = (operation_type == 'add') return self.image_service.update(context, internal_id, image)
def fake_show(ctx, image_id): raise exception.ImageNotFound(image_id='fake-image')