aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2016-04-25 16:08:36 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-04-26 12:28:43 +0200
commit7941356ee3d58d59712594579583638ebaa2065d (patch)
tree390418924d9b8a5183956d4339e86fbc0495312c
parent1fb1f2cdaa08715e815b5a18cd7d1bb31a3a8441 (diff)
downloadsonarqube-7941356ee3d58d59712594579583638ebaa2065d.tar.gz
sonarqube-7941356ee3d58d59712594579583638ebaa2065d.zip
SONAR−7565 add RESTARTING status in /api/system/status
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java42
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java41
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java11
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java38
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java18
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java3
9 files changed, 161 insertions, 15 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java
new file mode 100644
index 00000000000..cd868258633
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.app;
+
+/**
+ * Holds a boolean flag representing the restarting status of the WebServer.
+ * This boolean is {@code false} by default and can safely be changed concurrently using methods {@link #set()} and
+ * {@link #unset()}.
+ */
+public interface RestartFlagHolder {
+ /**
+ * @return whether restarting flag has been set or not.
+ */
+ boolean isRestarting();
+
+ /**
+ * Sets the restarting flag to {@code true}, no matter it already is or not.
+ */
+ void set();
+
+ /**
+ * Sets the restarting flag to {@code false}, no matter it already is or not.
+ */
+ void unset();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java
new file mode 100644
index 00000000000..8b9af93053e
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java
@@ -0,0 +1,41 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.app;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class RestartFlagHolderImpl implements RestartFlagHolder {
+ private final AtomicBoolean restarting = new AtomicBoolean(false);
+
+ @Override
+ public boolean isRestarting() {
+ return restarting.get();
+ }
+
+ @Override
+ public void set() {
+ restarting.set(true);
+ }
+
+ @Override
+ public void unset() {
+ restarting.set(false);
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index a801164fd20..68f4dadbd91 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -157,10 +157,12 @@ public class Platform {
if (!started) {
return Status.BOOTING;
}
- if (levelSafeMode != null && currentLevel == levelSafeMode) {
+ PlatformLevel current = this.currentLevel;
+ PlatformLevel levelSafe = this.levelSafeMode;
+ if (levelSafe != null && current == levelSafe) {
return Status.SAFEMODE;
}
- if (currentLevel == level4) {
+ if (current == level4) {
return Status.UP;
}
return Status.BOOTING;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
index a64ef830bf2..6f2a5b1b667 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
@@ -36,6 +36,7 @@ import org.sonar.db.semaphore.SemaphoresImpl;
import org.sonar.db.version.DatabaseVersion;
import org.sonar.db.version.MigrationStepModule;
import org.sonar.server.app.ProcessCommandWrapperImpl;
+import org.sonar.server.app.RestartFlagHolderImpl;
import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.platform.DatabaseServerCompatibility;
@@ -70,6 +71,7 @@ public class PlatformLevel1 extends PlatformLevel {
add(
SonarQubeVersionFactory.create(System2.INSTANCE),
ProcessCommandWrapperImpl.class,
+ RestartFlagHolderImpl.class,
WebServerSettings.class,
ServerImpl.class,
UuidFactoryImpl.INSTANCE,
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 69fba19b975..58c87ac0750 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
@@ -27,6 +27,7 @@ import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.web.UserRole;
import org.sonar.server.app.ProcessCommandWrapper;
+import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
import org.sonar.server.user.UserSession;
@@ -41,12 +42,14 @@ public class RestartAction implements SystemWsAction {
private final Settings settings;
private final Platform platform;
private final ProcessCommandWrapper processCommandWrapper;
+ private final RestartFlagHolder restartFlagHolder;
- public RestartAction(UserSession userSession, Settings settings, Platform platform, ProcessCommandWrapper processCommandWrapper) {
+ public RestartAction(UserSession userSession, Settings settings, Platform platform, ProcessCommandWrapper processCommandWrapper, RestartFlagHolder restartFlagHolder) {
this.userSession = userSession;
this.settings = settings;
this.platform = platform;
this.processCommandWrapper = processCommandWrapper;
+ this.restartFlagHolder = restartFlagHolder;
}
@Override
@@ -65,11 +68,17 @@ public class RestartAction implements SystemWsAction {
public void handle(Request request, Response response) {
if (settings.getBoolean("sonar.web.dev")) {
LOGGER.info("Fast restarting WebServer...");
- platform.restart();
- LOGGER.info("WebServer restarted");
+ restartFlagHolder.set();
+ try {
+ platform.restart();
+ LOGGER.info("WebServer restarted");
+ } finally {
+ restartFlagHolder.unset();
+ }
} else {
userSession.checkPermission(UserRole.ADMIN);
LOGGER.info("SonarQube restart requested by {}", userSession.getLogin());
+ restartFlagHolder.set();
processCommandWrapper.requestSQRestart();
}
response.noContent();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java
index b7b6a99f2cc..57b6c420553 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java
@@ -31,6 +31,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.IsAliveMapper;
import org.sonar.db.version.DatabaseMigration;
+import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
/**
@@ -44,12 +45,14 @@ public class StatusAction implements SystemWsAction {
private final DatabaseMigration databaseMigration;
private final Platform platform;
private final DbClient dbClient;
+ private final RestartFlagHolder restartFlagHolder;
- public StatusAction(Server server, DatabaseMigration databaseMigration, Platform platform, DbClient dbClient) {
+ public StatusAction(Server server, DatabaseMigration databaseMigration, Platform platform, DbClient dbClient, RestartFlagHolder restartFlagHolder) {
this.server = server;
this.databaseMigration = databaseMigration;
this.platform = platform;
this.dbClient = dbClient;
+ this.restartFlagHolder = restartFlagHolder;
}
@Override
@@ -60,6 +63,8 @@ public class StatusAction implements SystemWsAction {
"<li>UP: SonarQube instance is up and running</li>" +
"<li>DOWN: SonarQube instance is up but not running because SQ can not connect to database or " +
"migration has failed (refer to WS /api/system/migrate_db for details) or some other reason (check logs).</li>" +
+ "<li>RESTARTING: SonarQube instance is still up but a restart has been requested " +
+ "(refer to WS /api/system/restart for details).</li>" +
"<li>DB_MIGRATION_NEEDED: database migration is required. DB migration can be started using WS /api/system/migrate_db.</li>" +
"<li>DB_MIGRATION_RUNNING: DB migration is running (refer to WS /api/system/migrate_db for details)</li>" +
"</ul>")
@@ -97,7 +102,7 @@ public class StatusAction implements SystemWsAction {
// unless the Platform's status is UP or SAFEMODE
return Status.DOWN;
case UP:
- return Status.UP;
+ return restartFlagHolder.isRestarting() ? Status.RESTARTING : Status.UP;
case SAFEMODE:
return computeFromDbMigrationStatus();
default:
@@ -133,7 +138,7 @@ public class StatusAction implements SystemWsAction {
}
private enum Status {
- UP, DOWN, DB_MIGRATION_NEEDED, DB_MIGRATION_RUNNING
+ UP, DOWN, DB_MIGRATION_NEEDED, DB_MIGRATION_RUNNING, RESTARTING
}
}
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 8d08facfdf5..c45b101dd55 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
@@ -22,11 +22,14 @@ package org.sonar.server.platform.ws;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
import org.sonar.api.config.Settings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.api.web.UserRole;
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.tester.UserSessionRule;
@@ -34,8 +37,8 @@ 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.verify;
public class RestartActionTest {
@Rule
@@ -48,7 +51,10 @@ public class RestartActionTest {
private Settings settings = new Settings();
private Platform platform = mock(Platform.class);
private ProcessCommandWrapper processCommandWrapper = mock(ProcessCommandWrapper.class);
- private RestartAction sut = new RestartAction(userSessionRule, settings, platform, processCommandWrapper);
+ private RestartFlagHolder restartFlagHolder = mock(RestartFlagHolder.class);
+ private RestartAction sut = new RestartAction(userSessionRule, settings, platform, processCommandWrapper, restartFlagHolder);
+ private InOrder inOrder = Mockito.inOrder(platform, restartFlagHolder, processCommandWrapper);
+
private WsActionTester actionTester = new WsActionTester(sut);
@Test
@@ -59,7 +65,30 @@ public class RestartActionTest {
WsTester tester = new WsTester(ws);
tester.newPostRequest("api/system", "restart").execute();
- verify(platform).restart();
+ InOrder inOrder = Mockito.inOrder(platform, restartFlagHolder);
+ inOrder.verify(restartFlagHolder).set();
+ inOrder.verify(platform).restart();
+ inOrder.verify(restartFlagHolder).unset();
+ }
+
+ @Test
+ public void restart_flag_is_unset_in_dev_mode_even_if_restart_fails() throws Exception {
+ settings.setProperty("sonar.web.dev", true);
+ RuntimeException toBeThrown = new RuntimeException("simulating platform.restart() failed");
+ doThrow(toBeThrown).when(platform).restart();
+
+ SystemWs ws = new SystemWs(sut);
+
+ WsTester tester = new WsTester(ws);
+ try {
+ tester.newPostRequest("api/system", "restart").execute();
+ } catch (RuntimeException e) {
+ assertThat(e).isSameAs(toBeThrown);
+ } finally {
+ inOrder.verify(restartFlagHolder).set();
+ inOrder.verify(platform).restart();
+ inOrder.verify(restartFlagHolder).unset();
+ }
}
@Test
@@ -75,7 +104,8 @@ public class RestartActionTest {
actionTester.newRequest().execute();
- verify(processCommandWrapper).requestSQRestart();
+ inOrder.verify(restartFlagHolder).set();
+ inOrder.verify(processCommandWrapper).requestSQRestart();
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java
index 74ef58d2ad4..2e0960a2d81 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java
@@ -31,6 +31,8 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.IsAliveMapper;
import org.sonar.db.version.DatabaseMigration;
+import org.sonar.server.app.RestartFlagHolder;
+import org.sonar.server.app.RestartFlagHolderImpl;
import org.sonar.server.platform.Platform;
import org.sonar.server.ws.WsTester;
@@ -54,6 +56,7 @@ public class StatusActionTest {
private static final String STATUS_DOWN = "DOWN";
private static final String STATUS_MIGRATION_NEEDED = "DB_MIGRATION_NEEDED";
private static final String STATUS_MIGRATION_RUNNING = "DB_MIGRATION_RUNNING";
+ private static final String STATUS_RESTARTING = "RESTARTING";
private static final Set<DatabaseMigration.Status> SUPPORTED_DATABASE_MIGRATION_STATUSES = of(DatabaseMigration.Status.FAILED, DatabaseMigration.Status.NONE,
DatabaseMigration.Status.SUCCEEDED, DatabaseMigration.Status.RUNNING);
private static final Set<Platform.Status> SUPPORTED_PLATFORM_STATUSES = of(Platform.Status.BOOTING, Platform.Status.SAFEMODE, Platform.Status.UP);
@@ -64,7 +67,8 @@ public class StatusActionTest {
private DbClient dbClient = mock(DbClient.class);
private DbSession dbSession = mock(DbSession.class);
private IsAliveMapper isAliveMapper = mock(IsAliveMapper.class);
- private StatusAction underTest = new StatusAction(server, databaseMigration, platform, dbClient);
+ private RestartFlagHolder restartFlagHolder = new RestartFlagHolderImpl();
+ private StatusAction underTest = new StatusAction(server, databaseMigration, platform, dbClient, restartFlagHolder);
private Request request = mock(Request.class);
@@ -97,6 +101,7 @@ public class StatusActionTest {
public void verify_example() throws Exception {
when(isAliveMapper.isAlive()).thenReturn(IsAliveMapper.IS_ALIVE_RETURNED_VALUE);
when(platform.status()).thenReturn(Platform.Status.UP);
+ restartFlagHolder.unset();
WsTester.TestResponse response = new WsTester.TestResponse();
underTest.handle(request, response);
@@ -105,13 +110,22 @@ public class StatusActionTest {
}
@Test
- public void status_is_UP_if_platform_is_UP_whatever_databaseMigration_status_is() throws Exception {
+ public void status_is_UP_if_platform_is_UP_and_restartFlag_is_false_whatever_databaseMigration_status_is() throws Exception {
for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
verifyStatus(Platform.Status.UP, databaseMigrationStatus, STATUS_UP);
}
}
@Test
+ public void status_is_RESTARTING_if_platform_is_UP_and_restartFlag_is_true_whatever_databaseMigration_status_is() throws Exception {
+ restartFlagHolder.set();
+
+ for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
+ verifyStatus(Platform.Status.UP, databaseMigrationStatus, STATUS_RESTARTING);
+ }
+ }
+
+ @Test
public void status_is_DOWN_if_platform_is_BOOTING_whatever_databaseMigration_status_is() throws Exception {
for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
verifyStatus(Platform.Status.BOOTING, databaseMigrationStatus, STATUS_DOWN);
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 adda7539e6b..112df0694a3 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
@@ -23,6 +23,7 @@ import org.junit.Test;
import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.app.ProcessCommandWrapper;
+import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.monitoring.ProcessSystemInfoClient;
import org.sonar.server.tester.AnonymousMockUserSession;
@@ -37,7 +38,7 @@ public class SystemWsTest {
@Test
public void define() {
- RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class), mock(ProcessCommandWrapper.class));
+ RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class), mock(ProcessCommandWrapper.class), mock(RestartFlagHolder.class));
InfoAction action2 = new InfoAction(new AnonymousMockUserSession(), processSystemInfoClient);
SystemWs ws = new SystemWs(action1, action2);
WebService.Context context = new WebService.Context();