Skip to content

Commit

Permalink
buildbotServiceManager: factorize for buildslave manager
Browse files Browse the repository at this point in the history
This factorize the buildslave manager child management code to be used
by other managers.

Buildslaves are becoming BuildbotServices, with generic constructor, checkConfig(), and reconfigService()

Notable changes:
- slave.slavename -> slave.name
  This makes naming more generic. slave.slavename is kept as an aliased property

- slave.master -> property
  Special property of BuildbotService climb up the parents until master is found

Signed-off-by: Pierre Tardy <pierre.tardy@intel.com>
  • Loading branch information
Pierre Tardy committed Mar 30, 2015
1 parent e8b0624 commit 24c3756
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 173 deletions.
122 changes: 58 additions & 64 deletions master/buildbot/buildslave/base.py
Expand Up @@ -37,8 +37,7 @@
from buildbot.util.eventual import eventually


class AbstractBuildSlave(service.ReconfigurableServiceMixin,
service.AsyncMultiService, object):
class AbstractBuildSlave(service.BuildbotService, object):

"""This is the master-side representative for a remote buildbot slave.
There is exactly one for each slave described in the config file (the
Expand All @@ -55,7 +54,7 @@ class AbstractBuildSlave(service.ReconfigurableServiceMixin,
# reconfig slaves after builders
reconfig_priority = 64

def __init__(self, name, password, max_builds=None,
def checkConfig(self, name, password, max_builds=None,
notify_on_missing=None,
missing_timeout=10 * 60, # Ten minutes
properties=None, locks=None, keepalive_interval=3600):
Expand All @@ -73,13 +72,11 @@ def __init__(self, name, password, max_builds=None,
can be used
@type locks: dictionary
"""
name = ascii2unicode(name)
self.name = name = ascii2unicode(name)

if properties is None:
properties = {}

service.AsyncMultiService.__init__(self)
self.slavename = name
self.password = password

# protocol registration
Expand All @@ -88,7 +85,6 @@ def __init__(self, name, password, max_builds=None,
# these are set when the service is started
self.botmaster = None
self.manager = None
self.master = None
self.buildslaveid = None

self.slave_status = SlaveStatus(name)
Expand Down Expand Up @@ -125,7 +121,12 @@ def __init__(self, name, password, max_builds=None,
self._old_builder_list = None

def __repr__(self):
return "<%s %r>" % (self.__class__.__name__, self.slavename)
return "<%s %r>" % (self.__class__.__name__, self.name)

@property
def slavename(self):
# slavename is now an alias to twisted.Service's name
return self.name

def updateLocks(self):
"""Convert the L{LockAccess} objects in C{self.locks} into real lock
Expand Down Expand Up @@ -182,7 +183,7 @@ def _lockReleased(self):
builds."""
if not self.botmaster:
return # oh well..
self.botmaster.maybeStartBuildsForSlave(self.slavename)
self.botmaster.maybeStartBuildsForSlave(self.name)

def _applySlaveInfo(self, info):
if not info:
Expand All @@ -203,65 +204,65 @@ def setServiceParent(self, parent):
# botmaster needs to set before setServiceParent which calls startService

self.manager = parent
self.master = parent.master
self.botmaster = parent.master.botmaster
return service.AsyncMultiService.setServiceParent(self, parent)

@defer.inlineCallbacks
def startService(self):
self.updateLocks()
self.startMissingTimer()

self.buildslaveid = yield self.master.data.updates.findBuildslaveId(
self.slavename)
self.name)

yield self._getSlaveInfo()
yield service.AsyncMultiService.startService(self)

@defer.inlineCallbacks
def reconfigServiceWithBuildbotConfig(self, new_config):
# Given a new BuildSlave, configure this one identically. Because
# BuildSlave objects are remotely referenced, we can't replace them
def reconfigService(self, name, password, max_builds=None,
notify_on_missing=None, missing_timeout=3600,
properties=None, locks=None, keepalive_interval=3600):
# Given a BuildSlave config arguments, configure this one identically.
# Because BuildSlave objects are remotely referenced, we can't replace them
# without disconnecting the slave, yet there's no reason to do that.
new = self.findNewSlaveInstance(new_config)

assert self.slavename == new.slavename
self.password = new.password

# update our records with the buildslave manager
if not self.registration:
self.registration = yield self.master.buildslaves.register(self)
yield self.registration.update(new, new_config)
assert self.name == name
self.password = password

# adopt new instance's configuration parameters
self.max_builds = new.max_builds
self.access = new.access
self.notify_on_missing = new.notify_on_missing
self.max_builds = max_builds
self.access = []
if locks:
self.access = locks
self.notify_on_missing = notify_on_missing

if self.missing_timeout != new.missing_timeout:
if self.missing_timeout != missing_timeout:
running_missing_timer = self.missing_timer
self.stopMissingTimer()
self.missing_timeout = new.missing_timeout
self.missing_timeout = missing_timeout
if running_missing_timer:
self.startMissingTimer()

properties = Properties()
properties.updateFromProperties(new.properties)
self.properties = properties
if properties is None:
properties = {}
self.properties = Properties()
self.properties.update(properties, "BuildSlave")
self.properties.setProperty("slavename", name, "BuildSlave")

# update our records with the buildslave manager
if not self.registration:
self.registration = yield self.master.buildslaves.register(self)
yield self.registration.update(self, self.master.config)

self.updateLocks()

bids = [b._builderid for b in self.botmaster.getBuildersForSlave(self.slavename)]
bids = [b._builderid for b in self.botmaster.getBuildersForSlave(self.name)]
yield self.master.data.updates.buildslaveConfigured(self.buildslaveid, self.master.masterid, bids)

# update the attached slave's notion of which builders are attached.
# This assumes that the relevant builders have already been configured,
# which is why the reconfig_priority is set low in this class.
yield self.updateSlave()

yield service.ReconfigurableServiceMixin.reconfigServiceWithBuildbotConfig(self,
new_config)

@defer.inlineCallbacks
def stopService(self):
if self.registration:
Expand All @@ -270,13 +271,6 @@ def stopService(self):
self.stopMissingTimer()
yield service.AsyncMultiService.stopService(self)

def findNewSlaveInstance(self, new_config):
# TODO: called multiple times per reconfig; use 1-element cache?
for sl in new_config.slaves:
if sl.slavename == self.slavename:
return sl
assert 0, "no new slave named '%s'" % self.slavename

def startMissingTimer(self):
if self.notify_on_missing and self.missing_timeout and self.parent:
self.stopMissingTimer() # in case it's already running
Expand All @@ -301,7 +295,7 @@ def _missing_timer_fired(self):
status = buildmaster.getStatus()
text = "The Buildbot working for '%s'\n" % status.getTitle()
text += ("has noticed that the buildslave named %s went away\n" %
self.slavename)
self.name)
text += "\n"
text += ("It last disconnected at %s (buildmaster-local time)\n" %
time.ctime(time.time() - self.missing_timeout)) # approx
Expand All @@ -314,7 +308,7 @@ def _missing_timer_fired(self):
text += " %s\n" % status.getTitleURL()
text += "\n"
text += "%s\n" % status.getURLForThing(self.slave_status)
subject = "Buildbot: buildslave %s was lost" % self.slavename
subject = "Buildbot: buildslave %s was lost" % self.name
return self._mail_missing_message(subject, text)

