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

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