From d7df6d3c31db2ca875d8dec2c0b873cc04b7738e Mon Sep 17 00:00:00 2001 From: Daniel Schwarz Date: Mon, 18 Sep 2017 10:48:23 +0200 Subject: [PATCH] SONAR-9802 fail restarting attempts on cluster nodes --- .../server/platform/ws/RestartAction.java | 9 +++++++- .../server/platform/ws/RestartActionTest.java | 21 ++++++++++++++++++- .../server/platform/ws/SystemWsTest.java | 3 ++- .../sonarqube/tests/cluster/ClusterTest.java | 20 ++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java index 3a5160d573a..00d5aaebdc0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java @@ -28,6 +28,7 @@ import org.sonar.api.utils.log.Loggers; 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; /** @@ -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 @@ -62,6 +66,9 @@ public class RestartAction implements SystemWsAction { @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(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java index 87195c8d5c6..059e2e0e064 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java @@ -31,6 +31,7 @@ import org.sonar.server.app.ProcessCommandWrapper; 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; @@ -38,6 +39,7 @@ 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 @@ -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); @@ -72,6 +76,7 @@ public class RestartActionTest { @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(); @@ -92,6 +97,7 @@ public class RestartActionTest { @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(); @@ -99,6 +105,7 @@ public class RestartActionTest { @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); @@ -106,8 +113,19 @@ public class RestartActionTest { 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(); @@ -118,6 +136,7 @@ public class RestartActionTest { @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(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java index 33490259467..593619663da 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java @@ -27,6 +27,7 @@ import org.sonar.ce.http.CeHttpClientImpl; 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; @@ -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(); diff --git a/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java b/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java index 5bf9ac21c7b..615c077fd95 100644 --- a/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java +++ b/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java @@ -39,6 +39,7 @@ import org.junit.rules.TestRule; 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; @@ -263,6 +264,25 @@ public class ClusterTest { } } + @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)) { -- 2.39.5