Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cassandra-migration-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package org.cognitor.cassandra.migration.spring;

import com.datastax.driver.core.Cluster;
import org.cognitor.cassandra.migration.Database;
import org.cognitor.cassandra.migration.MigrationRepository;
import org.cognitor.cassandra.migration.collector.FailOnDuplicatesCollector;
import org.cognitor.cassandra.migration.collector.IgnoreDuplicatesCollector;
import org.cognitor.cassandra.migration.keyspace.KeyspaceDefinition;
import org.cognitor.cassandra.migration.scanner.ScannerRegistry;
import org.cognitor.cassandra.migration.spring.health.MigrationStatus;
import org.cognitor.cassandra.migration.spring.scanner.SpringBootLocationScanner;
import org.cognitor.cassandra.migration.tasks.TaskChain;
import org.cognitor.cassandra.migration.tasks.TaskChainBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
Expand All @@ -28,41 +32,71 @@
@ConditionalOnClass(Cluster.class)
public class CassandraMigrationAutoConfiguration {
private final CassandraMigrationConfigurationProperties properties;
private final Cluster cluster;

@Autowired
public CassandraMigrationAutoConfiguration(CassandraMigrationConfigurationProperties properties) {
public CassandraMigrationAutoConfiguration(CassandraMigrationConfigurationProperties properties, Cluster cluster) {
this.properties = properties;
this.cluster = cluster;
}


@Bean
@Bean(initMethod = "execute")
@ConditionalOnBean(Cluster.class)
@ConditionalOnMissingBean(TaskChain.class)
public TaskChain migrationProcess(Cluster cluster) {
public TaskChain migrationProcess() {
if (properties.isEnabled()) {
return createMigrationTaskChain();
} else {
return createEmptyTaskChain();
}
}

private TaskChain createEmptyTaskChain() {
return new TaskChain();
}

private TaskChain createMigrationTaskChain() {
return new TaskChainBuilder(cluster,
migrationConfiguration(),
migrationRepository())
.buildTaskChain(migrationDatabase());
}

@Bean
org.cognitor.cassandra.migration.Configuration migrationConfiguration() {
if (!properties.hasKeyspaceName()) {
throw new IllegalStateException("Please specify ['cassandra.migration.keyspace-name'] in" +
" order to migrate your database");
}
KeyspaceDefinition keyspaceDefinition = new KeyspaceDefinition(properties.getKeyspaceName())
.with(properties.getReplicationStrategy());
return new TaskChainBuilder(cluster,
new org.cognitor.cassandra.migration.Configuration(keyspaceDefinition)
.setChecksumValidation(properties.isChecksumValidation())
return new org.cognitor.cassandra.migration.Configuration(keyspaceDefinition).setChecksumValidation(properties.isChecksumValidation())
.setValidateOnly(properties.isChecksumValidationOnly())
.setRecalculateChecksum(properties.isRecalculateChecksum())
.setRecalculateChecksumOnly(properties.isRecalculateChecksumOnly())
.setConsistencyLevel(properties.getConsistencyLevel())
.setCreateKeyspace(properties.isCreateKeyspace()),
createRepository())
.buildTaskChain();
.setCreateKeyspace(properties.isCreateKeyspace());
}

@Bean
Copy link
Owner

@patka patka May 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are using the bean in the HealthIndicator you should use it in the migrationTaskChain method as well by having it autowired. Otherwise you end up having two instances of that class. This is not necessarily bad but the idea of Spring is to have beans as Singletons unless explicitly stated otherwise.

Database migrationDatabase(){
return new Database(cluster, migrationConfiguration());
}

private MigrationRepository createRepository() {
@ConditionalOnMissingBean(MigrationRepository.class)
@Bean
MigrationRepository migrationRepository() {
ScannerRegistry registry = new ScannerRegistry();
registry.register(ScannerRegistry.JAR_SCHEME, new SpringBootLocationScanner());
if (properties.getStrategy() == ScriptCollectorStrategy.FAIL_ON_DUPLICATES) {
return new MigrationRepository(properties.getScriptLocation(), new FailOnDuplicatesCollector(), registry);
}
return new MigrationRepository(properties.getScriptLocation(), new IgnoreDuplicatesCollector(), registry);
}

@ConditionalOnClass(HealthIndicator.class)
@Bean
MigrationStatus migrationStatus() {
return new MigrationStatus(migrationRepository(), migrationDatabase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
@ConfigurationProperties(prefix = "cassandra.migration")
public class CassandraMigrationConfigurationProperties {
private boolean enabled = true;
private ScriptCollectorStrategy strategy = ScriptCollectorStrategy.FAIL_ON_DUPLICATES;
private String scriptLocation = MigrationRepository.DEFAULT_SCRIPT_PATH;
private String keyspaceName;
Expand All @@ -29,6 +30,14 @@ public class CassandraMigrationConfigurationProperties {
private boolean recalculateChecksum = false;
private ConsistencyLevel consistencyLevel = ConsistencyLevel.QUORUM;

public boolean isEnabled() {
return enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

/**
* @return The location of the migration scripts. Never null.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.cognitor.cassandra.migration.spring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.DependsOn;

@DependsOn("migrationProcess")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface AfterMigration {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.cognitor.cassandra.migration.spring.health;

import org.cognitor.cassandra.migration.Database;
import org.cognitor.cassandra.migration.MigrationRepository;
import org.cognitor.cassandra.migration.spring.CassandraMigrationConfigurationProperties;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@EnableConfigurationProperties(CassandraMigrationConfigurationProperties.class)
public class MigrationStatus implements HealthIndicator {

private final MigrationRepository migrationRepository;
private final Database migrationDatabase;

public MigrationStatus(MigrationRepository migrationRepository, Database database) {
this.migrationRepository = migrationRepository;
this.migrationDatabase = database;
}

@Override
public Health health() {
try {
int latestVersion = migrationRepository.getLatestVersion();
final int dbVersion = migrationDatabase.getVersion();

if(latestVersion != dbVersion) {
return Health.unknown()
.withDetail("databaseVersion", dbVersion)
.withDetail("sourceVersion", latestVersion)
.build();
} else {
return Health.up()
.withDetail("databaseVersion", dbVersion)
.withDetail("sourceVersion", latestVersion)
.build();
}
} catch (Throwable ex) {
return Health.unknown().withException(ex).build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.datastax.driver.core.ConsistencyLevel;
import org.junit.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.core.Is.is;
Expand Down Expand Up @@ -30,7 +32,7 @@ public void shouldPopulatePropertiesWhenPropertiesFileGiven() {
addEnvironment(context, "cassandra.migration.network-strategy.data-centers.boston=3");
addEnvironment(context, "cassandra.migration.network-strategy.data-centers.seattle=2");
addEnvironment(context, "cassandra.migration.network-strategy.data-centers.tokyo=2");
context.register(CassandraMigrationAutoConfiguration.class);
context.register(PropertiesTestConfiguration.class);
context.refresh();
CassandraMigrationConfigurationProperties properties =
context.getBean(CassandraMigrationConfigurationProperties.class);
Expand All @@ -49,12 +51,23 @@ public void shouldPopulatePropertiesWhenPropertiesFileGiven() {
public void shouldReturnDefaultValuesWhenNoOptionalPropertiesGiven() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(CassandraMigrationAutoConfiguration.class);
context.register(PropertiesTestConfiguration.class);
context.refresh();
CassandraMigrationConfigurationProperties properties =
context.getBean(CassandraMigrationConfigurationProperties.class);
assertThat(properties.hasKeyspaceName(), is(false));
assertThat(properties.getScriptLocation(), is(equalTo("cassandra/migration")));
assertThat(properties.getStrategy(), is(equalTo(ScriptCollectorStrategy.FAIL_ON_DUPLICATES)));
}
}

@Configuration
@EnableConfigurationProperties({CassandraMigrationConfigurationProperties.class})
static class PropertiesTestConfiguration {
private final CassandraMigrationConfigurationProperties properties;

public PropertiesTestConfiguration(CassandraMigrationConfigurationProperties properties) {
this.properties = properties;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public TaskChainBuilder(Cluster cluster, Configuration configuration, MigrationR

public TaskChain buildTaskChain() {
Database database = new Database(cluster, configuration);
return buildTaskChain(database);
}

public TaskChain buildTaskChain(Database database) {
TaskChain chain = new TaskChain();
if (configuration.isRecalculateChecksumOnly()) {
return chain.addTask(new RecalculateChecksumTask(database, migrationRepository));
Expand Down