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