Require container & disk formats on image create
Fixes lp 933702 For images created via the glance CLI, the container and disk formats were previously defaulted if not explicitly set. However if created via the python or REST APIs, these attributes were not defaulted if unset. There is no real sensible default for these formats, so now an image create fails with 400 "Bad Request" if the format metadata are missing. Also we ensure unset image metadata are not reported in x-image-meta-* headers in order to disambiguate None and empty string values. Change-Id: I8189383f5f9adf42a8cdac7f8dc7e9327baf46da
This commit is contained in:
parent
f8f9f17112
commit
62c913c3ad
19
bin/glance
19
bin/glance
@ -141,7 +141,7 @@ def print_image_formatted(client, image):
|
||||
print "Container format: %s" % image['container_format']
|
||||
print "Minimum Ram Required (MB): %s" % image['min_ram']
|
||||
print "Minimum Disk Required (GB): %s" % image['min_disk']
|
||||
if image['owner']:
|
||||
if image.get('owner'):
|
||||
print "Owner: %s" % image['owner']
|
||||
if len(image['properties']) > 0:
|
||||
for k, v in image['properties'].items():
|
||||
@ -173,10 +173,9 @@ is_public Optional. If specified, interpreted as a boolean value
|
||||
protected Optional. If specified, interpreted as a boolean value
|
||||
and enables or disables deletion protection.
|
||||
The default value is False.
|
||||
disk_format Optional. Possible values are 'vhd','vmdk','raw', 'qcow2',
|
||||
and 'ami'. Default value is 'raw'.
|
||||
container_format Optional. Possible values are 'ovf' and 'ami'.
|
||||
Default value is 'ovf'.
|
||||
disk_format Required. Possible values are 'vhd','vmdk','raw', 'qcow2',
|
||||
and 'ami'.
|
||||
container_format Required. Possible values are 'ovf' and 'ami'.
|
||||
location Optional. When specified, should be a readable location
|
||||
in the form of a URI: $STORE://LOCATION. For example, if
|
||||
the image data is stored in a file on the local
|
||||
@ -202,7 +201,8 @@ EXAMPLES
|
||||
location=http://images.ubuntu.org/images/lucid-10.04-i686.iso \\
|
||||
distro="Ubuntu 10.04 LTS"
|
||||
|
||||
%(prog)s add name="My Image" distro="Ubuntu 10.04 LTS" < /tmp/myimage.iso"""
|
||||
%(prog)s add name="My Image" disk_format=raw container_format=ovf \\
|
||||
distro="Ubuntu 10.04 LTS" < /tmp/myimage.iso"""
|
||||
c = get_client(options)
|
||||
|
||||
try:
|
||||
@ -220,10 +220,13 @@ EXAMPLES
|
||||
fields.pop('is_public', False)),
|
||||
'protected': utils.bool_from_string(
|
||||
fields.pop('protected', False)),
|
||||
'disk_format': fields.pop('disk_format', 'raw'),
|
||||
'min_disk': fields.pop('min_disk', 0),
|
||||
'min_ram': fields.pop('min_ram', 0),
|
||||
'container_format': fields.pop('container_format', 'ovf')}
|
||||
}
|
||||
|
||||
for format in ['disk_format', 'container_format']:
|
||||
if format in fields:
|
||||
image_meta[format] = fields.pop(format)
|
||||
|
||||
# Strip any args that are not supported
|
||||
unsupported_fields = ['status', 'size']
|
||||
|
@ -131,8 +131,8 @@ like so::
|
||||
name A name for the image.
|
||||
is_public If specified, interpreted as a boolean value
|
||||
and sets or unsets the image's availability to the public.
|
||||
disk_format Format of the disk image
|
||||
container_format Format of the container
|
||||
disk_format Format of the disk image (required)
|
||||
container_format Format of the container (required)
|
||||
|
||||
All other field names are considered to be custom properties so be careful
|
||||
to spell field names correctly. :)
|
||||
@ -186,21 +186,27 @@ that the image should be public -- anyone should be able to fetch it.
|
||||
Here is how we'd upload this image to Glance. Change example IP number to your
|
||||
server IP number.::
|
||||
|
||||
$> glance add name="My Image" is_public=true < /tmp/images/myimage.iso \
|
||||
--host=65.114.169.29
|
||||
$> glance add name="My Image" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
--host=65.114.169.29 < /tmp/images/myimage.iso
|
||||
|
||||
Note that the disk container formats are no longer defaulted and are thus
|
||||
strictly required.
|
||||
|
||||
If Glance was able to successfully upload and store your VM image data and
|
||||
metadata attributes, you would see something like this::
|
||||
|
||||
$> glance add name="My Image" is_public=true < /tmp/images/myimage.iso \
|
||||
--host=65.114.169.29
|
||||
$> glance add name="My Image" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
--host=65.114.169.29 < /tmp/images/myimage.iso
|
||||
Added new image with ID: 991baaf9-cc0d-4183-a201-8facdf1a1430
|
||||
|
||||
You can use the ``--verbose`` (or ``-v``) command-line option to print some more
|
||||
information about the metadata that was saved with the image::
|
||||
|
||||
$> glance --verbose add name="My Image" is_public=true < \
|
||||
/tmp/images/myimage.iso --host=65.114.169.29
|
||||
$> glance --verbose add name="My Image" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
--host=65.114.169.29 < /tmp/images/myimage.iso
|
||||
Added new image with ID: 541424be-27b1-49d6-a55b-6430b8ae0f5f
|
||||
Returned the following metadata for the new image:
|
||||
container_format => ovf
|
||||
@ -221,8 +227,9 @@ information about the metadata that was saved with the image::
|
||||
If you are unsure about what will be added, you can use the ``--dry-run``
|
||||
command-line option, which will simply show you what *would* have happened::
|
||||
|
||||
$> glance --dry-run add name="Foo" distro="Ubuntu" is_public=True < \
|
||||
/tmp/images/myimage.iso --host=65.114.169.29
|
||||
$> glance --dry-run add name="Foo" distro="Ubuntu" is_public=True \
|
||||
container_format=ovf disk_format=raw \
|
||||
--host=65.114.169.29 < /tmp/images/myimage.iso
|
||||
Dry run. We would have done the following:
|
||||
Add new image with metadata:
|
||||
container_format => ovf
|
||||
@ -243,42 +250,46 @@ Examples of uploading different kinds of images
|
||||
|
||||
To upload an EC2 tarball VM image::
|
||||
|
||||
$> glance add name="ubuntu-10.10-amd64" is_public=true < \
|
||||
/root/maverick-server-uec-amd64.tar.gz
|
||||
$> glance add name="ubuntu-10.10-amd64" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
< /root/maverick-server-uec-amd64.tar.gz
|
||||
|
||||
To upload an EC2 tarball VM image with an associated property (e.g., distro)::
|
||||
|
||||
$> glance add name="ubuntu-10.10-amd64" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
distro="ubuntu 10.10" < /root/maverick-server-uec-amd64.tar.gz
|
||||
|
||||
To upload an EC2 tarball VM image from a URL::
|
||||
|
||||
$> glance add name="uubntu-10.04-amd64" is_public=true \
|
||||
container_format=ovf disk_format=raw \
|
||||
location="http://uec-images.ubuntu.com/lucid/current/\
|
||||
lucid-server-uec-amd64.tar.gz"
|
||||
|
||||
To upload a qcow2 image::
|
||||
|
||||
$> glance add name="ubuntu-11.04-amd64" is_public=true \
|
||||
distro="ubuntu 11.04" disk_format="qcow2" < /data/images/rock_natty.qcow2
|
||||
container_format=ovf disk_format=qcow2 \
|
||||
distro="ubuntu 11.04" < /data/images/rock_natty.qcow2
|
||||
|
||||
To upload a kernel file, ramdisk file and filesystem image file::
|
||||
|
||||
$> glance add --disk-format=aki --container-format=aki \
|
||||
$> glance add disk_format=aki container_format=aki \
|
||||
./maverick-server-uec-amd64-vmlinuz-virtual \
|
||||
maverick-server-uec-amd64-vmlinuz-virtual
|
||||
$> glance add --disk-format=ari --container-format=ari \
|
||||
$> glance add disk_format=ari container_format=ari \
|
||||
./maverick-server-uec-amd64-loader maverick-server-uec-amd64-loader
|
||||
# Determine what the ids associated with the kernel and ramdisk files
|
||||
$> glance index
|
||||
# Assuming the ids are 7 and 8:
|
||||
$> glance add --disk-format=ami --container-format=ami --kernel=7 \
|
||||
$> glance add disk_format=ami container_format=ami --kernel=7 \
|
||||
--ramdisk=8 ./maverick-server-uec-amd64.img maverick-server-uec-amd64.img
|
||||
|
||||
To upload a raw image file::
|
||||
|
||||
$> glance add --disk_format=raw ./maverick-server-uec-amd64.img \
|
||||
maverick-server-uec-amd64.img_v2
|
||||
$> glance add disk_format=raw container_format=ovf \
|
||||
./maverick-server-uec-amd64.img maverick-server-uec-amd64.img_v2
|
||||
|
||||
|
||||
Register a virtual machine image in another location
|
||||
|
@ -181,8 +181,8 @@ following shows an example of the HTTP headers returned from the above
|
||||
|
||||
x-image-meta-uri http://glance.example.com/images/71c675ab-d94f-49cd-a114-e12490b328d9
|
||||
x-image-meta-name Ubuntu 10.04 Plain 5GB
|
||||
x-image-meta-disk-format vhd
|
||||
x-image-meta-container-format ovf
|
||||
x-image-meta-disk_format vhd
|
||||
x-image-meta-container_format ovf
|
||||
x-image-meta-size 5368709120
|
||||
x-image-meta-checksum c2e5db72bd7fd153f53ede5da5a06de3
|
||||
x-image-meta-created_at 2010-02-03 09:34:01
|
||||
@ -244,8 +244,8 @@ returned from the above ``GET`` request::
|
||||
|
||||
x-image-meta-uri http://glance.example.com/images/71c675ab-d94f-49cd-a114-e12490b328d9
|
||||
x-image-meta-name Ubuntu 10.04 Plain 5GB
|
||||
x-image-meta-disk-format vhd
|
||||
x-image-meta-container-format ovf
|
||||
x-image-meta-disk_format vhd
|
||||
x-image-meta-container_format ovf
|
||||
x-image-meta-size 5368709120
|
||||
x-image-meta-checksum c2e5db72bd7fd153f53ede5da5a06de3
|
||||
x-image-meta-created_at 2010-02-03 09:34:01
|
||||
@ -353,14 +353,14 @@ The list of metadata headers that Glance accepts are listed below.
|
||||
store that is marked default. See the configuration option ``default_store``
|
||||
for more information.
|
||||
|
||||
* ``x-image-meta-disk-format``
|
||||
* ``x-image-meta-disk_format``
|
||||
|
||||
This header is optional. Valid values are one of ``aki``, ``ari``, ``ami``,
|
||||
``raw``, ``iso``, ``vhd``, ``vdi``, ``qcow2``, or ``vmdk``.
|
||||
|
||||
For more information, see :doc:`About Disk and Container Formats <formats>`
|
||||
|
||||
* ``x-image-meta-container-format``
|
||||
* ``x-image-meta-container_format``
|
||||
|
||||
This header is optional. Valid values are one of ``aki``, ``ari``, ``ami``,
|
||||
``bare``, or ``ovf``.
|
||||
|
@ -77,16 +77,14 @@ def image_meta_to_http_headers(image_meta):
|
||||
"""
|
||||
headers = {}
|
||||
for k, v in image_meta.items():
|
||||
if v is None:
|
||||
v = ''
|
||||
if k == 'properties':
|
||||
for pk, pv in v.items():
|
||||
if pv is None:
|
||||
pv = ''
|
||||
headers["x-image-meta-property-%s"
|
||||
% pk.lower()] = unicode(pv)
|
||||
else:
|
||||
headers["x-image-meta-%s" % k.lower()] = unicode(v)
|
||||
if v is not None:
|
||||
if k == 'properties':
|
||||
for pk, pv in v.items():
|
||||
if pv is not None:
|
||||
headers["x-image-meta-property-%s"
|
||||
% pk.lower()] = unicode(pv)
|
||||
else:
|
||||
headers["x-image-meta-%s" % k.lower()] = unicode(v)
|
||||
return headers
|
||||
|
||||
|
||||
|
@ -313,11 +313,11 @@ def validate_image(values):
|
||||
msg = "Invalid image status '%s' for image." % status
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if disk_format and disk_format not in DISK_FORMATS:
|
||||
if not disk_format or disk_format not in DISK_FORMATS:
|
||||
msg = "Invalid disk format '%s' for image." % disk_format
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if container_format and container_format not in CONTAINER_FORMATS:
|
||||
if not container_format or container_format not in CONTAINER_FORMATS:
|
||||
msg = "Invalid container format '%s' for image." % container_format
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
|
@ -25,7 +25,7 @@ import tempfile
|
||||
|
||||
from glance.common import utils
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import execute, skip_if_disabled
|
||||
from glance.tests.utils import execute, skip_if_disabled, minimal_headers
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
FIVE_GB = 5 * 1024 * 1024 * 1024
|
||||
@ -86,9 +86,7 @@ class TestApi(functional.FunctionalTest):
|
||||
# 2. POST /images with public image named Image1
|
||||
# attribute and no custom properties. Verify a 200 OK is returned
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -124,8 +122,8 @@ class TestApi(functional.FunctionalTest):
|
||||
'x-image-meta-name': 'Image1',
|
||||
'x-image-meta-is_public': 'True',
|
||||
'x-image-meta-status': 'active',
|
||||
'x-image-meta-disk_format': '',
|
||||
'x-image-meta-container_format': '',
|
||||
'x-image-meta-disk_format': 'raw',
|
||||
'x-image-meta-container_format': 'ovf',
|
||||
'x-image-meta-size': str(FIVE_KB)}
|
||||
|
||||
expected_std_headers = {
|
||||
@ -157,8 +155,8 @@ class TestApi(functional.FunctionalTest):
|
||||
self.assertEqual(response.status, 200)
|
||||
|
||||
expected_result = {"images": [
|
||||
{"container_format": None,
|
||||
"disk_format": None,
|
||||
{"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"name": "Image1",
|
||||
"checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
|
||||
@ -176,8 +174,8 @@ class TestApi(functional.FunctionalTest):
|
||||
"status": "active",
|
||||
"name": "Image1",
|
||||
"deleted": False,
|
||||
"container_format": None,
|
||||
"disk_format": None,
|
||||
"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"is_public": True,
|
||||
"deleted_at": None,
|
||||
@ -217,8 +215,8 @@ class TestApi(functional.FunctionalTest):
|
||||
"status": "active",
|
||||
"name": "Image1",
|
||||
"deleted": False,
|
||||
"container_format": None,
|
||||
"disk_format": None,
|
||||
"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"is_public": True,
|
||||
"deleted_at": None,
|
||||
@ -314,9 +312,7 @@ class TestApi(functional.FunctionalTest):
|
||||
|
||||
# 1. POST /images with public image named Image1
|
||||
# with no location or image data
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers)
|
||||
@ -324,8 +320,8 @@ class TestApi(functional.FunctionalTest):
|
||||
data = json.loads(content)
|
||||
self.assertEqual(data['image']['checksum'], None)
|
||||
self.assertEqual(data['image']['size'], 0)
|
||||
self.assertEqual(data['image']['container_format'], None)
|
||||
self.assertEqual(data['image']['disk_format'], None)
|
||||
self.assertEqual(data['image']['container_format'], 'ovf')
|
||||
self.assertEqual(data['image']['disk_format'], 'raw')
|
||||
self.assertEqual(data['image']['name'], "Image1")
|
||||
self.assertEqual(data['image']['is_public'], True)
|
||||
|
||||
@ -341,8 +337,8 @@ class TestApi(functional.FunctionalTest):
|
||||
self.assertEqual(data['images'][0]['id'], image_id)
|
||||
self.assertEqual(data['images'][0]['checksum'], None)
|
||||
self.assertEqual(data['images'][0]['size'], 0)
|
||||
self.assertEqual(data['images'][0]['container_format'], None)
|
||||
self.assertEqual(data['images'][0]['disk_format'], None)
|
||||
self.assertEqual(data['images'][0]['container_format'], 'ovf')
|
||||
self.assertEqual(data['images'][0]['disk_format'], 'raw')
|
||||
self.assertEqual(data['images'][0]['name'], "Image1")
|
||||
|
||||
# 3. HEAD /images
|
||||
@ -394,8 +390,8 @@ class TestApi(functional.FunctionalTest):
|
||||
hashlib.md5(image_data).hexdigest())
|
||||
self.assertEqual(data['images'][0]['id'], image_id)
|
||||
self.assertEqual(data['images'][0]['size'], FIVE_KB)
|
||||
self.assertEqual(data['images'][0]['container_format'], None)
|
||||
self.assertEqual(data['images'][0]['disk_format'], None)
|
||||
self.assertEqual(data['images'][0]['container_format'], 'ovf')
|
||||
self.assertEqual(data['images'][0]['disk_format'], 'raw')
|
||||
self.assertEqual(data['images'][0]['name'], "Image1")
|
||||
|
||||
# DELETE image
|
||||
@ -592,6 +588,8 @@ class TestApi(functional.FunctionalTest):
|
||||
'X-Image-Meta-Location': 'http://example.com/fakeimage',
|
||||
'X-Image-Meta-Size': str(FIVE_GB),
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-disk_format': 'raw',
|
||||
'X-image-Meta-container_format': 'ovf',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
@ -633,7 +631,8 @@ class TestApi(functional.FunctionalTest):
|
||||
response, content = http.request(path, 'POST',
|
||||
body=test_data_file.name)
|
||||
self.assertEqual(response.status, 400)
|
||||
expected = "Content-Type must be application/octet-stream"
|
||||
expected = ("Failed to reserve image. Got error: "
|
||||
"Data supplied was not valid. Details: 400 Bad Request")
|
||||
self.assertTrue(expected in content,
|
||||
"Could not find '%s' in '%s'" % (expected, content))
|
||||
|
||||
@ -1014,27 +1013,21 @@ class TestApi(functional.FunctionalTest):
|
||||
image_ids = []
|
||||
|
||||
# 1. POST /images with three public images with various attributes
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers)
|
||||
self.assertEqual(response.status, 201)
|
||||
image_ids.append(json.loads(content)['image']['id'])
|
||||
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image2',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image2')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers)
|
||||
self.assertEqual(response.status, 201)
|
||||
image_ids.append(json.loads(content)['image']['id'])
|
||||
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image3',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image3')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers)
|
||||
@ -1325,3 +1318,40 @@ class TestApi(functional.FunctionalTest):
|
||||
expect_launch=False,
|
||||
expected_exitcode=255,
|
||||
**self.__dict__.copy())
|
||||
|
||||
def _do_test_unset_required_format(self, format):
|
||||
"""
|
||||
We test that missing container/disk format fails with 400 "Bad Request"
|
||||
|
||||
:see https://bugs.launchpad.net/glance/+bug/933702
|
||||
"""
|
||||
self.cleanup()
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
|
||||
# POST /images without given format being specified
|
||||
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()
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST',
|
||||
headers=headers,
|
||||
body=test_data_file.name)
|
||||
self.assertEqual(response.status, 400)
|
||||
type = format.replace('_format', '')
|
||||
expected = "Details: Invalid %s format 'None' for image" % type
|
||||
self.assertTrue(expected in content,
|
||||
"Could not find '%s' in '%s'" % (expected, content))
|
||||
|
||||
self.stop_servers()
|
||||
|
||||
@skip_if_disabled
|
||||
def test_unset_container_format(self):
|
||||
self._do_test_unset_required_format('container_format')
|
||||
|
||||
@skip_if_disabled
|
||||
def test_unset_disk_format(self):
|
||||
self._do_test_unset_required_format('disk_format')
|
||||
|
@ -23,7 +23,7 @@ import tempfile
|
||||
|
||||
from glance.common import utils
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import execute
|
||||
from glance.tests.utils import execute, minimal_add_command
|
||||
|
||||
|
||||
class TestBinGlance(functional.FunctionalTest):
|
||||
@ -54,8 +54,9 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
self.assertEqual('', out.strip())
|
||||
|
||||
# 1. Add public image
|
||||
cmd = "bin/glance --port=%d add is_public=True"\
|
||||
" name=MyImage location=http://example.com" % api_port
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'location=http://example.com')
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -99,8 +100,10 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
image_file.write("XXX")
|
||||
image_file.flush()
|
||||
file_name = image_file.name
|
||||
cmd = "bin/glance --port=%d add is_public=True name=MyImage " \
|
||||
"location=http://example.com < %s" % (api_port, file_name)
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'location=http://example.com < %s' %
|
||||
file_name)
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -153,8 +156,9 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
image_file.write("XXX")
|
||||
image_file.flush()
|
||||
image_file_name = image_file.name
|
||||
cmd = "bin/glance --port=%d add is_public=True"\
|
||||
" name=MyImage < %s" % (api_port, image_file_name)
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'< %s' % image_file_name)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -227,7 +231,10 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
self.assertEqual('', out.strip())
|
||||
|
||||
# 1. Add public image
|
||||
cmd = "bin/glance --port=%d add name=MyImage" % api_port
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'location=http://example.com',
|
||||
public=False)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -355,8 +362,9 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
|
||||
# 1. Add some images
|
||||
for i in range(1, 5):
|
||||
cmd = "bin/glance --port=%d add is_public=True name=MyName " \
|
||||
" foo=bar" % api_port
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'foo=bar')
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
self.assertEqual(0, exitcode)
|
||||
@ -705,7 +713,11 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
image_file.flush()
|
||||
image_file_name = image_file.name
|
||||
cmd = "bin/glance --port=%d add is_public=True"\
|
||||
" disk_format=raw container_format=ovf " \
|
||||
" name=MyImage < %s" % (api_port, image_file_name)
|
||||
cmd = minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'< %s' % image_file_name)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
@ -771,8 +783,10 @@ class TestBinGlance(functional.FunctionalTest):
|
||||
self.assertEqual('', out.strip())
|
||||
|
||||
# 1. Add public image
|
||||
cmd = "echo testdata | bin/glance --port=%d add is_public=True"\
|
||||
" protected=True name=MyImage" % api_port
|
||||
cmd = ("echo testdata | " +
|
||||
minimal_add_command(api_port,
|
||||
'MyImage',
|
||||
'protected=True'))
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
|
@ -27,7 +27,7 @@ import unittest
|
||||
|
||||
from glance.common import utils
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import execute
|
||||
from glance.tests.utils import execute, minimal_headers
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
|
||||
@ -54,9 +54,7 @@ class TestBinGlanceCacheManage(functional.FunctionalTest):
|
||||
image identifier.
|
||||
"""
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': name,
|
||||
'X-Image-Meta-Is-Public': 'true'}
|
||||
headers = minimal_headers(name)
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
|
@ -35,7 +35,9 @@ import httplib2
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import (skip_if_disabled,
|
||||
execute,
|
||||
xattr_writes_supported)
|
||||
xattr_writes_supported,
|
||||
minimal_headers,
|
||||
)
|
||||
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
@ -90,9 +92,7 @@ class BaseCacheMiddlewareTest(object):
|
||||
|
||||
# Add an image and verify a 200 OK is returned
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -177,6 +177,8 @@ class BaseCacheMiddlewareTest(object):
|
||||
# Add a remote image and verify a 201 Created is returned
|
||||
remote_uri = 'http://%s:%d/images/2' % (remote_ip, remote_port)
|
||||
headers = {'X-Image-Meta-Name': 'Image2',
|
||||
'X-Image-Meta-disk_format': 'raw',
|
||||
'X-Image-Meta-container_format': 'ovf',
|
||||
'X-Image-Meta-Is-Public': 'True',
|
||||
'X-Image-Meta-Location': remote_uri}
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
@ -226,9 +228,8 @@ class BaseCacheManageMiddlewareTest(object):
|
||||
identifier
|
||||
"""
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': '%s' % name,
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('%s' % name)
|
||||
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
|
@ -22,7 +22,7 @@ import os
|
||||
import tempfile
|
||||
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import execute
|
||||
from glance.tests.utils import execute, minimal_headers, minimal_add_command
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
FIVE_GB = 5 * 1024 * 1024 * 1024
|
||||
@ -44,9 +44,7 @@ class TestMiscellaneous(functional.FunctionalTest):
|
||||
# 1. POST /images with public image named Image1
|
||||
# attribute and no custom properties. Verify a 200 OK is returned
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -132,8 +130,9 @@ class TestMiscellaneous(functional.FunctionalTest):
|
||||
image_file.write("XXX")
|
||||
image_file.flush()
|
||||
image_file_name = image_file.name
|
||||
cmd = "bin/glance --port=%d add is_public=True name=MyImage "\
|
||||
"size=12345 < %s" % (self.api_port, image_file_name)
|
||||
cmd = minimal_add_command(self.api_port,
|
||||
'MyImage',
|
||||
'size=12345 < %s' % image_file_name)
|
||||
|
||||
exitcode, out, err = execute(cmd)
|
||||
|
||||
|
@ -23,7 +23,11 @@ import os
|
||||
|
||||
from glance.tests import functional
|
||||
from glance.tests.functional import keystone_utils
|
||||
from glance.tests.utils import execute, skip_if_disabled
|
||||
from glance.tests.utils import (execute,
|
||||
skip_if_disabled,
|
||||
minimal_headers,
|
||||
minimal_add_command,
|
||||
)
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
FIVE_GB = 5 * 1024 * 1024 * 1024
|
||||
@ -46,9 +50,8 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
|
||||
# First, we need to push an image up
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Auth-Token': keystone_utils.pattieblack_token,
|
||||
'X-Image-Meta-Name': 'Image1'}
|
||||
headers = minimal_headers('Image1', public=False)
|
||||
headers['X-Auth-Token'] = keystone_utils.pattieblack_token
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -298,9 +301,8 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
|
||||
# Need to push an image up
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Auth-Token': keystone_utils.pattieblack_token,
|
||||
'X-Image-Meta-Name': 'Image1'}
|
||||
headers = minimal_headers('Image1', public=False)
|
||||
headers['X-Auth-Token'] = keystone_utils.pattieblack_token
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -478,7 +480,7 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(response.status, 200)
|
||||
self.assertEqual(response['x-image-meta-name'], "Image1")
|
||||
self.assertEqual(response['x-image-meta-is_public'], "False")
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
self.assertFalse('x-image-meta-owner' in response)
|
||||
|
||||
# And of course the image itself
|
||||
headers = {'X-Auth-Token': keystone_utils.pattieblack_token}
|
||||
@ -490,7 +492,7 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(content, "*" * FIVE_KB)
|
||||
self.assertEqual(response['x-image-meta-name'], "Image1")
|
||||
self.assertEqual(response['x-image-meta-is_public'], "False")
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
self.assertFalse('x-image-meta-owner' in response)
|
||||
|
||||
# Pattieblack can't change is-public, though
|
||||
headers = {'X-Auth-Token': keystone_utils.pattieblack_token,
|
||||
@ -531,8 +533,7 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
|
||||
# Make sure anonymous user can't push up an image
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1'}
|
||||
headers = minimal_headers('Image1', public=False)
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -541,9 +542,8 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
|
||||
# Now push up an image for anonymous user to try to access
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Auth-Token': keystone_utils.pattieblack_token,
|
||||
'X-Image-Meta-Name': 'Image1'}
|
||||
headers = minimal_headers('Image1', public=False)
|
||||
headers['X-Auth-Token'] = keystone_utils.pattieblack_token
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
http = httplib2.Http()
|
||||
response, content = http.request(path, 'POST', headers=headers,
|
||||
@ -644,7 +644,7 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(response.status, 200)
|
||||
self.assertEqual(response['x-image-meta-name'], "Image1")
|
||||
self.assertEqual(response['x-image-meta-is_public'], "False")
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
self.assertFalse('x-image-meta-owner' in response)
|
||||
|
||||
# And even the image itself...
|
||||
path = "http://%s:%d/v1/images/%s" % ("0.0.0.0", self.api_port,
|
||||
@ -655,7 +655,7 @@ class TestPrivateImagesApi(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(content, "*" * FIVE_KB)
|
||||
self.assertEqual(response['x-image-meta-name'], "Image1")
|
||||
self.assertEqual(response['x-image-meta-is_public'], "False")
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
self.assertFalse('x-image-meta-owner' in response)
|
||||
|
||||
# Anonymous still shouldn't be able to make the image
|
||||
# public...
|
||||
@ -835,7 +835,7 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
self.assertEqual(response.status, 200)
|
||||
self.assertEqual(response['x-image-meta-name'], "MyImage")
|
||||
self.assertEqual(response['x-image-meta-is_public'], "True")
|
||||
self.assertEqual(response['x-image-meta-owner'], '')
|
||||
self.assertFalse('x-image-meta-owner' in response)
|
||||
|
||||
self.stop_servers()
|
||||
|
||||
@ -850,8 +850,8 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
"""
|
||||
Test the CLI with the noauth strategy defaulted to.
|
||||
"""
|
||||
cmd = ("bin/glance --port=%d --auth_token=%s add name=MyImage" %
|
||||
(self.api_port, keystone_utils.pattieblack_token))
|
||||
suffix = '--auth_token=%s' % keystone_utils.pattieblack_token
|
||||
cmd = minimal_add_command(self.api_port, 'MyImage', suffix, False)
|
||||
self._do_test_glance_cli(cmd)
|
||||
|
||||
@skip_if_disabled
|
||||
@ -860,11 +860,12 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
Test the CLI with the keystone (v1) strategy enabled via
|
||||
command line switches.
|
||||
"""
|
||||
substitutions = (self.api_port, self.auth_port, 'keystone',
|
||||
substitutions = (self.auth_port, 'keystone',
|
||||
'pattieblack', 'secrete')
|
||||
cmd = ("bin/glance --port=%d --auth_url=http://localhost:%d/v1.0 "
|
||||
"--auth_strategy=%s --username=%s --password=%s "
|
||||
" add name=MyImage" % substitutions)
|
||||
suffix = ("--auth_url=http://localhost:%d/v1.0 "
|
||||
"--auth_strategy=%s --username=%s --password=%s "
|
||||
% substitutions)
|
||||
cmd = minimal_add_command(self.api_port, 'MyImage', suffix, False)
|
||||
self._do_test_glance_cli(cmd)
|
||||
|
||||
@skip_if_disabled
|
||||
@ -877,7 +878,7 @@ class TestPrivateImagesCli(keystone_utils.KeystoneTests):
|
||||
os.environ['OS_AUTH_STRATEGY'] = 'keystone'
|
||||
os.environ['OS_AUTH_USER'] = 'pattieblack'
|
||||
os.environ['OS_AUTH_KEY'] = 'secrete'
|
||||
cmd = "bin/glance --port=%d add name=MyImage" % self.api_port
|
||||
cmd = minimal_add_command(self.api_port, 'MyImage', public=False)
|
||||
self._do_test_glance_cli(cmd)
|
||||
|
||||
@skip_if_disabled
|
||||
|
@ -22,7 +22,7 @@ import json
|
||||
|
||||
from glance.tests import functional
|
||||
from glance.tests.functional import keystone_utils
|
||||
from glance.tests.utils import execute, skip_if_disabled
|
||||
from glance.tests.utils import execute, skip_if_disabled, minimal_headers
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
FIVE_GB = 5 * 1024 * 1024 * 1024
|
||||
@ -32,8 +32,7 @@ class TestSharedImagesApi(keystone_utils.KeystoneTests):
|
||||
def _push_image(self):
|
||||
# First, we need to push an image up
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1'}
|
||||
headers = minimal_headers('Image1', public=False)
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
response, content = self._request(path, 'POST',
|
||||
keystone_utils.pattieblack_token,
|
||||
@ -378,8 +377,7 @@ class TestSharedImagesCli(keystone_utils.KeystoneTests):
|
||||
def _push_image(self, name=1):
|
||||
# First, we need to push an image up
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': str(name)}
|
||||
headers = minimal_headers(str(name), public=False)
|
||||
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
response, content = self._request(path, 'POST',
|
||||
keystone_utils.pattieblack_token,
|
||||
|
@ -45,7 +45,7 @@ from glance.common import exception
|
||||
from glance.common import utils
|
||||
from glance.store.location import get_location_from_uri
|
||||
from glance.tests import functional
|
||||
from glance.tests.utils import execute, skip_if_disabled
|
||||
from glance.tests.utils import execute, skip_if_disabled, minimal_headers
|
||||
|
||||
FIVE_KB = 5 * 1024
|
||||
FIVE_GB = 5 * 1024 * 1024 * 1024
|
||||
@ -144,9 +144,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
# 2. POST /images with public image named Image1
|
||||
# attribute and no custom properties. Verify a 200 OK is returned
|
||||
image_data = "*" * FIVE_KB
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers,
|
||||
@ -183,8 +181,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
'x-image-meta-name': 'Image1',
|
||||
'x-image-meta-is_public': 'True',
|
||||
'x-image-meta-status': 'active',
|
||||
'x-image-meta-disk_format': '',
|
||||
'x-image-meta-container_format': '',
|
||||
'x-image-meta-disk_format': 'raw',
|
||||
'x-image-meta-container_format': 'ovf',
|
||||
'x-image-meta-size': str(FIVE_KB)}
|
||||
|
||||
expected_std_headers = {
|
||||
@ -216,8 +214,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
self.assertEqual(response.status, 200)
|
||||
|
||||
expected_result = {"images": [
|
||||
{"container_format": None,
|
||||
"disk_format": None,
|
||||
{"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"name": "Image1",
|
||||
"checksum": "c2e5db72bd7fd153f53ede5da5a06de3",
|
||||
@ -235,8 +233,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
"status": "active",
|
||||
"name": "Image1",
|
||||
"deleted": False,
|
||||
"container_format": None,
|
||||
"disk_format": None,
|
||||
"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"is_public": True,
|
||||
"deleted_at": None,
|
||||
@ -276,8 +274,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
"status": "active",
|
||||
"name": "Image1",
|
||||
"deleted": False,
|
||||
"container_format": None,
|
||||
"disk_format": None,
|
||||
"container_format": "ovf",
|
||||
"disk_format": "raw",
|
||||
"id": image_id,
|
||||
"is_public": True,
|
||||
"deleted_at": None,
|
||||
@ -366,9 +364,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
|
||||
# 1. POST /images with public image named Image1
|
||||
# with no location or image data
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers)
|
||||
@ -376,8 +372,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
data = json.loads(content)
|
||||
self.assertEqual(data['image']['checksum'], None)
|
||||
self.assertEqual(data['image']['size'], 0)
|
||||
self.assertEqual(data['image']['container_format'], None)
|
||||
self.assertEqual(data['image']['disk_format'], None)
|
||||
self.assertEqual(data['image']['container_format'], 'ovf')
|
||||
self.assertEqual(data['image']['disk_format'], 'raw')
|
||||
self.assertEqual(data['image']['name'], "Image1")
|
||||
self.assertEqual(data['image']['is_public'], True)
|
||||
|
||||
@ -393,8 +389,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
self.assertEqual(data['images'][0]['id'], image_id)
|
||||
self.assertEqual(data['images'][0]['checksum'], None)
|
||||
self.assertEqual(data['images'][0]['size'], 0)
|
||||
self.assertEqual(data['images'][0]['container_format'], None)
|
||||
self.assertEqual(data['images'][0]['disk_format'], None)
|
||||
self.assertEqual(data['images'][0]['container_format'], 'ovf')
|
||||
self.assertEqual(data['images'][0]['disk_format'], 'raw')
|
||||
self.assertEqual(data['images'][0]['name'], "Image1")
|
||||
|
||||
# 3. HEAD /images
|
||||
@ -446,8 +442,8 @@ class TestSSL(functional.FunctionalTest):
|
||||
hashlib.md5(image_data).hexdigest())
|
||||
self.assertEqual(data['images'][0]['id'], image_id)
|
||||
self.assertEqual(data['images'][0]['size'], FIVE_KB)
|
||||
self.assertEqual(data['images'][0]['container_format'], None)
|
||||
self.assertEqual(data['images'][0]['disk_format'], None)
|
||||
self.assertEqual(data['images'][0]['container_format'], 'ovf')
|
||||
self.assertEqual(data['images'][0]['disk_format'], 'raw')
|
||||
self.assertEqual(data['images'][0]['name'], "Image1")
|
||||
|
||||
self.stop_servers()
|
||||
@ -633,11 +629,9 @@ class TestSSL(functional.FunctionalTest):
|
||||
# X-Image-Meta-Location attribute to make Glance forego
|
||||
# "adding" the image data.
|
||||
# Verify a 201 OK is returned
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Location': 'https://example.com/fakeimage',
|
||||
'X-Image-Meta-Size': str(FIVE_GB),
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
headers['X-Image-Meta-Location'] = 'https://example.com/fakeimage'
|
||||
headers['X-Image-Meta-Size'] = str(FIVE_GB)
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers)
|
||||
@ -678,7 +672,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
response, content = https.request(path, 'POST',
|
||||
body=test_data_file.name)
|
||||
self.assertEqual(response.status, 400)
|
||||
expected = "Content-Type must be application/octet-stream"
|
||||
expected = "Data supplied was not valid. Details: 400 Bad Request"
|
||||
self.assertTrue(expected in content,
|
||||
"Could not find '%s' in '%s'" % (expected, content))
|
||||
|
||||
@ -956,9 +950,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
self.assertEqual(content, '{"images": []}')
|
||||
|
||||
# 1. POST /images with three public images with various attributes
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image1',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image1')
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers)
|
||||
@ -967,9 +959,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
|
||||
image_ids = [data['image']['id']]
|
||||
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image2',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image2')
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers)
|
||||
@ -978,9 +968,7 @@ class TestSSL(functional.FunctionalTest):
|
||||
|
||||
image_ids.append(data['image']['id'])
|
||||
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': 'Image3',
|
||||
'X-Image-Meta-Is-Public': 'True'}
|
||||
headers = minimal_headers('Image3')
|
||||
path = "https://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
|
||||
https = httplib2.Http(disable_ssl_certificate_validation=True)
|
||||
response, content = https.request(path, 'POST', headers=headers)
|
||||
|
@ -2194,6 +2194,32 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
res = req.get_response(self.api)
|
||||
self.assertEquals(res.status_int, 401)
|
||||
|
||||
def _do_test_add_image_missing_format(self, missing):
|
||||
"""Tests creation of an image with missing format"""
|
||||
fixture_headers = {'x-image-meta-store': 'file',
|
||||
'x-image-meta-disk-format': 'vhd',
|
||||
'x-image-meta-container-format': 'ovf',
|
||||
'x-image-meta-name': 'fake image #3'}
|
||||
|
||||
header = 'x-image-meta-' + missing.replace('_', '-')
|
||||
|
||||
del fixture_headers[header]
|
||||
|
||||
req = webob.Request.blank("/images")
|
||||
req.method = 'POST'
|
||||
for k, v in fixture_headers.iteritems():
|
||||
req.headers[k] = v
|
||||
res = req.get_response(self.api)
|
||||
self.assertEquals(res.status_int, httplib.BAD_REQUEST)
|
||||
|
||||
def test_add_image_missing_disk_format(self):
|
||||
"""Tests creation of an image with missing disk format"""
|
||||
self._do_test_add_image_missing_format('disk_format')
|
||||
|
||||
def test_add_image_missing_container_type(self):
|
||||
"""Tests creation of an image with missing container format"""
|
||||
self._do_test_add_image_missing_format('container_format')
|
||||
|
||||
def test_register_and_upload(self):
|
||||
"""
|
||||
Test that the process of registering an image with
|
||||
@ -2714,6 +2740,8 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
# We will stop the process after the reservation stage, then
|
||||
# try to delete the image.
|
||||
fixture_headers = {'x-image-meta-store': 'file',
|
||||
'x-image-meta-disk-format': 'vhd',
|
||||
'x-image-meta-container-format': 'ovf',
|
||||
'x-image-meta-name': 'fake image #3'}
|
||||
|
||||
req = webob.Request.blank("/images")
|
||||
@ -2735,6 +2763,8 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
||||
def test_delete_protected_image(self):
|
||||
fixture_headers = {'x-image-meta-store': 'file',
|
||||
'x-image-meta-name': 'fake image #3',
|
||||
'x-image-meta-disk-format': 'vhd',
|
||||
'x-image-meta-container-format': 'ovf',
|
||||
'x-image-meta-protected': 'True'}
|
||||
|
||||
req = webob.Request.blank("/images")
|
||||
|
@ -145,3 +145,32 @@ class UtilsTestCase(unittest.TestCase):
|
||||
self.assertTrue(ciphertext != plaintext)
|
||||
text = crypt.urlsafe_decrypt(key, ciphertext)
|
||||
self.assertTrue(plaintext == text)
|
||||
|
||||
def test_empty_metadata_headers(self):
|
||||
"""Ensure unset metadata is not encoded in HTTP headers"""
|
||||
|
||||
metadata = {
|
||||
'foo': 'bar',
|
||||
'snafu': None,
|
||||
'bells': 'whistles',
|
||||
'unset': None,
|
||||
'empty': '',
|
||||
'properties': {
|
||||
'distro': '',
|
||||
'arch': None,
|
||||
'user': 'nobody',
|
||||
},
|
||||
}
|
||||
|
||||
headers = utils.image_meta_to_http_headers(metadata)
|
||||
|
||||
self.assertFalse('x-image-meta-snafu' in headers)
|
||||
self.assertFalse('x-image-meta-uset' in headers)
|
||||
self.assertFalse('x-image-meta-snafu' in headers)
|
||||
self.assertFalse('x-image-meta-property-arch' in headers)
|
||||
|
||||
self.assertEquals(headers.get('x-image-meta-foo'), 'bar')
|
||||
self.assertEquals(headers.get('x-image-meta-bells'), 'whistles')
|
||||
self.assertEquals(headers.get('x-image-meta-empty'), '')
|
||||
self.assertEquals(headers.get('x-image-meta-property-distro'), '')
|
||||
self.assertEquals(headers.get('x-image-meta-property-user'), 'nobody')
|
||||
|
@ -230,7 +230,10 @@ class TestHelpers(unittest.TestCase):
|
||||
response.headers = headers
|
||||
result = utils.get_image_meta_from_headers(response)
|
||||
for k, v in fixture.iteritems():
|
||||
self.assertEqual(v, result[k])
|
||||
if v is not None:
|
||||
self.assertEqual(v, result[k])
|
||||
else:
|
||||
self.assertFalse(k in result)
|
||||
|
||||
def test_boolean_header_values(self):
|
||||
"""
|
||||
|
@ -310,3 +310,21 @@ def xattr_writes_supported(path):
|
||||
os.unlink(fake_filepath)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def minimal_headers(name, public=True):
|
||||
headers = {'Content-Type': 'application/octet-stream',
|
||||
'X-Image-Meta-Name': name,
|
||||
'X-Image-Meta-disk_format': 'raw',
|
||||
'X-Image-Meta-container_format': 'ovf',
|
||||
}
|
||||
if public:
|
||||
headers['X-Image-Meta-Is-Public'] = 'True'
|
||||
return headers
|
||||
|
||||
|
||||
def minimal_add_command(port, name, suffix='', public=True):
|
||||
visibility = 'is_public=True' if public else ''
|
||||
return ("bin/glance --port=%d add %s"
|
||||
" disk_format=raw container_format=ovf"
|
||||
" name=%s %s" % (port, visibility, name, suffix))
|
||||
|
Loading…
Reference in New Issue
Block a user