Blame SOURCES/0063-v2v-o-rhv-upload-Use-Unix-domain-socket-to-access-im.patch

97ae69
From c9f230d57b10e776c490b2cc92212c2a3304bd4e Mon Sep 17 00:00:00 2001
97ae69
From: "Richard W.M. Jones" <rjones@redhat.com>
97ae69
Date: Mon, 18 Jun 2018 15:34:37 +0100
97ae69
Subject: [PATCH] v2v: -o rhv-upload: Use Unix domain socket to access imageio
97ae69
 (RHBZ#1588088).
97ae69
97ae69
In the case where virt-v2v runs on the same server as the imageio
97ae69
daemon that we are talking to, it may be possible to optimize access
97ae69
using a Unix domain socket.
97ae69
97ae69
This is only an optimization.  If it fails or if we're not running on
97ae69
the same server it will fall back to the usual HTTPS over TCP
97ae69
connection.
97ae69
97ae69
Thanks: Nir Soffer, Daniel Erez.
97ae69
(cherry picked from commit b7a2e6270d53200d2df471c36a1fb2b46db8bbac)
97ae69
---
97ae69
 v2v/rhv-upload-plugin.py | 61 ++++++++++++++++++++++++++++++++++++++--
97ae69
 1 file changed, 58 insertions(+), 3 deletions(-)
97ae69
97ae69
diff --git a/v2v/rhv-upload-plugin.py b/v2v/rhv-upload-plugin.py
97ae69
index f215eaecf..8805e3552 100644
97ae69
--- a/v2v/rhv-upload-plugin.py
97ae69
+++ b/v2v/rhv-upload-plugin.py
97ae69
@@ -19,11 +19,12 @@
97ae69
 import builtins
97ae69
 import json
97ae69
 import logging
97ae69
+import socket
97ae69
 import ssl
97ae69
 import sys
97ae69
 import time
97ae69
 
97ae69
-from http.client import HTTPSConnection
97ae69
+from http.client import HTTPSConnection, HTTPConnection
97ae69
 from urllib.parse import urlparse
97ae69
 
97ae69
 import ovirtsdk4 as sdk
97ae69
@@ -56,6 +57,28 @@ def debug(s):
97ae69
         print(s, file=sys.stderr)
97ae69
         sys.stderr.flush()
97ae69
 
97ae69
+def find_host(connection):
97ae69
+    """Return the current host object or None."""
97ae69
+    try:
97ae69
+        with builtins.open("/etc/vdsm/vdsm.id") as f:
97ae69
+            vdsm_id = f.readline().strip()
97ae69
+    except Exception as e:
97ae69
+        return None
97ae69
+    debug("hw_id = %r" % vdsm_id)
97ae69
+
97ae69
+    hosts_service = connection.system_service().hosts_service()
97ae69
+    hosts = hosts_service.list(
97ae69
+        search="hw_id=%s" % vdsm_id,
97ae69
+        case_sensitive=False,
97ae69
+    )
97ae69
+    if len(hosts) == 0:
97ae69
+        return None
97ae69
+
97ae69
+    host = hosts[0]
97ae69
+    debug("host.id = %r" % host.id)
97ae69
+
97ae69
+    return types.Host(id = host.id)
97ae69
+
97ae69
 def open(readonly):
97ae69
     # Parse out the username from the output_conn URL.
97ae69
     parsed = urlparse(params['output_conn'])
97ae69
@@ -121,9 +144,11 @@ def open(readonly):
97ae69
     transfers_service = system_service.image_transfers_service()
97ae69
 
97ae69
     # Create a new image transfer.
97ae69
+    host = find_host(connection)
97ae69
     transfer = transfers_service.add(
97ae69
         types.ImageTransfer(
97ae69
             disk = types.Disk(id = disk.id),
97ae69
+            host = host,
97ae69
             inactivity_timeout = 3600,
97ae69
         )
97ae69
     )
97ae69
@@ -170,6 +195,7 @@ def open(readonly):
97ae69
     can_flush = False
97ae69
     can_trim = False
97ae69
     can_zero = False
97ae69
+    unix_socket = None
97ae69
 
97ae69
     http.putrequest("OPTIONS", destination_url.path)
97ae69
     http.putheader("Authorization", transfer.signed_ticket)
97ae69
@@ -186,6 +212,7 @@ def open(readonly):
97ae69
         can_flush = "flush" in j['features']
97ae69
         can_trim = "trim" in j['features']
97ae69
         can_zero = "zero" in j['features']
97ae69
+        unix_socket = j.get('unix_socket')
97ae69
 
97ae69
     # Old imageio servers returned either 405 Method Not Allowed or
97ae69
     # 204 No Content (with an empty body).  If we see that we leave
97ae69
@@ -197,8 +224,17 @@ def open(readonly):
97ae69
         raise RuntimeError("could not use OPTIONS request: %d: %s" %
97ae69
                            (r.status, r.reason))
97ae69
 
97ae69
-    debug("imageio features: flush=%r trim=%r zero=%r" %
97ae69
-          (can_flush, can_trim, can_zero))
97ae69
+    debug("imageio features: flush=%r trim=%r zero=%r unix_socket=%r" %
97ae69
+          (can_flush, can_trim, can_zero, unix_socket))
97ae69
+
97ae69
+    # If we are connected to imageio on the local host and the
97ae69
+    # transfer features a unix_socket then we can reconnect to that.
97ae69
+    if host is not None and unix_socket is not None:
97ae69
+        try:
97ae69
+            http = UnixHTTPConnection(unix_socket)
97ae69
+            debug("optimizing connection using unix socket %r" % unix_socket)
97ae69
+        except:
97ae69
+            pass
97ae69
 
97ae69
     # Save everything we need to make requests in the handle.
97ae69
     return {
97ae69
@@ -463,3 +499,22 @@ def close(h):
97ae69
         raise
97ae69
 
97ae69
     connection.close()
97ae69
+
97ae69
+# Modify http.client.HTTPConnection to work over a Unix domain socket.
97ae69
+# Derived from uhttplib written by Erik van Zijst under an MIT license.
97ae69
+# (https://pypi.org/project/uhttplib/)
97ae69
+# Ported to Python 3 by Irit Goihman.
97ae69
+
97ae69
+class UnsupportedError(Exception):
97ae69
+    pass
97ae69
+
97ae69
+class UnixHTTPConnection(HTTPConnection):
97ae69
+    def __init__(self, path, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
97ae69
+        self.path = path
97ae69
+        HTTPConnection.__init__(self, "localhost", timeout=timeout)
97ae69
+
97ae69
+    def connect(self):
97ae69
+        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
97ae69
+        if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
97ae69
+            self.sock.settimeout(timeout)
97ae69
+        self.sock.connect(self.path)
97ae69
-- 
fd1da6
2.17.2
97ae69