Example #1
0
    def delete(self, context, image_id):
        """Delete the given image.

        :raises: ImageNotFound if the image does not exist.

        """
        removed = self.images.pop(image_id, None)
        if not removed:
            raise exception.ImageNotFound(image_id=image_id)
Example #2
0
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.Invalid(six.text_type(exc_value))
    return exc_value
Example #3
0
    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
Example #4
0
    def show(self, context, image_id, include_locations=False,
             show_deleted=True):
        """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.warning('Unable to find image id %s.  Have images: %s',
                    image_id, self.images)
        raise exception.ImageNotFound(image_id=image_id)
Example #5
0
    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.

        """
        try:
            self._client.call(context, 1, '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)
        return True
Example #6
0
    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('patron.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))
Example #7
0
    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]
Example #8
0
 def safe_image_show(ctx, image_id):
     if image_id:
         return self.image_api.get(ctx, image_id, show_deleted=False)
     else:
         raise exception.ImageNotFound(image_id='')
Example #9
0
class ImageMetaDataTestV21(test.NoDBTestCase):
    controller_class = image_metadata_v21.ImageMetadataController
    invalid_request = exception.ValidationError

    def setUp(self):
        super(ImageMetaDataTestV21, self).setUp()
        self.controller = self.controller_class()

    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_index(self, get_all_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata')
        res_dict = self.controller.index(req, '123')
        expected = {'metadata': {'key1': 'value1'}}
        self.assertEqual(res_dict, expected)
        get_all_mocked.assert_called_once_with(mock.ANY, '123')

    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_show(self, get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        res_dict = self.controller.show(req, '123', 'key1')
        self.assertIn('meta', res_dict)
        self.assertEqual(len(res_dict['meta']), 1)
        self.assertEqual('value1', res_dict['meta']['key1'])
        get_mocked.assert_called_once_with(mock.ANY, '123')

    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_show_not_found(self, _get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key9')
        self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req,
                          '123', 'key9')

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id='100'))
    def test_show_image_not_found(self, _get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/100/metadata/key1')
        self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req,
                          '100', 'key9')

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_create(self, get_mocked, update_mocked, quota_mocked):
        mock_result = copy.deepcopy(get_image_123())
        mock_result['properties']['key7'] = 'value7'
        update_mocked.return_value = mock_result
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata')
        req.method = 'POST'
        body = {"metadata": {"key7": "value7"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"
        res = self.controller.create(req, '123', body=body)
        get_mocked.assert_called_once_with(mock.ANY, '123')
        expected = copy.deepcopy(get_image_123())
        expected['properties'] = {
            'key1': 'value1',  # existing meta
            'key7': 'value7'  # new meta
        }
        quota_mocked.assert_called_once_with(mock.ANY, expected["properties"])
        update_mocked.assert_called_once_with(mock.ANY,
                                              '123',
                                              expected,
                                              data=None,
                                              purge_props=True)

        expected_output = {'metadata': {'key1': 'value1', 'key7': 'value7'}}
        self.assertEqual(expected_output, res)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id='100'))
    def test_create_image_not_found(self, _get_mocked, update_mocked,
                                    quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/100/metadata')
        req.method = 'POST'
        body = {"metadata": {"key7": "value7"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller.create,
                          req,
                          '100',
                          body=body)
        self.assertFalse(quota_mocked.called)
        self.assertFalse(update_mocked.called)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_update_all(self, get_mocked, update_mocked, quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata')
        req.method = 'PUT'
        body = {"metadata": {"key9": "value9"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"
        res = self.controller.update_all(req, '123', body=body)
        get_mocked.assert_called_once_with(mock.ANY, '123')
        expected = copy.deepcopy(get_image_123())
        expected['properties'] = {
            'key9': 'value9'  # replace meta
        }
        quota_mocked.assert_called_once_with(mock.ANY, expected["properties"])
        update_mocked.assert_called_once_with(mock.ANY,
                                              '123',
                                              expected,
                                              data=None,
                                              purge_props=True)

        expected_output = {'metadata': {'key9': 'value9'}}
        self.assertEqual(expected_output, res)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id='100'))
    def test_update_all_image_not_found(self, _get_mocked, quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/100/metadata')
        req.method = 'PUT'
        body = {"metadata": {"key9": "value9"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller.update_all,
                          req,
                          '100',
                          body=body)
        self.assertFalse(quota_mocked.called)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_update_item(self, _get_mocked, update_mocked, quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        req.method = 'PUT'
        body = {"meta": {"key1": "zz"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"
        res = self.controller.update(req, '123', 'key1', body=body)
        expected = copy.deepcopy(get_image_123())
        expected['properties'] = {
            'key1': 'zz'  # changed meta
        }
        quota_mocked.assert_called_once_with(mock.ANY, expected["properties"])
        update_mocked.assert_called_once_with(mock.ANY,
                                              '123',
                                              expected,
                                              data=None,
                                              purge_props=True)

        expected_output = {'meta': {'key1': 'zz'}}
        self.assertEqual(res, expected_output)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id='100'))
    def test_update_item_image_not_found(self, _get_mocked, quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/100/metadata/key1')
        req.method = 'PUT'
        body = {"meta": {"key1": "zz"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPNotFound,
                          self.controller.update,
                          req,
                          '100',
                          'key1',
                          body=body)
        self.assertFalse(quota_mocked.called)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get')
    def test_update_item_bad_body(self, get_mocked, update_mocked,
                                  quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        req.method = 'PUT'
        body = {"key1": "zz"}
        req.body = ''
        req.headers["content-type"] = "application/json"

        self.assertRaises(self.invalid_request,
                          self.controller.update,
                          req,
                          '123',
                          'key1',
                          body=body)
        self.assertFalse(get_mocked.called)
        self.assertFalse(quota_mocked.called)
        self.assertFalse(update_mocked.called)

    @mock.patch(CHK_QUOTA_STR,
                side_effect=webob.exc.HTTPRequestEntityTooLarge(
                    explanation='', headers={'Retry-After': 0}))
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get')
    def test_update_item_too_many_keys(self, get_mocked, update_mocked,
                                       _quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        req.method = 'PUT'
        body = {"meta": {"foo": "bar"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller.update,
                          req,
                          '123',
                          'key1',
                          body=body)
        self.assertFalse(get_mocked.called)
        self.assertFalse(update_mocked.called)

    @mock.patch(CHK_QUOTA_STR)
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_update_item_body_uri_mismatch(self, _get_mocked, update_mocked,
                                           quota_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/bad')
        req.method = 'PUT'
        body = {"meta": {"key1": "value1"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPBadRequest,
                          self.controller.update,
                          req,
                          '123',
                          'bad',
                          body=body)
        self.assertFalse(quota_mocked.called)
        self.assertFalse(update_mocked.called)

    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_delete(self, _get_mocked, update_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        req.method = 'DELETE'
        res = self.controller.delete(req, '123', 'key1')
        expected = copy.deepcopy(get_image_123())
        expected['properties'] = {}
        update_mocked.assert_called_once_with(mock.ANY,
                                              '123',
                                              expected,
                                              data=None,
                                              purge_props=True)

        self.assertIsNone(res)

    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_delete_not_found(self, _get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/blah')
        req.method = 'DELETE'

        self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req,
                          '123', 'blah')

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id='100'))
    def test_delete_image_not_found(self, _get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/100/metadata/key1')
        req.method = 'DELETE'

        self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req,
                          '100', 'key1')

    @mock.patch(CHK_QUOTA_STR,
                side_effect=webob.exc.HTTPForbidden(explanation='',
                                                    headers={'Retry-After':
                                                             0}))
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_too_many_metadata_items_on_create(self, _get_mocked,
                                               update_mocked, _quota_mocked):
        body = {"metadata": {"foo": "bar"}}
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata')
        req.method = 'POST'
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller.create,
                          req,
                          '123',
                          body=body)
        self.assertFalse(update_mocked.called)

    @mock.patch(CHK_QUOTA_STR,
                side_effect=webob.exc.HTTPForbidden(explanation='',
                                                    headers={'Retry-After':
                                                             0}))
    @mock.patch('patron.image.api.API.update')
    @mock.patch('patron.image.api.API.get', return_value=get_image_123())
    def test_too_many_metadata_items_on_put(self, _get_mocked, update_mocked,
                                            _quota_mocked):
        body = {"metadata": {"foo": "bar"}}
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/blah')
        req.method = 'PUT'
        body = {"meta": {"blah": "blah", "blah1": "blah1"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(self.invalid_request,
                          self.controller.update,
                          req,
                          '123',
                          'blah',
                          body=body)
        self.assertFalse(update_mocked.called)

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotAuthorized(image_id='123'))
    def test_image_not_authorized_update(self, _get_mocked):
        req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
        req.method = 'PUT'
        body = {"meta": {"key1": "value1"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller.update,
                          req,
                          '123',
                          'key1',
                          body=body)

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotAuthorized(image_id='123'))
    def test_image_not_authorized_update_all(self, _get_mocked):
        image_id = 131
        # see patron.tests.unit.api.openstack.fakes:_make_image_fixtures

        req = fakes.HTTPRequest.blank('/v2/fake/images/%s/metadata/key1' %
                                      image_id)
        req.method = 'PUT'
        body = {"metadata": {"key1": "value1"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller.update_all,
                          req,
                          image_id,
                          body=body)

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotAuthorized(image_id='123'))
    def test_image_not_authorized_create(self, _get_mocked):
        image_id = 131
        # see patron.tests.unit.api.openstack.fakes:_make_image_fixtures

        req = fakes.HTTPRequest.blank('/v2/fake/images/%s/metadata/key1' %
                                      image_id)
        req.method = 'POST'
        body = {"metadata": {"key1": "value1"}}
        req.body = jsonutils.dumps(body)
        req.headers["content-type"] = "application/json"

        self.assertRaises(webob.exc.HTTPForbidden,
                          self.controller.create,
                          req,
                          image_id,
                          body=body)
Example #10
0
class ImagesControllerTestV21(test.NoDBTestCase):
    """Test of the OpenStack API /images application controller w/Glance.
    """
    image_controller_class = images_v21.ImagesController
    url_base = '/v3'
    bookmark_base = ''
    http_request = fakes.HTTPRequestV3

    def setUp(self):
        """Run before each test."""
        super(ImagesControllerTestV21, self).setUp()
        fakes.stub_out_networking(self.stubs)
        fakes.stub_out_rate_limiting(self.stubs)
        fakes.stub_out_key_pair_funcs(self.stubs)
        fakes.stub_out_compute_api_snapshot(self.stubs)
        fakes.stub_out_compute_api_backup(self.stubs)

        self.controller = self.image_controller_class()
        self.url_prefix = "http://localhost%s/images" % self.url_base
        self.bookmark_prefix = "http://localhost%s/images" % self.bookmark_base
        self.uuid = 'fa95aaf5-ab3b-4cd8-88c0-2be7dd051aaf'
        self.server_uuid = "aa640691-d1a7-4a67-9d3c-d35ee6b3cc74"
        self.server_href = ("http://localhost%s/servers/%s" %
                            (self.url_base, self.server_uuid))
        self.server_bookmark = ("http://localhost%s/servers/%s" %
                                (self.bookmark_base, self.server_uuid))
        self.alternate = "%s/images/%s"

        self.expected_image_123 = {
            "image": {
                'id':
                '123',
                'name':
                'public image',
                'metadata': {
                    'key1': 'value1'
                },
                'updated':
                NOW_API_FORMAT,
                'created':
                NOW_API_FORMAT,
                'status':
                'ACTIVE',
                'minDisk':
                10,
                'progress':
                100,
                'minRam':
                128,
                "links": [{
                    "rel": "self",
                    "href": "%s/123" % self.url_prefix
                }, {
                    "rel": "bookmark",
                    "href": "%s/123" % self.bookmark_prefix
                }, {
                    "rel":
                    "alternate",
                    "type":
                    "application/vnd.openstack.image",
                    "href":
                    self.alternate % (glance.generate_glance_url(), 123),
                }],
            },
        }

        self.expected_image_124 = {
            "image": {
                'id':
                '124',
                'name':
                'queued snapshot',
                'metadata': {
                    u'instance_uuid': self.server_uuid,
                    u'user_id': u'fake',
                },
                'updated':
                NOW_API_FORMAT,
                'created':
                NOW_API_FORMAT,
                'status':
                'SAVING',
                'progress':
                25,
                'minDisk':
                0,
                'minRam':
                0,
                'server': {
                    'id':
                    self.server_uuid,
                    "links": [{
                        "rel": "self",
                        "href": self.server_href,
                    }, {
                        "rel": "bookmark",
                        "href": self.server_bookmark,
                    }],
                },
                "links": [{
                    "rel": "self",
                    "href": "%s/124" % self.url_prefix
                }, {
                    "rel": "bookmark",
                    "href": "%s/124" % self.bookmark_prefix
                }, {
                    "rel":
                    "alternate",
                    "type":
                    "application/vnd.openstack.image",
                    "href":
                    self.alternate % (glance.generate_glance_url(), 124),
                }],
            },
        }

    @mock.patch('patron.image.api.API.get', return_value=IMAGE_FIXTURES[0])
    def test_get_image(self, get_mocked):
        request = self.http_request.blank(self.url_base + 'images/123')
        actual_image = self.controller.show(request, '123')
        self.assertThat(actual_image,
                        matchers.DictMatches(self.expected_image_123))
        get_mocked.assert_called_once_with(mock.ANY, '123')

    @mock.patch('patron.image.api.API.get', return_value=IMAGE_FIXTURES[1])
    def test_get_image_with_custom_prefix(self, _get_mocked):
        self.flags(osapi_compute_link_prefix='https://zoo.com:42',
                   osapi_glance_link_prefix='http://circus.com:34')
        fake_req = self.http_request.blank(self.url_base + 'images/124')
        actual_image = self.controller.show(fake_req, '124')

        expected_image = self.expected_image_124
        expected_image["image"]["links"][0]["href"] = (
            "https://zoo.com:42%s/images/124" % self.url_base)
        expected_image["image"]["links"][1]["href"] = (
            "https://zoo.com:42%s/images/124" % self.bookmark_base)
        expected_image["image"]["links"][2]["href"] = (
            "http://circus.com:34/images/124")
        expected_image["image"]["server"]["links"][0]["href"] = (
            "https://zoo.com:42%s/servers/%s" %
            (self.url_base, self.server_uuid))
        expected_image["image"]["server"]["links"][1]["href"] = (
            "https://zoo.com:42%s/servers/%s" %
            (self.bookmark_base, self.server_uuid))

        self.assertThat(actual_image, matchers.DictMatches(expected_image))

    @mock.patch('patron.image.api.API.get',
                side_effect=exception.ImageNotFound(image_id=''))
    def test_get_image_404(self, _get_mocked):
        fake_req = self.http_request.blank(self.url_base + 'images/unknown')
        self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
                          fake_req, 'unknown')

    @mock.patch('patron.image.api.API.get_all', return_value=IMAGE_FIXTURES)
    def test_get_image_details(self, get_all_mocked):
        request = self.http_request.blank(self.url_base + 'images/detail')
        response = self.controller.detail(request)

        get_all_mocked.assert_called_once_with(mock.ANY, filters={})
        response_list = response["images"]

        image_125 = copy.deepcopy(self.expected_image_124["image"])
        image_125['id'] = '125'
        image_125['name'] = 'saving snapshot'
        image_125['progress'] = 50
        image_125["links"][0]["href"] = "%s/125" % self.url_prefix
        image_125["links"][1]["href"] = "%s/125" % self.bookmark_prefix
        image_125["links"][2]["href"] = ("%s/images/125" %
                                         glance.generate_glance_url())

        image_126 = copy.deepcopy(self.expected_image_124["image"])
        image_126['id'] = '126'
        image_126['name'] = 'active snapshot'
        image_126['status'] = 'ACTIVE'
        image_126['progress'] = 100
        image_126["links"][0]["href"] = "%s/126" % self.url_prefix
        image_126["links"][1]["href"] = "%s/126" % self.bookmark_prefix
        image_126["links"][2]["href"] = ("%s/images/126" %
                                         glance.generate_glance_url())

        image_127 = copy.deepcopy(self.expected_image_124["image"])
        image_127['id'] = '127'
        image_127['name'] = 'killed snapshot'
        image_127['status'] = 'ERROR'
        image_127['progress'] = 0
        image_127["links"][0]["href"] = "%s/127" % self.url_prefix
        image_127["links"][1]["href"] = "%s/127" % self.bookmark_prefix
        image_127["links"][2]["href"] = ("%s/images/127" %
                                         glance.generate_glance_url())

        image_128 = copy.deepcopy(self.expected_image_124["image"])
        image_128['id'] = '128'
        image_128['name'] = 'deleted snapshot'
        image_128['status'] = 'DELETED'
        image_128['progress'] = 0
        image_128["links"][0]["href"] = "%s/128" % self.url_prefix
        image_128["links"][1]["href"] = "%s/128" % self.bookmark_prefix
        image_128["links"][2]["href"] = ("%s/images/128" %
                                         glance.generate_glance_url())

        image_129 = copy.deepcopy(self.expected_image_124["image"])
        image_129['id'] = '129'
        image_129['name'] = 'pending_delete snapshot'
        image_129['status'] = 'DELETED'
        image_129['progress'] = 0
        image_129["links"][0]["href"] = "%s/129" % self.url_prefix
        image_129["links"][1]["href"] = "%s/129" % self.bookmark_prefix
        image_129["links"][2]["href"] = ("%s/images/129" %
                                         glance.generate_glance_url())

        image_130 = copy.deepcopy(self.expected_image_123["image"])
        image_130['id'] = '130'
        image_130['name'] = None
        image_130['metadata'] = {}
        image_130['minDisk'] = 0
        image_130['minRam'] = 0
        image_130["links"][0]["href"] = "%s/130" % self.url_prefix
        image_130["links"][1]["href"] = "%s/130" % self.bookmark_prefix
        image_130["links"][2]["href"] = ("%s/images/130" %
                                         glance.generate_glance_url())

        image_131 = copy.deepcopy(self.expected_image_123["image"])
        image_131['id'] = '131'
        image_131['name'] = None
        image_131['metadata'] = {}
        image_131['minDisk'] = 0
        image_131['minRam'] = 0
        image_131["links"][0]["href"] = "%s/131" % self.url_prefix
        image_131["links"][1]["href"] = "%s/131" % self.bookmark_prefix
        image_131["links"][2]["href"] = ("%s/images/131" %
                                         glance.generate_glance_url())

        expected = [
            self.expected_image_123["image"], self.expected_image_124["image"],
            image_125, image_126, image_127, image_128, image_129, image_130,
            image_131
        ]

        self.assertThat(expected, matchers.DictListMatches(response_list))

    @mock.patch('patron.image.api.API.get_all')
    def test_get_image_details_with_limit(self, get_all_mocked):
        request = self.http_request.blank(self.url_base +
                                          'images/detail?limit=2')
        self.controller.detail(request)
        get_all_mocked.assert_called_once_with(mock.ANY, limit=2, filters={})

    @mock.patch('patron.image.api.API.get_all')
    def test_get_image_details_with_limit_and_page_size(self, get_all_mocked):
        request = self.http_request.blank(self.url_base +
                                          'images/detail?limit=2&page_size=1')
        self.controller.detail(request)
        get_all_mocked.assert_called_once_with(mock.ANY,
                                               limit=2,
                                               filters={},
                                               page_size=1)

    @mock.patch('patron.image.api.API.get_all')
    def _detail_request(self, filters, request, get_all_mocked):
        self.controller.detail(request)
        get_all_mocked.assert_called_once_with(mock.ANY, filters=filters)

    def test_image_detail_filter_with_name(self):
        filters = {'name': 'testname'}
        request = self.http_request.blank(self.url_base + 'images/detail'
                                          '?name=testname')
        self._detail_request(filters, request)

    def test_image_detail_filter_with_status(self):
        filters = {'status': 'active'}
        request = self.http_request.blank(self.url_base + 'images/detail'
                                          '?status=ACTIVE')
        self._detail_request(filters, request)

    def test_image_detail_filter_with_property(self):
        filters = {'property-test': '3'}
        request = self.http_request.blank(self.url_base + 'images/detail'
                                          '?property-test=3')
        self._detail_request(filters, request)

    def test_image_detail_filter_server_href(self):
        filters = {'property-instance_uuid': self.uuid}
        request = self.http_request.blank(self.url_base +
                                          'images/detail?server=' + self.uuid)
        self._detail_request(filters, request)

    def test_image_detail_filter_server_uuid(self):
        filters = {'property-instance_uuid': self.uuid}
        request = self.http_request.blank(self.url_base +
                                          'images/detail?server=' + self.uuid)
        self._detail_request(filters, request)

    def test_image_detail_filter_changes_since(self):
        filters = {'changes-since': '2011-01-24T17:08Z'}
        request = self.http_request.blank(self.url_base + 'images/detail'
                                          '?changes-since=2011-01-24T17:08Z')
        self._detail_request(filters, request)

    def test_image_detail_filter_with_type(self):
        filters = {'property-image_type': 'BASE'}
        request = self.http_request.blank(self.url_base +
                                          'images/detail?type=BASE')
        self._detail_request(filters, request)

    def test_image_detail_filter_not_supported(self):
        filters = {'status': 'active'}
        request = self.http_request.blank(self.url_base +
                                          'images/detail?status='
                                          'ACTIVE&UNSUPPORTEDFILTER=testname')
        self._detail_request(filters, request)

    def test_image_detail_no_filters(self):
        filters = {}
        request = self.http_request.blank(self.url_base + 'images/detail')
        self._detail_request(filters, request)

    @mock.patch('patron.image.api.API.get_all', side_effect=exception.Invalid)
    def test_image_detail_invalid_marker(self, _get_all_mocked):
        request = self.http_request.blank(self.url_base + '?marker=invalid')
        self.assertRaises(webob.exc.HTTPBadRequest, self.controller.detail,
                          request)

    def test_generate_alternate_link(self):
        view = images_view.ViewBuilder()
        request = self.http_request.blank(self.url_base + 'images/1')
        generated_url = view._get_alternate_link(request, 1)
        actual_url = "%s/images/1" % glance.generate_glance_url()
        self.assertEqual(generated_url, actual_url)

    def _check_response(self, controller_method, response, expected_code):
        self.assertEqual(expected_code, controller_method.wsgi_code)

    @mock.patch('patron.image.api.API.delete')
    def test_delete_image(self, delete_mocked):
        request = self.http_request.blank(self.url_base + 'images/124')
        request.method = 'DELETE'
        response = self.controller.delete(request, '124')
        self._check_response(self.controller.delete, response, 204)
        delete_mocked.assert_called_once_with(mock.ANY, '124')

    @mock.patch('patron.image.api.API.delete',
                side_effect=exception.ImageNotAuthorized(image_id='123'))
    def test_delete_deleted_image(self, _delete_mocked):
        # If you try to delete a deleted image, you get back 403 Forbidden.
        request = self.http_request.blank(self.url_base + 'images/123')
        request.method = 'DELETE'
        self.assertRaises(webob.exc.HTTPForbidden, self.controller.delete,
                          request, '123')

    @mock.patch('patron.image.api.API.delete',
                side_effect=exception.ImageNotFound(image_id='123'))
    def test_delete_image_not_found(self, _delete_mocked):
        request = self.http_request.blank(self.url_base + 'images/300')
        request.method = 'DELETE'
        self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
                          request, '300')

    @mock.patch('patron.image.api.API.get_all',
                return_value=[IMAGE_FIXTURES[0]])
    def test_get_image_next_link(self, get_all_mocked):
        request = self.http_request.blank(self.url_base + 'imagesl?limit=1')
        response = self.controller.index(request)
        response_links = response['images_links']
        href_parts = urlparse.urlparse(response_links[0]['href'])
        self.assertEqual(self.url_base + '/images', href_parts.path)
        params = urlparse.parse_qs(href_parts.query)
        self.assertThat({
            'limit': ['1'],
            'marker': [IMAGE_FIXTURES[0]['id']]
        }, matchers.DictMatches(params))

    @mock.patch('patron.image.api.API.get_all',
                return_value=[IMAGE_FIXTURES[0]])
    def test_get_image_details_next_link(self, get_all_mocked):
        request = self.http_request.blank(self.url_base +
                                          'images/detail?limit=1')
        response = self.controller.detail(request)
        response_links = response['images_links']
        href_parts = urlparse.urlparse(response_links[0]['href'])
        self.assertEqual(self.url_base + '/images/detail', href_parts.path)
        params = urlparse.parse_qs(href_parts.query)
        self.assertThat({
            'limit': ['1'],
            'marker': [IMAGE_FIXTURES[0]['id']]
        }, matchers.DictMatches(params))
Example #11
0
 def test_get_image_meta_no_image(self):
     error = exception.ImageNotFound(image_id='fake-image')
     self._test_get_image_meta_exception(error)