Procházet zdrojové kódy

SONAR−7565 add RESTARTING status in /api/system/status

tags/5.5-RC2
Sébastien Lesaint před 8 roky
rodič
revize
e1af4751c2

+ 42
- 0
server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolder.java Zobrazit soubor

@@ -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();
}

+ 41
- 0
server/sonar-server/src/main/java/org/sonar/server/app/RestartFlagHolderImpl.java Zobrazit soubor

@@ -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);
}
}

+ 4
- 2
server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java Zobrazit soubor

@@ -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;

+ 2
- 0
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java Zobrazit soubor

@@ -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,

+ 12
- 3
server/sonar-server/src/main/java/org/sonar/server/platform/ws/RestartAction.java Zobrazit soubor

@@ -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();

+ 8
- 3
server/sonar-server/src/main/java/org/sonar/server/platform/ws/StatusAction.java Zobrazit soubor

@@ -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
}

}

+ 34
- 4
server/sonar-server/src/test/java/org/sonar/server/platform/ws/RestartActionTest.java Zobrazit soubor

@@ -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

+ 16
- 2
server/sonar-server/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java Zobrazit soubor

@@ -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,12 +110,21 @@ 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()) {

+ 2
- 1
server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java Zobrazit soubor

@@ -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();

Načítá se…
Zrušit
Uložit