Polishing

Reformat code. Use state key for health indicator details. Add health method declaration to VaultOperations. Switch actuator dependency to optional dependency. Add tests.

Original pull request: gh-29
Fixes gh-24
This commit is contained in:
Mark Paluch
2016-08-27 07:51:05 +02:00
parent a747663447
commit d1e710bd7f
7 changed files with 145 additions and 35 deletions

View File

@@ -24,6 +24,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>

View File

@@ -39,7 +39,8 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnExpression("${health.vault.enabled:true}")
@AutoConfigureBefore({ EndpointAutoConfiguration.class })
@AutoConfigureAfter({ HealthIndicatorAutoConfiguration.class })
public class VaultConfigBootstrapHealthIndicator{
public class VaultConfigBootstrapHealthIndicator {
@Bean
@ConditionalOnMissingBean(name = "vaultHealthIndicator")
public HealthIndicator vaultHealthIndicator() {

View File

@@ -24,27 +24,34 @@ import org.springframework.cloud.vault.VaultHealthResponse;
* @author Stuart Ingram
*/
public class VaultHealthIndicator implements HealthIndicator {
@Autowired
private VaultTemplate vaultTemplate;
@Override
public Health health() {
try {
VaultHealthResponse vaultHealthResponse = vaultTemplate.health();
if(!vaultHealthResponse.isInitialized()) {
return Health.down().withDetail("Vault uninitialized",null).build();
} else if (vaultHealthResponse.isSealed()) {
return Health.down().withDetail("Vault sealed",null).build();
} else if (vaultHealthResponse.isStandby()) {
return Health.outOfService().withDetail("Vault in standby",null).build();
} else {
return Health.up().build();
if (!vaultHealthResponse.isInitialized()) {
return Health.down().withDetail("state", "Vault uninitialized").build();
}
if (vaultHealthResponse.isSealed()) {
return Health.down().withDetail("state", "Vault sealed").build();
}
if (vaultHealthResponse.isStandby()) {
return Health.outOfService().withDetail("state", "Vault in standby").build();
}
return Health.up().build();
}
catch(Exception e) {
catch (Exception e) {
return Health.down().build();
}
}
}

View File

@@ -19,6 +19,7 @@ import java.net.URI;
import java.util.Map;
import org.springframework.cloud.vault.VaultClientResponse;
import org.springframework.cloud.vault.VaultHealthResponse;
/**
* Interface that specified a basic set of Vault operations, implemented by
@@ -57,6 +58,13 @@ public interface VaultOperations {
<T> T doWithVault(String pathTemplate, Map<String, ?> variables,
SessionCallback sessionCallback);
/**
* Query the current Vault service for it's health status.
*
* @return A {@link VaultHealthResponse} containing the current service status.
*/
VaultHealthResponse health();
/**
* Callback to execute actions within an authenticated {@link VaultSession}.
*

View File

@@ -35,6 +35,8 @@ import org.springframework.util.Assert;
*/
public class VaultTemplate implements InitializingBean, VaultOperations {
private final static String HEALTH_URL_TEMPLATE = "sys/health";
private final VaultProperties properties;
private final VaultClient client;
private final ClientAuthentication clientAuthentication;
@@ -100,7 +102,7 @@ public class VaultTemplate implements InitializingBean, VaultOperations {
Assert.notNull(sessionCallback, "SessionCallback must not be null!");
URI uri = client.buildUri(properties, path);
URI uri = VaultClient.buildUri(properties, path);
return sessionCallback.doWithVault(uri, vaultSession);
}
@@ -114,29 +116,10 @@ public class VaultTemplate implements InitializingBean, VaultOperations {
return sessionCallback.doWithVault(uri, vaultSession);
}
private final static String HEALTH_URL_TEMPLATE = "sys/health";
/**
* Query the current Vault service for it's health status
*
* @return A {@link VaultHealthResponse} containing the current service status.
*/
@Override
public VaultHealthResponse health() {
URI uri = client.buildUri(properties, HEALTH_URL_TEMPLATE);
URI uri = VaultClient.buildUri(properties, HEALTH_URL_TEMPLATE);
return client.health(uri);
}
/**
* Check whether Vault is available (vault created and unsealed).
*
* @return
*/
public boolean isAvailable() {
try{
VaultHealthResponse health = health();
return health.isInitialized() && !health.isSealed();
} catch(Exception e) {
return false;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2016 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 static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.cloud.vault.VaultHealthResponse;
/**
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class VaultHealthIndicatorUnitTests {
@InjectMocks
VaultHealthIndicator healthIndicator = new VaultHealthIndicator();
@Mock
VaultTemplate vaultTemplate;
@Test
public void shouldReportHealthyService() throws Exception {
VaultHealthResponse healthResponse = new VaultHealthResponse();
healthResponse.setInitialized(true);
when(vaultTemplate.health()).thenReturn(healthResponse);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.UP);
assertThat(health.getDetails()).isEmpty();
}
@Test
public void shouldReportSealedService() throws Exception {
VaultHealthResponse healthResponse = new VaultHealthResponse();
healthResponse.setInitialized(true);
healthResponse.setSealed(true);
when(vaultTemplate.health()).thenReturn(healthResponse);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("state", "Vault sealed");
}
@Test
public void shouldReportUninitializedService() throws Exception {
VaultHealthResponse healthResponse = new VaultHealthResponse();
when(vaultTemplate.health()).thenReturn(healthResponse);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).containsEntry("state", "Vault uninitialized");
}
@Test
public void shouldReportStandbyService() throws Exception {
VaultHealthResponse healthResponse = new VaultHealthResponse();
healthResponse.setInitialized(true);
healthResponse.setStandby(true);
when(vaultTemplate.health()).thenReturn(healthResponse);
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
assertThat(health.getDetails()).containsEntry("state", "Vault in standby");
}
@Test
public void exceptionsShouldReportDownStatus() throws Exception {
when(vaultTemplate.health()).thenThrow(new IllegalStateException());
Health health = healthIndicator.health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
assertThat(health.getDetails()).isEmpty();
}
}

View File

@@ -21,16 +21,18 @@ import lombok.Data;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Value object to bind HTTP API responses for sys/health
* Value object to bind HTTP API responses for sys/health.
*
* @author Stuart Ingram
* @author Bill Koch
*/
@Data
public class VaultHealthResponse {
private boolean initialized;
private boolean sealed;
private boolean standby;
@JsonProperty("server_time_utc")
private int serverTimeUtc;
}