Ok, long post ahead. So Flavio and I took a look at this issue. It seems like for some reason, glance does not know the size of the image when using v2. Looking at the relevant part of the code (https://github.com/openstack/glance/blob/master/glance/api/v2/image_data.py#L269-L278) it seems like the glanceclient does not set the 'Content-Length' field. Let's fix that! 1) This seems like an easy fix ------------------------------- diff --git a/glanceclient/v2/images.py b/glanceclient/v2/images.py index f69fed5..549d9a1 100644 --- a/glanceclient/v2/images.py +++ b/glanceclient/v2/images.py @@ -212,7 +212,10 @@ class Controller(object): :param image_size: Unused - present for backwards compatibility """ url = '/v2/images/%s/file' % image_id - hdrs = {'Content-Type': 'application/octet-stream'} + hdrs = { + 'Content-Type': 'application/octet-stream', + 'Content-Length': str(image_size) + } body = image_data self.http_client.put(url, headers=hdrs, data=body) diff --git a/glanceclient/v2/shell.py b/glanceclient/v2/shell.py index dfd91fb..b0b31ad 100644 --- a/glanceclient/v2/shell.py +++ b/glanceclient/v2/shell.py @@ -80,9 +80,10 @@ def do_image_create(gc, args): "privileges to it" % file_name) image = gc.images.create(**fields) try: - if utils.get_data_file(args) is not None: + image_data = utils.get_data_file(args) + if image_data is not None: args.id = image['id'] - args.size = None + args.size = utils.get_file_size(image_data) do_image_upload(gc, args) image = gc.images.get(args.id) finally: Let's try to create the image using the same command as OP, and let's take a look at the output: ... REQ: curl -g -i -X PUT http://10.0.2.15:9292/v2/images/7e5f0103-4aff-4aa7-82a1-213193fe6639/file -H "Content-Length: 41126400" -H "User-Agent: python-glanceclient" -H "Content-Type: application/octet-stream" -H "X-Auth-Token: {SHA1}e1dfe1ae3fe336c01b7e50c862689785db13de92" -d '' ... Some very long stacktrace... TypeError: must be string or buffer, not generator must be string or buffer, not generator Indeed, we have a generator object (see the request) because we send our image chunk by chunk. Apparently, you cannot send data "chunk by chunk" when specifying a content-length (because it implies you're giving the whole thing in one go). So, the fix is not as simple as expected, which raises one very important question... 2) How does v1 deal with this? ------------------------------- The glanceclient does not set the Content-Length header when using v1. Instead it sets the x-image-meta-size header, and glance v1 uses that to retrieve the size of the image (https://github.com/openstack/glance/blob/master/glance/api/v1/images.py#L1229-L1236). 3) What should we do about v2? ------------------------------ I believe we should send the total length using a header other than 'Content-Length', like v1 does (possibly using the 'x-image-meta-size' header), and make sure it is read by RequestDeserializer.upload. This would require 1 patch in python-glanceclient, and 1 patch in glance. What do people think?