Reuse class Manager from common code
Class `Managers` from `glanceclient.common.base` module is similar to class `apiclient:ManagerWithFind` from common code. In this patch: - class glanceclient.common.base:Managers replaced by apiclient:ManagerWithFind - module glanceclient.common.base marked as 'deprecated' Related to bp common-client-library-2 Change-Id: I41da4a9188e97ca2c07b6234fc2ac0a877553d3f
This commit is contained in:
@@ -15,71 +15,21 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
Base utilities to build API operation managers and objects on top of.
|
Base utilities to build API operation managers and objects on top of.
|
||||||
|
|
||||||
|
DEPRECATED post v.0.12.0. Use 'glanceclient.openstack.common.apiclient.base'
|
||||||
|
instead of this module."
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy
|
import warnings
|
||||||
|
|
||||||
from glanceclient.openstack.common.apiclient import base
|
from glanceclient.openstack.common.apiclient import base
|
||||||
|
|
||||||
# Python 2.4 compat
|
|
||||||
try:
|
warnings.warn("The 'glanceclient.common.base' module is deprecated post "
|
||||||
all
|
"v.0.12.0. Use 'glanceclient.openstack.common.apiclient.base' "
|
||||||
except NameError:
|
"instead of this one.", DeprecationWarning)
|
||||||
def all(iterable):
|
|
||||||
return True not in (not x for x in iterable)
|
|
||||||
|
|
||||||
|
|
||||||
def getid(obj):
|
getid = base.getid
|
||||||
"""
|
Manager = base.ManagerWithFind
|
||||||
Abstracts the common pattern of allowing both an object or an object's ID
|
Resource = base.Resource
|
||||||
(UUID) as a parameter when dealing with relationships.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return obj.id
|
|
||||||
except AttributeError:
|
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
|
||||||
"""
|
|
||||||
Managers interact with a particular type of API (servers, flavors, images,
|
|
||||||
etc.) and provide CRUD operations for them.
|
|
||||||
"""
|
|
||||||
resource_class = None
|
|
||||||
|
|
||||||
def __init__(self, api):
|
|
||||||
self.api = api
|
|
||||||
|
|
||||||
def _list(self, url, response_key, obj_class=None, body=None):
|
|
||||||
resp, body = self.api.json_request('GET', url)
|
|
||||||
|
|
||||||
if obj_class is None:
|
|
||||||
obj_class = self.resource_class
|
|
||||||
|
|
||||||
data = body[response_key]
|
|
||||||
return ([obj_class(self, res, loaded=True) for res in data if res],
|
|
||||||
resp)
|
|
||||||
|
|
||||||
def _delete(self, url):
|
|
||||||
resp = self.api.raw_request('DELETE', url)
|
|
||||||
return resp[0]
|
|
||||||
|
|
||||||
def _update(self, url, body, response_key=None):
|
|
||||||
resp, body = self.api.json_request('PUT', url, body=body)
|
|
||||||
# PUT requests may not return a body
|
|
||||||
if body:
|
|
||||||
return self.resource_class(self, body[response_key])
|
|
||||||
|
|
||||||
|
|
||||||
class Resource(base.Resource):
|
|
||||||
"""
|
|
||||||
A resource represents a particular instance of an object (tenant, user,
|
|
||||||
etc). This is pretty much just a bag for attributes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def to_dict(self):
|
|
||||||
# Note(akurilin): There is a patch in Oslo, that adds to_dict() method
|
|
||||||
# to common Resource - I1db6c12a1f798de7f7fafd0c34fb0ef523610153.
|
|
||||||
# When Oslo code comes, we will be in able to remove this method
|
|
||||||
# and class at all.
|
|
||||||
return copy.deepcopy(self._info)
|
|
||||||
|
@@ -327,6 +327,36 @@ class HTTPClient(object):
|
|||||||
|
|
||||||
return self._http_request(url, method, **kwargs)
|
return self._http_request(url, method, **kwargs)
|
||||||
|
|
||||||
|
def client_request(self, method, url, **kwargs):
|
||||||
|
# NOTE(akurilin): this method provides compatibility with methods which
|
||||||
|
# expects requests.Response object(for example - methods of
|
||||||
|
# class Managers from common code).
|
||||||
|
if 'json' in kwargs and 'body' not in kwargs:
|
||||||
|
kwargs['body'] = kwargs.pop('json')
|
||||||
|
resp, body = self.json_request(method, url, **kwargs)
|
||||||
|
resp.json = lambda: body
|
||||||
|
resp.content = bool(body)
|
||||||
|
resp.status_code = resp.status
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def head(self, url, **kwargs):
|
||||||
|
return self.client_request("HEAD", url, **kwargs)
|
||||||
|
|
||||||
|
def get(self, url, **kwargs):
|
||||||
|
return self.client_request("GET", url, **kwargs)
|
||||||
|
|
||||||
|
def post(self, url, **kwargs):
|
||||||
|
return self.client_request("POST", url, **kwargs)
|
||||||
|
|
||||||
|
def put(self, url, **kwargs):
|
||||||
|
return self.client_request("PUT", url, **kwargs)
|
||||||
|
|
||||||
|
def delete(self, url, **kwargs):
|
||||||
|
return self.raw_request("DELETE", url, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, url, **kwargs):
|
||||||
|
return self.client_request("PATCH", url, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class OpenSSLConnectionDelegator(object):
|
class OpenSSLConnectionDelegator(object):
|
||||||
"""
|
"""
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from glanceclient.common import base
|
from glanceclient.openstack.common.apiclient import base
|
||||||
|
|
||||||
|
|
||||||
class ImageMember(base.Resource):
|
class ImageMember(base.Resource):
|
||||||
@@ -28,13 +28,13 @@ class ImageMember(base.Resource):
|
|||||||
self.manager.delete(self)
|
self.manager.delete(self)
|
||||||
|
|
||||||
|
|
||||||
class ImageMemberManager(base.Manager):
|
class ImageMemberManager(base.ManagerWithFind):
|
||||||
resource_class = ImageMember
|
resource_class = ImageMember
|
||||||
|
|
||||||
def get(self, image, member_id):
|
def get(self, image, member_id):
|
||||||
image_id = base.getid(image)
|
image_id = base.getid(image)
|
||||||
url = '/v1/images/%s/members/%s' % (image_id, member_id)
|
url = '/v1/images/%s/members/%s' % (image_id, member_id)
|
||||||
resp, body = self.api.json_request('GET', url)
|
resp, body = self.client.json_request('GET', url)
|
||||||
member = body['member']
|
member = body['member']
|
||||||
member['image_id'] = image_id
|
member['image_id'] = image_id
|
||||||
return ImageMember(self, member, loaded=True)
|
return ImageMember(self, member, loaded=True)
|
||||||
@@ -60,7 +60,7 @@ class ImageMemberManager(base.Manager):
|
|||||||
def _list_by_image(self, image):
|
def _list_by_image(self, image):
|
||||||
image_id = base.getid(image)
|
image_id = base.getid(image)
|
||||||
url = '/v1/images/%s/members' % image_id
|
url = '/v1/images/%s/members' % image_id
|
||||||
resp, body = self.api.json_request('GET', url)
|
resp, body = self.client.json_request('GET', url)
|
||||||
out = []
|
out = []
|
||||||
for member in body['members']:
|
for member in body['members']:
|
||||||
member['image_id'] = image_id
|
member['image_id'] = image_id
|
||||||
@@ -70,7 +70,7 @@ class ImageMemberManager(base.Manager):
|
|||||||
def _list_by_member(self, member):
|
def _list_by_member(self, member):
|
||||||
member_id = base.getid(member)
|
member_id = base.getid(member)
|
||||||
url = '/v1/shared-images/%s' % member_id
|
url = '/v1/shared-images/%s' % member_id
|
||||||
resp, body = self.api.json_request('GET', url)
|
resp, body = self.client.json_request('GET', url)
|
||||||
out = []
|
out = []
|
||||||
for member in body['shared_images']:
|
for member in body['shared_images']:
|
||||||
member['member_id'] = member_id
|
member['member_id'] = member_id
|
||||||
@@ -84,7 +84,7 @@ class ImageMemberManager(base.Manager):
|
|||||||
"""Creates an image."""
|
"""Creates an image."""
|
||||||
url = '/v1/images/%s/members/%s' % (base.getid(image), member_id)
|
url = '/v1/images/%s/members/%s' % (base.getid(image), member_id)
|
||||||
body = {'member': {'can_share': can_share}}
|
body = {'member': {'can_share': can_share}}
|
||||||
self._update(url, body=body)
|
self._put(url, json=body)
|
||||||
|
|
||||||
def replace(self, image, members):
|
def replace(self, image, members):
|
||||||
memberships = []
|
memberships = []
|
||||||
@@ -100,4 +100,4 @@ class ImageMemberManager(base.Manager):
|
|||||||
obj['can_share'] = member['can_share']
|
obj['can_share'] = member['can_share']
|
||||||
memberships.append(obj)
|
memberships.append(obj)
|
||||||
url = '/v1/images/%s/members' % base.getid(image)
|
url = '/v1/images/%s/members' % base.getid(image)
|
||||||
self.api.json_request('PUT', url, {}, {'memberships': memberships})
|
self.client.json_request('PUT', url, {}, {'memberships': memberships})
|
||||||
|
@@ -19,8 +19,8 @@ import json
|
|||||||
import six
|
import six
|
||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
from glanceclient.common import base
|
|
||||||
from glanceclient.common import utils
|
from glanceclient.common import utils
|
||||||
|
from glanceclient.openstack.common.apiclient import base
|
||||||
from glanceclient.openstack.common import strutils
|
from glanceclient.openstack.common import strutils
|
||||||
|
|
||||||
UPDATE_PARAMS = ('name', 'disk_format', 'container_format', 'min_disk',
|
UPDATE_PARAMS = ('name', 'disk_format', 'container_format', 'min_disk',
|
||||||
@@ -56,9 +56,19 @@ class Image(base.Resource):
|
|||||||
return self.manager.data(self, **kwargs)
|
return self.manager.data(self, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ImageManager(base.Manager):
|
class ImageManager(base.ManagerWithFind):
|
||||||
resource_class = Image
|
resource_class = Image
|
||||||
|
|
||||||
|
def _list(self, url, response_key, obj_class=None, body=None):
|
||||||
|
resp = self.client.get(url)
|
||||||
|
|
||||||
|
if obj_class is None:
|
||||||
|
obj_class = self.resource_class
|
||||||
|
|
||||||
|
data = resp.json()[response_key]
|
||||||
|
return ([obj_class(self, res, loaded=True) for res in data if res],
|
||||||
|
resp)
|
||||||
|
|
||||||
def _image_meta_from_headers(self, headers):
|
def _image_meta_from_headers(self, headers):
|
||||||
meta = {'properties': {}}
|
meta = {'properties': {}}
|
||||||
safe_decode = strutils.safe_decode
|
safe_decode = strutils.safe_decode
|
||||||
@@ -112,10 +122,9 @@ class ImageManager(base.Manager):
|
|||||||
:param image: image object or id to look up
|
:param image: image object or id to look up
|
||||||
:rtype: :class:`Image`
|
:rtype: :class:`Image`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
image_id = base.getid(image)
|
image_id = base.getid(image)
|
||||||
resp, body = self.api.raw_request('HEAD', '/v1/images/%s'
|
resp, body = self.client.raw_request(
|
||||||
% parse.quote(str(image_id)))
|
'HEAD', '/v1/images/%s' % parse.quote(str(image_id)))
|
||||||
meta = self._image_meta_from_headers(dict(resp.getheaders()))
|
meta = self._image_meta_from_headers(dict(resp.getheaders()))
|
||||||
return_request_id = kwargs.get('return_req_id', None)
|
return_request_id = kwargs.get('return_req_id', None)
|
||||||
if return_request_id is not None:
|
if return_request_id is not None:
|
||||||
@@ -131,8 +140,8 @@ class ImageManager(base.Manager):
|
|||||||
:rtype: iterable containing image data
|
:rtype: iterable containing image data
|
||||||
"""
|
"""
|
||||||
image_id = base.getid(image)
|
image_id = base.getid(image)
|
||||||
resp, body = self.api.raw_request('GET', '/v1/images/%s'
|
resp, body = self.client.raw_request(
|
||||||
% parse.quote(str(image_id)))
|
'GET', '/v1/images/%s' % parse.quote(str(image_id)))
|
||||||
checksum = resp.getheader('x-image-meta-checksum', None)
|
checksum = resp.getheader('x-image-meta-checksum', None)
|
||||||
if do_checksum and checksum is not None:
|
if do_checksum and checksum is not None:
|
||||||
body.set_checksum(checksum)
|
body.set_checksum(checksum)
|
||||||
@@ -244,7 +253,7 @@ class ImageManager(base.Manager):
|
|||||||
|
|
||||||
def delete(self, image, **kwargs):
|
def delete(self, image, **kwargs):
|
||||||
"""Delete an image."""
|
"""Delete an image."""
|
||||||
resp = self._delete("/v1/images/%s" % base.getid(image))
|
resp = self._delete("/v1/images/%s" % base.getid(image))[0]
|
||||||
return_request_id = kwargs.get('return_req_id', None)
|
return_request_id = kwargs.get('return_req_id', None)
|
||||||
if return_request_id is not None:
|
if return_request_id is not None:
|
||||||
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
return_request_id.append(resp.getheader(OS_REQ_ID_HDR, None))
|
||||||
@@ -275,7 +284,7 @@ class ImageManager(base.Manager):
|
|||||||
if copy_from is not None:
|
if copy_from is not None:
|
||||||
hdrs['x-glance-api-copy-from'] = copy_from
|
hdrs['x-glance-api-copy-from'] = copy_from
|
||||||
|
|
||||||
resp, body_iter = self.api.raw_request(
|
resp, body_iter = self.client.raw_request(
|
||||||
'POST', '/v1/images', headers=hdrs, body=image_data)
|
'POST', '/v1/images', headers=hdrs, body=image_data)
|
||||||
body = json.loads(''.join([c for c in body_iter]))
|
body = json.loads(''.join([c for c in body_iter]))
|
||||||
return_request_id = kwargs.get('return_req_id', None)
|
return_request_id = kwargs.get('return_req_id', None)
|
||||||
@@ -319,7 +328,7 @@ class ImageManager(base.Manager):
|
|||||||
hdrs['x-glance-api-copy-from'] = copy_from
|
hdrs['x-glance-api-copy-from'] = copy_from
|
||||||
|
|
||||||
url = '/v1/images/%s' % base.getid(image)
|
url = '/v1/images/%s' % base.getid(image)
|
||||||
resp, body_iter = self.api.raw_request(
|
resp, body_iter = self.client.raw_request(
|
||||||
'PUT', url, headers=hdrs, body=image_data)
|
'PUT', url, headers=hdrs, body=image_data)
|
||||||
body = json.loads(''.join([c for c in body_iter]))
|
body = json.loads(''.join([c for c in body_iter]))
|
||||||
return_request_id = kwargs.get('return_req_id', None)
|
return_request_id = kwargs.get('return_req_id', None)
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
from glanceclient.common import base
|
from glanceclient.openstack.common.apiclient import base
|
||||||
|
|
||||||
|
|
||||||
class TestBase(testtools.TestCase):
|
class TestBase(testtools.TestCase):
|
||||||
|
@@ -44,6 +44,32 @@ class FakeAPI(object):
|
|||||||
fixture = self._request(*args, **kwargs)
|
fixture = self._request(*args, **kwargs)
|
||||||
return FakeResponse(fixture[0]), fixture[1]
|
return FakeResponse(fixture[0]), fixture[1]
|
||||||
|
|
||||||
|
def client_request(self, method, url, **kwargs):
|
||||||
|
if 'json' in kwargs and 'body' not in kwargs:
|
||||||
|
kwargs['body'] = kwargs.pop('json')
|
||||||
|
resp, body = self.json_request(method, url, **kwargs)
|
||||||
|
resp.json = lambda: body
|
||||||
|
resp.content = bool(body)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def head(self, url, **kwargs):
|
||||||
|
return self.client_request("HEAD", url, **kwargs)
|
||||||
|
|
||||||
|
def get(self, url, **kwargs):
|
||||||
|
return self.client_request("GET", url, **kwargs)
|
||||||
|
|
||||||
|
def post(self, url, **kwargs):
|
||||||
|
return self.client_request("POST", url, **kwargs)
|
||||||
|
|
||||||
|
def put(self, url, **kwargs):
|
||||||
|
return self.client_request("PUT", url, **kwargs)
|
||||||
|
|
||||||
|
def delete(self, url, **kwargs):
|
||||||
|
return self.raw_request("DELETE", url, **kwargs)
|
||||||
|
|
||||||
|
def patch(self, url, **kwargs):
|
||||||
|
return self.client_request("PATCH", url, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class FakeResponse(object):
|
class FakeResponse(object):
|
||||||
def __init__(self, headers, body=None,
|
def __init__(self, headers, body=None,
|
||||||
|
@@ -837,6 +837,7 @@ class ImageTest(testtools.TestCase):
|
|||||||
image = self.mgr.get('1')
|
image = self.mgr.get('1')
|
||||||
image.delete()
|
image.delete()
|
||||||
expect = [
|
expect = [
|
||||||
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('HEAD', '/v1/images/1', {}, None),
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('DELETE', '/v1/images/1', {}, None),
|
('DELETE', '/v1/images/1', {}, None),
|
||||||
]
|
]
|
||||||
@@ -846,6 +847,7 @@ class ImageTest(testtools.TestCase):
|
|||||||
image = self.mgr.get('1')
|
image = self.mgr.get('1')
|
||||||
image.update(name='image-5')
|
image.update(name='image-5')
|
||||||
expect = [
|
expect = [
|
||||||
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('HEAD', '/v1/images/1', {}, None),
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('PUT', '/v1/images/1', {'x-image-meta-name': 'image-5'}, None),
|
('PUT', '/v1/images/1', {'x-image-meta-name': 'image-5'}, None),
|
||||||
]
|
]
|
||||||
@@ -855,6 +857,7 @@ class ImageTest(testtools.TestCase):
|
|||||||
image = self.mgr.get('1')
|
image = self.mgr.get('1')
|
||||||
data = ''.join([b for b in image.data()])
|
data = ''.join([b for b in image.data()])
|
||||||
expect = [
|
expect = [
|
||||||
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('HEAD', '/v1/images/1', {}, None),
|
('HEAD', '/v1/images/1', {}, None),
|
||||||
('GET', '/v1/images/1', {}, None),
|
('GET', '/v1/images/1', {}, None),
|
||||||
]
|
]
|
||||||
@@ -870,6 +873,7 @@ class ImageTest(testtools.TestCase):
|
|||||||
image = self.mgr.get('2')
|
image = self.mgr.get('2')
|
||||||
data = ''.join([b for b in image.data(do_checksum=False)])
|
data = ''.join([b for b in image.data(do_checksum=False)])
|
||||||
expect = [
|
expect = [
|
||||||
|
('HEAD', '/v1/images/2', {}, None),
|
||||||
('HEAD', '/v1/images/2', {}, None),
|
('HEAD', '/v1/images/2', {}, None),
|
||||||
('GET', '/v1/images/2', {}, None),
|
('GET', '/v1/images/2', {}, None),
|
||||||
]
|
]
|
||||||
@@ -891,6 +895,7 @@ class ImageTest(testtools.TestCase):
|
|||||||
image = self.mgr.get('3')
|
image = self.mgr.get('3')
|
||||||
data = ''.join([b for b in image.data(do_checksum=False)])
|
data = ''.join([b for b in image.data(do_checksum=False)])
|
||||||
expect = [
|
expect = [
|
||||||
|
('HEAD', '/v1/images/3', {}, None),
|
||||||
('HEAD', '/v1/images/3', {}, None),
|
('HEAD', '/v1/images/3', {}, None),
|
||||||
('GET', '/v1/images/3', {}, None),
|
('GET', '/v1/images/3', {}, None),
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user