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