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