Add 'flyway' and 'liquibase' actuator endpoints
Add `/flyway` and `/liquibase` actuator endpoints to provide details of any database migrations that have been applied. Fixes gh-3434 Closes gh-3435
This commit is contained in:
parent
7e58483ead
commit
3995c16ba6
|
|
@ -112,6 +112,11 @@
|
|||
<artifactId>activemq-broker</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
|
@ -122,6 +127,11 @@
|
|||
<artifactId>infinispan-spring4</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.liquibase</groupId>
|
||||
<artifactId>liquibase-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint;
|
||||
|
|
@ -33,8 +36,10 @@ import org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEn
|
|||
import org.springframework.boot.actuate.endpoint.DumpEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.FlywayEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
|
|
@ -45,12 +50,15 @@ import org.springframework.boot.actuate.health.HealthIndicator;
|
|||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.bind.PropertiesConfigurationFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
@ -70,8 +78,10 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
|||
* @author Greg Turnquist
|
||||
* @author Christian Dupuis
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
|
||||
public class EndpointAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
|
@ -161,6 +171,32 @@ public class EndpointAutoConfiguration {
|
|||
return new ConfigurationPropertiesReportEndpoint();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Flyway.class)
|
||||
@ConditionalOnClass(Flyway.class)
|
||||
static class FlywayEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public FlywayEndpoint flywayEndpoint(Flyway flyway) {
|
||||
return new FlywayEndpoint(flyway);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(SpringLiquibase.class)
|
||||
@ConditionalOnClass(SpringLiquibase.class)
|
||||
static class LiquibaseEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LiquibaseEndpoint liquibaseEndpoint(SpringLiquibase liquibase) {
|
||||
return new LiquibaseEndpoint(liquibase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(AbstractHandlerMethodMapping.class)
|
||||
protected static class RequestMappingEndpointConfiguration {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.flywaydb.core.api.MigrationInfo;
|
||||
import org.flywaydb.core.api.MigrationState;
|
||||
import org.flywaydb.core.api.MigrationType;
|
||||
import org.springframework.boot.actuate.endpoint.FlywayEndpoint.FlywayMigration;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose flyway info.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.flyway", ignoreUnknownFields = true)
|
||||
public class FlywayEndpoint extends AbstractEndpoint<List<FlywayMigration>> {
|
||||
|
||||
private final Flyway flyway;
|
||||
|
||||
public FlywayEndpoint(Flyway flyway) {
|
||||
super("flyway");
|
||||
Assert.notNull(flyway, "Flyway must not be null");
|
||||
this.flyway = flyway;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlywayMigration> invoke() {
|
||||
List<FlywayMigration> migrations = new ArrayList<FlywayMigration>();
|
||||
for (MigrationInfo info : this.flyway.info().all()) {
|
||||
migrations.add(new FlywayMigration(info));
|
||||
}
|
||||
return migrations;
|
||||
}
|
||||
|
||||
public static class FlywayMigration {
|
||||
|
||||
private MigrationType type;
|
||||
|
||||
private Integer checksum;
|
||||
|
||||
private String version;
|
||||
|
||||
private String description;
|
||||
|
||||
private String script;
|
||||
|
||||
private MigrationState state;
|
||||
|
||||
private Date installedOn;
|
||||
|
||||
private Integer executionTime;
|
||||
|
||||
public FlywayMigration(MigrationInfo info) {
|
||||
this.type = info.getType();
|
||||
this.checksum = info.getChecksum();
|
||||
this.version = info.getVersion().toString();
|
||||
this.description = info.getDescription();
|
||||
this.script = info.getScript();
|
||||
this.state = info.getState();
|
||||
this.installedOn = info.getInstalledOn();
|
||||
this.executionTime = info.getExecutionTime();
|
||||
}
|
||||
|
||||
public MigrationType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public Integer getChecksum() {
|
||||
return this.checksum;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return this.script;
|
||||
}
|
||||
|
||||
public MigrationState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
public Date getInstalledOn() {
|
||||
return this.installedOn;
|
||||
}
|
||||
|
||||
public Integer getExecutionTime() {
|
||||
return this.executionTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import liquibase.changelog.StandardChangeLogHistoryService;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Endpoint} to expose liquibase info.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "endpoints.liquibase", ignoreUnknownFields = true)
|
||||
public class LiquibaseEndpoint extends AbstractEndpoint<List<Map<String, ?>>> {
|
||||
|
||||
private final SpringLiquibase liquibase;
|
||||
|
||||
public LiquibaseEndpoint(SpringLiquibase liquibase) {
|
||||
super("liquibase");
|
||||
Assert.notNull(liquibase, "Liquibase must not be null");
|
||||
this.liquibase = liquibase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, ?>> invoke() {
|
||||
StandardChangeLogHistoryService service = new StandardChangeLogHistoryService();
|
||||
try {
|
||||
DatabaseFactory factory = DatabaseFactory.getInstance();
|
||||
DataSource dataSource = this.liquibase.getDataSource();
|
||||
JdbcConnection connection = new JdbcConnection(dataSource.getConnection());
|
||||
Database database = factory.findCorrectDatabaseImplementation(connection);
|
||||
return service.queryDatabaseChangeLogTable(database);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to get Liquibase changelog", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -26,8 +26,10 @@ import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint
|
|||
import org.springframework.boot.actuate.endpoint.BeansEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.DumpEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.FlywayEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.LiquibaseEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
|
|
@ -36,7 +38,9 @@ import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
|||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.metrics.Metric;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
|
@ -55,6 +59,7 @@ import static org.junit.Assert.assertTrue;
|
|||
* @author Greg Turnquist
|
||||
* @author Christian Dupuis
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class EndpointAutoConfigurationTests {
|
||||
|
||||
|
|
@ -156,6 +161,28 @@ public class EndpointAutoConfigurationTests {
|
|||
assertNull(endpoint.invoke().get("git"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlywayEndpoint() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
FlywayAutoConfiguration.class, EndpointAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
FlywayEndpoint endpoint = this.context.getBean(FlywayEndpoint.class);
|
||||
assertNotNull(endpoint);
|
||||
assertEquals(1, endpoint.invoke().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiquibaseEndpoint() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class, EndpointAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
LiquibaseEndpoint endpoint = this.context.getBean(LiquibaseEndpoint.class);
|
||||
assertNotNull(endpoint);
|
||||
assertEquals(1, endpoint.invoke().size());
|
||||
}
|
||||
|
||||
private void load(Class<?>... config) {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
this.context.register(config);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link FlywayEndpoint}.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class FlywayEndpointTests extends AbstractEndpointTests<FlywayEndpoint> {
|
||||
|
||||
public FlywayEndpointTests() {
|
||||
super(Config.class, FlywayEndpoint.class, "flyway", true, "endpoints.flyway");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invoke() throws Exception {
|
||||
assertThat(getEndpointBean().invoke().size(), is(1));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ EmbeddedDataSourceConfiguration.class, FlywayAutoConfiguration.class })
|
||||
public static class Config {
|
||||
|
||||
@Autowired
|
||||
private Flyway flyway;
|
||||
|
||||
@Bean
|
||||
public FlywayEndpoint endpoint() {
|
||||
return new FlywayEndpoint(this.flyway);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import liquibase.integration.spring.SpringLiquibase;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link LiquibaseEndpoint}.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class LiquibaseEndpointTests extends AbstractEndpointTests<LiquibaseEndpoint> {
|
||||
|
||||
public LiquibaseEndpointTests() {
|
||||
super(Config.class, LiquibaseEndpoint.class, "liquibase", true,
|
||||
"endpoints.liquibase");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invoke() throws Exception {
|
||||
assertThat(getEndpointBean().invoke().size(), is(1));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ EmbeddedDataSourceConfiguration.class, LiquibaseAutoConfiguration.class })
|
||||
public static class Config {
|
||||
|
||||
@Autowired
|
||||
private SpringLiquibase liquibase;
|
||||
|
||||
@Bean
|
||||
public LiquibaseEndpoint endpoint() {
|
||||
return new LiquibaseEndpoint(this.liquibase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: 1
|
||||
author: marceloverdijk
|
||||
changes:
|
||||
- createTable:
|
||||
tableName: customer
|
||||
columns:
|
||||
- column:
|
||||
name: id
|
||||
type: int
|
||||
autoIncrement: true
|
||||
constraints:
|
||||
primaryKey: true
|
||||
nullable: false
|
||||
- column:
|
||||
name: name
|
||||
type: varchar(50)
|
||||
constraints:
|
||||
nullable: false
|
||||
Loading…
Reference in New Issue