Trees | Indices | Help |
|
---|
|
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 getRequestCharset 27 from buildbot.schedulers.forcesched import ForceScheduler 28 from buildbot.schedulers.forcesched import InheritBuildParameter, NestedParameter 29 from buildbot.schedulers.forcesched import ValidationError 30 from buildbot.status.web.build import BuildsResource, StatusResourceBuild 31 from buildbot import util 32 import collections35 40 41 @defer.inlineCallbacks6343 authz = self.getAuthz(req) 44 res = yield authz.actionAllowed('forceAllBuilds', req) 45 46 if not res: 47 defer.returnValue(path_to_authzfail(req)) 48 return 49 50 builders = None 51 if self.selectedOrAll == 'all': 52 builders = self.status.getBuilderNames() 53 elif self.selectedOrAll == 'selected': 54 builders = [b for b in req.args.get("selected", []) if b] 55 56 for bname in builders: 57 builder_status = self.status.getBuilder(bname) 58 ar = ForceBuildActionResource(builder_status) 59 d = ar.performAction(req) 60 d.addErrback(log.err, "(ignored) while trying to force build") 61 # back to the welcome page 62 defer.returnValue(path_to_root(req))65 70 71 @defer.inlineCallbacks9973 authz = self.getAuthz(req) 74 res = yield authz.actionAllowed('stopAllBuilds', req) 75 if not res: 76 defer.returnValue(path_to_authzfail(req)) 77 return 78 79 builders = None 80 if self.selectedOrAll == 'all': 81 builders = self.status.getBuilderNames() 82 elif self.selectedOrAll == 'selected': 83 builders = [b for b in req.args.get("selected", []) if b] 84 85 for bname in builders: 86 builder_status = self.status.getBuilder(bname) 87 (state, current_builds) = builder_status.getState() 88 if state != "building": 89 continue 90 for b in current_builds: 91 build_status = builder_status.getBuild(b.number) 92 if not build_status: 93 continue 94 build = StatusResourceBuild(build_status) 95 build.stop(req, auth_ok=True) 96 97 # go back to the welcome page 98 defer.returnValue(path_to_root(req))101 105 106 @defer.inlineCallbacks121108 log.msg("web ping of builder '%s'" % self.builder_status.getName()) 109 res = yield self.getAuthz(req).actionAllowed('pingBuilder', req, 110 self.builder_status) 111 if not res: 112 log.msg("..but not authorized") 113 defer.returnValue(path_to_authzfail(req)) 114 return 115 116 c = interfaces.IControl(self.getBuildmaster(req)) 117 bc = c.getBuilder(self.builder_status.getName()) 118 bc.ping() 119 # send the user back to the builder page 120 defer.returnValue(path_to_builder(req, self.builder_status))123 127 128 @defer.inlineCallbacks170130 # check if this is allowed 131 res = yield self.getAuthz(req).actionAllowed(self.action, req, 132 self.builder_status) 133 if not res: 134 log.msg("..but not authorized") 135 defer.returnValue(path_to_authzfail(req)) 136 return 137 138 master = self.getBuildmaster(req) 139 owner = self.getAuthz(req).getUsernameFull(req) 140 schedulername = req.args.get("forcescheduler", ["<unknown>"])[0] 141 if schedulername == "<unknown>": 142 defer.returnValue((path_to_builder(req, self.builder_status), 143 "forcescheduler arg not found")) 144 return 145 146 args = req.args.copy() 147 148 # decode all of the args 149 encoding = getRequestCharset(req) 150 for name, argl in args.iteritems(): 151 args[name] = [ arg.decode(encoding) for arg in argl ] 152 153 # damn html's ungeneric checkbox implementation... 154 for cb in args.get("checkbox", []): 155 args[cb] = True 156 157 builder_name = self.builder_status.getName() 158 159 for sch in master.allSchedulers(): 160 if schedulername == sch.name: 161 try: 162 yield sch.force(owner, builder_name, **args) 163 msg = "" 164 except ValidationError, e: 165 msg = html.escape(e.message.encode('ascii','ignore')) 166 break 167 168 # send the user back to the builder page 169 defer.returnValue((path_to_builder(req, self.builder_status), msg))172 pname = "%s.%s"%(sch.name, field.fullName) 173 174 default = field.default 175 if isinstance(field, InheritBuildParameter): 176 # yes, I know, its bad to overwrite the parameter attribute, 177 # but I dont have any other simple way of doing this atm. 178 field.choices = field.compatible_builds(master.status, buildername) 179 if field.choices: 180 default = field.choices[0] 181 182 default = req.args.get(pname, [default])[0] 183 if "bool" in field.type: 184 default_props[pname] = "checked" if default else "" 185 else: 186 # filter out unicode chars, and html stuff 187 if isinstance(default, unicode): 188 default = html.escape(default.encode('utf-8','ignore')) 189 default_props[pname] = default 190 191 if isinstance(field, NestedParameter): 192 for subfield in field.fields: 193 buildForceContextForField(req, default_props, sch, subfield, master, buildername)194196 force_schedulers = {} 197 default_props = collections.defaultdict(str) 198 for sch in master.allSchedulers(): 199 if isinstance(sch, ForceScheduler) and (buildername is None or(buildername in sch.builderNames)): 200 force_schedulers[sch.name] = sch 201 for field in sch.all_fields: 202 buildForceContextForField(req, default_props, sch, field, master, buildername) 203 204 cxt['force_schedulers'] = force_schedulers 205 cxt['default_props'] = default_props206209 addSlash = True 210 214324216 return "Buildbot: %s" % self.builder_status.getName()217219 b = {} 220 221 b['num'] = build.getNumber() 222 b['link'] = path_to_build(req, build) 223 224 when = build.getETA() 225 if when is not None: 226 b['when'] = util.formatInterval(when) 227 b['when_time'] = time.strftime("%H:%M:%S", 228 time.localtime(time.time() + when)) 229 230 step = build.getCurrentStep() 231 # TODO: is this necessarily the case? 232 if not step: 233 b['current_step'] = "[waiting for Lock]" 234 else: 235 if step.isWaitingForLocks(): 236 b['current_step'] = "%s [waiting for Lock]" % step.getName() 237 else: 238 b['current_step'] = step.getName() 239 240 b['stop_url'] = path_to_build(req, build) + '/stop' 241 242 return b243 244 @defer.inlineCallbacks246 b = self.builder_status 247 248 cxt['name'] = b.getName() 249 req.setHeader('Cache-Control', 'no-cache') 250 slaves = b.getSlaves() 251 connected_slaves = [s for s in slaves if s.isConnected()] 252 253 cxt['current'] = [self.builder(x, req) for x in b.getCurrentBuilds()] 254 255 cxt['pending'] = [] 256 statuses = yield b.getPendingBuildRequestStatuses() 257 for pb in statuses: 258 changes = [] 259 260 source = yield pb.getSourceStamp() 261 submitTime = yield pb.getSubmitTime() 262 bsid = yield pb.getBsid() 263 264 properties = yield \ 265 pb.master.db.buildsets.getBuildsetProperties(bsid) 266 267 if source.changes: 268 for c in source.changes: 269 changes.append({ 'url' : path_to_change(req, c), 270 'who' : c.who, 271 'revision' : c.revision, 272 'repo' : c.repository }) 273 274 cxt['pending'].append({ 275 'when': time.strftime("%b %d %H:%M:%S", 276 time.localtime(submitTime)), 277 'delay': util.formatInterval(util.now() - submitTime), 278 'id': pb.brid, 279 'changes' : changes, 280 'num_changes' : len(changes), 281 'properties' : properties, 282 }) 283 284 numbuilds = int(req.args.get('numbuilds', ['5'])[0]) 285 recent = cxt['recent'] = [] 286 for build in b.generateFinishedBuilds(num_builds=int(numbuilds)): 287 recent.append(self.get_line_values(req, build, False)) 288 289 sl = cxt['slaves'] = [] 290 connected_slaves = 0 291 for slave in slaves: 292 s = {} 293 sl.append(s) 294 s['link'] = path_to_slave(req, slave) 295 s['name'] = slave.getName() 296 c = s['connected'] = slave.isConnected() 297 if c: 298 s['admin'] = unicode(slave.getAdmin() or '', 'utf-8') 299 connected_slaves += 1 300 cxt['connected_slaves'] = connected_slaves 301 302 cxt['authz'] = self.getAuthz(req) 303 cxt['builder_url'] = path_to_builder(req, b) 304 buildForceContext(cxt, req, self.getBuildmaster(req), b.getName()) 305 template = req.site.buildbot_service.templates.get_template("builder.html") 306 defer.returnValue(template.render(**cxt))307309 return PingBuilderActionResource(self.builder_status)310312 if path == "force": 313 return ForceBuildActionResource(self.builder_status) 314 if path == "ping": 315 return self.ping(req) 316 if path == "cancelbuild": 317 return CancelChangeResource(self.builder_status) 318 if path == "stopchange": 319 return StopChangeResource(self.builder_status) 320 if path == "builds": 321 return BuildsResource(self.builder_status) 322 323 return HtmlResource.getChild(self, path, req)326 330 331 @defer.inlineCallbacks364333 try: 334 request_id = req.args.get("id", [None])[0] 335 if request_id == "all": 336 cancel_all = True 337 else: 338 cancel_all = False 339 request_id = int(request_id) 340 except: 341 request_id = None 342 343 authz = self.getAuthz(req) 344 if request_id: 345 c = interfaces.IControl(self.getBuildmaster(req)) 346 builder_control = c.getBuilder(self.builder_status.getName()) 347 348 brcontrols = yield builder_control.getPendingBuildRequestControls() 349 350 for build_req in brcontrols: 351 if cancel_all or (build_req.brid == request_id): 352 log.msg("Cancelling %s" % build_req) 353 res = yield authz.actionAllowed('cancelPendingBuild', req, 354 build_req) 355 if res: 356 build_req.cancel() 357 else: 358 defer.returnValue(path_to_authzfail(req)) 359 return 360 if not cancel_all: 361 break 362 363 defer.returnValue(path_to_builder(req, self.builder_status))366 367 @defer.inlineCallbacks404369 try: 370 request_change = req.args.get("change", [None])[0] 371 request_change = int(request_change) 372 except: 373 request_change = None 374 375 authz = self.getAuthz(req) 376 if request_change: 377 c = interfaces.IControl(self.getBuildmaster(req)) 378 builder_control = c.getBuilder(builder_status.getName()) 379 380 brcontrols = yield builder_control.getPendingBuildRequestControls() 381 build_controls = dict((x.brid, x) for x in brcontrols) 382 383 build_req_statuses = yield \ 384 builder_status.getPendingBuildRequestStatuses() 385 386 for build_req in build_req_statuses: 387 ss = yield build_req.getSourceStamp() 388 389 if not ss.changes: 390 continue 391 392 for change in ss.changes: 393 if change.number == request_change: 394 control = build_controls[build_req.brid] 395 log.msg("Cancelling %s" % control) 396 res = yield authz.actionAllowed('stopChange', req, control) 397 if (auth_ok or res): 398 control.cancel() 399 else: 400 defer.returnValue(False) 401 return 402 403 defer.returnValue(True)407 411 412 @defer.inlineCallbacks421414 """Cancel all pending builds that include a given numbered change.""" 415 success = yield self.stopChangeForBuilder(req, self.builder_status) 416 417 if not success: 418 defer.returnValue(path_to_authzfail(req)) 419 else: 420 defer.returnValue(path_to_builder(req, self.builder_status))424 428 429 @defer.inlineCallbacks446431 """Cancel all pending builds that include a given numbered change.""" 432 authz = self.getAuthz(req) 433 res = yield authz.actionAllowed('stopChange', req) 434 if not res: 435 defer.returnValue(path_to_authzfail(req)) 436 return 437 438 for bname in self.status.getBuilderNames(): 439 builder_status = self.status.getBuilder(bname) 440 res = yield self.stopChangeForBuilder(req, builder_status, auth_ok=True) 441 if not res: 442 defer.returnValue(path_to_authzfail(req)) 443 return 444 445 defer.returnValue(path_to_root(req))450 454470456 if path == "forceall": 457 return self.forceall(req) 458 if path == "stopall": 459 return self.stopall(req) 460 if path == "stopchangeall": 461 return StopChangeAllResource(self.status) 462 463 return HtmlResource.getChild(self, path, req)464 467473 477491479 if path == "forceselected": 480 return self.forceselected(req) 481 if path == "stopselected": 482 return self.stopselected(req) 483 484 return HtmlResource.getChild(self, path, req)485 488494 pageTitle = "Builders" 495 addSlash = True 496 497 @defer.inlineCallbacks564499 status = self.getStatus(req) 500 encoding = getRequestCharset(req) 501 502 builders = req.args.get("builder", status.getBuilderNames()) 503 branches = [ b.decode(encoding) 504 for b in req.args.get("branch", []) 505 if b ] 506 507 # get counts of pending builds for each builder 508 brstatus_ds = [] 509 brcounts = {} 510 def keep_count(statuses, builderName): 511 brcounts[builderName] = len(statuses)512 for builderName in builders: 513 builder_status = status.getBuilder(builderName) 514 d = builder_status.getPendingBuildRequestStatuses() 515 d.addCallback(keep_count, builderName) 516 brstatus_ds.append(d) 517 yield defer.gatherResults(brstatus_ds) 518 519 cxt['branches'] = branches 520 bs = cxt['builders'] = [] 521 522 building = 0 523 online = 0 524 base_builders_url = path_to_root(req) + "builders/" 525 for bn in builders: 526 bld = { 'link': base_builders_url + urllib.quote(bn, safe=''), 527 'name': bn } 528 bs.append(bld) 529 530 builder = status.getBuilder(bn) 531 builds = list(builder.generateFinishedBuilds(map_branches(branches), 532 num_builds=1)) 533 if builds: 534 b = builds[0] 535 bld['build_url'] = (bld['link'] + "/builds/%d" % b.getNumber()) 536 label = None 537 all_got_revisions = b.getAllGotRevisions() 538 # If len = 1 then try if revision can be used as label. 539 if len(all_got_revisions) == 1: 540 label = all_got_revisions[all_got_revisions.keys()[0]] 541 if not label or len(str(label)) > 20: 542 label = "#%d" % b.getNumber() 543 544 bld['build_label'] = label 545 bld['build_text'] = " ".join(b.getText()) 546 bld['build_css_class'] = build_get_class(b) 547 548 current_box = ICurrentBox(builder).getBox(status, brcounts) 549 bld['current_box'] = current_box.td() 550 551 builder_status = builder.getState()[0] 552 if builder_status == "building": 553 building += 1 554 online += 1 555 elif builder_status != "offline": 556 online += 1 557 558 cxt['authz'] = self.getAuthz(req) 559 cxt['num_building'] = building 560 cxt['num_online'] = online 561 buildForceContext(cxt, req, self.getBuildmaster(req)) 562 template = req.site.buildbot_service.templates.get_template("builders.html") 563 defer.returnValue(template.render(**cxt))566 s = self.getStatus(req) 567 if path in s.getBuilderNames(): 568 builder_status = s.getBuilder(path) 569 return StatusResourceBuilder(builder_status) 570 if path == "_all": 571 return StatusResourceAllBuilders(self.getStatus(req)) 572 if path == "_selected": 573 return StatusResourceSelectedBuilders(self.getStatus(req)) 574 575 return HtmlResource.getChild(self, path, req)576
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Wed Nov 21 16:23:01 2012 | http://epydoc.sourceforge.net |