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

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