image membership management works

This commit is contained in:
Brian Waldon
2012-04-03 17:39:32 -07:00
parent b87b1b5086
commit c72e4dd2b5
6 changed files with 72 additions and 33 deletions

View File

@@ -57,6 +57,8 @@ class HTTPClient(httplib2.Http):
string_parts.append(header)
logger.debug("REQ: %s\n" % "".join(string_parts))
if 'raw_body' in kwargs:
logger.debug("REQ BODY (RAW): %s\n" % (kwargs['raw_body']))
if 'body' in kwargs:
logger.debug("REQ BODY: %s\n" % (kwargs['body']))
logger.debug("RESP: %s\nRESP BODY: %s\n", resp, body)
@@ -71,9 +73,14 @@ class HTTPClient(httplib2.Http):
_kwargs = copy.copy(kwargs)
_kwargs.setdefault('headers', kwargs.get('headers', {}))
_kwargs['headers']['User-Agent'] = USER_AGENT
if 'body' in kwargs and kwargs['body'] is not None:
if 'raw_body' in _kwargs:
raw_body = _kwargs.pop('raw_body')
if raw_body is not None:
_kwargs['headers']['Content-Type'] = 'application/octet-stream'
_kwargs['body'] = kwargs['body']
_kwargs['body'] = raw_body
elif 'body' in kwargs and kwargs['body'] is not None:
_kwargs['headers']['Content-Type'] = 'application/json'
_kwargs['body'] = json.dumps(kwargs['body'])
resp, body = super(HTTPClient, self).request(url, method, **_kwargs)
self.http_log((url, method,), _kwargs, resp, body)

View File

@@ -64,16 +64,14 @@ class ImageMemberManager(base.Manager):
def _list_by_member(self, member):
member_id = base.getid(member)
resp, body = self.api.get('/v1/shared_images/%s' % member_id)
resp, body = self.api.get('/v1/shared-images/%s' % member_id)
out = []
for member in body['shared_images']:
member['member_id'] = member_id
out.append(ImageMember(self, member, loaded=True))
return out
def delete(self, member):
member_id = member.member_id
image_id = member.image_id
def delete(self, image_id, member_id):
self._delete("/v1/images/%s/members/%s" % (image_id, member_id))
def create(self, image, member_id, can_share=False):

View File

@@ -140,7 +140,8 @@ class ImageManager(base.Manager):
if copy_from is not None:
hdrs['x-glance-api-copy-from'] = copy_from
resp, body = self.api.post('/v1/images', headers=hdrs, body=image_data)
resp, body = self.api.post('/v1/images', headers=hdrs,
raw_body=image_data)
return Image(self, body['image'])
def update(self, image, **kwargs):
@@ -171,5 +172,5 @@ class ImageManager(base.Manager):
image_id = base.getid(image)
resp, body = self.api.put('/v1/images/%s' % image_id, headers=hdrs,
body=image_data)
raw_body=image_data)
return Image(self, body['image'])

View File