def updateSlave(self):
Expand Down Expand Up @@ -381,9 +375,9 @@ def attached(self, conn):
log.msg("bot attached")
self.messageReceivedFromSlave()
self.stopMissingTimer()
self.master.status.slaveConnected(self.slavename)
self.master.status.slaveConnected(self.name)
yield self.updateSlave()
yield self.botmaster.maybeStartBuildsForSlave(self.slavename)
yield self.botmaster.maybeStartBuildsForSlave(self.name)

def messageReceivedFromSlave(self):
now = time.time()
Expand All @@ -398,8 +392,8 @@ def detached(self):
self.slave_status.removeGracefulWatcher(self._gracefulChanged)
self.slave_status.removePauseWatcher(self._pauseChanged)
self.slave_status.setConnected(False)
log.msg("BuildSlave.detached(%s)" % self.slavename)
self.master.status.slaveDisconnected(self.slavename)
log.msg("BuildSlave.detached(%s)" % self.name)
self.master.status.slaveDisconnected(self.name)
self.releaseLocks()
yield self.master.data.updates.buildslaveDisconnected(
buildslaveid=self.buildslaveid,
Expand All @@ -424,7 +418,7 @@ def disconnect(self):

if self.conn is None:
return defer.succeed(None)
log.msg("disconnecting old slave %s now" % self.slavename)
log.msg("disconnecting old slave %s now" % self.name)
# When this Deferred fires, we'll be ready to accept the new slave
return self._disconnect(self.conn)

Expand All @@ -447,7 +441,7 @@ def _disconnected():
return d

def sendBuilderList(self):
our_builders = self.botmaster.getBuildersForSlave(self.slavename)
our_builders = self.botmaster.getBuildersForSlave(self.name)
blist = [(b.name, b.config.slavebuilddir) for b in our_builders]
if blist == self._old_builder_list:
return defer.succeed(None)
Expand All @@ -461,7 +455,7 @@ def sentBuilderList(ign):
return d

def shutdownRequested(self):
log.msg("slave %s wants to shut down" % self.slavename)
log.msg("slave %s wants to shut down" % self.name)
self.slave_status.setGraceful(True)

def addSlaveBuilder(self, sb):
Expand All @@ -475,7 +469,7 @@ def removeSlaveBuilder(self, sb):

def buildFinished(self, sb):
"""This is called when a build on this slave is finished."""
self.botmaster.maybeStartBuildsForSlave(self.slavename)
self.botmaster.maybeStartBuildsForSlave(self.name)

def canStartBuild(self):
"""
Expand Down Expand Up @@ -561,9 +555,9 @@ def maybeShutdown(self):

def _pauseChanged(self, paused):
if paused is True:
self.botmaster.master.status.slavePaused(self.slavename)
self.botmaster.master.status.slavePaused(self.name)
else:
self.botmaster.master.status.slaveUnpaused(self.slavename)
self.botmaster.master.status.slaveUnpaused(self.name)

def pause(self):
"""Stop running new builds on the slave."""
Expand All @@ -572,7 +566,7 @@ def pause(self):
def unpause(self):
"""Restart running new builds on the slave."""
self.slave_status.setPaused(False)
self.botmaster.maybeStartBuildsForSlave(self.slavename)
self.botmaster.maybeStartBuildsForSlave(self.name)

def isPaused(self):
return self.slave_status.isPaused()
Expand Down Expand Up @@ -691,7 +685,7 @@ def _substantiate(self, build):
def start_instance_result(result):
# If we don't report success, then preparation failed.
if not result:
log.msg("Slave '%s' does not want to substantiate at this time" % (self.slavename,))
log.msg("Slave '%s' does not want to substantiate at this time" % (self.name,))
d = self.substantiation_deferred
self.substantiation_deferred = None
d.callback(False)
Expand All @@ -712,7 +706,7 @@ def clean_up(failure):
def attached(self, bot):
if self.substantiation_deferred is None and self.build_wait_timeout >= 0:
msg = 'Slave %s received connection while not trying to ' \
'substantiate. Disconnecting.' % (self.slavename,)
'substantiate. Disconnecting.' % (self.name,)
log.msg(msg)
self._disconnect(bot)
return defer.fail(RuntimeError(msg))
Expand Down Expand Up @@ -740,7 +734,7 @@ def _substantiation_failed(self, failure):
status = buildmaster.getStatus()
text = "The Buildbot working for '%s'\n" % status.getTitle()
text += ("has noticed that the latent buildslave named %s \n" %
self.slavename)
self.name)
text += "never substantiated after a request\n"
text += "\n"
text += ("The request was made at %s (buildmaster-local time)\n" %
Expand All @@ -749,7 +743,7 @@ def _substantiation_failed(self, failure):
text += "Sincerely,\n"
text += " The Buildbot\n"
text += " %s\n" % status.getTitleURL()
subject = "Buildbot: buildslave %s never substantiated" % self.slavename
subject = "Buildbot: buildslave %s never substantiated" % self.name
return self._mail_missing_message(subject, text)

def canStartBuild(self):
Expand Down Expand Up @@ -798,7 +792,7 @@ def insubstantiate(self, fast=False):
self.building.clear() # just to be sure
yield d
self.insubstantiating = False
self.botmaster.maybeStartBuildsForSlave(self.slavename)
self.botmaster.maybeStartBuildsForSlave(self.name)

@defer.inlineCallbacks
def _soft_disconnect(self, fast=False):
Expand Down Expand Up @@ -861,7 +855,7 @@ def updateSlave(self):
@return: a Deferred that indicates when an attached slave has
accepted the new builders and/or released the old ones."""
for b in self.botmaster.getBuildersForSlave(self.slavename):
for b in self.botmaster.getBuildersForSlave(self.name):
if b.name not in self.slavebuilders:
b.addLatentSlave(self)
return AbstractBuildSlave.updateSlave(self)
Expand Down Expand Up @@ -903,12 +897,12 @@ def _set_failed(why):

@d.addCallback
def _substantiated(res):
log.msg(r"Slave %s substantiated \o/" % self.slavename)
log.msg(r"Slave %s substantiated \o/" % self.name)
self.substantiated = True
if not self.substantiation_deferred:
log.msg("No substantiation deferred for %s" % self.slavename)
log.msg("No substantiation deferred for %s" % self.name)
if self.substantiation_deferred:
log.msg("Firing %s substantiation deferred with success" % self.slavename)
log.msg("Firing %s substantiation deferred with success" % self.name)
d = self.substantiation_deferred
self.substantiation_deferred = None
self.substantiation_build = None
Expand Down

0 comments on commit 24c3756

Please sign in to comment.