def ping(self, req): log.msg("web ping of builder '%s'" % self.builder_status.getName()) if not self.getAuthz(req).actionAllowed('pingBuilder', req, self.builder_status): log.msg("..but not authorized") return Redirect(path_to_authfail(req)) c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder_status.getName()) bc.ping() # send the user back to the builder page return Redirect(path_to_builder(req, self.builder_status))
def performAction(self, req): url = None authz = self.getAuthz(req) d = authz.actionAllowed(self.action, req, self.builder) wfd = defer.waitForDeferred(d) yield wfd res = wfd.getResult() if not res: url = path_to_authzfail(req) else: # get a control object c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder.getName()) b = self.build_status builder_name = self.builder.getName() log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) name = authz.getUsernameFull(req) comments = req.args.get("comments", ["<no reason specified>"])[0] reason = ("The web-page 'rebuild' button was pressed by " "'%s': %s\n" % (name, comments)) msg = "" extraProperties = getAndCheckProperties(req) if not bc or not b.isFinished() or extraProperties is None: msg = "could not rebuild: " if b.isFinished(): msg += "build still not finished " if bc: msg += "could not get builder control" else: d = bc.rebuildBuild(b, reason, extraProperties) wfd = defer.waitForDeferred(d) yield wfd tup = wfd.getResult() # check that (bsid, brids) were properly stored if not (isinstance(tup, tuple) and isinstance(tup[0], int) and isinstance(tup[1], dict)): msg = "rebuilding a build failed " + str(tup) # we're at # http://localhost:8080/builders/NAME/builds/5/rebuild?[args] # Where should we send them? # # Ideally it would be to the per-build page that they just started, # but we don't know the build number for it yet (besides, it might # have to wait for a current build to finish). The next-most # preferred place is somewhere that the user can see tangible # evidence of their build starting (or to see the reason that it # didn't start). This should be the Builder page. url = path_to_builder(req, self.builder), msg yield url
def force(self, req, auth_ok=False): name = req.args.get("username", ["<unknown>"])[0] reason = req.args.get("comments", ["<no reason specified>"])[0] branch = req.args.get("branch", [""])[0] revision = req.args.get("revision", [""])[0] r = "The web-page 'force build' button was pressed by '%s': %s\n" \ % (html.escape(name), html.escape(reason)) log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" " by user '%s'" % (self.builder_status.getName(), branch, revision, name)) # check if this is allowed if not auth_ok: if not self.getAuthz(req).actionAllowed('forceBuild', req, self.builder_status): log.msg("..but not authorized") return Redirect(path_to_authfail(req)) # keep weird stuff out of the branch revision, and property strings. # TODO: centralize this somewhere. if not re.match(r'^[\w\.\-\/]*$', branch): log.msg("bad branch '%s'" % branch) return Redirect(path_to_builder(req, self.builder_status)) if not re.match(r'^[\w\.\-\/]*$', revision): log.msg("bad revision '%s'" % revision) return Redirect(path_to_builder(req, self.builder_status)) properties = getAndCheckProperties(req) if properties is None: return Redirect(path_to_builder(req, self.builder_status)) if not branch: branch = None if not revision: revision = None # TODO: if we can authenticate that a particular User pushed the # button, use their name instead of None, so they'll be informed of # the results. # TODO2: we can authenticate that a particular User pushed the button # now, so someone can write this support. but it requires a # buildbot.changes.changes.Change instance which is tedious at this # stage to compute s = SourceStamp(branch=branch, revision=revision) try: c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder_status.getName()) bc.submitBuildRequest(s, r, properties, now=True) except interfaces.NoSlaveError: # TODO: tell the web user that their request could not be # honored pass # send the user back to the builder page return Redirect(path_to_builder(req, self.builder_status))
def perspective_requestBuild(self, buildername, reason, branch, revision, properties={}): c = interfaces.IControl(self.master) bc = c.getBuilder(buildername) ss = SourceStamp(branch, revision) bpr = Properties() bpr.update(properties, "remote requestBuild") return bc.submitBuildRequest(ss, reason, bpr)
def perspective_forcewait(self, builder='build', reason='', branch='', revision='', pdict={}): log.msg('forcewait called') branch_validate = self.master.config.validation['branch'] revision_validate = self.master.config.validation['revision'] pname_validate = self.master.config.validation['property_name'] pval_validate = self.master.config.validation['property_value'] if not branch_validate.match(branch): log.msg("bad branch '%s'" % branch) return if not revision_validate.match(revision): log.msg("bad revision '%s'" % revision) return properties = Properties() if pdict: for prop in pdict: pname = prop pvalue = pdict[prop] if not pname_validate.match(pname) or \ not pval_validate.match(pvalue): log.msg("bad property name='%s', value='%s'" % (pname, pvalue)) return log.msg('set property %s %s' % (pname, pvalue)) properties.setProperty(pname, pvalue, "Force Build PB") c = interfaces.IControl(self.master) b = c.getBuilder(builder) ss = SourceStamp(branch=branch, revision=revision) dr = defer.Deferred() def started(s): log.msg('force started') dr.callback(s.getNumber()) def requested(breq): log.msg('force requested') breq.subscribe(started) d2 = b.submitBuildRequest(ss, reason, props=properties.asDict()) d2.addCallback(requested) d2.addErrback(log.err, "while forcing a build") return dr
def performAction(self, req): log.msg("web ping of builder '%s'" % self.builder_status.getName()) res = yield self.getAuthz(req).actionAllowed('pingBuilder', req, self.builder_status) if not res: log.msg("..but not authorized") defer.returnValue(path_to_authzfail(req)) return c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder_status.getName()) bc.ping() # send the user back to the builder page defer.returnValue(path_to_builder(req, self.builder_status))
def _testSlave_1(self, res, t1): self.failUnlessEqual(len(t1.events), 2) self.failUnlessEqual(t1.events[0], ("builderChangedState", "dummy", "idle")) self.failUnlessEqual(t1.events[1], ("builderChangedState", "testdummy", "idle")) t1.events = [] c = interfaces.IControl(self.master) req = BuildRequest("forced build for testing", SourceStamp()) c.getBuilder("dummy").requestBuild(req) d = req.waitUntilFinished() d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") dl = defer.DeferredList([d, d2]) dl.addCallback(self._testSlave_2) return dl
def stopChangeForBuilder(self, req, builder_status, auth_ok=False): try: request_change = req.args.get("change", [None])[0] request_change = int(request_change) except: request_change = None authz = self.getAuthz(req) if request_change: c = interfaces.IControl(self.getBuildmaster(req)) builder_control = c.getBuilder(builder_status.getName()) wfd = defer.waitForDeferred( builder_control.getPendingBuildRequestControls()) yield wfd brcontrols = wfd.getResult() build_controls = dict((x.brid, x) for x in brcontrols) wfd = defer.waitForDeferred( builder_status.getPendingBuildRequestStatuses()) yield wfd build_req_statuses = wfd.getResult() for build_req in build_req_statuses: wfd = defer.waitForDeferred(build_req.getSourceStamp()) yield wfd ss = wfd.getResult() if not ss.changes: continue for change in ss.changes: if change.number == request_change: control = build_controls[build_req.brid] log.msg("Cancelling %s" % control) d = authz.actionAllowed('stopChange', req, control) wfd = defer.waitForDeferred(d) yield wfd res = wfd.getResult() if (auth_ok or res): control.cancel() else: yield False return yield True
def performAction(self, req): try: request_id = req.args.get("id", [None])[0] if request_id == "all": cancel_all = True else: cancel_all = False request_id = int(request_id) except: request_id = None authz = self.getAuthz(req) if request_id: c = interfaces.IControl(self.getBuildmaster(req)) builder_control = c.getBuilder(self.builder_status.getName()) brcontrols = yield builder_control.getPendingBuildRequestControls() for build_req in brcontrols: if cancel_all or (build_req.brid == request_id): log.msg("Cancelling %s" % build_req) res = yield authz.actionAllowed('cancelPendingBuild', req, build_req) if res: yield build_req.cancel() else: defer.returnValue(path_to_authzfail(req)) return if not cancel_all: break args = req.args.copy() returnpage = args.get("returnpage", None) if returnpage is None: defer.returnValue((path_to_builder(req, self.builder_status))) elif "builders" in returnpage: defer.returnValue( (path_to_builders(req, self.builder_status.getProject()))) elif "buildqueue" in returnpage: defer.returnValue(path_to_buildqueue(req)) elif "builders_json": s = self.getStatus(req) defer.returnValue( (s.getBuildbotURL() + path_to_json_builders(req, self.builder_status.getProject())))
def performAction(self, req): log.msg("web ping of builder '%s'" % self.builder_status.getName()) d = self.getAuthz(req).actionAllowed('pingBuilder', req, self.builder_status) wfd = defer.waitForDeferred(d) yield wfd res = wfd.getResult() if not res: log.msg("..but not authorized") yield path_to_authzfail(req) return c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder_status.getName()) bc.ping() # send the user back to the builder page yield path_to_builder(req, self.builder_status)
def get_candidates(self, builder_names): result = [] master_control = interfaces.IControl(self.master) for name in builder_names: builder_control = master_control.getBuilder(name) pending = yield builder_control.getPendingBuildRequestControls() # How can it even return None? if pending is None: continue for buildrequest in pending: result.append( (buildrequest, [buildrequest.original_request.source])) defer.returnValue(result)
def create_master(self, **kwargs): assert not self.master, "you called create_master twice" # probably because you subclassed RunMixin instead of MasterMixin self.slaves = {} if self.basedir is None: self.basedir = self.mktemp() basedir = self.basedir os.makedirs(basedir) self.master = master.BuildMaster(basedir, **kwargs) spec = dbspec.DBSpec.from_url("sqlite:///state.sqlite", basedir=basedir) sm = schema.DBSchemaManager(spec, basedir) sm.upgrade(quiet=True) self.master.loadDatabase(spec) self.master.readConfig = True self.master.startService() self.status = self.master.getStatus() self.control = interfaces.IControl(self.master)
def build(self, req): [builders, error] = self.getBuilders(req) if error is not None: return error reason = str(req.args.get("comments", [""])[0]) if len(reason) < 1: reason = "<no reason specified>" [properties, error] = self.getProperties(req) if error is not None: return error log.msg("web force build with properties for builders=[%s]" % ( " ".join(builders))) failed_builders = [] control = interfaces.IControl(self.getBuildmaster(req)) source_stamp = SourceStamp(branch=None, revision=None) for builder_name in builders: bc = control.getBuilder(builder_name) if not bc: failed_builders.append((builder_name, "Failed to get builder controller")) log("could not force build %s - failed to get build control" % ( builder_name)) continue try: bc.submitBuildRequest(source_stamp, reason, properties) except interfaces.NoSlaveError: failed_builders.append((builder_name, "No slave available")) if (len(failed_builders) > 0): reasons = ["<dt>%s</dt><dd>%s</dd>" % ( cgi.escape(x[0]), cgi.escape(x[1])) for x in failed_builders] return BuildError("The following builders failed to build: <dl>%s</dl>" % ( "\n".join(reasons)), req, False) # this isn't an error, but at this point I'm feeling lazy # it should realy be a templated html instead HTML = "<p>Build request submitted.</p>" return BuildError(HTML, req, False)
def rebuild(self, req): # check auth if not self.getAuthz(req).actionAllowed( 'forceBuild', req, self.build_status.getBuilder()): return Redirect(path_to_authfail(req)) # get a control object c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.build_status.getBuilder().getName()) b = self.build_status builder_name = b.getBuilder().getName() log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) name = req.args.get("username", ["<unknown>"])[0] comments = req.args.get("comments", ["<no reason specified>"])[0] reason = ("The web-page 'rebuild' button was pressed by " "'%s': %s\n" % (name, comments)) extraProperties = getAndCheckProperties(req) if not bc or not b.isFinished() or extraProperties is None: log.msg("could not rebuild: bc=%s, isFinished=%s" % (bc, b.isFinished())) # TODO: indicate an error else: d = bc.rebuildBuild(b, reason, extraProperties) d.addErrback(log.err, "while rebuilding a build") # we're at # http://localhost:8080/builders/NAME/builds/5/rebuild?[args] # Where should we send them? # # Ideally it would be to the per-build page that they just started, # but we don't know the build number for it yet (besides, it might # have to wait for a current build to finish). The next-most # preferred place is somewhere that the user can see tangible # evidence of their build starting (or to see the reason that it # didn't start). This should be the Builder page. r = Redirect(path_to_builder(req, self.build_status.getBuilder())) d = defer.Deferred() reactor.callLater(1, d.callback, r) return DeferredResource(d)
def get_candidates(self, builder_names): result = [] master_status = self.master.status master_control = interfaces.IControl(self.master) for name in builder_names: builder_status = master_status.getBuilder(name) state, current_builds = builder_status.getState() if not current_builds: continue builder_control = master_control.getBuilder(name) for build in current_builds: source_stamps = yield build.getSourceStamps() result.append((builder_control.getBuild(build.getNumber()), source_stamps)) defer.returnValue(result)
def performAction(self, req): try: request_id = req.args.get("id", [None])[0] if request_id == "all": cancel_all = True else: cancel_all = False request_id = int(request_id) except: request_id = None authz = self.getAuthz(req) if request_id: c = interfaces.IControl(self.getBuildmaster(req)) builder_control = c.getBuilder(self.builder_status.getName()) wfd = defer.waitForDeferred( builder_control.getPendingBuildRequestControls()) yield wfd brcontrols = wfd.getResult() for build_req in brcontrols: if cancel_all or (build_req.brid == request_id): log.msg("Cancelling %s" % build_req) d = authz.actionAllowed('cancelPendingBuild', req, build_req) wfd = defer.waitForDeferred(d) yield wfd res = wfd.getResult() if res: build_req.cancel() else: yield path_to_authzfail(req) return if not cancel_all: break yield path_to_builder(req, self.builder_status)
def performAction(self, req): status = self.getStatus(req) master = req.site.buildbot_service.master c = interfaces.IControl(self.getBuildmaster(req)) buildrequest = [int(b) for b in req.args.get("cancelselected", []) if b] brdicts = yield master.db.buildrequests.getBuildRequestInQueue(brids=buildrequest) for brdict in brdicts: br = yield BuildRequest.fromBrdict( master, brdict) b = master.botmaster.builders[brdict['buildername']] brc = BuildRequestControl(b, br) yield brc.cancel() # go back to the buildqueue page pending_builds_url = req.args.get("pending_builds_url", None) if pending_builds_url: defer.returnValue(pending_builds_url[0]) elif req.args.has_key("ajax"): defer.returnValue(path_to_buildqueue_json(req)) else: defer.returnValue(path_to_buildqueue(req))
def _testPing_1(self, res): d = interfaces.IControl(self.master).getBuilder("dummy").ping(1) d.addCallback(self._testPing_2) return d
def setServiceParent(self, parent): base.StatusReceiverMultiService.setServiceParent(self, parent) self.f.status = parent.getStatus() if self.allowForce: self.f.control = interfaces.IControl(parent)
def perspective_pingBuilder(self, buildername): c = interfaces.IControl(self.master) bc = c.getBuilder(buildername) bc.ping()
def _testRequest_1(self, res): c = interfaces.IControl(self.master) bss = c.submitBuildSet(["force"], SourceStamp(), "I was bored") # X d = bss.waitUntilFinished() return d
def performAction(self, req): url = None authz = self.getAuthz(req) res = yield authz.actionAllowed(self.action, req, self.builder) if not res: url = path_to_authzfail(req) else: # get a control object c = interfaces.IControl(self.getBuildmaster(req)) bc = c.getBuilder(self.builder.getName()) b = self.build_status builder_name = self.builder.getName() log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) name = authz.getUsernameFull(req) comments = req.args.get("comments", ["<no reason specified>"])[0] comments.decode(getRequestCharset(req)) reason = self.rebuildString % { 'build_number': b.getNumber(), 'owner': b.getInterestedUsers(), 'rebuild_owner': name, 'rebuild_comments': comments } useSourcestamp = req.args.get("useSourcestamp", None) if useSourcestamp and useSourcestamp == ['updated']: absolute = False else: absolute = True msg = "" extraProperties = getAndCheckProperties(req) if not bc or not b.isFinished() or extraProperties is None: msg = "could not rebuild: " if b.isFinished(): msg += "build still not finished " if bc: msg += "could not get builder control" else: tup = yield bc.rebuildBuild(b, reason=reason, extraProperties=extraProperties, absolute=absolute) # rebuildBuild returns None on error (?!) if not tup: msg = "rebuilding a build failed " + str(tup) # we're at # http://localhost:8080/builders/NAME/builds/5/rebuild?[args] # Where should we send them? # # Ideally it would be to the per-build page that they just started, # but we don't know the build number for it yet (besides, it might # have to wait for a current build to finish). The next-most # preferred place is somewhere that the user can see tangible # evidence of their build starting (or to see the reason that it # didn't start). This should be the Builder page. url = path_to_builder(req, self.builder), msg defer.returnValue(url)
def setServiceParent(self, parent): self.f.status = parent if self.allowForce: self.f.control = interfaces.IControl(self.master) return base.StatusReceiverMultiService.setServiceParent(self, parent)
def perspective_requestBuild(self, buildername, reason, branch, revision): c = interfaces.IControl(self.master) bc = c.getBuilder(buildername) ss = SourceStamp(branch, revision) br = BuildRequest(reason, ss, buildername) bc.requestBuild(br)
def _testSlave_2(self, res): # t1 subscribes to builds, but not anything lower-level ev = self.t1.events self.failUnlessEqual(len(ev), 4) self.failUnlessEqual(ev[0][0:3], ("builderChangedState", "dummy", "building")) self.failUnlessEqual(ev[1][0], "buildStarted") self.failUnlessEqual(ev[2][0:2] + ev[2][3:4], ("buildFinished", "dummy", builder.SUCCESS)) self.failUnlessEqual(ev[3][0:3], ("builderChangedState", "dummy", "idle")) self.failUnlessEqual( [ev[0] for ev in self.t3.events], [ "builderAdded", "builderChangedState", # offline "builderAdded", "builderChangedState", # idle "builderChangedState", # offline "builderChangedState", # idle "builderChangedState", # building "buildStarted", "stepStarted", "stepETAUpdate", "stepFinished", "stepStarted", "stepETAUpdate", "logStarted", "logFinished", "stepFinished", "buildFinished", "builderChangedState", # idle ]) b = self.s1.getLastFinishedBuild() self.failUnless(b) self.failUnlessEqual(b.getBuilder().getName(), "dummy") self.failUnlessEqual(b.getNumber(), 0) self.failUnlessEqual(b.getSourceStamp().branch, None) self.failUnlessEqual(b.getSourceStamp().patch, None) self.failUnlessEqual(b.getSourceStamp().revision, None) self.failUnlessEqual(b.getReason(), "forced build for testing") self.failUnlessEqual(b.getChanges(), ()) self.failUnlessEqual(b.getResponsibleUsers(), []) self.failUnless(b.isFinished()) self.failUnlessEqual(b.getText(), ['build', 'successful']) self.failUnlessEqual(b.getColor(), "green") self.failUnlessEqual(b.getResults(), builder.SUCCESS) steps = b.getSteps() self.failUnlessEqual(len(steps), 2) eta = 0 st1 = steps[0] self.failUnlessEqual(st1.getName(), "dummy") self.failUnless(st1.isFinished()) self.failUnlessEqual(st1.getText(), ["delay", "1 secs"]) start, finish = st1.getTimes() self.failUnless(0.5 < (finish - start) < 10) self.failUnlessEqual(st1.getExpectations(), []) self.failUnlessEqual(st1.getLogs(), []) eta += finish - start st2 = steps[1] self.failUnlessEqual(st2.getName(), "remote dummy") self.failUnless(st2.isFinished()) self.failUnlessEqual(st2.getText(), ["remote", "delay", "2 secs"]) start, finish = st2.getTimes() self.failUnless(1.5 < (finish - start) < 10) eta += finish - start self.failUnlessEqual(st2.getExpectations(), [('output', 38, None)]) logs = st2.getLogs() self.failUnlessEqual(len(logs), 1) self.failUnlessEqual(logs[0].getName(), "stdio") self.failUnlessEqual(logs[0].getText(), "data") self.eta = eta # now we run it a second time, and we should have an ETA self.t4 = t4 = STarget(["builder", "build", "eta"]) self.master.getStatus().subscribe(t4) c = interfaces.IControl(self.master) req = BuildRequest("forced build for testing", SourceStamp()) c.getBuilder("dummy").requestBuild(req) d = req.waitUntilFinished() d2 = self.master.botmaster.waitUntilBuilderIdle("dummy") dl = defer.DeferredList([d, d2]) dl.addCallback(self._testSlave_3) return dl