diff options
author | Angelos Evripiotis <jevripiotis@bloomberg.net> | 2019-10-11 13:25:11 +0100 |
---|---|---|
committer | Angelos Evripiotis <jevripiotis@bloomberg.net> | 2019-10-15 15:37:59 +0100 |
commit | 739753bbb54ac958d1762f95992cbc7b4ec8d3fe (patch) | |
tree | dd7838d66d242cfd123eb2903ab9f3b390567c05 | |
parent | 7d0bff1ff0b9e32bf9555ed8b68f8e1caed677a2 (diff) | |
download | buildstream-aevri/win32_receive_signals.tar.gz |
cas: localhost tcp/ip connection when on win32aevri/win32_receive_signals
To support Windows, add the possibility of connecting to buildbox-casd
via a localhost connection, instead of a UNIX socket.
-rw-r--r-- | src/buildstream/_cas/cascache.py | 11 | ||||
-rw-r--r-- | src/buildstream/_cas/casdprocessmanager.py | 45 |
2 files changed, 52 insertions, 4 deletions
diff --git a/src/buildstream/_cas/cascache.py b/src/buildstream/_cas/cascache.py index 4114d9fff..8638e4d01 100644 --- a/src/buildstream/_cas/cascache.py +++ b/src/buildstream/_cas/cascache.py @@ -26,6 +26,7 @@ import contextlib import ctypes import multiprocessing import signal +import sys import time import grpc @@ -38,7 +39,7 @@ from .. import _signals, utils from ..types import FastEnum from .._exceptions import CASCacheError -from .casdprocessmanager import CASDProcessManager +from .casdprocessmanager import CASDProcessManager, ConnectionType from .casremote import _CASBatchRead, _CASBatchUpdate _BUFFER_SIZE = 65536 @@ -76,8 +77,14 @@ class CASCache(): if casd: log_dir = os.path.join(self.casdir, "logs") + + if sys.platform == 'win32': + connection_type = ConnectionType.LOCALHOST_PORT + else: + connection_type = ConnectionType.UNIX_SOCKET + self._casd_process_manager = CASDProcessManager( - path, log_dir, log_level, cache_quota, protect_session_blobs) + path, log_dir, log_level, cache_quota, protect_session_blobs, connection_type) else: self._casd_process_manager = None diff --git a/src/buildstream/_cas/casdprocessmanager.py b/src/buildstream/_cas/casdprocessmanager.py index fb6caf807..40f945f24 100644 --- a/src/buildstream/_cas/casdprocessmanager.py +++ b/src/buildstream/_cas/casdprocessmanager.py @@ -21,6 +21,7 @@ import contextlib import os import shutil import signal +import socket import subprocess import sys import tempfile @@ -32,9 +33,31 @@ from ..types import FastEnum _CASD_MAX_LOGFILES = 10 +# Note that we want to make sure that BuildStream and buildbox-casd are on the +# same page about what the hostname is, for that reason we may want to avoid +# e.g. empty string as the hostname. We also don't want buildbox-casd to accept +# connections from other machines in this use-case. +# +# Note that buildbox-casd will stop with an error if it fails to listen on all +# addresses, but if it sucessfully listens on any then it will continue. For +# this reason we don't want to choose `localhost` as the hostname, otherwise it +# will also bind to the ipv6 address `::1`. +# +_HOSTNAME = "127.0.0.1" + class ConnectionType(FastEnum): UNIX_SOCKET = 0 + LOCALHOST_PORT = 1 + + +# Note that it's necessary to use the LOCALHOST_PORT option on Windows, because +# grpc doesn't support AF_UNIX on win32 yet. You can verify this in the grpc +# source by searching for 'GRPC_HAVE_UNIX_SOCKET'. +# +# There also isn't support in grpc for receiving a WSADuplicateSocket, so we +# can't pass one over. You can verify this in the grpc source by searching for +# 'WSASocket' and noting that the lpProtocolInfo parameter is always null. # CASDProcessManager @@ -62,8 +85,11 @@ class CASDProcessManager: ): self._log_dir = log_dir - assert connection_type == ConnectionType.UNIX_SOCKET - self._connection = _UnixSocketConnection() + if connection_type == ConnectionType.UNIX_SOCKET: + self._connection = _UnixSocketConnection() + else: + assert connection_type == ConnectionType.LOCALHOST_PORT + self._connection = _LocalhostPortConnection() casd_args = [utils.get_host_tool('buildbox-casd')] casd_args.append('--bind=' + self.connection_string) @@ -242,6 +268,21 @@ class CASDProcessManager: self._failure_callback() +class _LocalhostPortConnection: + def __init__(self): + # Note that there is a race-condition between us finding an available + # port and buildbox-casd taking ownership of it. If another process + # takes the port in the mean time, we will later fail with an error. + with socket.socket() as s: + s.bind((_HOSTNAME, 0)) + hostname, port = s.getsockname() + assert hostname == _HOSTNAME + self.connection_string = "{}:{}".format(hostname, port) + + def release_resouces(self): + pass + + class _UnixSocketConnection: def __init__(self): # Place socket in global/user temporary directory to avoid hitting |