Add reactive health indicator.
Closes gh-221.
This commit is contained in:
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
@@ -28,7 +27,7 @@ import org.springframework.vault.support.VaultHealth;
|
||||
* @author Stuart Ingram
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultHealthIndicator implements HealthIndicator {
|
||||
public class VaultHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
|
||||
@@ -36,41 +35,38 @@ public class VaultHealthIndicator implements HealthIndicator {
|
||||
this.vaultOperations = vaultOperations;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Health health() {
|
||||
protected void doHealthCheck(Builder builder) {
|
||||
|
||||
try {
|
||||
|
||||
VaultHealth vaultHealthResponse = vaultOperations.opsForSys().health();
|
||||
|
||||
Builder healthBuilder = getHealthBuilder(vaultHealthResponse);
|
||||
if (!vaultHealthResponse.isInitialized()) {
|
||||
builder.down().withDetail("state", "Vault uninitialized");
|
||||
}
|
||||
else
|
||||
|
||||
if (StringUtils.hasText(vaultHealthResponse.getVersion())) {
|
||||
healthBuilder = healthBuilder.withDetail("version",
|
||||
vaultHealthResponse.getVersion());
|
||||
if (vaultHealthResponse.isSealed()) {
|
||||
builder.down().withDetail("state", "Vault sealed");
|
||||
}
|
||||
else
|
||||
|
||||
if (vaultHealthResponse.isStandby()) {
|
||||
builder.up().withDetail("state", "Vault in standby");
|
||||
}
|
||||
else {
|
||||
builder.up();
|
||||
}
|
||||
|
||||
return healthBuilder.build();
|
||||
if (StringUtils.hasText(vaultHealthResponse.getVersion())) {
|
||||
builder.withDetail("version",
|
||||
vaultHealthResponse.getVersion());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Health.down(e).build();
|
||||
builder.down(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Builder getHealthBuilder(VaultHealth vaultHealthResponse) {
|
||||
|
||||
if (!vaultHealthResponse.isInitialized()) {
|
||||
return Health.down().withDetail("state", "Vault uninitialized");
|
||||
}
|
||||
|
||||
if (vaultHealthResponse.isSealed()) {
|
||||
return Health.down().withDetail("state", "Vault sealed");
|
||||
}
|
||||
|
||||
if (vaultHealthResponse.isStandby()) {
|
||||
return Health.up().withDetail("state", "Vault in standby");
|
||||
}
|
||||
|
||||
return Health.up();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2016-2018 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.cloud.vault.config;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for Vault providing beans for the application context.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnEnabledHealthIndicator("vault")
|
||||
@ConditionalOnBean(VaultBootstrapConfiguration.class)
|
||||
@ConditionalOnClass(HealthIndicator.class)
|
||||
@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true)
|
||||
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
|
||||
@Import({ VaultHealthIndicatorConfiguration.class,
|
||||
VaultReactiveHealthIndicatorConfiguration.class })
|
||||
public class VaultHealthIndicatorAutoConfiguration {
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2018 the original author or authors.
|
||||
* Copyright 2018 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.
|
||||
@@ -18,33 +18,23 @@ package org.springframework.cloud.vault.config;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
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.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} for Vault providing beans for the application context.
|
||||
* Configuration for {@link VaultHealthIndicator}.
|
||||
*
|
||||
* @author Stuart Ingram
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(HealthIndicator.class)
|
||||
@ConditionalOnBean(VaultBootstrapConfiguration.class)
|
||||
@ConditionalOnEnabledHealthIndicator("vault")
|
||||
@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true)
|
||||
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
|
||||
public class VaultHealthIndicatorConfiguration extends
|
||||
@ConditionalOnBean(VaultOperations.class)
|
||||
class VaultHealthIndicatorConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<VaultHealthIndicator, VaultOperations> {
|
||||
|
||||
private final Map<String, VaultOperations> vaultTemplates;
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2018 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.cloud.vault.config;
|
||||
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Data;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.core.ReactiveVaultOperations;
|
||||
import org.springframework.vault.support.VaultHealth;
|
||||
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||
|
||||
/**
|
||||
* Reactive health indicator reporting Vault's availability.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public class VaultReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
|
||||
|
||||
private final ReactiveVaultOperations vaultOperations;
|
||||
|
||||
public VaultReactiveHealthIndicator(ReactiveVaultOperations vaultOperations) {
|
||||
this.vaultOperations = vaultOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Builder builder) {
|
||||
|
||||
try {
|
||||
|
||||
return vaultOperations
|
||||
.doWithSession(it -> it.get().uri("sys/health").exchange())
|
||||
.flatMap(it -> it.bodyToMono(VaultHealthImpl.class))
|
||||
.onErrorResume(WebClientResponseException.class,
|
||||
VaultReactiveHealthIndicator::deserializeError)
|
||||
.map(vaultHealthResponse -> {
|
||||
return getHealth(builder, vaultHealthResponse);
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Mono.just(builder.down(e).build());
|
||||
}
|
||||
}
|
||||
|
||||
private static Mono<? extends VaultHealthImpl> deserializeError(
|
||||
WebClientResponseException e) {
|
||||
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
return Mono.just(mapper.readValue(e.getResponseBodyAsByteArray(),
|
||||
VaultHealthImpl.class));
|
||||
}
|
||||
catch (Exception jsonError) {
|
||||
UndeclaredThrowableException t = new UndeclaredThrowableException(jsonError);
|
||||
t.addSuppressed(e);
|
||||
return Mono.error(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static Health getHealth(Builder builder, VaultHealthImpl vaultHealthResponse) {
|
||||
|
||||
if (!vaultHealthResponse.isInitialized()) {
|
||||
builder.withDetail("state", "Vault uninitialized");
|
||||
}
|
||||
else
|
||||
|
||||
if (vaultHealthResponse.isSealed()) {
|
||||
builder.down().withDetail("state", "Vault sealed");
|
||||
}
|
||||
else
|
||||
|
||||
if (vaultHealthResponse.isStandby()) {
|
||||
builder.up().withDetail("state", "Vault in standby");
|
||||
}
|
||||
else {
|
||||
builder.up();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(vaultHealthResponse.getVersion())) {
|
||||
builder.withDetail("version", vaultHealthResponse.getVersion());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class VaultHealthImpl implements VaultHealth {
|
||||
|
||||
private final boolean initialized;
|
||||
private final boolean sealed;
|
||||
private final boolean standby;
|
||||
private final int serverTimeUtc;
|
||||
|
||||
@Nullable
|
||||
private final String version;
|
||||
|
||||
private VaultHealthImpl(@JsonProperty("initialized") boolean initialized,
|
||||
@JsonProperty("sealed") boolean sealed,
|
||||
@JsonProperty("standby") boolean standby,
|
||||
@JsonProperty("server_time_utc") int serverTimeUtc,
|
||||
@Nullable @JsonProperty("version") String version) {
|
||||
|
||||
this.initialized = initialized;
|
||||
this.sealed = sealed;
|
||||
this.standby = standby;
|
||||
this.serverTimeUtc = serverTimeUtc;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2018 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.cloud.vault.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.vault.core.ReactiveVaultOperations;
|
||||
|
||||
/**
|
||||
* Configuration for {@link VaultReactiveHealthIndicator}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Flux.class)
|
||||
@ConditionalOnBean(ReactiveVaultOperations.class)
|
||||
class VaultReactiveHealthIndicatorConfiguration
|
||||
extends
|
||||
CompositeReactiveHealthIndicatorConfiguration<VaultReactiveHealthIndicator, ReactiveVaultOperations> {
|
||||
|
||||
private final Map<String, ReactiveVaultOperations> reactiveVaultTemplates;
|
||||
|
||||
public VaultReactiveHealthIndicatorConfiguration(
|
||||
Map<String, ReactiveVaultOperations> reactiveVaultTemplates) {
|
||||
this.reactiveVaultTemplates = reactiveVaultTemplates;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = { "vaultReactiveHealthIndicator" })
|
||||
public ReactiveHealthIndicator vaultHealthIndicator() {
|
||||
return this.createHealthIndicator(this.reactiveVaultTemplates);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Auto-Configuration
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.vault.config.VaultHealthIndicatorConfiguration
|
||||
org.springframework.cloud.vault.config.VaultHealthIndicatorAutoConfiguration
|
||||
# Bootstrap Configuration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.vault.config.DiscoveryClientVaultBootstrapConfiguration,\
|
||||
|
||||
Reference in New Issue
Block a user