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

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