2007-01-24 22:24:01 +08:00
|
|
|
import sys, os
|
|
|
|
import py
|
|
|
|
import time
|
|
|
|
import thread, threading
|
2007-02-04 22:05:01 +08:00
|
|
|
from py.__.test.rsession.master import MasterNode
|
|
|
|
from py.__.test.rsession.slave import setup_slave
|
|
|
|
|
2007-02-05 23:11:05 +08:00
|
|
|
from py.__.test.rsession import repevent
|
|
|
|
from py.__.execnet.register import PopenCmdGateway
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
class HostInfo(object):
|
|
|
|
""" Class trying to store all necessary attributes
|
|
|
|
for host
|
|
|
|
"""
|
2007-02-04 22:05:01 +08:00
|
|
|
_hostname2list = {}
|
|
|
|
localdest = None
|
2007-01-24 22:24:01 +08:00
|
|
|
|
2007-02-04 22:05:01 +08:00
|
|
|
def __init__(self, spec):
|
|
|
|
parts = spec.split(':', 1)
|
|
|
|
self.hostname = parts.pop(0)
|
|
|
|
if parts:
|
|
|
|
self.relpath = parts[0]
|
|
|
|
else:
|
|
|
|
self.relpath = "pytestcache-" + self.hostname
|
|
|
|
self.hostid = self._getuniqueid(self.hostname)
|
|
|
|
|
|
|
|
def _getuniqueid(self, hostname):
|
|
|
|
l = self._hostname2list.setdefault(hostname, [])
|
|
|
|
hostid = hostname + "_" * len(l)
|
|
|
|
l.append(hostid)
|
|
|
|
return hostid
|
|
|
|
|
|
|
|
def initgateway(self, python="python"):
|
|
|
|
assert not hasattr(self, 'gw')
|
2007-02-05 23:11:05 +08:00
|
|
|
if self.hostname == "localhost":
|
|
|
|
cmd = 'cd ~; %s -u -c "exec input()"' % python
|
|
|
|
gw = PopenCmdGateway(cmd)
|
2007-02-04 22:05:01 +08:00
|
|
|
else:
|
|
|
|
gw = py.execnet.SshGateway(self.hostname,
|
|
|
|
remotepython=python)
|
|
|
|
self.gw = gw
|
|
|
|
channel = gw.remote_exec("""
|
|
|
|
import os
|
|
|
|
targetdir = %r
|
|
|
|
if not os.path.isabs(targetdir):
|
2007-02-05 08:36:00 +08:00
|
|
|
homedir = os.environ.get('HOME', '')
|
|
|
|
if not homedir:
|
|
|
|
homedir = os.environ.get('HOMEPATH', '.')
|
2007-02-04 22:05:01 +08:00
|
|
|
targetdir = os.path.join(homedir, targetdir)
|
|
|
|
if not os.path.exists(targetdir):
|
|
|
|
os.makedirs(targetdir)
|
|
|
|
channel.send(os.path.abspath(targetdir))
|
|
|
|
""" % self.relpath)
|
|
|
|
self.gw_remotepath = channel.receive()
|
|
|
|
#print "initialized", gw, "with remotepath", self.gw_remotepath
|
|
|
|
if self.hostname == "localhost":
|
|
|
|
self.localdest = py.path.local(self.gw_remotepath)
|
|
|
|
assert self.localdest.check(dir=1)
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
def __str__(self):
|
2007-02-04 22:05:01 +08:00
|
|
|
return "<HostInfo %s:%s>" % (self.hostname, self.relpath)
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.hostid)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return self.hostid == other.hostid
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self == other
|
|
|
|
|
2007-01-25 00:46:46 +08:00
|
|
|
class HostRSync(py.execnet.RSync):
|
2007-02-04 22:05:01 +08:00
|
|
|
""" RSyncer that filters out common files
|
2007-01-24 22:24:01 +08:00
|
|
|
"""
|
2007-02-04 22:05:01 +08:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
self._synced = {}
|
2007-02-05 09:14:17 +08:00
|
|
|
ignores= None
|
|
|
|
if 'ignores' in kwargs:
|
|
|
|
ignores = kwargs.pop('ignores')
|
|
|
|
self._ignores = ignores or []
|
2007-02-05 23:11:05 +08:00
|
|
|
kwargs['delete'] = True
|
2007-02-04 22:05:01 +08:00
|
|
|
super(HostRSync, self).__init__(*args, **kwargs)
|
2007-01-24 22:24:01 +08:00
|
|
|
|
|
|
|
def filter(self, path):
|
2007-02-04 22:05:01 +08:00
|
|
|
path = py.path.local(path)
|
|
|
|
if not path.ext in ('.pyc', '.pyo'):
|
|
|
|
if not path.basename.endswith('~'):
|
|
|
|
if path.check(dotfile=0):
|
2007-02-05 09:14:17 +08:00
|
|
|
for x in self._ignores:
|
|
|
|
if path == x:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
return True
|
2007-02-04 22:05:01 +08:00
|
|
|
|
|
|
|
def add_target_host(self, host, destrelpath=None, finishedcallback=None):
|
|
|
|
key = host.hostname, host.relpath
|
|
|
|
if key in self._synced:
|
|
|
|
if finishedcallback:
|
|
|
|
finishedcallback()
|
|
|
|
return False
|
|
|
|
self._synced[key] = True
|
|
|
|
# the follow attributes are set from host.initgateway()
|
|
|
|
gw = host.gw
|
|
|
|
remotepath = host.gw_remotepath
|
|
|
|
if destrelpath is not None:
|
|
|
|
remotepath = os.path.join(remotepath, destrelpath)
|
|
|
|
super(HostRSync, self).add_target(gw,
|
|
|
|
remotepath,
|
|
|
|
finishedcallback)
|
|
|
|
return True # added the target
|
2007-01-25 00:46:46 +08:00
|
|
|
|
|
|
|
class HostManager(object):
|
2007-02-05 08:14:11 +08:00
|
|
|
def __init__(self, config, hosts=None):
|
2007-01-25 00:46:46 +08:00
|
|
|
self.config = config
|
2007-02-05 08:14:11 +08:00
|
|
|
if hosts is None:
|
|
|
|
hosts = self.config.getvalue("dist_hosts")
|
|
|
|
hosts = [HostInfo(x) for x in hosts]
|
|
|
|
self.hosts = hosts
|
2007-01-25 00:46:46 +08:00
|
|
|
|
|
|
|
def prepare_gateways(self):
|
2007-02-04 22:05:01 +08:00
|
|
|
dist_remotepython = self.config.getvalue("dist_remotepython")
|
2007-02-05 08:14:11 +08:00
|
|
|
for host in self.hosts:
|
2007-02-04 22:05:01 +08:00
|
|
|
host.initgateway(python=dist_remotepython)
|
2007-02-05 07:21:35 +08:00
|
|
|
host.gw.host = host
|
2007-02-04 22:05:01 +08:00
|
|
|
|
|
|
|
def init_rsync(self, reporter):
|
2007-02-05 07:21:35 +08:00
|
|
|
# send each rsync root
|
2007-02-04 22:05:01 +08:00
|
|
|
roots = self.config.getvalue_pathlist("dist_rsync_roots")
|
2007-02-05 09:14:17 +08:00
|
|
|
ignores = self.config.getvalue_pathlist("dist_rsync_ignore")
|
2007-02-04 22:05:01 +08:00
|
|
|
if roots is None:
|
|
|
|
roots = [self.config.topdir]
|
|
|
|
self.prepare_gateways()
|
2007-02-05 09:14:17 +08:00
|
|
|
rsync = HostRSync(ignores=ignores)
|
2007-02-04 22:05:01 +08:00
|
|
|
for root in roots:
|
|
|
|
destrelpath = root.relto(self.config.topdir)
|
2007-02-05 08:14:11 +08:00
|
|
|
for host in self.hosts:
|
2007-02-05 07:34:23 +08:00
|
|
|
reporter(repevent.HostRSyncing(host))
|
2007-02-04 22:05:01 +08:00
|
|
|
def donecallback():
|
2007-02-05 07:34:23 +08:00
|
|
|
reporter(repevent.HostReady(host))
|
2007-02-04 22:05:01 +08:00
|
|
|
rsync.add_target_host(host, destrelpath,
|
|
|
|
finishedcallback=donecallback)
|
|
|
|
rsync.send(root)
|
|
|
|
|
2007-02-05 08:23:14 +08:00
|
|
|
def setup_hosts(self, reporter):
|
2007-02-04 22:05:01 +08:00
|
|
|
self.init_rsync(reporter)
|
2007-01-25 00:46:46 +08:00
|
|
|
nodes = []
|
2007-02-05 08:14:11 +08:00
|
|
|
for host in self.hosts:
|
2007-02-04 22:05:01 +08:00
|
|
|
if hasattr(host.gw, 'remote_exec'): # otherwise dummy for tests :/
|
|
|
|
ch = setup_slave(host, self.config)
|
2007-02-05 07:12:12 +08:00
|
|
|
nodes.append(MasterNode(ch, reporter))
|
2007-01-25 00:46:46 +08:00
|
|
|
return nodes
|
2007-01-24 22:24:01 +08:00
|
|
|
|
2007-01-25 00:46:46 +08:00
|
|
|
def teardown_hosts(self, reporter, channels, nodes,
|
|
|
|
waiter=lambda : time.sleep(.1), exitfirst=False):
|
|
|
|
for channel in channels:
|
|
|
|
channel.send(None)
|
|
|
|
|
|
|
|
clean = exitfirst
|
|
|
|
while not clean:
|
|
|
|
clean = True
|
|
|
|
for node in nodes:
|
|
|
|
if node.pending:
|
|
|
|
clean = False
|
|
|
|
waiter()
|
|
|
|
self.teardown_gateways(reporter, channels)
|
|
|
|
|
|
|
|
def kill_channels(self, channels):
|
|
|
|
for channel in channels:
|
|
|
|
channel.send(42)
|
|
|
|
|
|
|
|
def teardown_gateways(self, reporter, channels):
|
|
|
|
for channel in channels:
|
|
|
|
try:
|
2007-02-05 07:34:23 +08:00
|
|
|
repevent.wrapcall(reporter, channel.waitclose)
|
2007-01-25 00:46:46 +08:00
|
|
|
except KeyboardInterrupt, SystemExit:
|
|
|
|
raise
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
channel.gateway.exit()
|