[Buildbot-devel] Hooking a new TCP-listening service into the BuildMaster

Greg Ward gerg.ward+buildbot at gmail.com
Thu Jan 31 20:14:33 UTC 2008


Hi all --

I'm integrating Buildbot with an external build database.  The idea is 
that every build is described in a table 'builds' and queued in a table 
'build_queue'.  Whenever a build finishes, I want to:
   - update 'builds' to record the state of the build (passed/failed),
     the current time (so I can track build times), etc.
   - send email including info from the build database (eg. build time)
   - check 'build_queue' to see if there are any builds waiting to run
     and start the next one

To my amazement, I seem to have got all this working with a custom 
implementation of IStatusReceiver.

The final piece of the puzzle: if Buildbot is idle, I need to kick it 
whenever a build is added to the external build queue.  (If a build is 
queued while Buildbot is busy, we can ignore the event: the queued build 
will start because of the check-queue-on-finish code I've already 
implemented.)

My best idea so far:
   - implement a little class called BuildTrigger, which uses
     reactor.listenTCP() with a tiny little TriggerProtocol
     to await client connections
   - when a connction is received, do the following
     - check that a builder (or buildslave?) is available
     - check if there are any builds in the build queue
     - if both true: start the next queued build
   - in master.cfg, instantiate BuildTrigger and start it listening

But I'm stuck on that "check if a builder is available".  Clearly I need 
to get my hands on the BuildMaster object.  But my BuildTrigger class is 
  outside the charmed inner circle of Buildbot's own code, even though 
it'll be running in the same process.  So how do I find my way to the 
BuildMaster?  I've read enough code that I strongly suspect the answer 
will involve Twisted services... but I don't quite see how to make it 
all work.  Hints?  Tips?  Advice?

Oh yeah, here are my BuildTrigger and TriggerProtocol classes so far:

class BuildTrigger:
     """
     Object that sits around waiting for an incoming TCP connection to
     wake it up, at which point it checks if builders/slaves are idle,
     checks if any builds are waiting in the build queue, and
     (possibly) starts a new build pair.
     """
     def __init__(self, port):
         self.port = port

     def start(self):
         factory = protocol.Factory()
         factory.protocol = lambda: TriggerProtocol(self)
         reactor.listenTCP(self.port, factory)

     # called by TriggerProtocol.connectionMade()
     def triggerBuild(self):
         # 1) dig up the BuildMaster and check if a builder is idle
         # 2) connect to the build database and query the build queue
         # 3) if appropriate, start a build

class TriggerProtocol(protocol.Protocol):
     def __init__(self, trigger):
         assert isinstance(trigger, BuildTrigger)
         self.trigger = trigger

     def connectionMade(self):
         self.trigger.triggerBuild()
         self.transport.loseConnection()

     def connectionLost(self, reason):
         pass

Thanks!

         Greg




More information about the devel mailing list