Add fail-fast option.
Fixes gh-3.
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.vault;
|
||||
|
||||
import static com.sun.org.apache.xalan.internal.xsltc.compiler.sym.error;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -24,11 +26,13 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.Value;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import org.springframework.cloud.vault.VaultProperties.AppIdProperties;
|
||||
import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -40,6 +44,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@CommonsLog
|
||||
public class VaultClient {
|
||||
|
||||
public static final String API_VERSION = "v1";
|
||||
@@ -61,6 +66,10 @@ public class VaultClient {
|
||||
String url = buildUrl();
|
||||
|
||||
HttpHeaders headers = createHeaders(vaultToken);
|
||||
Exception error = null;
|
||||
String errorBody = null;
|
||||
|
||||
log.info(String.format("Fetching config from server at: %s", url));
|
||||
try {
|
||||
ResponseEntity<VaultResponse> response = this.rest.exchange(url,
|
||||
HttpMethod.GET, new HttpEntity<>(headers), VaultResponse.class,
|
||||
@@ -68,16 +77,30 @@ public class VaultClient {
|
||||
|
||||
HttpStatus status = response.getStatusCode();
|
||||
if (status == HttpStatus.OK) {
|
||||
if(response.getBody().getData() != null){
|
||||
if (response.getBody().getData() != null) {
|
||||
return secureBackendAccessor.transformProperties(response.getBody().getData());
|
||||
}
|
||||
}
|
||||
} catch (HttpStatusCodeException e) {
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
catch (HttpServerErrorException e) {
|
||||
error = e;
|
||||
if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders()
|
||||
.getContentType())) {
|
||||
errorBody = e.getResponseBodyAsString();
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (properties.isFailFast()) {
|
||||
throw new IllegalStateException(
|
||||
"Could not locate PropertySource and the fail fast property is set, failing",
|
||||
error);
|
||||
}
|
||||
|
||||
log.warn(String.format("Could not locate PropertySource: %s"
|
||||
, (errorBody == null ? error==null ? "key not found" : error.getMessage() : errorBody)));
|
||||
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@@ -70,6 +70,11 @@ public class VaultProperties {
|
||||
@NotEmpty
|
||||
private String profileSeparator = ",";
|
||||
|
||||
/**
|
||||
* Fail fast if data cannot be obtained from Vault.
|
||||
*/
|
||||
private boolean failFast = false;
|
||||
|
||||
/**
|
||||
* Static vault token. Required if {@link #authentication} is {@code TOKEN}.
|
||||
*/
|
||||
|
||||
@@ -18,13 +18,13 @@ package org.springframework.cloud.vault;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
import org.springframework.cloud.vault.VaultProperties.AppIdProperties;
|
||||
import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Mark Paluch
|
||||
@@ -36,10 +36,11 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultClient> {
|
||||
|
||||
private String context;
|
||||
private Map<String, String> properties = new LinkedHashMap<>();
|
||||
|
||||
|
||||
private transient VaultState vaultState;
|
||||
|
||||
public VaultPropertySource(String context, VaultClient source, VaultProperties properties, VaultState state) {
|
||||
public VaultPropertySource(String context, VaultClient source,
|
||||
VaultProperties properties, VaultState state) {
|
||||
super(context, source);
|
||||
this.context = context;
|
||||
this.vaultProperties = properties;
|
||||
@@ -62,8 +63,19 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultClient> {
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(String.format("Unable to read properties from vault for %s ",
|
||||
accessor.variables()), e);
|
||||
|
||||
String message = String.format(
|
||||
"Unable to read properties from vault for %s ",
|
||||
accessor.variables());
|
||||
if (vaultProperties.isFailFast()) {
|
||||
if (e instanceof RuntimeException) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
throw new IllegalStateException(message, e);
|
||||
}
|
||||
|
||||
log.error(message, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,17 +88,17 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultClient> {
|
||||
this.context));
|
||||
|
||||
VaultProperties.MySql mySql = vaultProperties.getMysql();
|
||||
if(mySql.isEnabled()){
|
||||
if (mySql.isEnabled()) {
|
||||
accessors.add(SecureBackendAccessors.database(mySql));
|
||||
}
|
||||
|
||||
VaultProperties.PostgreSql postgreSql = vaultProperties.getPostgresql();
|
||||
if(postgreSql.isEnabled()){
|
||||
if (postgreSql.isEnabled()) {
|
||||
accessors.add(SecureBackendAccessors.database(postgreSql));
|
||||
}
|
||||
|
||||
VaultProperties.Cassandra cassandra = vaultProperties.getCassandra();
|
||||
if(cassandra.isEnabled()){
|
||||
if (cassandra.isEnabled()) {
|
||||
accessors.add(SecureBackendAccessors.database(cassandra));
|
||||
}
|
||||
return accessors;
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultClient} using the generic secret backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class GenericSecretIntegrationTests extends AbstractIntegrationTests {
|
||||
@@ -39,6 +40,7 @@ public class GenericSecretIntegrationTests extends AbstractIntegrationTests {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
vaultProperties.setFailFast(false);
|
||||
prepare().writeSecret("app-name", (Map) createData());
|
||||
vaultClient.setRest(new RestTemplate());
|
||||
}
|
||||
@@ -55,6 +57,17 @@ public class GenericSecretIntegrationTests extends AbstractIntegrationTests {
|
||||
@Test
|
||||
public void shouldReturnNullIfNotFound() throws Exception {
|
||||
|
||||
Map<String, String> secretProperties = vaultClient
|
||||
.read(generic(vaultProperties, "missing"), createToken());
|
||||
|
||||
assertThat(secretProperties).isEmpty();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void shouldFailOnFailFast() throws Exception {
|
||||
|
||||
vaultProperties.setFailFast(true);
|
||||
|
||||
Map<String, String> secretProperties = vaultClient
|
||||
.read(generic(vaultProperties, "missing"), createToken());
|
||||
|
||||
@@ -85,5 +98,4 @@ public class GenericSecretIntegrationTests extends AbstractIntegrationTests {
|
||||
data.put("boolean", "true");
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.configclient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
||||
/**
|
||||
* Tests for fail fast option.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class ApplicationFailFastTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
try {
|
||||
new SpringApplicationBuilder().sources(ApplicationFailFastTests.class).run(
|
||||
"--server.port=0", "--spring.cloud.vault.failFast=true",
|
||||
"--spring.cloud.vault.port=9999");
|
||||
fail("failFast option did not produce an exception");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e).hasMessageContaining("fail fast");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user