Skip to content

Commit

Permalink
SONAR-9802 fail restarting attempts on cluster nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Schwarz authored and Simon Brandhof committed Sep 26, 2017
1 parent df53863 commit d7df6d3
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 3 deletions.
Expand Up @@ -28,6 +28,7 @@
import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.WebServer;
import org.sonar.server.user.UserSession;

/**
Expand All @@ -42,13 +43,16 @@ public class RestartAction implements SystemWsAction {
private final Platform platform;
private final ProcessCommandWrapper processCommandWrapper;
private final RestartFlagHolder restartFlagHolder;
private final WebServer webServer;

public RestartAction(UserSession userSession, Configuration config, Platform platform, ProcessCommandWrapper processCommandWrapper, RestartFlagHolder restartFlagHolder) {
public RestartAction(UserSession userSession, Configuration config, Platform platform, ProcessCommandWrapper processCommandWrapper, RestartFlagHolder restartFlagHolder,
WebServer webServer) {
this.userSession = userSession;
this.config = config;
this.platform = platform;
this.processCommandWrapper = processCommandWrapper;
this.restartFlagHolder = restartFlagHolder;
this.webServer = webServer;
}

@Override
Expand All @@ -62,6 +66,9 @@ public void define(WebService.NewController controller) {

@Override
public void handle(Request request, Response response) {
if (!webServer.isStandalone()) {
throw new IllegalArgumentException("Restart not allowed for cluster nodes");
}
if (config.getBoolean("sonar.web.dev").orElse(false)) {
LOGGER.info("Fast restarting WebServer...");
restartFlagHolder.set();
Expand Down
Expand Up @@ -31,13 +31,15 @@
import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.WebServer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class RestartActionTest {
@Rule
Expand All @@ -51,13 +53,15 @@ public class RestartActionTest {
private Platform platform = mock(Platform.class);
private ProcessCommandWrapper processCommandWrapper = mock(ProcessCommandWrapper.class);
private RestartFlagHolder restartFlagHolder = mock(RestartFlagHolder.class);
private RestartAction sut = new RestartAction(userSessionRule, settings.asConfig(), platform, processCommandWrapper, restartFlagHolder);
private WebServer webServer = mock(WebServer.class);
private RestartAction sut = new RestartAction(userSessionRule, settings.asConfig(), platform, processCommandWrapper, restartFlagHolder, webServer);
private InOrder inOrder = Mockito.inOrder(platform, restartFlagHolder, processCommandWrapper);

private WsActionTester actionTester = new WsActionTester(sut);

@Test
public void restart_if_dev_mode() throws Exception {
when(webServer.isStandalone()).thenReturn(true);
settings.setProperty("sonar.web.dev", true);

SystemWs ws = new SystemWs(sut);
Expand All @@ -72,6 +76,7 @@ public void restart_if_dev_mode() throws Exception {

@Test
public void restart_flag_is_unset_in_dev_mode_even_if_restart_fails() throws Exception {
when(webServer.isStandalone()).thenReturn(true);
settings.setProperty("sonar.web.dev", true);
RuntimeException toBeThrown = new RuntimeException("simulating platform.restart() failed");
doThrow(toBeThrown).when(platform).restart();
Expand All @@ -92,22 +97,35 @@ public void restart_flag_is_unset_in_dev_mode_even_if_restart_fails() throws Exc

@Test
public void request_fails_in_production_mode_with_ForbiddenException_when_user_is_not_logged_in() {
when(webServer.isStandalone()).thenReturn(true);
expectedException.expect(ForbiddenException.class);

actionTester.newRequest().execute();
}

@Test
public void request_fails_in_production_mode_with_ForbiddenException_when_user_is_not_system_administrator() {
when(webServer.isStandalone()).thenReturn(true);
userSessionRule.logIn().setNonSystemAdministrator();

expectedException.expect(ForbiddenException.class);

actionTester.newRequest().execute();
}

@Test
public void request_fails_in_cluster_mode_with_IllegalArgumentException() {
when(webServer.isStandalone()).thenReturn(false);

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Restart not allowed for cluster nodes");

actionTester.newRequest().execute();
}

@Test
public void calls_ProcessCommandWrapper_requestForSQRestart_in_production_mode() throws Exception {
when(webServer.isStandalone()).thenReturn(true);
userSessionRule.logIn().setSystemAdministrator();

actionTester.newRequest().execute();
Expand All @@ -118,6 +136,7 @@ public void calls_ProcessCommandWrapper_requestForSQRestart_in_production_mode()

@Test
public void logs_login_of_authenticated_user_requesting_the_restart_in_production_mode() throws Exception {
when(webServer.isStandalone()).thenReturn(true);
String login = "BigBother";
userSessionRule.logIn(login).setSystemAdministrator();

Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.WebServer;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.tester.AnonymousMockUserSession;
import org.sonar.server.user.UserSession;
Expand All @@ -41,7 +42,7 @@ public class SystemWsTest {
@Test
public void define() {
RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Configuration.class), mock(Platform.class), mock(ProcessCommandWrapper.class),
mock(RestartFlagHolder.class));
mock(RestartFlagHolder.class), mock(WebServer.class));
InfoAction action2 = new InfoAction(new AnonymousMockUserSession(), ceHttpClient, mock(TelemetryDataLoader.class));
SystemWs ws = new SystemWs(action1, action2);
WebService.Context context = new WebService.Context();
Expand Down
20 changes: 20 additions & 0 deletions tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java
Expand Up @@ -39,6 +39,7 @@
import org.junit.rules.Timeout;
import org.sonarqube.ws.WsSystem;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;

import static com.google.common.base.Preconditions.checkState;
import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -263,6 +264,25 @@ public void restarting_all_application_nodes_elects_a_new_startup_leader() throw
}
}

@Test
public void restart_action_is_not_allowed_for_cluster_nodes() throws Exception {
try (Cluster cluster = newCluster(2, 1)) {
cluster.getNodes().forEach(Node::start);
cluster.getAppNodes().forEach(Node::waitForStatusUp);

cluster.getAppNodes().forEach(node -> {
try {
node.wsClient().system().restart();
fail("The restart webservice must not succeed on cluster nodes");
} catch (HttpException e) {
// all good, we expected this!
assertThat(e.code()).isEqualTo(400);
assertThat(e.content()).contains("Restart not allowed for cluster nodes");
}
});
}
}

@Test
public void health_becomes_RED_when_all_search_nodes_go_down() throws Exception {
try (Cluster cluster = newCluster(2, 1)) {
Expand Down

0 comments on commit d7df6d3

Please sign in to comment.