Blob Blame History Raw
From 320ba554d11f75c4c2753968505a1d3308b64dda Mon Sep 17 00:00:00 2001
From: Nir Soffer <nirsof@gmail.com>
Date: Mon, 25 Jun 2018 19:22:13 +0300
Subject: [PATCH] v2v: rvh-upload-plugin: Always read the response

Python manual warns[1]:

    Note that you must have read the whole response before you can send
    a new request to the server.

The reason for this warning is exposed only when the server is using
keep alive connections. When the response is not read, sending a new
request will fail with:

    httplib.ResponseNotReady

Even if Content-Length was 0 or the request has no content. The failure
looks like this when using --verbose:

nbdkit: python[1]: debug: zero count=33554432 offset=0 may_trim=1 fua=0
nbdkit: python[1]: debug: zero count=33554432 offset=33554432 may_trim=1 fua=0
nbdkit: python[1]: error: /home/nsoffer/src/libguestfs/tmp/rhvupload.Au2B5I/rhv-upload-plugin.py: zero: error: Request-sent
nbdkit: python[1]: debug: sending error reply: Input/output error
qemu-img: error writing zeroes at offset 0: Input/output error

Change all requests to read the whole response.

Tested with imageio patch supporting keep alive connections:
https://gerrit.ovirt.org/#/c/92296/

[1] https://docs.python.org/3.8/library/http.client.html#http.client.HTTPConnection.getresponse

(cherry picked from commit f4e0a8342dbeb2c779c76e1807a37b24a0c96feb)
---
 v2v/rhv-upload-plugin.py | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
index 7c5084efd..2eec375f7 100644
--- a/v2v/rhv-upload-plugin.py
+++ b/v2v/rhv-upload-plugin.py
@@ -197,11 +197,13 @@ def get_options(h):
     http.endheaders()
 
     r = http.getresponse()
+    data = r.read()
+
     if r.status == 200:
         # New imageio never needs authentication.
         h['needs_auth'] = False
 
-        j = json.loads(r.read())
+        j = json.loads(data)
         h['can_zero'] = "zero" in j['features']
         h['can_trim'] = "trim" in j['features']
         h['can_flush'] = "flush" in j['features']
@@ -276,6 +278,7 @@ def pread(h, count, offset):
         request_failed(h, r,
                        "could not read sector offset %d size %d" %
                        (offset, count))
+
     return r.read()
 
 def pwrite(h, buf, offset):
@@ -302,6 +305,8 @@ def pwrite(h, buf, offset):
                        "could not write sector offset %d size %d" %
                        (offset, count))
 
+    r.read()
+
 def zero(h, count, offset, may_trim):
     http = h['http']
     transfer = h['transfer']
@@ -330,6 +335,8 @@ def zero(h, count, offset, may_trim):
                        "could not zero sector offset %d size %d" %
                        (offset, count))
 
+    r.read()
+
 def emulate_zero(h, count, offset):
     # qemu-img convert starts by trying to zero/trim the whole device.
     # Since we've just created a new disk it's safe to ignore these
@@ -357,6 +364,8 @@ def emulate_zero(h, count, offset):
                            "could not write zeroes offset %d size %d" %
                            (offset, count))
 
+        r.read()
+
 def trim(h, count, offset):
     http = h['http']
     transfer = h['transfer']
@@ -378,6 +387,8 @@ def trim(h, count, offset):
                        "could not trim sector offset %d size %d" %
                        (offset, count))
 
+    r.read()
+
 def flush(h):
     http = h['http']
     transfer = h['transfer']
@@ -394,6 +405,8 @@ def flush(h):
     if r.status != 200:
         request_failed(h, r, "could not flush")
 
+    r.read()
+
 def delete_disk_on_failure(h):
     disk_service = h['disk_service']
     disk_service.remove()
-- 
2.17.1