]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-75 Automatic run of DB migrations on blue/green deployments
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 12 Jun 2018 22:08:48 +0000 (00:08 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 14 Jun 2018 18:20:53 +0000 (20:20 +0200)
server/sonar-server/src/main/java/org/sonar/server/platform/DatabaseServerCompatibility.java
server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerUpgradeStatus.java
server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java
server/sonar-server/src/test/java/org/sonar/server/platform/DatabaseServerCompatibilityTest.java
server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerUpgradeStatusTest.java
server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java

index dbb705fb6bba40ce328b661067c10692dfe31758..d252a90156a99f26c4bab16716808c32eb87f11c 100644 (file)
@@ -48,20 +48,19 @@ public class DatabaseServerCompatibility implements Startable {
       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<Long> 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);
+      }
     }
   }
 
index fa5e1945700dad51c2cf472d9981bd931b0be17b..211ca38efa2205cdaa9dfa723d2ba2c256ea86c2 100644 (file)
@@ -23,24 +23,25 @@ import java.util.Optional;
 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 final class DefaultServerUpgradeStatus implements ServerUpgradeStatus, St
     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();
index e6df46ba69d007bd80c24dfa81e99a66418b7b9d..ca387bae9325dd5bc0464b8f3edcff07b791fa6d 100644 (file)
@@ -25,13 +25,13 @@ import java.sql.PreparedStatement;
 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 @@ import org.sonar.server.platform.db.migration.step.MigrationSteps;
  * 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 class AutoDbMigration implements Startable {
 
   @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();
     }
   }
index 95a21163d633bf1c9508c28e64ab787610d8301a..a2de5fe0bfd4eada1460f267812131946a40fba2 100644 (file)
@@ -88,15 +88,14 @@ public class DatabaseServerCompatibilityTest {
   }
 
   @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();
   }
 }
index 22200ba9aed48888b280bfcb46cfb39a6481f665..b385ae7983e761117c1e1bece074a08055c046cf 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.server.platform;
 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 class DefaultServerUpgradeStatusTest {
     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();
+  }
 }
index 3626883317368ea52d598dc386fbb57b742323cd..7311a3f911a6a5ee2ef0d30d57352f58ea3f61fa 100644 (file)
@@ -24,7 +24,6 @@ import org.junit.Rule;
 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.MsSql;
 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 class AutoDbMigrationTest {
     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