aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-01-07 12:18:10 +0100
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-01-13 13:42:41 +0100
commit2b5701d42025b8cce2d192b494f61e91e591e591 (patch)
tree2a6d6d42b363324e9e868dc22b454ae3ddd094fe
parent73e02b6b9650e3af36e4fdb4aef243b9b92823ea (diff)
downloadsonarqube-2b5701d42025b8cce2d192b494f61e91e591e591.tar.gz
sonarqube-2b5701d42025b8cce2d192b494f61e91e591e591.zip
SONAR-7168 /api/system/restart now restarts SQ in production mode
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java48
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java75
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java3
3 files changed, 103 insertions, 23 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 5fa9bc0521d..d2caac6a8eb 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
@@ -19,14 +19,20 @@
*/
package org.sonar.server.platform.ws;
+import java.io.File;
import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.api.web.UserRole;
+import org.sonar.process.DefaultProcessCommands;
+import org.sonar.process.ProcessCommands;
import org.sonar.server.platform.Platform;
+import org.sonar.server.user.UserSession;
+
+import static com.google.common.base.Preconditions.checkArgument;
/**
* Implementation of the {@code restart} action for the System WebService.
@@ -34,11 +40,15 @@ import org.sonar.server.platform.Platform;
public class RestartAction implements SystemWsAction {
private static final Logger LOGGER = Loggers.get(RestartAction.class);
+ private static final String PROPERTY_SHARED_PATH = "process.sharedDir";
+ private static final String PROPERTY_PROCESS_INDEX = "process.index";
+ private final UserSession userSession;
private final Settings settings;
private final Platform platform;
- public RestartAction(Settings settings, Platform platform) {
+ public RestartAction(UserSession userSession, Settings settings, Platform platform) {
+ this.userSession = userSession;
this.settings = settings;
this.platform = platform;
}
@@ -46,8 +56,10 @@ public class RestartAction implements SystemWsAction {
@Override
public void define(WebService.NewController controller) {
controller.createAction("restart")
- .setDescription("Restart server. Available only on development mode (sonar.web.dev=true). " +
- "Ruby on Rails extensions are not reloaded.")
+ .setDescription("Restart server. " +
+ "In development mode (sonar.web.dev=true), performs a partial and quick restart of only the web server where " +
+ "Ruby on Rails extensions are not reloaded. " +
+ "In Production mode, require system administration permission and fully restart web server and Elastic Search processes.")
.setSince("4.3")
.setPost(true)
.setHandler(this);
@@ -55,14 +67,30 @@ public class RestartAction implements SystemWsAction {
@Override
public void handle(Request request, Response response) {
- if (!settings.getBoolean("sonar.web.dev")) {
- throw new ForbiddenException("Webservice available only in dev mode");
+ if (settings.getBoolean("sonar.web.dev")) {
+ LOGGER.info("Restart server");
+ platform.restart();
+ LOGGER.info("Server restarted");
+ } else {
+ LOGGER.info("Requesting SonarQube restart");
+ userSession.checkPermission(UserRole.ADMIN);
+ ProcessCommands commands = new DefaultProcessCommands(
+ nonNullValueAsFile(PROPERTY_SHARED_PATH), nonNullAsInt(PROPERTY_PROCESS_INDEX));
+ commands.askForRestart();
}
-
- LOGGER.info("Restart server");
- platform.restart();
- LOGGER.info("Server restarted");
response.noContent();
}
+ private int nonNullAsInt(String key) {
+ String s = settings.getString(key);
+ checkArgument(s != null, "Property %s is not set", key);
+ return Integer.parseInt(s);
+ }
+
+ public File nonNullValueAsFile(String key) {
+ String s = settings.getString(key);
+ checkArgument(s != null, "Property %s is not set", key);
+ return new File(s);
+ }
+
}
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 40ee840fe85..968f82aa2d6 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
@@ -19,20 +19,39 @@
*/
package org.sonar.server.platform.ws;
+import java.io.File;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
import org.sonar.api.config.Settings;
+import org.sonar.api.web.UserRole;
+import org.sonar.process.DefaultProcessCommands;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.platform.Platform;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
public class RestartActionTest {
+ private static final int PROCESS_NUMBER = 1;
+
+ @Rule
+ public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
Settings settings = new Settings();
Platform platform = mock(Platform.class);
- RestartAction sut = new RestartAction(settings, platform);
+ RestartAction sut = new RestartAction(userSessionRule, settings, platform);
+ WsActionTester actionTester = new WsActionTester(sut);
@Test
public void restart_if_dev_mode() throws Exception {
@@ -46,15 +65,47 @@ public class RestartActionTest {
}
@Test
- public void fail_if_production_mode() throws Exception {
- SystemWs ws = new SystemWs(sut);
+ public void requires_admin_permission_if_production_mode() {
+ expectedException.expect(ForbiddenException.class);
- WsTester tester = new WsTester(ws);
- try {
- tester.newPostRequest("api/system", "restart").execute();
- fail();
- } catch (ForbiddenException e) {
- verifyZeroInteractions(platform);
- }
+ actionTester.newRequest().execute();
}
+
+ @Test
+ public void fail_process_sharedDir_property_not_set_in_production_mode() throws Exception {
+ userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.sharedDir is not set");
+
+ actionTester.newRequest().execute();
+ }
+
+ @Test
+ public void fail_process_index_property_not_set_in_production_mode() throws Exception {
+ userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
+ settings.setProperty("process.sharedDir", temp.newFolder().getAbsolutePath());
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.index is not set");
+
+ actionTester.newRequest().execute();
+ }
+
+ @Test
+ public void askForRestart_in_shared_memory_in_production_mode() throws Exception {
+ int processNumber = 2;
+ File tempFolder = temp.newFolder().getAbsoluteFile();
+
+ userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
+ settings.setProperty("process.sharedDir", tempFolder.getAbsolutePath());
+ settings.setProperty("process.index", processNumber);
+
+ DefaultProcessCommands processCommands = new DefaultProcessCommands(tempFolder, processNumber);
+
+ actionTester.newRequest().execute();
+
+ assertThat(processCommands.askedForRestart()).isTrue();
+ }
+
}
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 db57cce361e..34aa22df9a7 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
@@ -24,6 +24,7 @@ import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.platform.Platform;
import org.sonar.server.tester.AnonymousMockUserSession;
+import org.sonar.server.user.UserSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -32,7 +33,7 @@ public class SystemWsTest {
@Test
public void define() {
- RestartAction action1 = new RestartAction(mock(Settings.class), mock(Platform.class));
+ RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class));
InfoAction action2 = new InfoAction(new AnonymousMockUserSession());
SystemWs ws = new SystemWs(action1, action2);
WebService.Context context = new WebService.Context();