@@ -47,18 +47,18 @@ def do_image_show(gc, args):
help='ID of image to reserve.')
@utils.arg('--name', metavar='<NAME>',
help='Name of image.')
@utils.arg('--disk_format', metavar='<CONTAINER_FORMAT>',
@utils.arg('--disk-format', metavar='<CONTAINER_FORMAT>',
help='Disk format of image.')
@utils.arg('--container_format', metavar='<DISK_FORMAT>',
@utils.arg('--container-format', metavar='<DISK_FORMAT>',
help='Container format of image.')
@utils.arg('--owner', metavar='<TENANT_ID>',
help='Tenant who should own image.')
@utils.arg('--size', metavar='<SIZE>',
help=('Size of image data (in bytes). Only used with'
' \'--location\' and \'--copy_from\'.'))
@utils.arg('--min_disk', metavar='<DISK_GB>',
@utils.arg('--min-disk', metavar='<DISK_GB>',
help='Minimum size of disk needed to boot image (in gigabytes).')
@utils.arg('--min_ram', metavar='<DISK_RAM>',
@utils.arg('--min-ram', metavar='<DISK_RAM>',
help='Minimum amount of ram needed to boot image (in megabytes).')
@utils.arg('--location', metavar='<IMAGE_URL>',
help=('URL where the data for this image already resides.'
@@ -67,7 +67,7 @@ def do_image_show(gc, args):
' you would specify \'file:///usr/share/image.tar.gz\'.'))
@utils.arg('--checksum', metavar='<CHECKSUM>',
help='Hash of image data used Glance can use for verification.')
@utils.arg('--copy_from', metavar='<IMAGE_URL>',
@utils.arg('--copy-from', metavar='<IMAGE_URL>',
help=('Similar to \'--location\' in usage, but this indicates that'
' the Glance server should immediately copy the data and'
' store it in its configured image store.'))
@@ -104,17 +104,17 @@ def do_image_create(gc, args):
@utils.arg('id', metavar='<IMAGE_ID>', help='ID of image to modify.')
@utils.arg('--name', metavar='<NAME>',
help='Name of image.')
@utils.arg('--disk_format', metavar='<CONTAINER_FORMAT>',
@utils.arg('--disk-format', metavar='<CONTAINER_FORMAT>',
help='Disk format of image.')
@utils.arg('--container_format', metavar='<DISK_FORMAT>',
@utils.arg('--container-format', metavar='<DISK_FORMAT>',
help='Container format of image.')
@utils.arg('--owner', metavar='<TENANT_ID>',
help='Tenant who should own image.')
@utils.arg('--size', metavar='<SIZE>',
help='Size of image data (in bytes).')
@utils.arg('--min_disk', metavar='<DISK_GB>',
@utils.arg('--min-disk', metavar='<DISK_GB>',
help='Minimum size of disk needed to boot image (in gigabytes).')
@utils.arg('--min_ram', metavar='<DISK_RAM>',
@utils.arg('--min-ram', metavar='<DISK_RAM>',
help='Minimum amount of ram needed to boot image (in megabytes).')
@utils.arg('--location', metavar='<IMAGE_URL>',
help=('URL where the data for this image already resides.'
@@ -123,13 +123,13 @@ def do_image_create(gc, args):
' you would specify \'file:///usr/share/image.tar.gz\'.'))
@utils.arg('--checksum', metavar='<CHECKSUM>',
help='Hash of image data used Glance can use for verification.')
@utils.arg('--copy_from', metavar='<IMAGE_URL>',
@utils.arg('--copy-from', metavar='<IMAGE_URL>',
help=('Similar to \'--location\' in usage, but this indicates that'
' the Glance server should immediately copy the data and'
' store it in its configured image store.'))
@utils.arg('--is_public', type=bool,
@utils.arg('--is-public', type=bool,
help='Make image accessible to the public.')
@utils.arg('--is_protected', type=bool,
@utils.arg('--is-protected', type=bool,
help='Prevent image from being deleted.')
@utils.arg('--property', metavar="<key=value>", action='append', default=[],
help=("Arbitrary property to associate with image. "
@@ -161,3 +161,40 @@ def do_image_update(gc, args):
def do_image_delete(gc, args):
"""Delete a specific image."""
gc.images.delete(args.id)
@utils.arg('--image-id', metavar='<IMAGE_ID>',
help='Filter results by an image ID.')
@utils.arg('--tenant-id', metavar='<TENANT_ID>',
help='Filter results by a tenant ID.')
def do_member_list(gc, args):
if args.image_id and args.tenant_id:
print 'Unable to filter members by both --image-id and --tenant-id.'
sys.exit(1)
elif args.image_id:
kwargs = {'image': args.image_id}
elif args.tenant_id:
kwargs = {'member': args.tenant_id}
else:
print 'Unable to list all members. Specify --image-id or --tenant-id'
sys.exit(1)
members = gc.image_members.list(**kwargs)
columns = ['Image ID', 'Member ID', 'Can Share']
utils.print_list(members, columns)
@utils.arg('image_id', metavar='<IMAGE_ID>',
help='Image to add member to.')
@utils.arg('tenant_id', metavar='<TENANT_ID>',
help='Tenant to add as member')
@utils.arg('--can-share', action='store_true', default=False,
help='Allow the specified tenant to share this image.')
def do_member_create(gc, args):
gc.image_members.create(args.image_id, args.tenant_id, args.can_share)
@utils.arg('image_id', metavar='<IMAGE_ID>',
help='Image to add member to.')
@utils.arg('tenant_id', metavar='<TENANT_ID>',
help='Tenant to add as member')
def do_member_delete(gc, args):
gc.image_members.delete(args.image_id, args.tenant_id)

View File

@@ -25,7 +25,7 @@ class ImageMemberManagerTest(unittest.TestCase):
def test_list_by_member(self):
members = self.mgr.list(member='1')
expect = [('GET', '/v1/shared_images/1', {}, None)]
expect = [('GET', '/v1/shared-images/1', {}, None)]
self.assertEqual(self.api.calls, expect)
self.assertEqual(len(members), 1)
self.assertEqual(members[0].member_id, '1')
@@ -41,12 +41,8 @@ class ImageMemberManagerTest(unittest.TestCase):
self.assertEqual(member.can_share, False)
def test_delete(self):
member = self.mgr.get(self.image, '1')
self.mgr.delete(member)
expect = [
('GET', '/v1/images/1/members/1', {}, None),
('DELETE', '/v1/images/1/members/1', {}, None),
]
self.mgr.delete('1', '1')
expect = [('DELETE', '/v1/images/1/members/1', {}, None)]
self.assertEqual(self.api.calls, expect)
def test_create(self):

View File

@@ -87,7 +87,7 @@ fixtures = {
'PUT': ({}, None),
'DELETE': ({}, None),
},
'/v1/shared_images/1': {
'/v1/shared-images/1': {
'GET': (
{},
{'shared_images': [
@@ -116,11 +116,11 @@ class FakeAPI(object):
def head(self, url):
return self._request('HEAD', url)
def post(self, url, headers=None, body=None):
return self._request('POST', url, headers, body)
def post(self, url, headers=None, body=None, raw_body=None):
return self._request('POST', url, headers, body or raw_body)
def put(self, url, headers=None, body=None):
return self._request('PUT', url, headers, body)
def put(self, url, headers=None, body=None, raw_body=None):
return self._request('PUT', url, headers, body or raw_body)
def delete(self, url):
return self._request('DELETE', url)