decoding, an artifact # of WSGI/webob dispatch?
now = timeutils.utcnow()
hour_ago = now.strftime('%Y-%m-%dT%H:%M:%S%%2B01:00')
params = "changes-since=%s" % hour_ago
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 3)
# 17. GET /images with future changes-since filter
tomorrow = timeutils.isotime(timeutils.utcnow() +
datetime.timedelta(1))
params = "changes-since=%s" % tomorrow
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 0)
# one timezone east of Greenwich equates to an hour from now
now = timeutils.utcnow()
hour_hence = now.strftime('%Y-%m-%dT%H:%M:%S-01:00')
params = "changes-since=%s" % hour_hence
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 0)
# 18. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "size_min=-1"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("filter size_min got -1" in content)
# 19. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "size_max=-1"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("filter size_max got -1" in content)
# 20. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "min_ram=-1"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("Bad value passed to filter min_ram got -1" in content)
# 21. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "protected=imalittleteapot"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("protected got imalittleteapot" in content)
# 22. GET /images with size_min filter
# Verify correct images returned with size >= expected
params = "is_public=imalittleteapot"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 400)
self.assertTrue("is_public got imalittleteapot" in content)
**** CubicPower OpenStack Study ****
def test_limited_images(self):
"""
Ensure marker and limit query params work
"""
# 0. GET /images
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.assertEqual(content, '{"images": []}')
image_ids = []
# 1. POST /images with three public images with various attributes
headers = minimal_headers('Image1')
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
headers = minimal_headers('Image2')
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
headers = minimal_headers('Image3')
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
# 2. GET /images with all images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
images = jsonutils.loads(content)['images']
self.assertEqual(len(images), 3)
# 3. GET /images with limit of 2
# Verify only two images were returned
params = "limit=2"
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)['images']
self.assertEqual(len(data), 2)
self.assertEqual(data[0]['id'], images[0]['id'])
self.assertEqual(data[1]['id'], images[1]['id'])
# 4. GET /images with marker
# Verify only two images were returned
params = "marker=%s" % images[0]['id']
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)['images']
self.assertEqual(len(data), 2)
self.assertEqual(data[0]['id'], images[1]['id'])
self.assertEqual(data[1]['id'], images[2]['id'])
# 5. GET /images with marker and limit
# Verify only one image was returned with the correct id
params = "limit=1&marker=%s" % images[1]['id']
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)['images']
self.assertEqual(len(data), 1)
self.assertEqual(data[0]['id'], images[2]['id'])
# 6. GET /images/detail with marker and limit
# Verify only one image was returned with the correct id
params = "limit=1&marker=%s" % images[1]['id']
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)['images']
self.assertEqual(len(data), 1)
self.assertEqual(data[0]['id'], images[2]['id'])
# DELETE images
for image_id in image_ids:
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'DELETE')
self.assertEqual(response.status, 200)
**** CubicPower OpenStack Study ****
def test_ordered_images(self):
"""
Set up three test images and ensure each query param filter works
"""
# 0. GET /images
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.assertEqual(content, '{"images": []}')
# 1. POST /images with three public images with various attributes
image_ids = []
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'Image1',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'ovf',
'X-Image-Meta-Disk-Format': 'vdi',
'X-Image-Meta-Size': '19',
'X-Image-Meta-Is-Public': 'True'}
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'ASDF',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'bare',
'X-Image-Meta-Disk-Format': 'iso',
'X-Image-Meta-Size': '2',
'X-Image-Meta-Is-Public': 'True'}
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'XYZ',
'X-Image-Meta-Status': 'saving',
'X-Image-Meta-Container-Format': 'ami',
'X-Image-Meta-Disk-Format': 'ami',
'X-Image-Meta-Size': '5',
'X-Image-Meta-Is-Public': 'True'}
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image_ids.append(jsonutils.loads(content)['image']['id'])
# 2. GET /images with no query params
# Verify three public images sorted by created_at desc
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 3)
self.assertEqual(data['images'][0]['id'], image_ids[2])
self.assertEqual(data['images'][1]['id'], image_ids[1])
self.assertEqual(data['images'][2]['id'], image_ids[0])
# 3. GET /images sorted by name asc
params = 'sort_key=name&sort_dir=asc'
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 3)
self.assertEqual(data['images'][0]['id'], image_ids[1])
self.assertEqual(data['images'][1]['id'], image_ids[0])
self.assertEqual(data['images'][2]['id'], image_ids[2])
# 4. GET /images sorted by size desc
params = 'sort_key=size&sort_dir=desc'
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 3)
self.assertEqual(data['images'][0]['id'], image_ids[0])
self.assertEqual(data['images'][1]['id'], image_ids[2])
self.assertEqual(data['images'][2]['id'], image_ids[1])
# 5. GET /images sorted by size desc with a marker
params = 'sort_key=size&sort_dir=desc&marker=%s' % image_ids[0]
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 2)
self.assertEqual(data['images'][0]['id'], image_ids[2])
self.assertEqual(data['images'][1]['id'], image_ids[1])
# 6. GET /images sorted by name asc with a marker
params = 'sort_key=name&sort_dir=asc&marker=%s' % image_ids[2]
path = "/v1/images?%s" % (params)
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
data = jsonutils.loads(content)
self.assertEqual(len(data['images']), 0)
# DELETE images
for image_id in image_ids:
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'DELETE')
self.assertEqual(response.status, 200)
**** CubicPower OpenStack Study ****
def test_duplicate_image_upload(self):
"""
Upload initial image, then attempt to upload duplicate image
"""
# 0. GET /images
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.assertEqual(content, '{"images": []}')
# 1. POST /images with public image named Image1
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'Image1',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'ovf',
'X-Image-Meta-Disk-Format': 'vdi',
'X-Image-Meta-Size': '19',
'X-Image-Meta-Is-Public': 'True'}
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
image = jsonutils.loads(content)['image']
# 2. POST /images with public image named Image1, and ID: 1
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'Image1 Update',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'ovf',
'X-Image-Meta-Disk-Format': 'vdi',
'X-Image-Meta-Size': '19',
'X-Image-Meta-Id': image['id'],
'X-Image-Meta-Is-Public': 'True'}
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 409)
**** CubicPower OpenStack Study ****
def test_delete_not_existing(self):
"""
We test the following:
0. GET /images/1
- Verify 404
1. DELETE /images/1
- Verify 404
"""
# 0. GET /images
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.assertEqual(content, '{"images": []}')
# 1. DELETE /images/1
# Verify 404 returned
path = "/v1/images/1"
response, content = self.http.request(path, 'DELETE')
self.assertEqual(response.status, 404)
**** CubicPower OpenStack Study ****
def _do_test_post_image_content_bad_format(self, format):
"""
We test that missing container/disk format fails with 400 "Bad Request"
:see https://bugs.launchpad.net/glance/+bug/933702
"""
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
images = jsonutils.loads(content)['images']
self.assertEqual(len(images), 0)
path = "/v1/images"
# POST /images without given format being specified
headers = minimal_headers('Image1')
headers['X-Image-Meta-' + format] = 'bad_value'
with tempfile.NamedTemporaryFile() as test_data_file:
test_data_file.write("XXX")
test_data_file.flush()
response, content = self.http.request(path, 'POST',
headers=headers,
body=test_data_file.name)
self.assertEqual(response.status, 400)
type = format.replace('_format', '')
expected = "Invalid %s format 'bad_value' for image" % type
self.assertTrue(expected in content,
"Could not find '%s' in '%s'" % (expected, content))
# make sure the image was not created
# Verify no public images
path = "/v1/images"
response, content = self.http.request(path, 'GET')
self.assertEqual(response.status, 200)
images = jsonutils.loads(content)['images']
self.assertEqual(len(images), 0)
**** CubicPower OpenStack Study ****
def test_post_image_content_bad_container_format(self):
self._do_test_post_image_content_bad_format('container_format')
**** CubicPower OpenStack Study ****
def test_post_image_content_bad_disk_format(self):
self._do_test_post_image_content_bad_format('disk_format')
**** CubicPower OpenStack Study ****
def _do_test_put_image_content_missing_format(self, format):
"""
We test that missing container/disk format only fails with
400 "Bad Request" when the image content is PUT (i.e. not
on the original POST of a queued image).
:see https://bugs.launchpad.net/glance/+bug/937216
"""
# POST queued image
path = "/v1/images"
headers = {
'X-Image-Meta-Name': 'Image1',
'X-Image-Meta-Is-Public': 'True',
}
response, content = self.http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
self.addDetail('image_data', testtools.content.json_content(data))
# PUT image content images without given format being specified
path = "/v1/images/%s" % (image_id)
headers = minimal_headers('Image1')
del headers['X-Image-Meta-' + format]
with tempfile.NamedTemporaryFile() as test_data_file:
test_data_file.write("XXX")
test_data_file.flush()
response, content = self.http.request(path, 'PUT',
headers=headers,
body=test_data_file.name)
self.assertEqual(response.status, 400)
type = format.replace('_format', '')
expected = "Invalid %s format 'None' for image" % type
self.assertTrue(expected in content,
"Could not find '%s' in '%s'" % (expected, content))
**** CubicPower OpenStack Study ****
def test_put_image_content_bad_container_format(self):
self._do_test_put_image_content_missing_format('container_format')
**** CubicPower OpenStack Study ****
def test_put_image_content_bad_disk_format(self):
self._do_test_put_image_content_missing_format('disk_format')
**** CubicPower OpenStack Study ****
def _do_test_mismatched_attribute(self, attribute, value):
"""
Test mismatched attribute.
"""
image_data = "*" * FIVE_KB
headers = minimal_headers('Image1')
headers[attribute] = value
path = "/v1/images"
response, content = self.http.request(path, 'POST', headers=headers,
body=image_data)
self.assertEqual(response.status, 400)
images_dir = os.path.join(self.test_dir, 'images')
image_count = len([name for name in os.listdir(images_dir)
if os.path.isfile(os.path.join(images_dir, name))])
self.assertEqual(image_count, 0)
**** CubicPower OpenStack Study ****
def test_mismatched_size(self):
"""
Test mismatched size.
"""
self._do_test_mismatched_attribute('x-image-meta-size',
str(FIVE_KB + 1))
**** CubicPower OpenStack Study ****
def test_mismatched_checksum(self):
"""
Test mismatched checksum.
"""
self._do_test_mismatched_attribute('x-image-meta-checksum',
'foobar')
**** CubicPower OpenStack Study ****
class TestApiWithFakeAuth(base.ApiTest):
**** CubicPower OpenStack Study ****
def __init__(self, *args, **kwargs):
super(TestApiWithFakeAuth, self).__init__(*args, **kwargs)
self.api_flavor = 'fakeauth'
self.registry_flavor = 'fakeauth'
**** CubicPower OpenStack Study ****
def test_ownership(self):
# Add an image with admin privileges and ensure the owner
# can be set to something other than what was used to authenticate
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
create_headers = {
'X-Image-Meta-Name': 'MyImage',
'X-Image-Meta-disk_format': 'raw',
'X-Image-Meta-container_format': 'ovf',
'X-Image-Meta-Is-Public': 'True',
'X-Image-Meta-Owner': 'tenant2',
}
create_headers.update(auth_headers)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=create_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('tenant2', response['x-image-meta-owner'])
# Now add an image without admin privileges and ensure the owner
# cannot be set to something other than what was used to authenticate
auth_headers = {
'X-Auth-Token': 'user1:tenant1:role1',
}
create_headers.update(auth_headers)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=create_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
# We have to be admin to see the owner
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
create_headers.update(auth_headers)
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('tenant1', response['x-image-meta-owner'])
# Make sure the non-privileged user can't update their owner either
update_headers = {
'X-Image-Meta-Name': 'MyImage2',
'X-Image-Meta-Owner': 'tenant2',
'X-Auth-Token': 'user1:tenant1:role1',
}
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'PUT',
headers=update_headers)
self.assertEqual(response.status, 200)
# We have to be admin to see the owner
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('tenant1', response['x-image-meta-owner'])
# An admin user should be able to update the owner
auth_headers = {
'X-Auth-Token': 'user1:tenant3:admin',
}
update_headers = {
'X-Image-Meta-Name': 'MyImage2',
'X-Image-Meta-Owner': 'tenant2',
}
update_headers.update(auth_headers)
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'PUT',
headers=update_headers)
self.assertEqual(response.status, 200)
path = "/v1/images/%s" % (image_id)
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('tenant2', response['x-image-meta-owner'])
**** CubicPower OpenStack Study ****
def test_image_visibility_to_different_users(self):
owners = ['admin', 'tenant1', 'tenant2', 'none']
visibilities = {'public': 'True', 'private': 'False'}
image_ids = {}
for owner in owners:
for visibility, is_public in visibilities.items():
name = '%s-%s' % (owner, visibility)
headers = {
'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': name,
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Is-Public': is_public,
'X-Image-Meta-Owner': owner,
'X-Auth-Token': 'createuser:createtenant:admin',
}
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_ids[name] = data['image']['id']
def list_images(tenant, role='', is_public=None):
auth_token = 'user:%s:%s' % (tenant, role)
headers = {'X-Auth-Token': auth_token}
path = "/v1/images/detail"
if is_public is not None:
path += '?is_public=%s' % is_public
response, content = self.http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 200)
return jsonutils.loads(content)['images']
# 1. Known user sees public and their own images
images = list_images('tenant1')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'tenant1')
# 2. Unknown user sees only public images
images = list_images('none')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 3. Unknown admin sees only public images
images = list_images('none', role='admin')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 4. Unknown admin, is_public=none, shows all images
images = list_images('none', role='admin', is_public='none')
self.assertEqual(len(images), 8)
# 5. Unknown admin, is_public=true, shows only public images
images = list_images('none', role='admin', is_public='true')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 6. Unknown admin, is_public=false, sees only private images
images = list_images('none', role='admin', is_public='false')
self.assertEqual(len(images), 4)
for image in images:
self.assertFalse(image['is_public'])
# 7. Known admin sees public and their own images
images = list_images('admin', role='admin')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'admin')
# 8. Known admin, is_public=none, shows all images
images = list_images('admin', role='admin', is_public='none')
self.assertEqual(len(images), 8)
# 9. Known admin, is_public=true, sees all public and their images
images = list_images('admin', role='admin', is_public='true')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'admin')
# 10. Known admin, is_public=false, sees all private images
images = list_images('admin', role='admin', is_public='false')
self.assertEqual(len(images), 4)
for image in images:
self.assertFalse(image['is_public'])
**** CubicPower OpenStack Study ****
def list_images(tenant, role='', is_public=None):
auth_token = 'user:%s:%s' % (tenant, role)
headers = {'X-Auth-Token': auth_token}
path = "/v1/images/detail"
if is_public is not None:
path += '?is_public=%s' % is_public
response, content = self.http.request(path, 'GET', headers=headers)
self.assertEqual(response.status, 200)
return jsonutils.loads(content)['images']
# 1. Known user sees public and their own images
images = list_images('tenant1')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'tenant1')
# 2. Unknown user sees only public images
images = list_images('none')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 3. Unknown admin sees only public images
images = list_images('none', role='admin')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 4. Unknown admin, is_public=none, shows all images
images = list_images('none', role='admin', is_public='none')
self.assertEqual(len(images), 8)
# 5. Unknown admin, is_public=true, shows only public images
images = list_images('none', role='admin', is_public='true')
self.assertEqual(len(images), 4)
for image in images:
self.assertTrue(image['is_public'])
# 6. Unknown admin, is_public=false, sees only private images
images = list_images('none', role='admin', is_public='false')
self.assertEqual(len(images), 4)
for image in images:
self.assertFalse(image['is_public'])
# 7. Known admin sees public and their own images
images = list_images('admin', role='admin')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'admin')
# 8. Known admin, is_public=none, shows all images
images = list_images('admin', role='admin', is_public='none')
self.assertEqual(len(images), 8)
# 9. Known admin, is_public=true, sees all public and their images
images = list_images('admin', role='admin', is_public='true')
self.assertEqual(len(images), 5)
for image in images:
self.assertTrue(image['is_public'] or image['owner'] == 'admin')
# 10. Known admin, is_public=false, sees all private images
images = list_images('admin', role='admin', is_public='false')
self.assertEqual(len(images), 4)
for image in images:
self.assertFalse(image['is_public'])
**** CubicPower OpenStack Study ****
def test_property_protections(self):
# Enable property protection
self.config(property_protection_file=self.property_file)
self.setUp()
CREATE_HEADERS = {
'X-Image-Meta-Name': 'MyImage',
'X-Image-Meta-disk_format': 'raw',
'X-Image-Meta-container_format': 'ovf',
'X-Image-Meta-Is-Public': 'True',
'X-Image-Meta-Owner': 'tenant2',
}
# Create an image for role member with extra properties
# Raises 403 since user is not allowed to create 'foo'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:member',
}
custom_props = {
'x-image-meta-property-foo': 'bar'
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 403)
# Create an image for role member without 'foo'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:member',
}
custom_props = {
'x-image-meta-property-x_owner_foo': 'o_s_bar',
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
# Returned image entity should have 'x_owner_foo'
data = jsonutils.loads(content)
self.assertEqual(data['image']['properties']['x_owner_foo'],
'o_s_bar')
# Create an image for role spl_role with extra properties
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
custom_props = {
'X-Image-Meta-Property-spl_create_prop': 'create_bar',
'X-Image-Meta-Property-spl_read_prop': 'read_bar',
'X-Image-Meta-Property-spl_update_prop': 'update_bar',
'X-Image-Meta-Property-spl_delete_prop': 'delete_bar'
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
# Attempt to update two properties, one protected(spl_read_prop), the
# other not(spl_update_prop). Request should be forbidden.
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
custom_props = {
'X-Image-Meta-Property-spl_read_prop': 'r',
'X-Image-Meta-Property-spl_update_prop': 'u',
'X-Glance-Registry-Purge-Props': 'False'
}
auth_headers.update(auth_headers)
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
# Attempt to create properties which are forbidden
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
custom_props = {
'X-Image-Meta-Property-spl_new_prop': 'new',
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(auth_headers)
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
# Attempt to update, create and delete properties
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
custom_props = {
'X-Image-Meta-Property-spl_create_prop': 'create_bar',
'X-Image-Meta-Property-spl_read_prop': 'read_bar',
'X-Image-Meta-Property-spl_update_prop': 'u',
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(auth_headers)
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
# Returned image entity should reflect the changes
image = jsonutils.loads(content)
# 'spl_update_prop' has update permission for spl_role
# hence the value has changed
self.assertEqual('u', image['image']['properties']['spl_update_prop'])
# 'spl_delete_prop' has delete permission for spl_role
# hence the property has been deleted
self.assertTrue('spl_delete_prop' not in image['image']['properties'])
# 'spl_create_prop' has create permission for spl_role
# hence the property has been created
self.assertEqual('create_bar',
image['image']['properties']['spl_create_prop'])
# Image Deletion should work
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'DELETE',
headers=auth_headers)
self.assertEqual(response.status, 200)
# This image should be no longer be directly accessible
auth_headers = {
'X-Auth-Token': 'user1:tenant1:spl_role',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 404)
**** CubicPower OpenStack Study ****
def test_property_protections_special_chars(self):
# Enable property protection
self.config(property_protection_file=self.property_file)
self.setUp()
CREATE_HEADERS = {
'X-Image-Meta-Name': 'MyImage',
'X-Image-Meta-disk_format': 'raw',
'X-Image-Meta-container_format': 'ovf',
'X-Image-Meta-Is-Public': 'True',
'X-Image-Meta-Owner': 'tenant2',
'X-Image-Meta-Size': '0',
}
# Create an image
auth_headers = {
'X-Auth-Token': 'user1:tenant1:member',
}
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
# Verify both admin and unknown role can create properties marked with
# '@'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_all_permitted_admin': '1'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertEqual('1',
image['image']['properties']['x_all_permitted_admin'])
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Image-Meta-Property-x_all_permitted_joe_soap': '1',
'X-Glance-Registry-Purge-Props': 'False'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertEqual(
'1', image['image']['properties']['x_all_permitted_joe_soap'])
# Verify both admin and unknown role can read properties marked with
# '@'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('1', response.get(
'x-image-meta-property-x_all_permitted_admin'))
self.assertEqual('1', response.get(
'x-image-meta-property-x_all_permitted_joe_soap'))
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertEqual('1', response.get(
'x-image-meta-property-x_all_permitted_admin'))
self.assertEqual('1', response.get(
'x-image-meta-property-x_all_permitted_joe_soap'))
# Verify both admin and unknown role can update properties marked with
# '@'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_all_permitted_admin': '2',
'X-Glance-Registry-Purge-Props': 'False'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertEqual('2',
image['image']['properties']['x_all_permitted_admin'])
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Image-Meta-Property-x_all_permitted_joe_soap': '2',
'X-Glance-Registry-Purge-Props': 'False'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertEqual(
'2', image['image']['properties']['x_all_permitted_joe_soap'])
# Verify both admin and unknown role can delete properties marked with
# '@'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_all_permitted_joe_soap': '2',
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertNotIn('x_all_permitted_admin', image['image']['properties'])
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 200)
image = jsonutils.loads(content)
self.assertNotIn('x_all_permitted_joe_soap',
image['image']['properties'])
# Verify neither admin nor unknown role can create a property protected
# with '!'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_none_permitted_admin': '1'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Image-Meta-Property-x_none_permitted_joe_soap': '1'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
# Verify neither admin nor unknown role can read properties marked with
# '!'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_none_read': '1'
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertRaises(KeyError,
response.get, 'X-Image-Meta-Property-x_none_read')
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'HEAD',
headers=auth_headers)
self.assertEqual(response.status, 200)
self.assertRaises(KeyError,
response.get, 'X-Image-Meta-Property-x_none_read')
# Verify neither admin nor unknown role can update properties marked
# with '!'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_none_update': '1'
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_none_update': '2'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Image-Meta-Property-x_none_update': '2'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
# Verify neither admin nor unknown role can delete properties marked
# with '!'
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Image-Meta-Property-x_none_delete': '1'
}
auth_headers.update(custom_props)
auth_headers.update(CREATE_HEADERS)
path = "/v1/images"
response, content = self.http.request(path, 'POST',
headers=auth_headers)
self.assertEqual(response.status, 201)
data = jsonutils.loads(content)
image_id = data['image']['id']
auth_headers = {
'X-Auth-Token': 'user1:tenant1:admin',
}
custom_props = {
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)
auth_headers = {
'X-Auth-Token': 'user1:tenant1:joe_soap',
}
custom_props = {
'X-Glance-Registry-Purge-Props': 'True'
}
auth_headers.update(custom_props)
path = "/v1/images/%s" % image_id
response, content = self.http.request(path, 'PUT',
headers=auth_headers)
self.assertEqual(response.status, 403)