Improved circuit breaker admin UI

This commit is contained in:
Kohsuke Kawaguchi 2015-12-15 10:36:13 -08:00
parent 117d42615f
commit ba11039732
7 changed files with 112 additions and 15 deletions

1
circuitBreaker.txt Normal file
View File

@ -0,0 +1 @@
Disabled sign-up temporarily

View File

@ -78,6 +78,11 @@
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler</artifactId>
<version>1.233</version>
</dependency>
<dependency>
<groupId>org.kohsuke.stapler</groupId>
<artifactId>stapler-openid-server</artifactId>

View File

@ -16,6 +16,8 @@ but it should look something like the following:
recaptchaPublicKey=6Ld--8ASAAAAANHmHaM1sdSYshtmXTin1BNtaw86
recaptchaPrivateKey=*****
managerPassword=*****
circuitBreakerFile=./circuitBreaker.txt
url=http://localhost:8080/account/
Finally, run the application with Jetty, then access `http://localhost:8080/`:

View File

@ -29,6 +29,13 @@ public class AdminUI {
this.app = app;
}
/**
* Exposes the circuit breaker to UI.
*/
public CircuitBreaker getCircuitBreaker() {
return app.circuitBreaker;
}
public HttpResponse doSearch(@QueryParameter String word) throws NamingException {
List<User> all = new ArrayList<User>();
LdapContext con = app.connect();

View File

@ -68,9 +68,13 @@ public class Application {
*/
public final JenkinsOpenIDServer openid;
// not exposing this to UI
/*package*/ final CircuitBreaker circuitBreaker;
public Application(Parameters params) throws IOException {
this.params = params;
this.openid = new JenkinsOpenIDServer(this);
this.circuitBreaker = new CircuitBreaker(params);
}
public Application(Properties config) throws IOException {
@ -141,7 +145,7 @@ public class Application {
return maybeSpammer(userid, firstName, lastName, email, ip, null);
}
checkCircuitBreakerOn(userid);
circuitBreaker.check();
String password = createRecord(userid, firstName, lastName, email);
LOGGER.info("User "+userid+" is from "+ip);
@ -151,20 +155,6 @@ public class Application {
return new HttpRedirect("doneMail");
}
/**
* We allow ourselves to temporarily shut down the sign up, primarily to combat spam.
*/
private void checkCircuitBreakerOn(String userid) throws IOException {
String f = params.circuitBreakerFile();
if (f!=null) {
File breaker = new File(f);
if (System.currentTimeMillis() < breaker.lastModified()) {
LOGGER.info("Rejecting sign up for "+userid+" due to circuit breaker");
throw new UserError(FileUtils.readFileToString(breaker));
}
}
}
private HttpResponse maybeSpammer(String userid, String firstName, String lastName, String email, String ip, Answer a) throws MessagingException, UnsupportedEncodingException {
String text = String.format(
"Rejecting, likely spam: %s / ip=%s email=%s userId=%s lastName=%s firstName=%s",

View File

@ -0,0 +1,73 @@
package org.jenkinsci.account;
import org.apache.commons.io.FileUtils;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.interceptor.RequirePOST;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;
/**
* Temporarily shut-off valve to disable sign-up.
*
* @author Kohsuke Kawaguchi
*/
public class CircuitBreaker {
private final File file;
public CircuitBreaker(File file) {
this.file = file;
}
public CircuitBreaker(Parameters params) {
String f = params.circuitBreakerFile();
if (f!=null)
this.file = new File(f);
else
this.file = new File("/no-such-file");
}
public boolean isOn() {
return System.currentTimeMillis() < file.lastModified();
}
/**
* Throws an exception if the circuit breaker is on.
*/
public void check() throws IOException {
if (isOn()) {
LOGGER.info("Rejecting sign up due to circuit breaker");
throw new UserError(FileUtils.readFileToString(file));
}
}
@RequirePOST
public HttpResponse doSet(@QueryParameter String time) throws ParseException {
Date t = makeFormatter().parse(time.trim());
file.setLastModified(t.getTime());
return HttpResponses.plainText("Successfully set");
}
/**
* Current effective date
*/
public String getDate() {
long dt = file.lastModified();
if (dt<=0)
return "(none)";
else
return makeFormatter().format(new Date(dt));
}
private SimpleDateFormat makeFormatter() {
return new SimpleDateFormat("yyyy/MM/dd HH:mm");
}
private static final Logger LOGGER = Logger.getLogger(CircuitBreaker.class.getName());
}

View File

@ -1,5 +1,6 @@
<j:jelly xmlns:j="jelly:core" xmlns:t="/org/jenkinsci/backend/taglib/layout">
<t:layout title="Administration">
<h1>Manage Users</h1>
<p>
Type the user name or the e-mail address to find the user.
</p>
@ -9,5 +10,23 @@
<input type="submit" style="margin-top:2em; display:block"/>
</form>
<h1 style="margin-top:2em">Set Circuit Breaker</h1>
<p>
Temporarily disable sign-up to fight spam until a certain time.
All times are in US Eastern Time, where the server is.
</p>
<j:if test="${it.circuitBreaker.isOn()}">
<p>
Circuit breaker is currently on until ${it.circuitBreaker.date}.
To disable it, set it to the time in the past, such as 2000/01/01 00:00.
</p>
</j:if>
<form method="post" action="circuitBreaker/set">
<h5>Circuit breaker is on until when? (YYYY/MM/DD HH:MM)</h5>
<input type="text" name="time" class="text"/>
<input type="submit" style="margin-top:2em; display:block"/>
</form>
</t:layout>
</j:jelly>