From 7db084d4099eef82dbd823a5f53dc527434d65dd Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 13 Jun 2018 00:08:48 +0200 Subject: [PATCH] SONARCLOUD-75 Automatic run of DB migrations on blue/green deployments --- .../platform/DatabaseServerCompatibility.java | 19 ++++++------ .../platform/DefaultServerUpgradeStatus.java | 15 ++++++---- .../db/migration/AutoDbMigration.java | 25 ++++++++-------- .../DatabaseServerCompatibilityTest.java | 7 ++--- .../DefaultServerUpgradeStatusTest.java | 17 ++++++++++- .../db/migration/AutoDbMigrationTest.java | 30 +++++++++++++++++-- 6 files changed, 78 insertions(+), 35 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java b/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java index dbb705fb6bba..d252a90156a9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java @@ -48,20 +48,19 @@ public void start() { throw MessageException.of("Database was upgraded to a more recent of SonarQube. Backup must probably be restored or db settings are incorrect."); } if (status == DatabaseVersion.Status.REQUIRES_UPGRADE) { - if (configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false)) { - throw new IllegalStateException("Blue/green deployment is not supported. Database must be upgraded."); - } - Optional currentVersion = this.version.getVersion(); if (currentVersion.isPresent() && currentVersion.get() < DatabaseVersion.MIN_UPGRADE_VERSION) { throw MessageException.of("Current version is too old. Please upgrade to Long Term Support version firstly."); } - String msg = "Database must be upgraded. Please backup database and browse /setup"; - Loggers.get(DatabaseServerCompatibility.class).warn(msg); - Loggers.get(STARTUP_LOGGER_NAME).warn('\n' - + HIGHLIGHTER + '\n' - + " " + msg - + '\n' + HIGHLIGHTER); + boolean blueGreen = configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false); + if (!blueGreen) { + String msg = "Database must be upgraded. Please backup database and browse /setup"; + Loggers.get(DatabaseServerCompatibility.class).warn(msg); + Loggers.get(STARTUP_LOGGER_NAME).warn('\n' + + HIGHLIGHTER + '\n' + + " " + msg + + '\n' + HIGHLIGHTER); + } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java index fa5e1945700d..211ca38efa22 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java @@ -23,24 +23,25 @@ import org.apache.commons.lang.builder.ReflectionToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.picocontainer.Startable; +import org.sonar.api.config.Configuration; import org.sonar.api.platform.ServerUpgradeStatus; +import org.sonar.process.ProcessProperties; import org.sonar.server.platform.db.migration.step.MigrationSteps; import org.sonar.server.platform.db.migration.version.DatabaseVersion; -/** - * @since 2.5 - */ -public final class DefaultServerUpgradeStatus implements ServerUpgradeStatus, Startable { +public class DefaultServerUpgradeStatus implements ServerUpgradeStatus, Startable { private final DatabaseVersion dbVersion; private final MigrationSteps migrationSteps; + private final Configuration configuration; // available when connected to db private long initialDbVersion; - public DefaultServerUpgradeStatus(DatabaseVersion dbVersion, MigrationSteps migrationSteps) { + public DefaultServerUpgradeStatus(DatabaseVersion dbVersion, MigrationSteps migrationSteps, Configuration configuration) { this.dbVersion = dbVersion; this.migrationSteps = migrationSteps; + this.configuration = configuration; } @Override @@ -69,6 +70,10 @@ public int getInitialDbVersion() { return (int) initialDbVersion; } + public boolean isBlueGreen() { + return configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false); + } + @Override public String toString() { return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java index e6df46ba69d0..ca387bae9325 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java @@ -25,13 +25,13 @@ import java.sql.SQLException; import org.apache.commons.dbutils.DbUtils; import org.picocontainer.Startable; -import org.sonar.api.platform.ServerUpgradeStatus; import org.sonar.api.utils.log.Loggers; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DdlUtils; import org.sonar.db.dialect.Dialect; import org.sonar.db.dialect.H2; +import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.db.migration.engine.MigrationEngine; import org.sonar.server.platform.db.migration.step.MigrationSteps; @@ -39,12 +39,12 @@ * FIXME fix this class to remove use of DdlUtils.createSchema */ public class AutoDbMigration implements Startable { - private final ServerUpgradeStatus serverUpgradeStatus; + private final DefaultServerUpgradeStatus serverUpgradeStatus; private final DbClient dbClient; private final MigrationEngine migrationEngine; private final MigrationSteps migrationSteps; - public AutoDbMigration(ServerUpgradeStatus serverUpgradeStatus, DbClient dbClient, MigrationEngine migrationEngine, MigrationSteps migrationSteps) { + public AutoDbMigration(DefaultServerUpgradeStatus serverUpgradeStatus, DbClient dbClient, MigrationEngine migrationEngine, MigrationSteps migrationSteps) { this.serverUpgradeStatus = serverUpgradeStatus; this.dbClient = dbClient; this.migrationEngine = migrationEngine; @@ -53,15 +53,16 @@ public AutoDbMigration(ServerUpgradeStatus serverUpgradeStatus, DbClient dbClien @Override public void start() { - if (!serverUpgradeStatus.isFreshInstall()) { - return; - } - - Loggers.get(getClass()).info("Automatically perform DB migration on fresh install"); - Dialect dialect = dbClient.getDatabase().getDialect(); - if (H2.ID.equals(dialect.getId())) { - installH2(); - } else { + if (serverUpgradeStatus.isFreshInstall()) { + Loggers.get(getClass()).info("Automatically perform DB migration on fresh install"); + Dialect dialect = dbClient.getDatabase().getDialect(); + if (H2.ID.equals(dialect.getId())) { + installH2(); + } else { + migrationEngine.execute(); + } + } else if (serverUpgradeStatus.isUpgraded() && serverUpgradeStatus.isBlueGreen()) { + Loggers.get(getClass()).info("Automatically perform DB migration on blue/green deployment"); migrationEngine.execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java index 95a21163d633..a2de5fe0bfd4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java @@ -88,15 +88,14 @@ public void do_nothing_if_up_to_date() { } @Test - public void fail_if_upgrade_required_on_blue_green_deployment() { + public void upgrade_automatically_if_blue_green_deployment() { settings.setProperty("sonar.blueGreenEnabled", "true"); DatabaseVersion version = mock(DatabaseVersion.class); when(version.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE); when(version.getVersion()).thenReturn(Optional.of(DatabaseVersion.MIN_UPGRADE_VERSION)); - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Blue/green deployment is not supported. Database must be upgraded."); - new DatabaseServerCompatibility(version, settings.asConfig()).start(); + + assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerUpgradeStatusTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerUpgradeStatusTest.java index 22200ba9aed4..b385ae7983e7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerUpgradeStatusTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerUpgradeStatusTest.java @@ -22,6 +22,8 @@ import java.util.Optional; import org.junit.Before; import org.junit.Test; +import org.sonar.api.config.internal.ConfigurationBridge; +import org.sonar.api.config.internal.MapSettings; import org.sonar.server.platform.db.migration.step.MigrationSteps; import org.sonar.server.platform.db.migration.version.DatabaseVersion; @@ -33,7 +35,8 @@ public class DefaultServerUpgradeStatusTest { private static final long LAST_VERSION = 150; private MigrationSteps migrationSteps = mock(MigrationSteps.class); private DatabaseVersion dbVersion = mock(DatabaseVersion.class); - private DefaultServerUpgradeStatus underTest = new DefaultServerUpgradeStatus(dbVersion, migrationSteps); + private MapSettings settings = new MapSettings(); + private DefaultServerUpgradeStatus underTest = new DefaultServerUpgradeStatus(dbVersion, migrationSteps, new ConfigurationBridge(settings)); @Before public void setUp() throws Exception { @@ -73,4 +76,16 @@ public void shouldNotBeUpgraded() { assertThat(underTest.isUpgraded()).isFalse(); assertThat(underTest.getInitialDbVersion()).isEqualTo((int) LAST_VERSION); } + + @Test + public void isBlueGreen() { + settings.clear(); + assertThat(underTest.isBlueGreen()).isFalse(); + + settings.setProperty("sonar.blueGreenEnabled", true); + assertThat(underTest.isBlueGreen()).isTrue(); + + settings.setProperty("sonar.blueGreenEnabled", false); + assertThat(underTest.isBlueGreen()).isFalse(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java index 362688331736..7311a3f911a6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java @@ -24,7 +24,6 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; -import org.sonar.api.platform.ServerUpgradeStatus; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.db.DbClient; @@ -35,6 +34,7 @@ import org.sonar.db.dialect.MySql; import org.sonar.db.dialect.Oracle; import org.sonar.db.dialect.PostgreSql; +import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.db.migration.engine.MigrationEngine; import org.sonar.server.platform.db.migration.step.MigrationSteps; @@ -53,7 +53,7 @@ public class AutoDbMigrationTest { public LogTester logTester = new LogTester(); private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); - private ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); + private DefaultServerUpgradeStatus serverUpgradeStatus = mock(DefaultServerUpgradeStatus.class); private MigrationEngine migrationEngine = mock(MigrationEngine.class); private MigrationSteps migrationSteps = mock(MigrationSteps.class); private AutoDbMigration underTest = new AutoDbMigration(serverUpgradeStatus, dbClient, migrationEngine, migrationSteps); @@ -116,7 +116,31 @@ public void start_does_nothing_if_not_fresh_install() { verify(noRealH2Creation).start(); verifyNoMoreInteractions(noRealH2Creation); verifyZeroInteractions(migrationEngine); - assertThat(logTester.logs()).isEmpty(); + assertThat(logTester.logs(LoggerLevel.INFO)).isEmpty(); + } + + @Test + public void start_runs_MigrationEngine_if_blue_green_upgrade() { + mockFreshInstall(false); + when(serverUpgradeStatus.isUpgraded()).thenReturn(true); + when(serverUpgradeStatus.isBlueGreen()).thenReturn(true); + + underTest.start(); + + verify(migrationEngine).execute(); + assertThat(logTester.logs(LoggerLevel.INFO)).contains("Automatically perform DB migration on blue/green deployment"); + } + + @Test + public void start_does_nothing_if_blue_green_but_no_upgrade() { + mockFreshInstall(false); + when(serverUpgradeStatus.isUpgraded()).thenReturn(false); + when(serverUpgradeStatus.isBlueGreen()).thenReturn(true); + + underTest.start(); + + verifyZeroInteractions(migrationEngine); + assertThat(logTester.logs(LoggerLevel.INFO)).isEmpty(); } @Test