Merge "Add request id to returned objects"
This commit is contained in:
@@ -36,6 +36,7 @@ else:
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import strutils
|
||||
import prettytable
|
||||
import wrapt
|
||||
|
||||
from glanceclient._i18n import _
|
||||
from glanceclient import exc
|
||||
@@ -472,3 +473,76 @@ class IterableWithLength(object):
|
||||
|
||||
def __len__(self):
|
||||
return self.length
|
||||
|
||||
|
||||
class RequestIdProxy(wrapt.ObjectProxy):
|
||||
def __init__(self, wrapped):
|
||||
# `wrapped` is a tuple: (original_obj, response_obj)
|
||||
super(RequestIdProxy, self).__init__(wrapped[0])
|
||||
self._self_wrapped = wrapped[0]
|
||||
req_id = _extract_request_id(wrapped[1])
|
||||
self._self_request_ids = [req_id]
|
||||
|
||||
@property
|
||||
def request_ids(self):
|
||||
return self._self_request_ids
|
||||
|
||||
@property
|
||||
def wrapped(self):
|
||||
return self._self_wrapped
|
||||
|
||||
|
||||
class GeneratorProxy(wrapt.ObjectProxy):
|
||||
def __init__(self, wrapped):
|
||||
super(GeneratorProxy, self).__init__(wrapped)
|
||||
self._self_wrapped = wrapped
|
||||
self._self_request_ids = []
|
||||
|
||||
def _set_request_ids(self, resp):
|
||||
if self._self_request_ids == []:
|
||||
req_id = _extract_request_id(resp)
|
||||
self._self_request_ids = [req_id]
|
||||
|
||||
def _next(self):
|
||||
obj, resp = next(self._self_wrapped)
|
||||
self._set_request_ids(resp)
|
||||
return obj
|
||||
|
||||
# Override generator's next method to add
|
||||
# request id on each iteration
|
||||
def next(self):
|
||||
return self._next()
|
||||
|
||||
# For Python 3 compatibility
|
||||
def __next__(self):
|
||||
return self._next()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
@property
|
||||
def request_ids(self):
|
||||
return self._self_request_ids
|
||||
|
||||
@property
|
||||
def wrapped(self):
|
||||
return self._self_wrapped
|
||||
|
||||
|
||||
def add_req_id_to_object():
|
||||
@wrapt.decorator
|
||||
def inner(wrapped, instance, args, kwargs):
|
||||
return RequestIdProxy(wrapped(*args, **kwargs))
|
||||
return inner
|
||||
|
||||
|
||||
def add_req_id_to_generator():
|
||||
@wrapt.decorator
|
||||
def inner(wrapped, instance, args, kwargs):
|
||||
return GeneratorProxy(wrapped(*args, **kwargs))
|
||||
return inner
|
||||
|
||||
|
||||
def _extract_request_id(resp):
|
||||
# TODO(rsjethani): Do we need more checks here?
|
||||
return resp.headers.get('x-openstack-request-id')
|
||||
|
||||
@@ -17,6 +17,7 @@ import sys
|
||||
|
||||
import mock
|
||||
from oslo_utils import encodeutils
|
||||
from requests import Response
|
||||
import six
|
||||
# NOTE(jokke): simplified transition to py3, behaves like py2 xrange
|
||||
from six.moves import range
|
||||
@@ -25,6 +26,15 @@ import testtools
|
||||
from glanceclient.common import utils
|
||||
|
||||
|
||||
REQUEST_ID = 'req-1234'
|
||||
|
||||
|
||||
def create_response_obj_with_req_id(req_id):
|
||||
resp = Response()
|
||||
resp.headers['x-openstack-request-id'] = req_id
|
||||
return resp
|
||||
|
||||
|
||||
class TestUtils(testtools.TestCase):
|
||||
|
||||
def test_make_size_human_readable(self):
|
||||
@@ -178,3 +188,43 @@ class TestUtils(testtools.TestCase):
|
||||
(name, value) = utils.safe_header(sensitive_header, None)
|
||||
self.assertEqual(sensitive_header, name)
|
||||
self.assertIsNone(value)
|
||||
|
||||
def test_generator_proxy(self):
|
||||
def _test_decorator():
|
||||
i = 1
|
||||
resp = create_response_obj_with_req_id(REQUEST_ID)
|
||||
while True:
|
||||
yield i, resp
|
||||
i += 1
|
||||
|
||||
gen_obj = _test_decorator()
|
||||
proxy = utils.GeneratorProxy(gen_obj)
|
||||
|
||||
# Proxy object should succeed in behaving as the
|
||||
# wrapped object
|
||||
self.assertTrue(isinstance(proxy, type(gen_obj)))
|
||||
|
||||
# Initially request_ids should be empty
|
||||
self.assertEqual([], proxy.request_ids)
|
||||
|
||||
# Only after we have started iterating we should
|
||||
# see non-empty `request_ids` property
|
||||
proxy.next()
|
||||
self.assertEqual([REQUEST_ID], proxy.request_ids)
|
||||
|
||||
# Even after multiple iterations `request_ids` property
|
||||
# should only contain one request id
|
||||
proxy.next()
|
||||
proxy.next()
|
||||
self.assertEqual(1, len(proxy.request_ids))
|
||||
|
||||
def test_request_id_proxy(self):
|
||||
def test_data(val):
|
||||
resp = create_response_obj_with_req_id(REQUEST_ID)
|
||||
return val, resp
|
||||
|
||||
# Object of any type except decorator can be passed to test_data
|
||||
proxy = utils.RequestIdProxy(test_data(11))
|
||||
# Verify that proxy object has a property `request_ids` and it is
|
||||
# a list of one request id
|
||||
self.assertEqual([REQUEST_ID], proxy.request_ids)
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# Copyright 2016 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import testtools
|
||||
|
||||
|
||||
class BaseController(testtools.TestCase):
|
||||
def __init__(self, api, schema_api, controller_class):
|
||||
self.controller = controller_class(api, schema_api)
|
||||
|
||||
def _assertRequestId(self, obj):
|
||||
self.assertIsNotNone(getattr(obj, 'request_ids', None))
|
||||
self.assertEqual(['req-1234'], obj.request_ids)
|
||||
|
||||
def list(self, *args, **kwargs):
|
||||
gen_obj = self.controller.list(*args, **kwargs)
|
||||
# For generator cases the request_ids property will be an empty list
|
||||
# until the underlying generator is invoked at-least once.
|
||||
resources = list(gen_obj)
|
||||
if len(resources) > 0:
|
||||
self._assertRequestId(gen_obj)
|
||||
else:
|
||||
# If list is empty that means geneator object has raised
|
||||
# StopIteration for first iteration and will not contain the
|
||||
# request_id in it.
|
||||
self.assertEqual([], gen_obj.request_ids)
|
||||
|
||||
return resources
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
resource = self.controller.get(*args, **kwargs)
|
||||
|
||||
self._assertRequestId(resource)
|
||||
return resource
|
||||
|
||||
def create(self, *args, **kwargs):
|
||||
resource = self.controller.create(*args, **kwargs)
|
||||
self._assertRequestId(resource)
|
||||
return resource
|
||||
|
||||
def create_multiple(self, *args, **kwargs):
|
||||
tags = self.controller.create_multiple(*args, **kwargs)
|
||||
actual = [tag.name for tag in tags]
|
||||
self._assertRequestId(tags)
|
||||
return actual
|
||||
|
||||
def update(self, *args, **properties):
|
||||
resource = self.controller.update(*args, **properties)
|
||||
self._assertRequestId(resource)
|
||||
return resource
|
||||
|
||||
def delete(self, *args):
|
||||
resp = self.controller.delete(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def delete_all(self, *args):
|
||||
resp = self.controller.delete_all(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def deactivate(self, *args):
|
||||
resp = self.controller.deactivate(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def reactivate(self, *args):
|
||||
resp = self.controller.reactivate(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def upload(self, *args, **kwargs):
|
||||
resp = self.controller.upload(*args, **kwargs)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def data(self, *args, **kwargs):
|
||||
body = self.controller.data(*args, **kwargs)
|
||||
self._assertRequestId(body)
|
||||
return body
|
||||
|
||||
def delete_locations(self, *args):
|
||||
resp = self.controller.delete_locations(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def add_location(self, *args, **kwargs):
|
||||
resp = self.controller.add_location(*args, **kwargs)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def update_location(self, *args, **kwargs):
|
||||
resp = self.controller.update_location(*args, **kwargs)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
def associate(self, *args, **kwargs):
|
||||
resource_types = self.controller.associate(*args, **kwargs)
|
||||
self._assertRequestId(resource_types)
|
||||
return resource_types
|
||||
|
||||
def deassociate(self, *args):
|
||||
resp = self.controller.deassociate(*args)
|
||||
self._assertRequestId(resp)
|
||||
|
||||
|
||||
class BaseResourceTypeController(BaseController):
|
||||
def __init__(self, api, schema_api, controller_class):
|
||||
super(BaseResourceTypeController, self).__init__(api, schema_api,
|
||||
controller_class)
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
resource_types = self.controller.get(*args)
|
||||
names = [rt.name for rt in resource_types]
|
||||
self._assertRequestId(resource_types)
|
||||
return names
|
||||
@@ -18,6 +18,7 @@ import mock
|
||||
import testtools
|
||||
|
||||
from glanceclient import exc
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import images
|
||||
|
||||
@@ -532,27 +533,25 @@ class TestController(testtools.TestCase):
|
||||
super(TestController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = images.Controller(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
images.Controller)
|
||||
|
||||
def test_list_images(self):
|
||||
# NOTE(bcwaldon):cast to list since the controller returns a generator
|
||||
images = list(self.controller.list())
|
||||
images = self.controller.list()
|
||||
self.assertEqual('3a4560a1-e585-443e-9b39-553b46ec92d1', images[0].id)
|
||||
self.assertEqual('image-1', images[0].name)
|
||||
self.assertEqual('6f99bf80-2ee6-47cf-acfe-1f1fabb7e810', images[1].id)
|
||||
self.assertEqual('image-2', images[1].name)
|
||||
|
||||
def test_list_images_paginated(self):
|
||||
# NOTE(bcwaldon):cast to list since the controller returns a generator
|
||||
images = list(self.controller.list(page_size=1))
|
||||
images = self.controller.list(page_size=1)
|
||||
self.assertEqual('3a4560a1-e585-443e-9b39-553b46ec92d1', images[0].id)
|
||||
self.assertEqual('image-1', images[0].name)
|
||||
self.assertEqual('6f99bf80-2ee6-47cf-acfe-1f1fabb7e810', images[1].id)
|
||||
self.assertEqual('image-2', images[1].name)
|
||||
|
||||
def test_list_images_paginated_with_limit(self):
|
||||
# NOTE(bcwaldon):cast to list since the controller returns a generator
|
||||
images = list(self.controller.list(limit=3, page_size=2))
|
||||
images = self.controller.list(limit=3, page_size=2)
|
||||
self.assertEqual('3a4560a1-e585-443e-9b39-553b46ec92d1', images[0].id)
|
||||
self.assertEqual('image-1', images[0].name)
|
||||
self.assertEqual('6f99bf80-2ee6-47cf-acfe-1f1fabb7e810', images[1].id)
|
||||
@@ -562,40 +561,40 @@ class TestController(testtools.TestCase):
|
||||
self.assertEqual(3, len(images))
|
||||
|
||||
def test_list_images_with_marker(self):
|
||||
images = list(self.controller.list(limit=1,
|
||||
marker='3a4560a1-e585-443e-9b39-553b46ec92d1'))
|
||||
images = self.controller.list(
|
||||
limit=1, marker='3a4560a1-e585-443e-9b39-553b46ec92d1')
|
||||
self.assertEqual('6f99bf80-2ee6-47cf-acfe-1f1fabb7e810', images[0].id)
|
||||
self.assertEqual('image-2', images[0].name)
|
||||
|
||||
def test_list_images_visibility_public(self):
|
||||
filters = {'filters': {'visibility': 'public'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_PUBLIC_ID, images[0].id)
|
||||
|
||||
def test_list_images_visibility_private(self):
|
||||
filters = {'filters': {'visibility': 'private'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_PRIVATE_ID, images[0].id)
|
||||
|
||||
def test_list_images_visibility_shared(self):
|
||||
filters = {'filters': {'visibility': 'shared'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_SHARED_ID, images[0].id)
|
||||
|
||||
def test_list_images_member_status_rejected(self):
|
||||
filters = {'filters': {'member_status': 'rejected'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_STATUS_REJECTED_ID, images[0].id)
|
||||
|
||||
def test_list_images_for_owner(self):
|
||||
filters = {'filters': {'owner': _OWNER_ID}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_OWNED_IMAGE_ID, images[0].id)
|
||||
|
||||
def test_list_images_for_checksum_single_image(self):
|
||||
fake_id = '3a4560a1-e585-443e-9b39-553b46ec92d1'
|
||||
filters = {'filters': {'checksum': _CHKSUM}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(1, len(images))
|
||||
self.assertEqual('%s' % fake_id, images[0].id)
|
||||
|
||||
@@ -603,32 +602,32 @@ class TestController(testtools.TestCase):
|
||||
fake_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
fake_id2 = '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810'
|
||||
filters = {'filters': {'checksum': _CHKSUM1}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % fake_id1, images[0].id)
|
||||
self.assertEqual('%s' % fake_id2, images[1].id)
|
||||
|
||||
def test_list_images_for_wrong_checksum(self):
|
||||
filters = {'filters': {'checksum': 'wrong'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
def test_list_images_for_bogus_owner(self):
|
||||
filters = {'filters': {'owner': _BOGUS_ID}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual([], images)
|
||||
|
||||
def test_list_images_for_bunch_of_filters(self):
|
||||
filters = {'filters': {'owner': _BOGUS_ID,
|
||||
'visibility': 'shared',
|
||||
'member_status': 'pending'}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(_EVERYTHING_ID, images[0].id)
|
||||
|
||||
def test_list_images_filters_encoding(self):
|
||||
filters = {"owner": u"ni\xf1o"}
|
||||
try:
|
||||
list(self.controller.list(filters=filters))
|
||||
self.controller.list(filters=filters)
|
||||
except KeyError:
|
||||
# NOTE(flaper87): It raises KeyError because there's
|
||||
# no fixture supporting this query:
|
||||
@@ -640,7 +639,7 @@ class TestController(testtools.TestCase):
|
||||
def test_list_images_for_tag_single_image(self):
|
||||
img_id = '3a4560a1-e585-443e-9b39-553b46ec92d1'
|
||||
filters = {'filters': {'tag': [_TAG1]}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(1, len(images))
|
||||
self.assertEqual('%s' % img_id, images[0].id)
|
||||
|
||||
@@ -648,7 +647,7 @@ class TestController(testtools.TestCase):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
img_id2 = '6f99bf80-2ee6-47cf-acfe-1f1fabb7e810'
|
||||
filters = {'filters': {'tag': [_TAG2]}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[0].id)
|
||||
self.assertEqual('%s' % img_id2, images[1].id)
|
||||
@@ -656,33 +655,32 @@ class TestController(testtools.TestCase):
|
||||
def test_list_images_for_multi_tags(self):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
filters = {'filters': {'tag': [_TAG1, _TAG2]}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(1, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[0].id)
|
||||
|
||||
def test_list_images_for_non_existent_tag(self):
|
||||
filters = {'filters': {'tag': ['fake']}}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
def test_list_images_for_invalid_tag(self):
|
||||
filters = {'filters': {'tag': [[]]}}
|
||||
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
list,
|
||||
self.controller.list(**filters))
|
||||
self.controller.list, **filters)
|
||||
|
||||
def test_list_images_with_single_sort_key(self):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort_key = 'name'
|
||||
images = list(self.controller.list(sort_key=sort_key))
|
||||
images = self.controller.list(sort_key=sort_key)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[0].id)
|
||||
|
||||
def test_list_with_multiple_sort_keys(self):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort_key = ['name', 'id']
|
||||
images = list(self.controller.list(sort_key=sort_key))
|
||||
images = self.controller.list(sort_key=sort_key)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[0].id)
|
||||
|
||||
@@ -690,8 +688,7 @@ class TestController(testtools.TestCase):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort_key = 'id'
|
||||
sort_dir = 'desc'
|
||||
images = list(self.controller.list(sort_key=sort_key,
|
||||
sort_dir=sort_dir))
|
||||
images = self.controller.list(sort_key=sort_key, sort_dir=sort_dir)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[1].id)
|
||||
|
||||
@@ -699,8 +696,7 @@ class TestController(testtools.TestCase):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort_key = ['name', 'id']
|
||||
sort_dir = 'desc'
|
||||
images = list(self.controller.list(sort_key=sort_key,
|
||||
sort_dir=sort_dir))
|
||||
images = self.controller.list(sort_key=sort_key, sort_dir=sort_dir)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[1].id)
|
||||
|
||||
@@ -708,61 +704,50 @@ class TestController(testtools.TestCase):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort_key = ['name', 'id']
|
||||
sort_dir = ['desc', 'asc']
|
||||
images = list(self.controller.list(sort_key=sort_key,
|
||||
sort_dir=sort_dir))
|
||||
images = self.controller.list(sort_key=sort_key, sort_dir=sort_dir)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[1].id)
|
||||
|
||||
def test_list_images_with_new_sorting_syntax(self):
|
||||
img_id1 = '2a4560b2-e585-443e-9b39-553b46ec92d1'
|
||||
sort = 'name:desc,size:asc'
|
||||
images = list(self.controller.list(sort=sort))
|
||||
images = self.controller.list(sort=sort)
|
||||
self.assertEqual(2, len(images))
|
||||
self.assertEqual('%s' % img_id1, images[1].id)
|
||||
|
||||
def test_list_images_sort_dirs_fewer_than_keys(self):
|
||||
sort_key = ['name', 'id', 'created_at']
|
||||
sort_dir = ['desc', 'asc']
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
list,
|
||||
self.controller.list(
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir))
|
||||
self.assertRaises(exc.HTTPBadRequest, self.controller.list,
|
||||
sort_key=sort_key, sort_dir=sort_dir)
|
||||
|
||||
def test_list_images_combined_syntax(self):
|
||||
sort_key = ['name', 'id']
|
||||
sort_dir = ['desc', 'asc']
|
||||
sort = 'name:asc'
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
list,
|
||||
self.controller.list(
|
||||
sort=sort,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir))
|
||||
self.controller.list, sort=sort, sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
def test_list_images_new_sorting_syntax_invalid_key(self):
|
||||
sort = 'INVALID:asc'
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
list,
|
||||
self.controller.list(
|
||||
sort=sort))
|
||||
self.assertRaises(exc.HTTPBadRequest, self.controller.list,
|
||||
sort=sort)
|
||||
|
||||
def test_list_images_new_sorting_syntax_invalid_direction(self):
|
||||
sort = 'name:INVALID'
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
list,
|
||||
self.controller.list(
|
||||
sort=sort))
|
||||
self.assertRaises(exc.HTTPBadRequest, self.controller.list,
|
||||
sort=sort)
|
||||
|
||||
def test_list_images_for_property(self):
|
||||
filters = {'filters': dict([('os_distro', 'NixOS')])}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(1, len(images))
|
||||
|
||||
def test_list_images_for_non_existent_property(self):
|
||||
filters = {'filters': dict([('my_little_property',
|
||||
'cant_be_this_cute')])}
|
||||
images = list(self.controller.list(**filters))
|
||||
images = self.controller.list(**filters)
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
def test_get_image(self):
|
||||
@@ -804,7 +789,7 @@ class TestController(testtools.TestCase):
|
||||
None)]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
|
||||
def reactivate_image(self):
|
||||
def test_reactivate_image(self):
|
||||
id_image = '87b634c1-f893-33c9-28a9-e5673c99239a'
|
||||
self.controller.reactivate(id_image)
|
||||
expect = [('POST',
|
||||
@@ -868,12 +853,12 @@ class TestController(testtools.TestCase):
|
||||
|
||||
def test_download_no_data(self):
|
||||
resp = utils.FakeResponse(headers={}, status_code=204)
|
||||
self.controller.http_client.get = mock.Mock(return_value=(resp, None))
|
||||
body = self.controller.data('image_id')
|
||||
self.assertIsNone(body)
|
||||
self.controller.controller.http_client.get = mock.Mock(
|
||||
return_value=(resp, None))
|
||||
self.controller.data('image_id')
|
||||
|
||||
def test_download_forbidden(self):
|
||||
self.controller.http_client.get = mock.Mock(
|
||||
self.controller.controller.http_client.get = mock.Mock(
|
||||
side_effect=exc.HTTPForbidden())
|
||||
try:
|
||||
self.controller.data('image_id')
|
||||
@@ -893,7 +878,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -912,7 +898,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -931,7 +918,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -953,7 +941,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -974,7 +963,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -999,7 +989,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -1016,7 +1007,8 @@ class TestController(testtools.TestCase):
|
||||
expect = [
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('PATCH', '/v2/images/%s' % image_id, expect_hdrs, expect_body),
|
||||
('GET', '/v2/images/%s' % image_id, {}, None),
|
||||
('GET', '/v2/images/%s' % image_id,
|
||||
{'x-openstack-request-id': 'req-1234'}, None),
|
||||
]
|
||||
self.assertEqual(expect, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
@@ -1040,8 +1032,9 @@ class TestController(testtools.TestCase):
|
||||
image_id, url, meta)
|
||||
self.assertIn(estr, str(e))
|
||||
|
||||
def _empty_get(self, image_id):
|
||||
return ('GET', '/v2/images/%s' % image_id, {}, None)
|
||||
def _empty_get(self, image_id, headers=None):
|
||||
return ('GET', '/v2/images/%s' % image_id,
|
||||
headers or {}, None)
|
||||
|
||||
def _patch_req(self, image_id, patch_body):
|
||||
c_type = 'application/openstack-images-v2.1-json-patch'
|
||||
@@ -1055,9 +1048,11 @@ class TestController(testtools.TestCase):
|
||||
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
||||
new_loc = {'url': 'http://spam.com/', 'metadata': {'spam': 'ham'}}
|
||||
add_patch = {'path': '/locations/-', 'value': new_loc, 'op': 'add'}
|
||||
headers = {'x-openstack-request-id': 'req-1234'}
|
||||
self.controller.add_location(image_id, **new_loc)
|
||||
self.assertEqual([self._patch_req(image_id, [add_patch]),
|
||||
self._empty_get(image_id)], self.api.calls)
|
||||
self._empty_get(image_id, headers=headers)],
|
||||
self.api.calls)
|
||||
|
||||
@mock.patch.object(images.Controller, '_send_image_update_request',
|
||||
side_effect=exc.HTTPBadRequest)
|
||||
@@ -1092,6 +1087,7 @@ class TestController(testtools.TestCase):
|
||||
def test_update_location(self):
|
||||
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
||||
new_loc = {'url': 'http://foo.com/', 'metadata': {'spam': 'ham'}}
|
||||
headers = {'x-openstack-request-id': 'req-1234'}
|
||||
fixture_idx = '/v2/images/%s' % (image_id)
|
||||
orig_locations = data_fixtures[fixture_idx]['GET'][1]['locations']
|
||||
loc_map = dict([(l['url'], l) for l in orig_locations])
|
||||
@@ -1101,12 +1097,13 @@ class TestController(testtools.TestCase):
|
||||
self.controller.update_location(image_id, **new_loc)
|
||||
self.assertEqual([self._empty_get(image_id),
|
||||
self._patch_req(image_id, mod_patch),
|
||||
self._empty_get(image_id)],
|
||||
self._empty_get(image_id, headers=headers)],
|
||||
self.api.calls)
|
||||
|
||||
def test_update_tags(self):
|
||||
image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8'
|
||||
tag_map = {'tags': ['tag01', 'tag02', 'tag03']}
|
||||
headers = {'x-openstack-request-id': 'req-1234'}
|
||||
|
||||
image = self.controller.update(image_id, **tag_map)
|
||||
|
||||
@@ -1115,7 +1112,7 @@ class TestController(testtools.TestCase):
|
||||
expected = [
|
||||
self._empty_get(image_id),
|
||||
self._patch_req(image_id, expected_body),
|
||||
self._empty_get(image_id)
|
||||
self._empty_get(image_id, headers=headers)
|
||||
]
|
||||
self.assertEqual(expected, self.api.calls)
|
||||
self.assertEqual(image_id, image.id)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import image_members
|
||||
|
||||
@@ -80,12 +81,12 @@ class TestController(testtools.TestCase):
|
||||
super(TestController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = image_members.Controller(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
image_members.Controller)
|
||||
|
||||
def test_list_image_members(self):
|
||||
image_id = IMAGE
|
||||
# NOTE(iccha): cast to list since the controller returns a generator
|
||||
image_members = list(self.controller.list(image_id))
|
||||
image_members = self.controller.list(image_id)
|
||||
self.assertEqual(IMAGE, image_members[0].image_id)
|
||||
self.assertEqual(MEMBER, image_members[0].member_id)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import metadefs
|
||||
|
||||
@@ -542,83 +543,79 @@ class TestNamespaceController(testtools.TestCase):
|
||||
super(TestNamespaceController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = metadefs.NamespaceController(self.api,
|
||||
self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
metadefs.NamespaceController)
|
||||
|
||||
def test_list_namespaces(self):
|
||||
namespaces = list(self.controller.list())
|
||||
|
||||
namespaces = self.controller.list()
|
||||
self.assertEqual(2, len(namespaces))
|
||||
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
|
||||
self.assertEqual(NAMESPACE2, namespaces[1]['namespace'])
|
||||
|
||||
def test_list_namespaces_paginate(self):
|
||||
namespaces = list(self.controller.list(page_size=1))
|
||||
|
||||
namespaces = self.controller.list(page_size=1)
|
||||
self.assertEqual(2, len(namespaces))
|
||||
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
|
||||
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
|
||||
|
||||
def test_list_with_limit_greater_than_page_size(self):
|
||||
namespaces = list(self.controller.list(page_size=1, limit=2))
|
||||
namespaces = self.controller.list(page_size=1, limit=2)
|
||||
self.assertEqual(2, len(namespaces))
|
||||
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
|
||||
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
|
||||
|
||||
def test_list_with_marker(self):
|
||||
namespaces = list(self.controller.list(marker=NAMESPACE6, page_size=2))
|
||||
namespaces = self.controller.list(marker=NAMESPACE6, page_size=2)
|
||||
self.assertEqual(2, len(namespaces))
|
||||
self.assertEqual(NAMESPACE7, namespaces[0]['namespace'])
|
||||
self.assertEqual(NAMESPACE8, namespaces[1]['namespace'])
|
||||
|
||||
def test_list_with_sort_dir(self):
|
||||
namespaces = list(self.controller.list(sort_dir='asc', limit=1))
|
||||
namespaces = self.controller.list(sort_dir='asc', limit=1)
|
||||
self.assertEqual(1, len(namespaces))
|
||||
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
|
||||
|
||||
def test_list_with_sort_dir_invalid(self):
|
||||
# NOTE(TravT): The clients work by returning an iterator.
|
||||
# Invoking the iterator is what actually executes the logic.
|
||||
ns_iterator = self.controller.list(sort_dir='foo')
|
||||
self.assertRaises(ValueError, next, ns_iterator)
|
||||
self.assertRaises(ValueError, self.controller.list, sort_dir='foo')
|
||||
|
||||
def test_list_with_sort_key(self):
|
||||
namespaces = list(self.controller.list(sort_key='created_at', limit=1))
|
||||
namespaces = self.controller.list(sort_key='created_at', limit=1)
|
||||
self.assertEqual(1, len(namespaces))
|
||||
self.assertEqual(NAMESPACE1, namespaces[0]['namespace'])
|
||||
|
||||
def test_list_with_sort_key_invalid(self):
|
||||
# NOTE(TravT): The clients work by returning an iterator.
|
||||
# Invoking the iterator is what actually executes the logic.
|
||||
ns_iterator = self.controller.list(sort_key='foo')
|
||||
self.assertRaises(ValueError, next, ns_iterator)
|
||||
self.assertRaises(ValueError, self.controller.list, sort_key='foo')
|
||||
|
||||
def test_list_namespaces_with_one_resource_type_filter(self):
|
||||
namespaces = list(self.controller.list(
|
||||
namespaces = self.controller.list(
|
||||
filters={
|
||||
'resource_types': [RESOURCE_TYPE1]
|
||||
}
|
||||
))
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(namespaces))
|
||||
self.assertEqual(NAMESPACE3, namespaces[0]['namespace'])
|
||||
|
||||
def test_list_namespaces_with_multiple_resource_types_filter(self):
|
||||
namespaces = list(self.controller.list(
|
||||
namespaces = self.controller.list(
|
||||
filters={
|
||||
'resource_types': [RESOURCE_TYPE1, RESOURCE_TYPE2]
|
||||
}
|
||||
))
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(namespaces))
|
||||
self.assertEqual(NAMESPACE4, namespaces[0]['namespace'])
|
||||
|
||||
def test_list_namespaces_with_visibility_filter(self):
|
||||
namespaces = list(self.controller.list(
|
||||
namespaces = self.controller.list(
|
||||
filters={
|
||||
'visibility': 'private'
|
||||
}
|
||||
))
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(namespaces))
|
||||
self.assertEqual(NAMESPACE5, namespaces[0]['namespace'])
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import six
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import metadefs
|
||||
|
||||
@@ -263,11 +264,11 @@ class TestObjectController(testtools.TestCase):
|
||||
super(TestObjectController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = metadefs.ObjectController(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
metadefs.ObjectController)
|
||||
|
||||
def test_list_object(self):
|
||||
objects = list(self.controller.list(NAMESPACE1))
|
||||
|
||||
objects = self.controller.list(NAMESPACE1)
|
||||
actual = [obj.name for obj in objects]
|
||||
self.assertEqual([OBJECT1, OBJECT2], actual)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import metadefs
|
||||
|
||||
@@ -238,12 +239,11 @@ class TestPropertyController(testtools.TestCase):
|
||||
super(TestPropertyController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = metadefs.PropertyController(self.api,
|
||||
self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
metadefs.PropertyController)
|
||||
|
||||
def test_list_property(self):
|
||||
properties = list(self.controller.list(NAMESPACE1))
|
||||
|
||||
properties = self.controller.list(NAMESPACE1)
|
||||
actual = [prop.name for prop in properties]
|
||||
self.assertEqual(sorted([PROPERTY1, PROPERTY2]), sorted(actual))
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import metadefs
|
||||
|
||||
@@ -151,18 +152,17 @@ class TestResoureTypeController(testtools.TestCase):
|
||||
super(TestResoureTypeController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = metadefs.ResourceTypeController(self.api,
|
||||
self.schema_api)
|
||||
self.controller = base.BaseResourceTypeController(
|
||||
self.api, self.schema_api, metadefs.ResourceTypeController)
|
||||
|
||||
def test_list_resource_types(self):
|
||||
resource_types = list(self.controller.list())
|
||||
resource_types = self.controller.list()
|
||||
names = [rt.name for rt in resource_types]
|
||||
self.assertEqual([RESOURCE_TYPE1, RESOURCE_TYPE2], names)
|
||||
|
||||
def test_get_resource_types(self):
|
||||
resource_types = list(self.controller.get(NAMESPACE1))
|
||||
names = [rt.name for rt in resource_types]
|
||||
self.assertEqual([RESOURCE_TYPE3, RESOURCE_TYPE4], names)
|
||||
resource_types = self.controller.get(NAMESPACE1)
|
||||
self.assertEqual([RESOURCE_TYPE3, RESOURCE_TYPE4], resource_types)
|
||||
|
||||
def test_associate_resource_types(self):
|
||||
resource_types = self.controller.associate(NAMESPACE1,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import metadefs
|
||||
|
||||
@@ -134,11 +135,11 @@ class TestTagController(testtools.TestCase):
|
||||
super(TestTagController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = metadefs.TagController(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
metadefs.TagController)
|
||||
|
||||
def test_list_tag(self):
|
||||
tags = list(self.controller.list(NAMESPACE1))
|
||||
|
||||
tags = self.controller.list(NAMESPACE1)
|
||||
actual = [tag.name for tag in tags]
|
||||
self.assertEqual([TAG1, TAG2], actual)
|
||||
|
||||
@@ -155,8 +156,7 @@ class TestTagController(testtools.TestCase):
|
||||
'tags': [TAGNEW2, TAGNEW3]
|
||||
}
|
||||
tags = self.controller.create_multiple(NAMESPACE1, **properties)
|
||||
actual = [tag.name for tag in tags]
|
||||
self.assertEqual([TAGNEW2, TAGNEW3], actual)
|
||||
self.assertEqual([TAGNEW2, TAGNEW3], tags)
|
||||
|
||||
def test_update_tag(self):
|
||||
properties = {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import image_tags
|
||||
|
||||
@@ -54,7 +55,8 @@ class TestController(testtools.TestCase):
|
||||
super(TestController, self).setUp()
|
||||
self.api = utils.FakeAPI(data_fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = image_tags.Controller(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
image_tags.Controller)
|
||||
|
||||
def test_update_image_tag(self):
|
||||
image_id = IMAGE
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import testtools
|
||||
|
||||
from glanceclient.tests.unit.v2 import base
|
||||
from glanceclient.tests import utils
|
||||
from glanceclient.v2 import tasks
|
||||
|
||||
@@ -252,11 +253,11 @@ class TestController(testtools.TestCase):
|
||||
super(TestController, self).setUp()
|
||||
self.api = utils.FakeAPI(fixtures)
|
||||
self.schema_api = utils.FakeSchemaAPI(schema_fixtures)
|
||||
self.controller = tasks.Controller(self.api, self.schema_api)
|
||||
self.controller = base.BaseController(self.api, self.schema_api,
|
||||
tasks.Controller)
|
||||
|
||||
def test_list_tasks(self):
|
||||
# NOTE(flwang): cast to list since the controller returns a generator
|
||||
tasks = list(self.controller.list())
|
||||
tasks = self.controller.list()
|
||||
self.assertEqual(_PENDING_ID, tasks[0].id)
|
||||
self.assertEqual('import', tasks[0].type)
|
||||
self.assertEqual('pending', tasks[0].status)
|
||||
@@ -265,8 +266,7 @@ class TestController(testtools.TestCase):
|
||||
self.assertEqual('processing', tasks[1].status)
|
||||
|
||||
def test_list_tasks_paginated(self):
|
||||
# NOTE(flwang): cast to list since the controller returns a generator
|
||||
tasks = list(self.controller.list(page_size=1))
|
||||
tasks = self.controller.list(page_size=1)
|
||||
self.assertEqual(_PENDING_ID, tasks[0].id)
|
||||
self.assertEqual('import', tasks[0].type)
|
||||
self.assertEqual(_PROCESSING_ID, tasks[1].id)
|
||||
@@ -274,38 +274,38 @@ class TestController(testtools.TestCase):
|
||||
|
||||
def test_list_tasks_with_status(self):
|
||||
filters = {'filters': {'status': 'processing'}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(_OWNED_TASK_ID, tasks[0].id)
|
||||
|
||||
def test_list_tasks_with_wrong_status(self):
|
||||
filters = {'filters': {'status': 'fake'}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(0, len(tasks))
|
||||
|
||||
def test_list_tasks_with_type(self):
|
||||
filters = {'filters': {'type': 'import'}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(_OWNED_TASK_ID, tasks[0].id)
|
||||
|
||||
def test_list_tasks_with_wrong_type(self):
|
||||
filters = {'filters': {'type': 'fake'}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(0, len(tasks))
|
||||
|
||||
def test_list_tasks_for_owner(self):
|
||||
filters = {'filters': {'owner': _OWNER_ID}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(_OWNED_TASK_ID, tasks[0].id)
|
||||
|
||||
def test_list_tasks_for_fake_owner(self):
|
||||
filters = {'filters': {'owner': _FAKE_OWNER_ID}}
|
||||
tasks = list(self.controller.list(**filters))
|
||||
tasks = self.controller.list(**filters)
|
||||
self.assertEqual(tasks, [])
|
||||
|
||||
def test_list_tasks_filters_encoding(self):
|
||||
filters = {"owner": u"ni\xf1o"}
|
||||
try:
|
||||
list(self.controller.list(filters=filters))
|
||||
self.controller.list(filters=filters)
|
||||
except KeyError:
|
||||
# NOTE(flaper87): It raises KeyError because there's
|
||||
# no fixture supporting this query:
|
||||
@@ -316,34 +316,33 @@ class TestController(testtools.TestCase):
|
||||
self.assertEqual(b"ni\xc3\xb1o", filters["owner"])
|
||||
|
||||
def test_list_tasks_with_marker(self):
|
||||
tasks = list(self.controller.list(marker=_PENDING_ID, page_size=1))
|
||||
tasks = self.controller.list(marker=_PENDING_ID, page_size=1)
|
||||
self.assertEqual(1, len(tasks))
|
||||
self.assertEqual(_PROCESSING_ID, tasks[0]['id'])
|
||||
|
||||
def test_list_tasks_with_single_sort_key(self):
|
||||
tasks = list(self.controller.list(sort_key='type'))
|
||||
tasks = self.controller.list(sort_key='type')
|
||||
self.assertEqual(2, len(tasks))
|
||||
self.assertEqual(_PENDING_ID, tasks[0].id)
|
||||
|
||||
def test_list_tasks_with_invalid_sort_key(self):
|
||||
self.assertRaises(ValueError,
|
||||
list,
|
||||
self.controller.list(sort_key='invalid'))
|
||||
self.controller.list, sort_key='invalid')
|
||||
|
||||
def test_list_tasks_with_desc_sort_dir(self):
|
||||
tasks = list(self.controller.list(sort_key='id', sort_dir='desc'))
|
||||
tasks = self.controller.list(sort_key='id', sort_dir='desc')
|
||||
self.assertEqual(2, len(tasks))
|
||||
self.assertEqual(_PENDING_ID, tasks[1].id)
|
||||
|
||||
def test_list_tasks_with_asc_sort_dir(self):
|
||||
tasks = list(self.controller.list(sort_key='id', sort_dir='asc'))
|
||||
tasks = self.controller.list(sort_key='id', sort_dir='asc')
|
||||
self.assertEqual(2, len(tasks))
|
||||
self.assertEqual(_PENDING_ID, tasks[0].id)
|
||||
|
||||
def test_list_tasks_with_invalid_sort_dir(self):
|
||||
self.assertRaises(ValueError,
|
||||
list,
|
||||
self.controller.list(sort_dir='invalid'))
|
||||
self.controller.list,
|
||||
sort_dir='invalid')
|
||||
|
||||
def test_get_task(self):
|
||||
task = self.controller.get(_PENDING_ID)
|
||||
|
||||
@@ -113,6 +113,7 @@ class FakeResponse(object):
|
||||
self.reason = reason
|
||||
self.version = version
|
||||
self.headers = headers
|
||||
self.headers['x-openstack-request-id'] = 'req-1234'
|
||||
self.status_code = status_code
|
||||
self.raw = RawRequest(headers, body=body, reason=reason,
|
||||
version=version, status=status_code)
|
||||
|
||||
@@ -32,24 +32,29 @@ class Controller(object):
|
||||
schema = self.schema_client.get('member')
|
||||
return warlock.model_factory(schema.raw(), schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, image_id):
|
||||
url = '/v2/images/%s/members' % image_id
|
||||
resp, body = self.http_client.get(url)
|
||||
for member in body['members']:
|
||||
yield self.model(member)
|
||||
yield self.model(member), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, image_id, member_id):
|
||||
self.http_client.delete('/v2/images/%s/members/%s' %
|
||||
(image_id, member_id))
|
||||
resp, body = self.http_client.delete('/v2/images/%s/members/%s' %
|
||||
(image_id, member_id))
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def update(self, image_id, member_id, member_status):
|
||||
url = '/v2/images/%s/members/%s' % (image_id, member_id)
|
||||
body = {'status': member_status}
|
||||
resp, updated_member = self.http_client.put(url, data=body)
|
||||
return self.model(updated_member)
|
||||
return self.model(updated_member), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, image_id, member_id):
|
||||
url = '/v2/images/%s/members' % image_id
|
||||
body = {'member': member_id}
|
||||
resp, created_member = self.http_client.post(url, data=body)
|
||||
return self.model(created_member)
|
||||
return self.model(created_member), resp
|
||||
|
||||
@@ -30,6 +30,7 @@ class Controller(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def update(self, image_id, tag_value):
|
||||
"""Update an image with the given tag.
|
||||
|
||||
@@ -37,8 +38,10 @@ class Controller(object):
|
||||
:param tag_value: value of the tag.
|
||||
"""
|
||||
url = '/v2/images/%s/tags/%s' % (image_id, tag_value)
|
||||
self.http_client.put(url)
|
||||
resp, body = self.http_client.put(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, image_id, tag_value):
|
||||
"""Delete the tag associated with the given image.
|
||||
|
||||
@@ -46,4 +49,5 @@ class Controller(object):
|
||||
:param tag_value: tag value to be deleted.
|
||||
"""
|
||||
url = '/v2/images/%s/tags/%s' % (image_id, tag_value)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
+57
-22
@@ -81,6 +81,7 @@ class Controller(object):
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
return sort
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, **kwargs):
|
||||
"""Retrieve a listing of Image objects.
|
||||
|
||||
@@ -97,6 +98,7 @@ class Controller(object):
|
||||
|
||||
def paginate(url, page_size, limit=None):
|
||||
next_url = url
|
||||
req_id_hdr = {}
|
||||
|
||||
while True:
|
||||
if limit and page_size > limit:
|
||||
@@ -105,7 +107,12 @@ class Controller(object):
|
||||
next_url = next_url.replace("limit=%s" % page_size,
|
||||
"limit=%s" % limit)
|
||||
|
||||
resp, body = self.http_client.get(next_url)
|
||||
resp, body = self.http_client.get(next_url, headers=req_id_hdr)
|
||||
# NOTE(rsjethani): Store curent request id so that it can be
|
||||
# used in subsequent requests. Refer bug #1525259
|
||||
req_id_hdr['x-openstack-request-id'] = \
|
||||
utils._extract_request_id(resp)
|
||||
|
||||
for image in body['images']:
|
||||
# NOTE(bcwaldon): remove 'self' for now until we have
|
||||
# an elegant way to pass it into the model constructor
|
||||
@@ -114,7 +121,7 @@ class Controller(object):
|
||||
# We do not validate the model when listing.
|
||||
# This prevents side-effects of injecting invalid
|
||||
# schema values via v1.
|
||||
yield self.unvalidated_model(**image)
|
||||
yield self.unvalidated_model(**image), resp
|
||||
if limit:
|
||||
limit -= 1
|
||||
if limit <= 0:
|
||||
@@ -173,17 +180,23 @@ class Controller(object):
|
||||
if isinstance(kwargs.get('marker'), six.string_types):
|
||||
url = '%s&marker=%s' % (url, kwargs['marker'])
|
||||
|
||||
for image in paginate(url, page_size, limit):
|
||||
yield image
|
||||
for image, resp in paginate(url, page_size, limit):
|
||||
yield image, resp
|
||||
|
||||
def get(self, image_id):
|
||||
@utils.add_req_id_to_object()
|
||||
def _get(self, image_id, header=None):
|
||||
url = '/v2/images/%s' % image_id
|
||||
resp, body = self.http_client.get(url)
|
||||
header = header or {}
|
||||
resp, body = self.http_client.get(url, headers=header)
|
||||
# NOTE(bcwaldon): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body.pop('self', None)
|
||||
return self.unvalidated_model(**body)
|
||||
return self.unvalidated_model(**body), resp
|
||||
|
||||
def get(self, image_id):
|
||||
return self._get(image_id)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def data(self, image_id, do_checksum=True):
|
||||
"""Retrieve data of an image.
|
||||
|
||||
@@ -194,7 +207,7 @@ class Controller(object):
|
||||
url = '/v2/images/%s/file' % image_id
|
||||
resp, body = self.http_client.get(url)
|
||||
if resp.status_code == codes.no_content:
|
||||
return None
|
||||
return None, resp
|
||||
|
||||
checksum = resp.headers.get('content-md5', None)
|
||||
content_length = int(resp.headers.get('content-length', 0))
|
||||
@@ -202,8 +215,9 @@ class Controller(object):
|
||||
if do_checksum and checksum is not None:
|
||||
body = utils.integrity_iter(body, checksum)
|
||||
|
||||
return utils.IterableWithLength(body, content_length)
|
||||
return utils.IterableWithLength(body, content_length), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def upload(self, image_id, image_data, image_size=None):
|
||||
"""Upload the data for an image.
|
||||
|
||||
@@ -214,13 +228,17 @@ class Controller(object):
|
||||
url = '/v2/images/%s/file' % image_id
|
||||
hdrs = {'Content-Type': 'application/octet-stream'}
|
||||
body = image_data
|
||||
self.http_client.put(url, headers=hdrs, data=body)
|
||||
resp, body = self.http_client.put(url, headers=hdrs, data=body)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, image_id):
|
||||
"""Delete an image."""
|
||||
url = '/v2/images/%s' % image_id
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, **kwargs):
|
||||
"""Create an image."""
|
||||
url = '/v2/images'
|
||||
@@ -236,17 +254,21 @@ class Controller(object):
|
||||
# NOTE(esheffield): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def deactivate(self, image_id):
|
||||
"""Deactivate an image."""
|
||||
url = '/v2/images/%s/actions/deactivate' % image_id
|
||||
return self.http_client.post(url)
|
||||
resp, body = self.http_client.post(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def reactivate(self, image_id):
|
||||
"""Reactivate an image."""
|
||||
url = '/v2/images/%s/actions/reactivate' % image_id
|
||||
return self.http_client.post(url)
|
||||
resp, body = self.http_client.post(url)
|
||||
return (resp, body), resp
|
||||
|
||||
def update(self, image_id, remove_props=None, **kwargs):
|
||||
"""Update attributes of an image.
|
||||
@@ -276,12 +298,16 @@ class Controller(object):
|
||||
|
||||
url = '/v2/images/%s' % image_id
|
||||
hdrs = {'Content-Type': 'application/openstack-images-v2.1-json-patch'}
|
||||
self.http_client.patch(url, headers=hdrs, data=image.patch)
|
||||
resp, _ = self.http_client.patch(url, headers=hdrs, data=image.patch)
|
||||
# Get request id from `patch` request so it can be passed to the
|
||||
# following `get` call
|
||||
req_id_hdr = {
|
||||
'x-openstack-request-id': utils._extract_request_id(resp)}
|
||||
|
||||
# NOTE(bcwaldon): calling image.patch doesn't clear the changes, so
|
||||
# we need to fetch the image again to get a clean history. This is
|
||||
# an obvious optimization for warlock
|
||||
return self.get(image_id)
|
||||
return self._get(image_id, req_id_hdr)
|
||||
|
||||
def _get_image_with_locations_or_fail(self, image_id):
|
||||
image = self.get(image_id)
|
||||
@@ -290,10 +316,13 @@ class Controller(object):
|
||||
'API access to image locations')
|
||||
return image
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def _send_image_update_request(self, image_id, patch_body):
|
||||
url = '/v2/images/%s' % image_id
|
||||
hdrs = {'Content-Type': 'application/openstack-images-v2.1-json-patch'}
|
||||
self.http_client.patch(url, headers=hdrs, data=json.dumps(patch_body))
|
||||
resp, body = self.http_client.patch(url, headers=hdrs,
|
||||
data=json.dumps(patch_body))
|
||||
return (resp, body), resp
|
||||
|
||||
def add_location(self, image_id, url, metadata):
|
||||
"""Add a new location entry to an image's list of locations.
|
||||
@@ -308,8 +337,11 @@ class Controller(object):
|
||||
"""
|
||||
add_patch = [{'op': 'add', 'path': '/locations/-',
|
||||
'value': {'url': url, 'metadata': metadata}}]
|
||||
self._send_image_update_request(image_id, add_patch)
|
||||
return self.get(image_id)
|
||||
response = self._send_image_update_request(image_id, add_patch)
|
||||
# Get request id from the above update request and pass the same to
|
||||
# following get request
|
||||
req_id_hdr = {'x-openstack-request-id': response.request_ids[0]}
|
||||
return self._get(image_id, req_id_hdr)
|
||||
|
||||
def delete_locations(self, image_id, url_set):
|
||||
"""Remove one or more location entries of an image.
|
||||
@@ -332,7 +364,7 @@ class Controller(object):
|
||||
url_indices.sort(reverse=True)
|
||||
patches = [{'op': 'remove', 'path': '/locations/%s' % url_idx}
|
||||
for url_idx in url_indices]
|
||||
self._send_image_update_request(image_id, patches)
|
||||
return self._send_image_update_request(image_id, patches)
|
||||
|
||||
def update_location(self, image_id, url, metadata):
|
||||
"""Update an existing location entry in an image's list of locations.
|
||||
@@ -359,6 +391,9 @@ class Controller(object):
|
||||
patches = [{'op': 'replace',
|
||||
'path': '/locations',
|
||||
'value': list(url_map.values())}]
|
||||
self._send_image_update_request(image_id, patches)
|
||||
response = self._send_image_update_request(image_id, patches)
|
||||
# Get request id from the above update request and pass the same to
|
||||
# following get request
|
||||
req_id_hdr = {'x-openstack-request-id': response.request_ids[0]}
|
||||
|
||||
return self.get(image_id)
|
||||
return self._get(image_id, req_id_hdr)
|
||||
|
||||
+109
-41
@@ -37,6 +37,7 @@ class NamespaceController(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, **kwargs):
|
||||
"""Create a namespace.
|
||||
|
||||
@@ -50,7 +51,7 @@ class NamespaceController(object):
|
||||
|
||||
resp, body = self.http_client.post(url, data=namespace)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
def update(self, namespace_name, **kwargs):
|
||||
"""Update a namespace.
|
||||
@@ -72,23 +73,34 @@ class NamespaceController(object):
|
||||
del namespace[elem]
|
||||
|
||||
url = '/v2/metadefs/namespaces/{0}'.format(namespace_name)
|
||||
self.http_client.put(url, data=namespace)
|
||||
|
||||
return self.get(namespace.namespace)
|
||||
# Pass the original wrapped value to http client.
|
||||
resp, _ = self.http_client.put(url, data=namespace.wrapped)
|
||||
# Get request id from `put` request so it can be passed to the
|
||||
# following `get` call
|
||||
req_id_hdr = {
|
||||
'x-openstack-request-id': utils._extract_request_id(resp)
|
||||
}
|
||||
return self._get(namespace.namespace, header=req_id_hdr)
|
||||
|
||||
def get(self, namespace, **kwargs):
|
||||
return self._get(namespace, **kwargs)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def _get(self, namespace, header=None, **kwargs):
|
||||
"""Get one namespace."""
|
||||
query_params = parse.urlencode(kwargs)
|
||||
if kwargs:
|
||||
query_params = '?%s' % query_params
|
||||
|
||||
url = '/v2/metadefs/namespaces/{0}{1}'.format(namespace, query_params)
|
||||
resp, body = self.http_client.get(url)
|
||||
header = header or {}
|
||||
resp, body = self.http_client.get(url, headers=header)
|
||||
# NOTE(bcwaldon): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, **kwargs):
|
||||
"""Retrieve a listing of Namespace objects.
|
||||
|
||||
@@ -117,7 +129,7 @@ class NamespaceController(object):
|
||||
# an elegant way to pass it into the model constructor
|
||||
# without conflict.
|
||||
namespace.pop('self', None)
|
||||
yield self.model(**namespace)
|
||||
yield self.model(**namespace), resp
|
||||
# NOTE(zhiyan): In order to resolve the performance issue
|
||||
# of JSON schema validation for image listing case, we
|
||||
# don't validate each image entry but do it only on first
|
||||
@@ -132,8 +144,8 @@ class NamespaceController(object):
|
||||
except KeyError:
|
||||
return
|
||||
else:
|
||||
for namespace in paginate(next_url):
|
||||
yield namespace
|
||||
for namespace, resp in paginate(next_url):
|
||||
yield namespace, resp
|
||||
|
||||
filters = kwargs.get('filters', {})
|
||||
filters = {} if filters is None else filters
|
||||
@@ -170,13 +182,15 @@ class NamespaceController(object):
|
||||
|
||||
url = '/v2/metadefs/namespaces?%s' % parse.urlencode(filters)
|
||||
|
||||
for namespace in paginate(url):
|
||||
yield namespace
|
||||
for namespace, resp in paginate(url):
|
||||
yield namespace, resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, namespace):
|
||||
"""Delete a namespace."""
|
||||
url = '/v2/metadefs/namespaces/{0}'.format(namespace)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
|
||||
class ResourceTypeController(object):
|
||||
@@ -190,6 +204,7 @@ class ResourceTypeController(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def associate(self, namespace, **kwargs):
|
||||
"""Associate a resource type with a namespace."""
|
||||
try:
|
||||
@@ -201,14 +216,17 @@ class ResourceTypeController(object):
|
||||
res_type)
|
||||
resp, body = self.http_client.post(url, data=res_type)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def deassociate(self, namespace, resource):
|
||||
"""Deassociate a resource type with a namespace."""
|
||||
url = '/v2/metadefs/namespaces/{0}/resource_types/{1}'. \
|
||||
format(namespace, resource)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self):
|
||||
"""Retrieve a listing of available resource types.
|
||||
|
||||
@@ -218,14 +236,15 @@ class ResourceTypeController(object):
|
||||
url = '/v2/metadefs/resource_types'
|
||||
resp, body = self.http_client.get(url)
|
||||
for resource_type in body['resource_types']:
|
||||
yield self.model(**resource_type)
|
||||
yield self.model(**resource_type), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def get(self, namespace):
|
||||
url = '/v2/metadefs/namespaces/{0}/resource_types'.format(namespace)
|
||||
resp, body = self.http_client.get(url)
|
||||
body.pop('self', None)
|
||||
for resource_type in body['resource_type_associations']:
|
||||
yield self.model(**resource_type)
|
||||
yield self.model(**resource_type), resp
|
||||
|
||||
|
||||
class PropertyController(object):
|
||||
@@ -239,6 +258,7 @@ class PropertyController(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, namespace, **kwargs):
|
||||
"""Create a property.
|
||||
|
||||
@@ -254,7 +274,7 @@ class PropertyController(object):
|
||||
|
||||
resp, body = self.http_client.post(url, data=prop)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
def update(self, namespace, prop_name, **kwargs):
|
||||
"""Update a property.
|
||||
@@ -272,18 +292,29 @@ class PropertyController(object):
|
||||
|
||||
url = '/v2/metadefs/namespaces/{0}/properties/{1}'.format(namespace,
|
||||
prop_name)
|
||||
self.http_client.put(url, data=prop)
|
||||
# Pass the original wrapped value to http client.
|
||||
resp, _ = self.http_client.put(url, data=prop.wrapped)
|
||||
# Get request id from `put` request so it can be passed to the
|
||||
# following `get` call
|
||||
req_id_hdr = {
|
||||
'x-openstack-request-id': utils._extract_request_id(resp)}
|
||||
|
||||
return self.get(namespace, prop.name)
|
||||
return self._get(namespace, prop.name, req_id_hdr)
|
||||
|
||||
def get(self, namespace, prop_name):
|
||||
return self._get(namespace, prop_name)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def _get(self, namespace, prop_name, header=None):
|
||||
url = '/v2/metadefs/namespaces/{0}/properties/{1}'.format(namespace,
|
||||
prop_name)
|
||||
resp, body = self.http_client.get(url)
|
||||
header = header or {}
|
||||
resp, body = self.http_client.get(url, headers=header)
|
||||
body.pop('self', None)
|
||||
body['name'] = prop_name
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, namespace, **kwargs):
|
||||
"""Retrieve a listing of metadata properties.
|
||||
|
||||
@@ -295,18 +326,22 @@ class PropertyController(object):
|
||||
|
||||
for key, value in body['properties'].items():
|
||||
value['name'] = key
|
||||
yield self.model(value)
|
||||
yield self.model(value), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, namespace, prop_name):
|
||||
"""Delete a property."""
|
||||
url = '/v2/metadefs/namespaces/{0}/properties/{1}'.format(namespace,
|
||||
prop_name)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete_all(self, namespace):
|
||||
"""Delete all properties in a namespace."""
|
||||
url = '/v2/metadefs/namespaces/{0}/properties'.format(namespace)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
|
||||
class ObjectController(object):
|
||||
@@ -320,6 +355,7 @@ class ObjectController(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, namespace, **kwargs):
|
||||
"""Create an object.
|
||||
|
||||
@@ -335,7 +371,7 @@ class ObjectController(object):
|
||||
|
||||
resp, body = self.http_client.post(url, data=obj)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
def update(self, namespace, object_name, **kwargs):
|
||||
"""Update an object.
|
||||
@@ -359,17 +395,28 @@ class ObjectController(object):
|
||||
|
||||
url = '/v2/metadefs/namespaces/{0}/objects/{1}'.format(namespace,
|
||||
object_name)
|
||||
self.http_client.put(url, data=obj)
|
||||
# Pass the original wrapped value to http client.
|
||||
resp, _ = self.http_client.put(url, data=obj.wrapped)
|
||||
# Get request id from `put` request so it can be passed to the
|
||||
# following `get` call
|
||||
req_id_hdr = {
|
||||
'x-openstack-request-id': utils._extract_request_id(resp)}
|
||||
|
||||
return self.get(namespace, obj.name)
|
||||
return self._get(namespace, obj.name, req_id_hdr)
|
||||
|
||||
def get(self, namespace, object_name):
|
||||
return self._get(namespace, object_name)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def _get(self, namespace, object_name, header=None):
|
||||
url = '/v2/metadefs/namespaces/{0}/objects/{1}'.format(namespace,
|
||||
object_name)
|
||||
resp, body = self.http_client.get(url)
|
||||
header = header or {}
|
||||
resp, body = self.http_client.get(url, headers=header)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, namespace, **kwargs):
|
||||
"""Retrieve a listing of metadata objects.
|
||||
|
||||
@@ -379,18 +426,22 @@ class ObjectController(object):
|
||||
resp, body = self.http_client.get(url)
|
||||
|
||||
for obj in body['objects']:
|
||||
yield self.model(obj)
|
||||
yield self.model(obj), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, namespace, object_name):
|
||||
"""Delete an object."""
|
||||
url = '/v2/metadefs/namespaces/{0}/objects/{1}'.format(namespace,
|
||||
object_name)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete_all(self, namespace):
|
||||
"""Delete all objects in a namespace."""
|
||||
url = '/v2/metadefs/namespaces/{0}/objects'.format(namespace)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
|
||||
class TagController(object):
|
||||
@@ -404,6 +455,7 @@ class TagController(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, namespace, tag_name):
|
||||
"""Create a tag.
|
||||
|
||||
@@ -416,8 +468,9 @@ class TagController(object):
|
||||
|
||||
resp, body = self.http_client.post(url)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def create_multiple(self, namespace, **kwargs):
|
||||
"""Create the list of tags.
|
||||
|
||||
@@ -440,7 +493,7 @@ class TagController(object):
|
||||
resp, body = self.http_client.post(url, data=tags)
|
||||
body.pop('self', None)
|
||||
for tag in body['tags']:
|
||||
yield self.model(tag)
|
||||
yield self.model(tag), resp
|
||||
|
||||
def update(self, namespace, tag_name, **kwargs):
|
||||
"""Update a tag.
|
||||
@@ -464,17 +517,28 @@ class TagController(object):
|
||||
|
||||
url = '/v2/metadefs/namespaces/{0}/tags/{1}'.format(namespace,
|
||||
tag_name)
|
||||
self.http_client.put(url, data=tag)
|
||||
# Pass the original wrapped value to http client.
|
||||
resp, _ = self.http_client.put(url, data=tag.wrapped)
|
||||
# Get request id from `put` request so it can be passed to the
|
||||
# following `get` call
|
||||
req_id_hdr = {
|
||||
'x-openstack-request-id': utils._extract_request_id(resp)}
|
||||
|
||||
return self.get(namespace, tag.name)
|
||||
return self._get(namespace, tag.name, req_id_hdr)
|
||||
|
||||
def get(self, namespace, tag_name):
|
||||
return self._get(namespace, tag_name)
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def _get(self, namespace, tag_name, header=None):
|
||||
url = '/v2/metadefs/namespaces/{0}/tags/{1}'.format(namespace,
|
||||
tag_name)
|
||||
resp, body = self.http_client.get(url)
|
||||
header = header or {}
|
||||
resp, body = self.http_client.get(url, headers=header)
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, namespace, **kwargs):
|
||||
"""Retrieve a listing of metadata tags.
|
||||
|
||||
@@ -484,15 +548,19 @@ class TagController(object):
|
||||
resp, body = self.http_client.get(url)
|
||||
|
||||
for tag in body['tags']:
|
||||
yield self.model(tag)
|
||||
yield self.model(tag), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete(self, namespace, tag_name):
|
||||
"""Delete a tag."""
|
||||
url = '/v2/metadefs/namespaces/{0}/tags/{1}'.format(namespace,
|
||||
tag_name)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def delete_all(self, namespace):
|
||||
"""Delete all tags in a namespace."""
|
||||
url = '/v2/metadefs/namespaces/{0}/tags'.format(namespace)
|
||||
self.http_client.delete(url)
|
||||
resp, body = self.http_client.delete(url)
|
||||
return (resp, body), resp
|
||||
|
||||
@@ -38,6 +38,7 @@ class Controller(object):
|
||||
return warlock.model_factory(schema.raw(),
|
||||
base_class=schemas.SchemaBasedModel)
|
||||
|
||||
@utils.add_req_id_to_generator()
|
||||
def list(self, **kwargs):
|
||||
"""Retrieve a listing of Task objects.
|
||||
|
||||
@@ -48,14 +49,14 @@ class Controller(object):
|
||||
def paginate(url):
|
||||
resp, body = self.http_client.get(url)
|
||||
for task in body['tasks']:
|
||||
yield task
|
||||
yield task, resp
|
||||
try:
|
||||
next_url = body['next']
|
||||
except KeyError:
|
||||
return
|
||||
else:
|
||||
for task in paginate(next_url):
|
||||
yield task
|
||||
for task, resp in paginate(next_url):
|
||||
yield task, resp
|
||||
|
||||
filters = kwargs.get('filters', {})
|
||||
|
||||
@@ -88,12 +89,13 @@ class Controller(object):
|
||||
filters[param] = encodeutils.safe_encode(value)
|
||||
|
||||
url = '/v2/tasks?%s' % six.moves.urllib.parse.urlencode(filters)
|
||||
for task in paginate(url):
|
||||
for task, resp in paginate(url):
|
||||
# NOTE(flwang): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
task.pop('self', None)
|
||||
yield self.model(**task)
|
||||
yield self.model(**task), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def get(self, task_id):
|
||||
"""Get a task based on given task id."""
|
||||
url = '/v2/tasks/%s' % task_id
|
||||
@@ -101,8 +103,9 @@ class Controller(object):
|
||||
# NOTE(flwang): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
@utils.add_req_id_to_object()
|
||||
def create(self, **kwargs):
|
||||
"""Create a new task."""
|
||||
url = '/v2/tasks'
|
||||
@@ -118,4 +121,4 @@ class Controller(object):
|
||||
# NOTE(flwang): remove 'self' for now until we have an elegant
|
||||
# way to pass it into the model constructor without conflict
|
||||
body.pop('self', None)
|
||||
return self.model(**body)
|
||||
return self.model(**body), resp
|
||||
|
||||
Reference in New Issue
Block a user