Skip to content

Commit

Permalink
Renames/moves vagrant:X11 to common.x11:X11Handler
Browse files Browse the repository at this point in the history
  • Loading branch information
remram44 committed Jan 23, 2015
1 parent 1b2a590 commit e1bed78
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 208 deletions.
210 changes: 2 additions & 208 deletions reprounzip-vagrant/reprounzip/unpackers/vagrant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@
from __future__ import unicode_literals

import argparse
import contextlib
import logging
import os
import paramiko
import pickle
from rpaths import PosixPath, Path
import scp
import socket
import subprocess
import sys
import tarfile
Expand All @@ -32,7 +30,7 @@
composite_action, target_must_exist, make_unique_name, shell_escape, \
select_installer, busybox_url, join_root, FileUploader, FileDownloader, \
get_runs
from reprounzip.unpackers.common.x11 import Xauth
from reprounzip.unpackers.common.x11 import X11Handler
from reprounzip.unpackers.vagrant.run_command import IgnoreMissingKey, \
run_interactive
from reprounzip.utils import unicode_, iteritems, check_output
Expand Down Expand Up @@ -336,210 +334,6 @@ def vagrant_setup_start(args):
sys.exit(1)


class X11(object):
"""X11 handler.
"""
DISPLAY_NUMBER = 15

SOCK2X = {socket.AF_INET: Xauth.FAMILY_INTERNET,
socket.AF_INET6: Xauth.FAMILY_INTERNET6}
X2SOCK = dict((v, k) for k, v in iteritems(SOCK2X))

def __init__(self, enabled, display=None):
self.enabled = enabled
if not self.enabled:
return

self.xauth = PosixPath('/.reprounzip_xauthority')
self.display = display if display is not None else self.DISPLAY_NUMBER
logging.debug("X11 support enabled; will create Xauthority file %s "
"for experiment. Display number is %d", self.xauth,
self.display)

# List of addresses that match the $DISPLAY variable
possible, tcp_portnum = self._locate_display()

if ('XAUTHORITY' in os.environ and
Path(os.environ['XAUTHORITY']).is_file()):
xauthority = Path(os.environ['XAUTHORITY'])
# Note: I'm assuming here that Xauthority has no XDG support
else:
xauthority = Path('~').expand_user() / '.Xauthority'

# Read Xauthority file
xauth_entries = {}
if xauthority.is_file():
with xauthority.open('rb') as fp:
entry = Xauth.from_file(fp)
if entry.name == 'MIT-MAGIC-COOKIE-1':
if entry.family == Xauth.FAMILY_LOCAL:
xauth_entries[(entry.family, None)] = entry.data
elif (entry.family == Xauth.FAMILY_INTERNET or
entry.family == Xauth.FAMILY_INTERNET6):
xauth_entries[(entry.family,
entry.address)] = entry.data

logging.debug("Possible X endpoints: %s", (possible,))

# Select socket and authentication cookie
self.xauth_record = None
self.connection_info = None
for family, address in possible:
# Checks that we have a cookie
entry = family, (None if family is Xauth.FAMILY_LOCAL else address)
if entry not in xauth_entries:
continue
if family == Xauth.FAMILY_LOCAL and hasattr(socket, 'AF_UNIX'):
# Checks that the socket exists
if not Path(address).exists():
continue
self.connection_info = (socket.AF_UNIX, socket.SOCK_STREAM,
address)
self.xauth_record = xauth_entries[(family, None)]
logging.debug("Will connect to local X display via UNIX "
"socket %s", address)
break
else:
# Checks that we have a cookie
family = self.X2SOCK[family]
self.connection_info = (family, socket.SOCK_STREAM,
(address, tcp_portnum))
self.xauth_record = xauth_entries[(family, address)]
logging.debug("Will connect to X display %s:%d via %s/TCP",
address, tcp_portnum,
"IPv6" if family == socket.AF_INET6 else "IPv4")
break

# Didn't find an Xauthority record -- assume no authentication is
# needed, but still set self.connection_info
if self.connection_info is None:
for family, address in possible:
if family == Xauth.FAMILY_LOCAL:
if not hasattr(socket, 'AF_UNIX'):
continue
self.connection_info = (socket.AF_UNIX, socket.SOCK_STREAM,
address)
logging.debug("Will connect to X display via UNIX socket "
"%s, no authentication", address)
break
else:
family = self.X2SOCK[family]
self.connection_info = (family, socket.SOCK_STREAM,
(address, tcp_portnum))
logging.debug(
"Will connect to X display %s:%d via %s/TCP, "
"no authentication", address, tcp_portnum,
"IPv6" if family == socket.AF_INET6 else "IPv4")
break

