Index: scripts/launch_slaves.py |
diff --git a/scripts/launch_slaves.py b/scripts/launch_slaves.py |
index b2810f639579c76a130709d4c73a07aa5245a228..b2c95f78ce9eb7c6b103a635525c133f09e8b9e4 100644 |
--- a/scripts/launch_slaves.py |
+++ b/scripts/launch_slaves.py |
@@ -19,56 +19,28 @@ import time |
buildbot_path = os.path.abspath(os.path.join(os.path.dirname(__file__), |
os.pardir)) |
-sys.path.append(os.path.join(buildbot_path, 'master')) |
sys.path.append(os.path.join(buildbot_path, 'site_config')) |
-sys.path.append(os.path.join(buildbot_path, 'third_party', 'chromium_buildbot', |
- 'scripts')) |
-sys.path.append(os.path.join(buildbot_path, 'third_party', 'chromium_buildbot', |
- 'site_config')) |
-sys.path.append(os.path.join(buildbot_path, 'third_party', 'chromium_buildbot', |
- 'third_party', 'buildbot_8_4p1')) |
-sys.path.append(os.path.join(buildbot_path, 'third_party', 'chromium_buildbot', |
- 'third_party', 'jinja2')) |
-sys.path.append(os.path.join(buildbot_path, 'third_party', 'chromium_buildbot', |
- 'third_party', 'twisted_8_1')) |
- |
- |
-import config |
+ |
import slave_hosts_cfg |
-import slaves_cfg |
CHROME_INTERNAL = 'https://chrome-internal.googlesource.com/' |
CHROME_SLAVE_DEPS_URL = CHROME_INTERNAL + 'chrome/tools/build/slave.DEPS' |
CHROME_SLAVE_INTERNAL_DEPS_URL = ( |
CHROME_INTERNAL + 'chrome/tools/build/internal.DEPS') |
-SKIA_URL = 'https://skia.googlesource.com/buildbot.git' |
GCLIENT = 'gclient.bat' if os.name == 'nt' else 'gclient' |
-GIT = 'git.bat' if os.name == 'nt' else 'git' |
-NEW_MASTER_NAME = { |
- 'Skia': 'Skia', |
- 'AndroidSkia': 'SkiaAndroid', |
- 'CompileSkia': 'SkiaCompile', |
- 'FYISkia': 'SkiaFYI', |
- 'PrivateSkia': 'SkiaInternal', |
-} |
-UPSTREAM_MASTER_PREFIX = 'client.skia' |
- |
# How often we should check each buildslave's keepalive conditions, in seconds. |
-DEFAULT_POLL_INTERVAL = 60 |
-PID_FILE = os.path.join('buildbot', 'third_party', 'chromium_buildbot', 'slave', |
- 'twistd.pid') |
+PID_FILE = os.path.join('build', 'slave', 'twistd.pid') |
+ |
# Maximum time (in seconds) to wait for PID_FILE to be written after the slave |
# is launched. If PID_FILE is not written by then, we assume an error occurred. |
PID_TIMEOUT = 60.0 |
- |
logger = None |
-# TODO(borenet): Share this code with launch_master.py. |
def IsRunning(pid): |
""" Determine whether a process with the given PID is running. |
@@ -88,12 +60,37 @@ def IsRunning(pid): |
return is_running |
+def _IsRunning(): |
+ """Determine if the BuildSlave is running in CWD |
+ |
+ If so, return its PID. Otherwise, return None. |
+ """ |
+ if os.path.isfile(PID_FILE): |
+ with open(PID_FILE) as f: |
+ pid = str(f.read()).rstrip() |
+ if IsRunning(pid): |
+ return pid |
+ return None |
+ |
+ |
+def _KillSlave(): |
+ """Kill the BuildSlave running in CWD.""" |
+ pid = _IsRunning() |
+ if not pid: |
+ print '_KillSlave: Slave not running.' |
+ return |
+ if os.name == 'nt': |
+ cmd = ['taskkill', '/F', '/T', '/PID', str(pid)] |
+ else: |
+ cmd = ['make', 'stop'] |
+ subprocess.check_call(cmd, cwd=os.path.join('buildbot', 'slave')) |
+ |
+ |
class BuildSlaveManager(multiprocessing.Process): |
- """ Manager process for BuildSlaves. Periodically checks that any |
- keepalive_conditions are met and kills or starts the slave accordingly. """ |
+ """Manager process for BuildSlaves.""" |
def __init__(self, slavename, checkout_path, copies, copy_src_dir, |
- master_name, keepalive_conditions, poll_interval): |
+ is_internal): |
""" Construct the BuildSlaveManager. |
slavename: string; the name of the slave to start. |
@@ -101,26 +98,22 @@ class BuildSlaveManager(multiprocessing.Process): |
copies: list of dictionaries; files to copy into the slave's source |
checkout. |
copy_src_dir: string; directory in which the files to copy reside. |
- master_name: string; name of the master to which this build slave connects. |
- This is NOT the hostname of the master, which is obtained from the |
- master class in config_private.py. |
- keepalive_conditions: list; commands which must succeed in order for the |
- slave to stay alive. |
- poll_interval: number; how often to verify the keepalive_conditions, in |
- seconds. |
+ is_internal: bool; whether this buildslave uses internal code. |
""" |
self._slavename = slavename |
self._checkout_path = checkout_path |
self._copies = copies |
self._copy_src_dir = os.path.abspath(copy_src_dir) |
- self._keepalive_conditions = keepalive_conditions |
- self._poll_interval = poll_interval |
- self._master_name = master_name |
+ self._is_internal = is_internal |
multiprocessing.Process.__init__(self) |
def _GClientConfig(self): |
"""Run 'gclient config'.""" |
- subprocess.check_call([GCLIENT, 'config', SKIA_URL]) |
+ config_url = (CHROME_SLAVE_INTERNAL_DEPS_URL if self._is_internal |
+ else CHROME_SLAVE_DEPS_URL) |
+ cmd = [GCLIENT, 'config', config_url, '--deps-file', '.DEPS.git'] |
+ print 'Running command: %s' % ' '.join(cmd) |
+ subprocess.check_call(cmd) |
def _SyncSources(self): |
""" Run 'gclient sync' on the buildbot sources. """ |
@@ -130,7 +123,7 @@ class BuildSlaveManager(multiprocessing.Process): |
if os.name == 'nt': |
os.environ['WIN_TOOLS_FORCE'] = '1' |
- subprocess.check_call([self.local_gclient]) |
+ subprocess.check_call([os.path.join(os.getcwd(), 'depot_tools', GCLIENT)]) |
del os.environ['WIN_TOOLS_FORCE'] |
# Perform Copies |
@@ -141,25 +134,9 @@ class BuildSlaveManager(multiprocessing.Process): |
print 'Copying %s to %s' % (src, dest) |
shutil.copy(src, dest) |
- @property |
- def master_host(self): |
- """Return the hostname of the master for this buildslave.""" |
- return config.Master.set_active_master(self._master_name).master_host |
- |
- @property |
- def slave_dir(self): |
- """Directory in which to launch the slave.""" |
- return os.path.join('buildbot', 'slave') |
- |
- @property |
- def local_gclient(self): |
- """Path to the local version of gclient within this slave's checkout.""" |
- return os.path.join(os.getcwd(), 'buildbot', 'third_party', 'depot_tools', |
- GCLIENT) |
- |
def _LaunchSlave(self): |
""" Launch the BuildSlave. """ |
- self._KillSlave() |
+ _KillSlave() |
self._SyncSources() |
@@ -167,106 +144,32 @@ class BuildSlaveManager(multiprocessing.Process): |
# We run different commands for the Windows shell |
cmd = 'setlocal&&' |
cmd += 'set TESTING_SLAVENAME=%s&&' % self._slavename |
- cmd += 'set TESTING_MASTER=%s&&' % self._master_name |
- if self.master_host: |
- cmd += 'set TESTING_MASTER_HOST=%s&&' % self.master_host |
cmd += 'run_slave.bat' |
cmd += '&& endlocal' |
else: |
cmd = 'TESTING_SLAVENAME=%s ' % self._slavename |
- cmd += 'TESTING_MASTER=%s ' % self._master_name |
- if self.master_host: |
- cmd += 'TESTING_MASTER_HOST=%s ' % self.master_host |
cmd += 'make start' |
print 'Running cmd: %s' % cmd |
- subprocess.check_call(cmd, shell=True, cwd=self.slave_dir) |
+ subprocess.check_call(cmd, shell=True, cwd=os.path.join('build', 'slave')) |
start_time = time.time() |
- while not self._IsRunning(): |
+ while not _IsRunning(): |
if time.time() - start_time > PID_TIMEOUT: |
raise Exception('Failed to launch %s' % self._slavename) |
time.sleep(1) |
- def _IsRunning(self): |
- """ Determine if this BuildSlave is running. If so, return its PID, |
- otherwise, return None. """ |
- if os.path.isfile(PID_FILE): |
- with open(PID_FILE) as f: |
- pid = str(f.read()).rstrip() |
- if IsRunning(pid): |
- return pid |
- return None |
- |
- def _KillSlave(self): |
- """ Kill the BuildSlave. """ |
- pid = self._IsRunning() |
- if not pid: |
- print 'BuildSlaveManager._KillSlave: Slave not running.' |
- return |
- if os.name == 'nt': |
- cmd = ['taskkill', '/F', '/T', '/PID', str(pid)] |
- else: |
- cmd = ['make', 'stop'] |
- subprocess.check_call(cmd, cwd=os.path.join('buildbot', 'slave')) |
- |
def run(self): |
""" Run the BuildSlaveManager. This overrides multiprocessing.Process's |
run() method. """ |
os.chdir(self._checkout_path) |
self._SyncSources() |
self._checkout_path = os.path.abspath(os.curdir) |
- self._KillSlave() |
- while True: |
- print 'Checking keepalive conditions for %s' % self._slavename |
- slave_can_run = True |
- for keepalive_condition in self._keepalive_conditions: |
- print 'Executing keepalive condition: %s' % keepalive_condition |
- proc = subprocess.Popen(keepalive_condition, stdout=subprocess.PIPE, |
- stderr=subprocess.STDOUT) |
- if proc.wait() != 0: |
- print 'Keepalive condition failed for %s: %s' % (self._slavename, |
- keepalive_condition) |
- print proc.communicate()[0] |
- slave_can_run = False |
- break |
- print proc.communicate()[0] |
- if not slave_can_run and self._IsRunning(): |
- self._KillSlave() |
- elif slave_can_run and not self._IsRunning(): |
- self._LaunchSlave() |
- print 'Successfully launched slave %s.' % self._slavename |
- time.sleep(self._poll_interval) |
+ _KillSlave() |
+ self._LaunchSlave() |
+ print 'Successfully launched slave %s.' % self._slavename |
print 'Slave process for %s has finished.' % self._slavename |
-class ChromeBuildSlaveManager(BuildSlaveManager): |
- """BuildSlaveManager for slaves using Chromium build code.""" |
- |
- def _GClientConfig(self): |
- """Run 'gclient config'.""" |
- config_url = ( |
- CHROME_SLAVE_INTERNAL_DEPS_URL if self._master_name == 'SkiaInternal' |
- else CHROME_SLAVE_DEPS_URL) |
- cmd = [GCLIENT, 'config', config_url, '--deps-file', '.DEPS.git'] |
- print 'Running command: %s' % ' '.join(cmd) |
- subprocess.check_call(cmd) |
- |
- @property |
- def master_host(self): |
- """Return the hostname of the master for this buildslave.""" |
- return None # Just use the default. |
- |
- @property |
- def slave_dir(self): |
- """Directory from which to launch the buildslave.""" |
- return os.path.join('build', 'slave') |
- |
- @property |
- def local_gclient(self): |
- """Path to the local version of gclient within this slave's checkout.""" |
- return os.path.join(os.getcwd(), 'depot_tools', GCLIENT) |
- |
- |
def ReadSlavesCfg(slaves_cfg_path): |
"""Read the given slaves.cfg path and return the slaves dict.""" |
cfg = {} |
@@ -274,59 +177,30 @@ def ReadSlavesCfg(slaves_cfg_path): |
return cfg['slaves'] |
-def RunSlave(slavename, slave_num, connects_to_new_master=False): |
+def RunSlave(slavename, slave_num, is_internal): |
""" Launch a single slave, checking out the buildbot tree if necessary. |
slavename: string indicating the hostname of the build slave to launch. |
- copies: dictionary with 'source' and 'destination' keys whose values are the |
- current location and destination location within the buildbot checkout of |
- files to be copied. |
+ slave_num: string; the ID number of this slave on this machine. This ensures |
+ that particular buildslaves always run in the same place on a given |
+ machine. |
+ is_internal: bool; whether this slave uses internal code. |
""" |
- print 'Starting slave: %s%s' % ( |
- slavename, ' (new)' if connects_to_new_master else '') |
+ print 'Starting slave: %s' % slavename |
start_dir = os.path.realpath(os.curdir) |
slave_dir = os.path.join(start_dir, slavename) |
- if connects_to_new_master and os.name == 'nt': |
+ if os.name == 'nt': |
slave_dir = os.path.join('c:\\', slave_num) |
- copies = (slave_hosts_cfg.CHROMEBUILD_COPIES if connects_to_new_master |
- else slave_hosts_cfg.DEFAULT_COPIES) |
+ copies = slave_hosts_cfg.CHROMEBUILD_COPIES |
# Create the slave directory if needed |
if not os.path.isdir(slave_dir): |
print 'Creating directory: %s' % slave_dir |
os.makedirs(slave_dir) |
- # Find the slave config dict and BuildSlaveManager type for this slave. |
- slave_cfg = {} |
- manager = (ChromeBuildSlaveManager if connects_to_new_master |
- else BuildSlaveManager) |
- for cfg in slaves_cfg.SLAVES: |
- if cfg['hostname'] == slavename: |
- slave_cfg = cfg |
- break |
- if not slave_cfg: |
- # Try looking at upstream masters. |
- upstream_masters_dir = os.path.join('third_party', |
- 'chromium_buildbot_tot', |
- 'masters') |
- for master_dir in os.listdir(upstream_masters_dir): |
- if master_dir.startswith('master.%s' % UPSTREAM_MASTER_PREFIX): |
- slaves_cfg_path = os.path.join( |
- upstream_masters_dir, master_dir, 'slaves.cfg') |
- for cfg in ReadSlavesCfg(slaves_cfg_path): |
- if cfg['hostname'] == slavename: |
- slave_cfg = cfg |
- break |
- if not slave_cfg: |
- raise Exception('No buildslave config found for %s!' % slavename) |
- |
# Launch the buildslave. |
- master_name = slave_cfg['master'] |
- if connects_to_new_master: |
- master_name = NEW_MASTER_NAME[master_name] |
- manager(slavename, slave_dir, copies, os.pardir, master_name, |
- slave_cfg.get('keepalive_conditions', []), DEFAULT_POLL_INTERVAL |
- ).start() |
+ BuildSlaveManager(slavename, slave_dir, copies, os.pardir, is_internal |
+ ).start() |
class FileLogger: |
@@ -399,13 +273,12 @@ def main(): |
slave_host = slave_hosts_cfg.get_slave_host_config(socket.gethostname()) |
slaves = slave_host.slaves |
print 'Attempting to launch build slaves:' |
- for slavename, _, connects_to_new_master in slaves: |
- print ' %s%s' % (slavename, |
- (' (new master)' if connects_to_new_master else '')) |
+ for slavename, _, _ in slaves: |
+ print ' %s' % slavename |
# Launch the build slaves |
- for slavename, slave_num, connects_to_new_master in slaves: |
- RunSlave(slavename, slave_num, connects_to_new_master) |
+ for slavename, slave_num, is_internal in slaves: |
+ RunSlave(slavename, slave_num, is_internal) |
if '__main__' == __name__: |