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 '<generator object _chunk_body at 0x7ffbe72d0c80>'
... 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...
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.
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 ------- ------- ------- --- v2/images. py b/glanceclient/ v2/images. py v2/images. py v2/images. py %s/file' % image_id octet-stream' } octet-stream' ,
self. http_client. put(url, headers=hdrs, data=body)
-------
diff --git a/glanceclient/
index f69fed5..549d9a1 100644
--- a/glanceclient/
+++ b/glanceclient/
@@ -212,7 +212,10 @@ class Controller(object):
:param image_size: Unused - present for backwards compatibility
"""
url = '/v2/images/
- hdrs = {'Content-Type': 'application/
+ hdrs = {
+ 'Content-Type': 'application/
+ 'Content-Length': str(image_size)
+ }
body = image_data
diff --git a/glanceclient/ v2/shell. py b/glanceclient/ v2/shell. py v2/shell. py v2/shell. py
" privileges to it" % file_name) create( **fields) data_file( args) is not None: data_file( args)
args. id = image['id'] file_size( image_data)
do_ image_upload( gc, args) get(args. id)
index dfd91fb..b0b31ad 100644
--- a/glanceclient/
+++ b/glanceclient/
@@ -80,9 +80,10 @@ def do_image_create(gc, args):
image = gc.images.
try:
- if utils.get_
+ image_data = utils.get_
+ if image_data is not None:
- args.size = None
+ args.size = utils.get_
image = gc.images.
finally:
Let's try to create the image using the same command as OP, and let's take a look at the output: 10.0.2. 15:9292/ v2/images/ 7e5f0103- 4aff-4aa7- 82a1-213193fe66 39/file -H "Content-Length: 41126400" -H "User-Agent: python- glanceclient" -H "Content-Type: application/ octet-stream" -H "X-Auth-Token: {SHA1}e1dfe1ae3 fe336c01b7e50c8 62689785db13de9 2" -d '<generator object _chunk_body at 0x7ffbe72d0c80>'
...
REQ: curl -g -i -X PUT http://
... 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? ------- ------- ------- --- /github. com/openstack/ glance/ blob/master/ glance/ api/v1/ images. py#L1229- L1236).
-------
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:/
3) What should we do about v2? ------- ------- ------- -- izer.upload. This would require 1 patch in python- glanceclient, and 1 patch in glance.
-------
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 RequestDeserial
What do people think?