1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18  import os, sys, re, time 
 19  from twisted.python import usage 
 20   
 22      buildbot_tac = os.path.join(dir, "buildbot.tac") 
 23      if not os.path.isfile(buildbot_tac): 
 24          print "no buildbot.tac" 
 25          return False 
 26   
 27      contents = open(buildbot_tac, "r").read() 
 28      return "Application('buildslave')" in contents 
  29   
 30   
 31   
 32   
 33   
 34   
 35   
 42   
 51   
 53          path = os.path.join(self.basedir, "info") 
 54          if not os.path.exists(path): 
 55              if not self.quiet: 
 56                  print "mkdir", path 
 57              os.mkdir(path) 
 58          created = False 
 59          admin = os.path.join(path, "admin") 
 60          if not os.path.exists(admin): 
 61              if not self.quiet: 
 62                  print "Creating info/admin, you need to edit it appropriately" 
 63              f = open(admin, "wt") 
 64              f.write("Your Name Here <admin@youraddress.invalid>\n") 
 65              f.close() 
 66              created = True 
 67          host = os.path.join(path, "host") 
 68          if not os.path.exists(host): 
 69              if not self.quiet: 
 70                  print "Creating info/host, you need to edit it appropriately" 
 71              f = open(host, "wt") 
 72              f.write("Please put a description of this build host here\n") 
 73              f.close() 
 74              created = True 
 75          access_uri = os.path.join(path, "access_uri") 
 76          if not os.path.exists(access_uri): 
 77              if not self.quiet: 
 78                  print "Not creating info/access_uri - add it if you wish" 
 79          if created and not self.quiet: 
 80              print "Please edit the files in %s appropriately." % path 
  81   
 86   
 87 -    def makeTAC(self, contents, secret=False): 
  88          tacfile = "buildbot.tac" 
 89          if os.path.exists(tacfile): 
 90              oldcontents = open(tacfile, "rt").read() 
 91              if oldcontents == contents: 
 92                  if not self.quiet: 
 93                      print "buildbot.tac already exists and is correct" 
 94                  return 
 95              if not self.quiet: 
 96                  print "not touching existing buildbot.tac" 
 97                  print "creating buildbot.tac.new instead" 
 98              tacfile = "buildbot.tac.new" 
 99          f = open(tacfile, "wt") 
100          f.write(contents) 
101          f.close() 
102          if secret: 
103              os.chmod(tacfile, 0600) 
  104   
105  slaveTACTemplate = [""" 
106  import os 
107   
108  from twisted.application import service 
109  from buildslave.bot import BuildSlave 
110   
111  basedir = r'%(basedir)s' 
112  rotateLength = %(log-size)s 
113  maxRotatedFiles = %(log-count)s 
114   
115  # if this is a relocatable tac file, get the directory containing the TAC 
116  if basedir == '.': 
117      import os.path 
118      basedir = os.path.abspath(os.path.dirname(__file__)) 
119   
120  # note: this line is matched against to check that this is a buildslave 
121  # directory; do not edit it. 
122  application = service.Application('buildslave') 
123  """, 
124  """ 
125  try: 
126    from twisted.python.logfile import LogFile 
127    from twisted.python.log import ILogObserver, FileLogObserver 
128    logfile = LogFile.fromFullPath(os.path.join(basedir, "twistd.log"), rotateLength=rotateLength, 
129                                   maxRotatedFiles=maxRotatedFiles) 
130    application.setComponent(ILogObserver, FileLogObserver(logfile).emit) 
131  except ImportError: 
132    # probably not yet twisted 8.2.0 and beyond, can't set log yet 
133    pass 
134  """, 
135  """ 
136  buildmaster_host = '%(host)s' 
137  port = %(port)d 
138  slavename = '%(name)s' 
139  passwd = '%(passwd)s' 
140  keepalive = %(keepalive)d 
141  usepty = %(usepty)d 
142  umask = %(umask)s 
143  maxdelay = %(maxdelay)d 
144   
145  s = BuildSlave(buildmaster_host, port, slavename, passwd, basedir, 
146                 keepalive, usepty, umask=umask, maxdelay=maxdelay) 
147  s.setServiceParent(application) 
148   
149  """] 
150   
181   
182   
183   
184 -def stop(config, signame="TERM", wait=False, returnFalseOnNotRunning=False): 
 185      import signal 
186      basedir = config['basedir'] 
187      quiet = config['quiet'] 
188   
189      if not isBuildslaveDir(config['basedir']): 
190          print "not a buildslave directory" 
191          sys.exit(1) 
192   
193      os.chdir(basedir) 
194      try: 
195          f = open("twistd.pid", "rt") 
196      except: 
197          if returnFalseOnNotRunning: 
198              return False 
199          if not quiet: print "buildslave not running." 
200          sys.exit(0) 
201      pid = int(f.read().strip()) 
202      signum = getattr(signal, "SIG"+signame) 
203      timer = 0 
204      try: 
205          os.kill(pid, signum) 
206      except OSError, e: 
207          if e.errno != 3: 
208              raise 
209   
210      if not wait: 
211          if not quiet: 
212              print "sent SIG%s to process" % signame 
213          return 
214      time.sleep(0.1) 
215      while timer < 10: 
216           
217          try: 
218              os.kill(pid, 0) 
219          except OSError: 
220              if not quiet: 
221                  print "buildslave process %d is dead" % pid 
222              return 
223          timer += 1 
224          time.sleep(1) 
225      if not quiet: 
226          print "never saw process go away" 
 227   
