Package buildbot :: Package status :: Package web :: Module builder
[frames] | no frames]

Source Code for Module buildbot.status.web.builder

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16   
 17  from twisted.web import html 
 18  import urllib, time 
 19  from twisted.python import log 
 20  from twisted.internet import defer 
 21  from buildbot import interfaces 
 22  from buildbot.status.web.base import HtmlResource, BuildLineMixin, \ 
 23      path_to_build, path_to_slave, path_to_builder, path_to_change, \ 
 24      path_to_root, ICurrentBox, build_get_class, \ 
 25      map_branches, path_to_authzfail, ActionResource 
 26  from buildbot.schedulers.forcesched import ForceScheduler, InheritBuildParameter 
 27  from buildbot.status.web.build import BuildsResource, StatusResourceBuild 
 28  from buildbot import util 
29 30 -class ForceAllBuildsActionResource(ActionResource):
31
32 - def __init__(self, status, selectedOrAll):
33 self.status = status 34 self.selectedOrAll = selectedOrAll 35 self.action = "forceAllBuilds"
36 37 @defer.deferredGenerator
38 - def performAction(self, req):
39 authz = self.getAuthz(req) 40 d = authz.actionAllowed('forceAllBuilds', req) 41 wfd = defer.waitForDeferred(d) 42 yield wfd 43 res = wfd.getResult() 44 45 if not res: 46 yield path_to_authzfail(req) 47 return 48 49 builders = None 50 if self.selectedOrAll == 'all': 51 builders = self.status.getBuilderNames() 52 elif self.selectedOrAll == 'selected': 53 builders = [b for b in req.args.get("selected", []) if b] 54 55 for bname in builders: 56 builder_status = self.status.getBuilder(bname) 57 ar = ForceBuildActionResource(builder_status) 58 d = ar.performAction(req) 59 d.addErrback(log.err, "(ignored) while trying to force build") 60 # back to the welcome page 61 yield path_to_root(req)
62
63 -class StopAllBuildsActionResource(ActionResource):
64
65 - def __init__(self, status, selectedOrAll):
66 self.status = status 67 self.selectedOrAll = selectedOrAll 68 self.action = "stopAllBuilds"
69 70 @defer.deferredGenerator
71 - def performAction(self, req):
72 authz = self.getAuthz(req) 73 d = authz.actionAllowed('stopAllBuilds', req) 74 wfd = defer.waitForDeferred(d) 75 yield wfd 76 res = wfd.getResult() 77 if not res: 78 yield path_to_authzfail(req) 79 return 80 81 builders = None 82 if self.selectedOrAll == 'all': 83 builders = self.status.getBuilderNames() 84 elif self.selectedOrAll == 'selected': 85 builders = [b for b in req.args.get("selected", []) if b] 86 87 for bname in builders: 88 builder_status = self.status.getBuilder(bname) 89 (state, current_builds) = builder_status.getState() 90 if state != "building": 91 continue 92 for b in current_builds: 93 build_status = builder_status.getBuild(b.number) 94 if not build_status: 95 continue 96 build = StatusResourceBuild(build_status) 97 build.stop(req, auth_ok=True) 98 # go back to the welcome page 99 yield path_to_root(req)
100
101 -class PingBuilderActionResource(ActionResource):
102
103 - def __init__(self, builder_status):
104 self.builder_status = builder_status 105 self.action = "pingBuilder"
106 107 @defer.deferredGenerator
108 - def performAction(self, req):
109 log.msg("web ping of builder '%s'" % self.builder_status.getName()) 110 d = self.getAuthz(req).actionAllowed('pingBuilder', req, self.builder_status) 111 wfd = defer.waitForDeferred(d) 112 yield wfd 113 res = wfd.getResult() 114 if not res: 115 log.msg("..but not authorized") 116 yield path_to_authzfail(req) 117 return 118 119 c = interfaces.IControl(self.getBuildmaster(req)) 120 bc = c.getBuilder(self.builder_status.getName()) 121 bc.ping() 122 # send the user back to the builder page 123 yield path_to_builder(req, self.builder_status)
124
125 -class ForceBuildActionResource(ActionResource):
126
127 - def __init__(self, builder_status):
128 self.builder_status = builder_status 129 self.action = "forceBuild"
130 131 @defer.deferredGenerator
132 - def performAction(self, req):
133 # check if this is allowed 134 d = self.getAuthz(req).actionAllowed(self.action, req, 135 self.builder_status) 136 wfd = defer.waitForDeferred(d) 137 yield wfd 138 res = wfd.getResult() 139 if not res: 140 log.msg("..but not authorized") 141 yield path_to_authzfail(req) 142 return 143 144 master = self.getBuildmaster(req) 145 owner = self.getAuthz(req).getUsernameFull(req) 146 schedulername = req.args.get("forcescheduler", ["<unknown>"])[0] 147 if schedulername == "<unknown>": 148 yield path_to_builder(req, self.builder_status), "forcescheduler arg not found" 149 return 150 for sch in master.allSchedulers(): 151 if schedulername == sch.name: 152 try: 153 d = sch.forceWithWebRequest(owner,self.builder_status.getName(),req) 154 msg = "" 155 except Exception, e: 156 msg = html.escape(e.message.encode('ascii','ignore')) 157 break 158 wfd = defer.waitForDeferred(d) 159 yield wfd 160 res = wfd.getResult() 161 # send the user back to the builder page 162 yield path_to_builder(req, self.builder_status), msg
163
164 -def buildForceContext(cxt, req, master, buildername=None):
165 force_schedulers = {} 166 default_props = {} 167 for sch in master.allSchedulers(): 168 if isinstance(sch, ForceScheduler) and (buildername is None or(buildername in sch.builderNames)): 169 force_schedulers[sch.name] = sch 170 for p in sch.all_fields: 171 pname = "%s.%s"%(sch.name, p.name) 172 default = p.default 173 if isinstance(p, InheritBuildParameter): 174 # yes, I know, its bad to overwrite the parameter attribute, 175 # but I dont have any other simple way of doing this atm. 176 p.choices = p.compatible_builds(master.status, buildername) 177 if p.choices: 178 default = p.choices[0] 179 default = req.args.get(pname, [default])[0] 180 if p.type=="bool": 181 default_props[pname] = default and "checked" or "" 182 else: 183 # filter out unicode chars, and html stuff 184 if type(default)==unicode: 185 default = html.escape(default.encode('ascii','ignore')) 186 default_props[pname] = default 187 cxt['force_schedulers'] = force_schedulers 188 cxt['default_props'] = default_props
189
190 # /builders/$builder 191 -class StatusResourceBuilder(HtmlResource, BuildLineMixin):
192 addSlash = True 193
194 - def __init__(self, builder_status):
195 HtmlResource.__init__(self) 196 self.builder_status = builder_status
197
198 - def getPageTitle(self, request):
199 return "Buildbot: %s" % self.builder_status.getName()
200
201 - def builder(self, build, req):
202 b = {} 203 204 b['num'] = build.getNumber() 205 b['link'] = path_to_build(req, build) 206 207 when = build.getETA() 208 if when is not None: 209 b['when'] = util.formatInterval(when) 210 b['when_time'] = time.strftime("%H:%M:%S", 211 time.localtime(time.time() + when)) 212 213 step = build.getCurrentStep() 214 # TODO: is this necessarily the case? 215 if not step: 216 b['current_step'] = "[waiting for Lock]" 217 else: 218 if step.isWaitingForLocks(): 219 b['current_step'] = "%s [waiting for Lock]" % step.getName() 220 else: 221 b['current_step'] = step.getName() 222 223 b['stop_url'] = path_to_build(req, build) + '/stop' 224 225 return b
226 227 @defer.deferredGenerator
228 - def content(self, req, cxt):
229 b = self.builder_status 230 231 cxt['name'] = b.getName() 232 req.setHeader('Cache-Control', 'no-cache') 233 slaves = b.getSlaves() 234 connected_slaves = [s for s in slaves if s.isConnected()] 235 236 cxt['current'] = [self.builder(x, req) for x in b.getCurrentBuilds()] 237 238 cxt['pending'] = [] 239 wfd = defer.waitForDeferred( 240 b.getPendingBuildRequestStatuses()) 241 yield wfd 242 statuses = wfd.getResult() 243 for pb in statuses: 244 changes = [] 245 246 wfd = defer.waitForDeferred( 247 pb.getSourceStamp()) 248 yield wfd 249 source = wfd.getResult() 250 251 wfd = defer.waitForDeferred( 252 pb.getSubmitTime()) 253 yield wfd 254 submitTime = wfd.getResult() 255 256 wfd = defer.waitForDeferred( 257 pb.getBsid()) 258 yield wfd 259 bsid = wfd.getResult() 260 261 wfd = defer.waitForDeferred( 262 pb.master.db.buildsets.getBuildsetProperties(bsid)) 263 yield wfd 264 properties = wfd.getResult() 265 266 if source.changes: 267 for c in source.changes: 268 changes.append({ 'url' : path_to_change(req, c), 269 'who' : c.who, 270 'revision' : c.revision, 271 'repo' : c.repository }) 272 273 cxt['pending'].append({ 274 'when': time.strftime("%b %d %H:%M:%S", 275 time.localtime(submitTime)), 276 'delay': util.formatInterval(util.now() - submitTime), 277 'id': pb.brid, 278 'changes' : changes, 279 'num_changes' : len(changes), 280 'properties' : properties, 281 }) 282 283 numbuilds = int(req.args.get('numbuilds', ['5'])[0]) 284 recent = cxt['recent'] = [] 285 for build in b.generateFinishedBuilds(num_builds=int(numbuilds)): 286 recent.append(self.get_line_values(req, build, False)) 287 288 sl = cxt['slaves'] = [] 289 connected_slaves = 0 290 for slave in slaves: 291 s = {} 292 sl.append(s) 293 s['link'] = path_to_slave(req, slave) 294 s['name'] = slave.getName() 295 c = s['connected'] = slave.isConnected() 296 if c: 297 s['admin'] = unicode(slave.getAdmin() or '', 'utf-8') 298 connected_slaves += 1 299 cxt['connected_slaves'] = connected_slaves 300 301 cxt['authz'] = self.getAuthz(req) 302 cxt['builder_url'] = path_to_builder(req, b) 303 buildForceContext(cxt, req, self.getBuildmaster(req), b.getName()) 304 template = req.site.buildbot_service.templates.get_template("builder.html") 305 yield template.render(**cxt)
306
307 - def ping(self, req):
308 return PingBuilderActionResource(self.builder_status)
309
310 - def getChild(self, path, req):
311 if path == "force": 312 return ForceBuildActionResource(self.builder_status) 313 if path == "ping": 314 return self.ping(req) 315 if path == "cancelbuild": 316 return CancelChangeResource(self.builder_status) 317 if path == "stopchange": 318 return StopChangeResource(self.builder_status) 319 if path == "builds": 320 return BuildsResource(self.builder_status) 321 322 return HtmlResource.getChild(self, path, req)
323
324 -class CancelChangeResource(ActionResource):
325
326 - def __init__(self, builder_status):
327 ActionResource.__init__(self) 328 self.builder_status = builder_status
329 330 @defer.deferredGenerator
331 - def performAction(self, req):
332 try: 333 request_id = req.args.get("id", [None])[0] 334 if request_id == "all": 335 cancel_all = True 336 else: 337 cancel_all = False 338 request_id = int(request_id) 339 except: 340 request_id = None 341 342 authz = self.getAuthz(req) 343 if request_id: 344 c = interfaces.IControl(self.getBuildmaster(req)) 345 builder_control = c.getBuilder(self.builder_status.getName()) 346 347 wfd = defer.waitForDeferred( 348 builder_control.getPendingBuildRequestControls()) 349 yield wfd 350 brcontrols = wfd.getResult() 351 352 for build_req in brcontrols: 353 if cancel_all or (build_req.brid == request_id): 354 log.msg("Cancelling %s" % build_req) 355 d = authz.actionAllowed('cancelPendingBuild', 356 req, build_req) 357 wfd = defer.waitForDeferred(d) 358 yield wfd 359 res = wfd.getResult() 360 if res: 361 build_req.cancel() 362 else: 363 yield path_to_authzfail(req) 364 return 365 if not cancel_all: 366 break 367 368 yield path_to_builder(req, self.builder_status)
369
370 -class StopChangeMixin(object):
371 372 @defer.deferredGenerator
373 - def stopChangeForBuilder(self, req, builder_status, auth_ok=False):
374 try: 375 request_change = req.args.get("change", [None])[0] 376 request_change = int(request_change) 377 except: 378 request_change = None 379 380 authz = self.getAuthz(req) 381 if request_change: 382 c = interfaces.IControl(self.getBuildmaster(req)) 383 builder_control = c.getBuilder(builder_status.getName()) 384 385 wfd = defer.waitForDeferred( 386 builder_control.getPendingBuildRequestControls()) 387 yield wfd 388 brcontrols = wfd.getResult() 389 390 build_controls = dict((x.brid, x) for x in brcontrols) 391 392 wfd = defer.waitForDeferred( 393 builder_status.getPendingBuildRequestStatuses()) 394 yield wfd 395 build_req_statuses = wfd.getResult() 396 397 for build_req in build_req_statuses: 398 wfd = defer.waitForDeferred( 399 build_req.getSourceStamp()) 400 yield wfd 401 ss = wfd.getResult() 402 403 if not ss.changes: 404 continue 405 406 for change in ss.changes: 407 if change.number == request_change: 408 control = build_controls[build_req.brid] 409 log.msg("Cancelling %s" % control) 410 d = authz.actionAllowed('stopChange', req, control) 411 wfd = defer.waitForDeferred(d) 412 yield wfd 413 res = wfd.getResult() 414 if (auth_ok or res): 415 control.cancel() 416 else: 417 yield False 418 return 419 420 yield True
421
422 423 -class StopChangeResource(StopChangeMixin, ActionResource):
424
425 - def __init__(self, builder_status):
426 ActionResource.__init__(self) 427 self.builder_status = builder_status
428 429 @defer.deferredGenerator
430 - def performAction(self, req):
431 """Cancel all pending builds that include a given numbered change.""" 432 wfd = defer.waitForDeferred( 433 self.stopChangeForBuilder(req, self.builder_status)) 434 yield wfd 435 success = wfd.getResult() 436 437 if not success: 438 yield path_to_authzfail(req) 439 else: 440 yield path_to_builder(req, self.builder_status)
441
442 443 -class StopChangeAllResource(StopChangeMixin, ActionResource):
444
445 - def __init__(self, status):
446 ActionResource.__init__(self) 447 self.status = status
448 449 @defer.deferredGenerator
450 - def performAction(self, req):
451 """Cancel all pending builds that include a given numbered change.""" 452 authz = self.getAuthz(req) 453 wfd = defer.waitForDeferred(authz.actionAllowed('stopChange', req)) 454 yield wfd 455 res = wfd.getResult() 456 if not res: 457 yield path_to_authzfail(req) 458 return 459 460 for bname in self.status.getBuilderNames(): 461 builder_status = self.status.getBuilder(bname) 462 wfd = defer.waitForDeferred( 463 self.stopChangeForBuilder(req, builder_status, auth_ok=True)) 464 yield wfd 465 if not wfd.getResult(): 466 yield path_to_authzfail(req) 467 return 468 469 yield path_to_root(req)
470
471 472 # /builders/_all 473 -class StatusResourceAllBuilders(HtmlResource, BuildLineMixin):
474
475 - def __init__(self, status):
476 HtmlResource.__init__(self) 477 self.status = status
478
479 - def getChild(self, path, req):
480 if path == "forceall": 481 return self.forceall(req) 482 if path == "stopall": 483 return self.stopall(req) 484 if path == "stopchangeall": 485 return StopChangeAllResource(self.status) 486 487 return HtmlResource.getChild(self, path, req)
488
489 - def forceall(self, req):
490 return ForceAllBuildsActionResource(self.status, 'all')
491
492 - def stopall(self, req):
493 return StopAllBuildsActionResource(self.status, 'all')
494
495 # /builders/_selected 496 -class StatusResourceSelectedBuilders(HtmlResource, BuildLineMixin):
497
498 - def __init__(self, status):
499 HtmlResource.__init__(self) 500 self.status = status
501
502 - def getChild(self, path, req):
503 if path == "forceselected": 504 return self.forceselected(req) 505 if path == "stopselected": 506 return self.stopselected(req) 507 508 return HtmlResource.getChild(self, path, req)
509
510 - def forceselected(self, req):
511 return ForceAllBuildsActionResource(self.status, 'selected')
512
513 - def stopselected(self, req):
514 return StopAllBuildsActionResource(self.status, 'selected')
515
516 # /builders 517 -class BuildersResource(HtmlResource):
518 pageTitle = "Builders" 519 addSlash = True 520 521 @defer.deferredGenerator
522 - def content(self, req, cxt):
523 status = self.getStatus(req) 524 525 builders = req.args.get("builder", status.getBuilderNames()) 526 branches = [b for b in req.args.get("branch", []) if b] 527 528 # get counts of pending builds for each builder 529 brstatus_ds = [] 530 brcounts = {} 531 def keep_count(statuses, builderName): 532 brcounts[builderName] = len(statuses)
533 for builderName in builders: 534 builder_status = status.getBuilder(builderName) 535 d = builder_status.getPendingBuildRequestStatuses() 536 d.addCallback(keep_count, builderName) 537 brstatus_ds.append(d) 538 wfd = defer.waitForDeferred( 539 defer.gatherResults(brstatus_ds)) 540 yield wfd 541 wfd.getResult() 542 543 cxt['branches'] = branches 544 bs = cxt['builders'] = [] 545 546 building = 0 547 online = 0 548 base_builders_url = path_to_root(req) + "builders/" 549 for bn in builders: 550 bld = { 'link': base_builders_url + urllib.quote(bn, safe=''), 551 'name': bn } 552 bs.append(bld) 553 554 builder = status.getBuilder(bn) 555 builds = list(builder.generateFinishedBuilds(map_branches(branches), 556 num_builds=1)) 557 if builds: 558 b = builds[0] 559 bld['build_url'] = (bld['link'] + "/builds/%d" % b.getNumber()) 560 label = b.getProperty("got_revision") 561 if not label or len(str(label)) > 20: 562 label = "#%d" % b.getNumber() 563 564 bld['build_label'] = label 565 bld['build_text'] = " ".join(b.getText()) 566 bld['build_css_class'] = build_get_class(b) 567 568 current_box = ICurrentBox(builder).getBox(status, brcounts) 569 bld['current_box'] = current_box.td() 570 571 builder_status = builder.getState()[0] 572 if builder_status == "building": 573 building += 1 574 online += 1 575 elif builder_status != "offline": 576 online += 1 577 578 cxt['authz'] = self.getAuthz(req) 579 cxt['num_building'] = building 580 cxt['num_online'] = online 581 buildForceContext(cxt, req, self.getBuildmaster(req)) 582 template = req.site.buildbot_service.templates.get_template("builders.html") 583 yield template.render(**cxt)
584
585 - def getChild(self, path, req):
586 s = self.getStatus(req) 587 if path in s.getBuilderNames(): 588 builder_status = s.getBuilder(path) 589 return StatusResourceBuilder(builder_status) 590 if path == "_all": 591 return StatusResourceAllBuilders(self.getStatus(req)) 592 if path == "_selected": 593 return StatusResourceSelectedBuilders(self.getStatus(req)) 594 595 return HtmlResource.getChild(self, path, req)
596