aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2018-06-12 23:20:55 +0200
committerSonarTech <sonartech@sonarsource.com>2018-06-14 20:20:53 +0200
commitccf2766838c80bcd45c28e2bb6594fc6a2d92fac (patch)
tree65f74a9f666ef48b29fe8cb41fd32713079ef99a /server
parentb1bb97f72137393ee3ff96252869e848fbc65786 (diff)
downloadsonarqube-ccf2766838c80bcd45c28e2bb6594fc6a2d92fac.tar.gz
sonarqube-ccf2766838c80bcd45c28e2bb6594fc6a2d92fac.zip
SONARCLOUD-75 Support DB migrations compatible with blue/green deployment
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/SupportsBlueGreen.java36
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java37
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java53
3 files changed, 117 insertions, 9 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/SupportsBlueGreen.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/SupportsBlueGreen.java
new file mode 100644
index 00000000000..71b57333630
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/SupportsBlueGreen.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info 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.platform.db.migration;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark an instance of {@link org.sonar.server.platform.db.migration.step.MigrationStep}
+ * as compatible with blue/green deployment
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface SupportsBlueGreen {
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java
index 027008ac89b..e32359119ba 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImpl.java
@@ -19,40 +19,65 @@
*/
package org.sonar.server.platform.db.migration.engine;
+import java.util.List;
import java.util.Optional;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.utils.AnnotationUtils;
import org.sonar.core.platform.ComponentContainer;
+import org.sonar.process.ProcessProperties;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.history.MigrationHistory;
import org.sonar.server.platform.db.migration.step.MigrationSteps;
import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
+import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
+
+import static java.lang.String.format;
public class MigrationEngineImpl implements MigrationEngine {
private final MigrationHistory migrationHistory;
private final ComponentContainer serverContainer;
private final MigrationContainerPopulator populator;
private final MigrationSteps migrationSteps;
+ private final Configuration configuration;
public MigrationEngineImpl(MigrationHistory migrationHistory, ComponentContainer serverContainer,
- MigrationContainerPopulator populator, MigrationSteps migrationSteps) {
+ MigrationContainerPopulator populator, MigrationSteps migrationSteps, Configuration configuration) {
this.migrationHistory = migrationHistory;
this.serverContainer = serverContainer;
this.populator = populator;
this.migrationSteps = migrationSteps;
+ this.configuration = configuration;
}
@Override
public void execute() {
MigrationContainer migrationContainer = new MigrationContainerImpl(serverContainer, populator);
-
+ boolean blueGreen = configuration.getBoolean(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey()).orElse(false);
try {
MigrationStepsExecutor stepsExecutor = migrationContainer.getComponentByType(MigrationStepsExecutor.class);
Optional<Long> lastMigrationNumber = migrationHistory.getLastMigrationNumber();
- if (lastMigrationNumber.isPresent()) {
- stepsExecutor.execute(migrationSteps.readFrom(lastMigrationNumber.get() + 1));
- } else {
- stepsExecutor.execute(migrationSteps.readAll());
+
+ List<RegisteredMigrationStep> steps = lastMigrationNumber
+ .map(i -> migrationSteps.readFrom(i + 1))
+ .orElse(migrationSteps.readAll());
+
+ if (blueGreen) {
+ ensureSupportBlueGreen(steps);
}
+
+ stepsExecutor.execute(steps);
+
} finally {
migrationContainer.cleanup();
}
}
+
+ private static void ensureSupportBlueGreen(List<RegisteredMigrationStep> steps) {
+ for (RegisteredMigrationStep step : steps) {
+ if (AnnotationUtils.getAnnotation(step.getStepClass(), SupportsBlueGreen.class) == null) {
+ throw new IllegalStateException(format("All migrations canceled. #%d does not support blue/green deployment: %s",
+ step.getMigrationNumber(), step.getDescription()));
+ }
+ }
+ }
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java
index 9b82616da45..161e95ed149 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/engine/MigrationEngineImplTest.java
@@ -19,20 +19,28 @@
*/
package org.sonar.server.platform.db.migration.engine;
+import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
-import org.sonar.api.config.Configuration;
+import org.sonar.api.config.internal.ConfigurationBridge;
+import org.sonar.api.config.internal.MapSettings;
import org.sonar.core.platform.ComponentContainer;
+import org.sonar.process.ProcessProperties;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.history.MigrationHistory;
import org.sonar.server.platform.db.migration.step.MigrationStep;
import org.sonar.server.platform.db.migration.step.MigrationSteps;
import org.sonar.server.platform.db.migration.step.MigrationStepsExecutor;
import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
+import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
public class MigrationEngineImplTest {
@@ -47,8 +55,8 @@ public class MigrationEngineImplTest {
};
private MigrationSteps migrationSteps = mock(MigrationSteps.class);
- private Configuration configuration;
- private MigrationEngineImpl underTest = new MigrationEngineImpl(migrationHistory, serverContainer, populator, migrationSteps, configuration);
+ private MapSettings settings = new MapSettings();
+ private MigrationEngineImpl underTest = new MigrationEngineImpl(migrationHistory, serverContainer, populator, migrationSteps, new ConfigurationBridge(settings));
@Test
public void execute_execute_all_steps_of_there_is_no_last_migration_number() {
@@ -74,4 +82,43 @@ public class MigrationEngineImplTest {
verify(stepsExecutor).execute(steps);
}
+ @Test
+ public void execute_steps_in_blue_green_mode() {
+ settings.setProperty(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey(), true);
+ when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(50L));
+ List<RegisteredMigrationStep> steps = singletonList(new RegisteredMigrationStep(1, "doo", TestBlueGreenMigrationStep.class));
+ when(migrationSteps.readFrom(51)).thenReturn(steps);
+
+ underTest.execute();
+
+ verify(migrationSteps).readFrom(51);
+ verify(stepsExecutor).execute(steps);
+ }
+
+ @Test
+ public void fail_blue_green_execution_if_some_migrations_are_not_compatible() {
+ settings.setProperty(ProcessProperties.Property.BLUE_GREEN_ENABLED.getKey(), true);
+ when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(50L));
+ List<RegisteredMigrationStep> steps = asList(
+ new RegisteredMigrationStep(1, "foo", TestBlueGreenMigrationStep.class),
+ new RegisteredMigrationStep(2, "bar", MigrationStep.class));
+ when(migrationSteps.readFrom(51)).thenReturn(steps);
+
+ try {
+ underTest.execute();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("All migrations canceled. #2 does not support blue/green deployment: bar");
+ verifyZeroInteractions(stepsExecutor);
+ }
+ }
+
+ @SupportsBlueGreen
+ private static class TestBlueGreenMigrationStep implements MigrationStep {
+
+ @Override
+ public void execute() throws SQLException {
+
+ }
+ }
}