242   
243   
245      optFlags = [ 
246          ['help', 'h', "Display this message"], 
247          ["quiet", "q", "Do not emit the commands being run"], 
248          ] 
249   
250      longdesc = """ 
251      Operates upon the specified <basedir> (or the current directory, if not 
252      specified). 
253      """ 
254   
255      opt_h = usage.Options.opt_help 
256   
258          if len(args) > 0: 
259              self['basedir'] = args[0] 
260          else: 
261               
262              self['basedir'] = os.getcwd() 
263          if len(args) > 1: 
264              raise usage.UsageError("I wasn't expecting so many arguments") 
 265   
266 -    def postOptions(self): 
 267          self['basedir'] = os.path.abspath(self['basedir']) 
  268   
270      optFlags = [ 
271          ['quiet', 'q', "Don't display startup log messages"], 
272          ] 
274          return "Usage:    buildslave start [<basedir>]" 
  275   
278          return "Usage:    buildslave stop [<basedir>]" 
 281      optFlags = [ 
282          ['quiet', 'q', "Don't display startup log messages"], 
283          ] 
285          return "Usage:    buildslave restart [<basedir>]" 
  286   
288      optFlags = [ 
289          ] 
290      optParameters = [ 
291          ] 
292   
294          return "Usage:    buildslave upgrade-slave [<basedir>]" 
 295   
296      longdesc = """ 
297      This command takes an existing buildslave working directory and 
298      upgrades it to the current version. 
299      """ 
 300   
302      basedir = os.path.expanduser(config['basedir']) 
303      buildbot_tac = open(os.path.join(basedir, "buildbot.tac")).read() 
304      new_buildbot_tac = buildbot_tac.replace( 
305          "from buildbot.slave.bot import BuildSlave", 
306          "from buildslave.bot import BuildSlave") 
307      if new_buildbot_tac != buildbot_tac: 
308          open(os.path.join(basedir, "buildbot.tac"), "w").write(new_buildbot_tac) 
309          print "buildbot.tac updated" 
310      else: 
311          print "No changes made" 
312   
313      return 0 
 314   
315   
317      optFlags = [ 
318          ["force", "f", "Re-use an existing directory"], 
319          ["relocatable", "r", 
320           "Create a relocatable buildbot.tac"], 
321          ["no-logrotate", "n", 
322           "Do not permit buildmaster rotate logs by itself"] 
323          ] 
324      optParameters = [ 
325          ["keepalive", "k", 600, 
326           "Interval at which keepalives should be sent (in seconds)"], 
327          ["usepty", None, 0, 
328           "(1 or 0) child processes should be run in a pty (default 0)"], 
329          ["umask", None, "None", 
330           "controls permissions of generated files. Use --umask=022 to be world-readable"], 
331          ["maxdelay", None, 300, 
332           "Maximum time between connection attempts"], 
333          ["log-size", "s", "10000000", 
334           "size at which to rotate twisted log files"], 
335          ["log-count", "l", "10", 
336           "limit the number of kept old twisted log files (None for unlimited)"], 
337          ] 
338       
339      longdesc = """ 
340      This command creates a buildslave working directory and buildbot.tac 
341      file. The bot will use the <name> and <passwd> arguments to authenticate 
342      itself when connecting to the master. All commands are run in a 
343      build-specific subdirectory of <basedir>. <master> is a string of the 
344      form 'hostname[:port]', and specifies where the buildmaster can be reached. 
345      port defaults to 9989 
346   
347      The appropriate values for <name>, <passwd>, and <master> should be 
348      provided to you by the buildmaster administrator. You must choose <basedir> 
349      yourself. 
350      """ 
351   
353          return "Usage:    buildslave create-slave [options] <basedir> <master> <name> <passwd>" 
 354   
356          if len(args) < 4: 
357              raise usage.UsageError("command needs more arguments") 
358          basedir, master, name, passwd = args 
359          if master[:5] == "http:": 
360              raise usage.UsageError("<master> is not a URL - do not use URL") 
361          self['basedir'] = basedir 
362          self['master'] = master 
363          self['name'] = name 
364          self['passwd'] = passwd 
 365   
366 -    def postOptions(self): 
 367          MakerBase.postOptions(self) 
368          self['usepty'] = int(self['usepty']) 
369          self['keepalive'] = int(self['keepalive']) 
370          self['maxdelay'] = int(self['maxdelay']) 
371          if not re.match('^\d+$', self['log-size']): 
372              raise usage.UsageError("log-size parameter needs to be an int") 
373          if not re.match('^\d+$', self['log-count']) and \ 
374                  self['log-count'] != 'None': 
375              raise usage.UsageError("log-count parameter needs to be an int "+ 
376                                     " or None") 
  377   
379      synopsis = "Usage:    buildslave <command> [command options]" 
380   
381      subCommands = [ 
382           
383          ['create-slave', None, SlaveOptions, 
384           "Create and populate a directory for a new buildslave"], 
385          ['upgrade-slave', None, UpgradeSlaveOptions, 
386           "Upgrade an existing buildslave directory for the current version"], 
387          ['start', None, StartOptions, "Start a buildslave"], 
388          ['stop', None, StopOptions, "Stop a buildslave"], 
389          ['restart', None, RestartOptions, 
390           "Restart a buildslave"], 
391          ] 
392   
397   
399          from twisted.python import log 
400          log.startLogging(sys.stderr) 
 401   
402 -    def postOptions(self): 
 403          if not hasattr(self, 'subOptions'): 
404              raise usage.UsageError("must specify a command") 
  405   
406   
437