if self.connection_info is None:
raise RuntimeError("Couldn't determine how to connect to local X "
"server, DISPLAY is %s" % (
repr(os.environ['DISPLAY'])
if 'DISPLAY' is os.environ
else 'not set'))

@classmethod
def _locate_display(cls):
"""Reads $DISPLAY and figures out possible sockets.
"""
# We default to ":0", Xming for instance doesn't set $DISPLAY
display = os.environ.get('DISPLAY', ':0')

# It might be the full path to a UNIX socket
if display.startswith('/'):
return [(Xauth.FAMILY_LOCAL, display)]

local_addr, local_display = display.rsplit(':', 1)
local_display = int(local_display.split('.', 1)[0])

# Let's order the socket families: IPv4 first, then v6, then others
def sort_families(gai, order={socket.AF_INET: 0, socket.AF_INET6: 1}):
return sorted(gai, key=lambda x: order.get(x[0], 999999))

# Network addresses of the local machine
local_addresses = []
port_num = 6000 + local_display
for family, socktype, proto, canonname, sockaddr in \
sort_families(socket.getaddrinfo(socket.gethostname(), 6000)):
try:
family = cls.SOCK2X[family]
except KeyError:
continue
local_addresses.append((family, sockaddr[0]))

logging.debug("Local addresses: %s", (local_addresses,))

# Determine possible addresses for $DISPLAY
if not local_addr:
possible = [(Xauth.FAMILY_LOCAL,
'/tmp/.X11-unix/X%d' % local_display)]
possible += local_addresses
else:
local_possible = False
possible = []
for family, socktype, proto, canonname, sockaddr in \
sort_families(socket.getaddrinfo(local_addr, 6000)):
try:
family = cls.SOCK2X[family]
except KeyError:
continue
if (family, sockaddr[0]) in local_addresses:
local_possible = True
possible.append(family, sockaddr[0])
if local_possible:
possible = [(Xauth.FAMILY_LOCAL,
'/tmp/.X11-unix/X%d' % local_display)] + possible

return possible, port_num

@property
def port_forward(self):
"""Builds the port forwarding info, for `run_interactive()`.
Just requests port 6000 on the remote host to be forwarded to the X
socket identified by `self.connection_info`.
"""
@contextlib.contextmanager
def connect(src_addr):
logging.info("Got remote X connection from %s", (src_addr,))
logging.debug("Connecting to X server: %s",
(self.connection_info,))
sock = socket.socket(*self.connection_info[:2])
sock.connect(self.connection_info[2])
yield sock
sock.close()
logging.info("X connection from %s closed", (src_addr,))

return [(6000 + self.display, connect)]

def fix_env(self, env):
"""Sets ``$XAUTHORITY`` and ``$DISPLAY`` in the environment.
"""
if not self.enabled:
return env
new_env = dict(env)
new_env['XAUTHORITY'] = str(self.xauth)
new_env['DISPLAY'] = '127.0.0.1:%d' % self.display
return new_env

@property
def init_cmds(self):
"""Gets the commands to setup X on the server before the experiment.
"""
if not self.enabled or self.xauth_record is None:
return []

xauth_record = Xauth(Xauth.FAMILY_INTERNET,
'127.0.0.1',
self.display,
self.xauth_record.name,
self.xauth_record.data)
buf = xauth_record.as_bytes()
xauth = ''.join(('\\x%02x' % buf[i:i + 1]) for i in xrange(len(buf)))
return ['echo -ne "%s" > %s' % (xauth, self.xauth)]


@target_must_exist
def vagrant_run(args):
"""Runs the experiment in the virtual machine.
Expand All @@ -554,7 +348,7 @@ def vagrant_run(args):
selected_runs = get_runs(runs, args.run, cmdline)

# X11 handler
x11 = X11(args.x11, args.x11_display)
x11 = X11Handler(args.x11, args.x11_display)

cmds = []
for run_number in selected_runs:
Expand Down
Loading

0 comments on commit e1bed78

Please sign in to comment.