Skip to content
Merged
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
13 changes: 8 additions & 5 deletions src/main/java/io/github/jopenlibs/vault/api/Logical.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ private LogicalResponse read(final String path, final logicalOperations operatio
.sslContext(config.getSslConfig().getSslContext())
.get();

// Validate response - don't treat 4xx class errors as exceptions, we want to return an error as the response
// Validate response - don't treat 4xx class errors as exceptions (except 412), we want to return an error as the response
// 412 (Precondition Failed) should be retried
if (restResponse.getStatus() != 200 && !(restResponse.getStatus() >= 400
&& restResponse.getStatus() < 500)) {
&& restResponse.getStatus() < 500 && restResponse.getStatus() != 412)) {
throw new VaultException(
"Vault responded with HTTP status code: " + restResponse.getStatus()
+ "\nResponse body: " + new String(restResponse.getBody(),
Expand Down Expand Up @@ -157,9 +158,10 @@ public LogicalResponse read(final String path, Boolean shouldRetry, final Intege
.sslContext(config.getSslConfig().getSslContext())
.get();

// Validate response - don't treat 4xx class errors as exceptions, we want to return an error as the response
// Validate response - don't treat 4xx class errors as exceptions (except 412), we want to return an error as the response
// 412 (Precondition Failed) should be retried
if (restResponse.getStatus() != 200 && !(restResponse.getStatus() >= 400
&& restResponse.getStatus() < 500)) {
&& restResponse.getStatus() < 500 && restResponse.getStatus() != 412)) {
throw new VaultException(
"Vault responded with HTTP status code: " + restResponse.getStatus()
+ "\nResponse body: " + new String(restResponse.getBody(),
Expand Down Expand Up @@ -297,9 +299,10 @@ private LogicalResponse write(final String path, final Map<String, Object> nameV
.post();

// HTTP Status should be either 200 (with content - e.g. PKI write) or 204 (no content)
// 412 (Precondition Failed) should be retried, so exclude it from the 4xx pass-through
final int restStatus = restResponse.getStatus();
if (restStatus == 200 || restStatus == 204 || (restResponse.getStatus() >= 400
&& restResponse.getStatus() < 500)) {
&& restResponse.getStatus() < 500 && restResponse.getStatus() != 412)) {
return new LogicalResponse(restResponse, attempt, operation);
} else {
throw new VaultException(
Expand Down
72 changes: 72 additions & 0 deletions src/test/java/io/github/jopenlibs/vault/RetryTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,76 @@ public void testRetries_Write() throws Exception {
VaultTestUtils.shutdownMockVault(server);
}

@Test
public void testRetries_Read_412() throws Exception {
final RetriesMockVault retriesMockVault = new RetriesMockVault(3, 412, 200,
"{\"lease_id\":\"12345\",\"renewable\":false,\"lease_duration\":10000,\"data\":{\"value\":\"mock\"}}");
final Server server = VaultTestUtils.initHttpMockVault(retriesMockVault);
server.start();

final VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999")
.token("mock_token").engineVersion(1).build();
final Vault vault = Vault.create(vaultConfig);
final LogicalResponse response = vault.withRetries(5, 100).logical().read("secret/hello");
assertEquals(3, response.getRetries());
assertEquals("mock", response.getData().get("value"));

VaultTestUtils.shutdownMockVault(server);
}

@Test
public void testRetries_Write_412() throws Exception {
final RetriesMockVault retriesMockVault = new RetriesMockVault(3, 412, 204, null);
final Server server = VaultTestUtils.initHttpMockVault(retriesMockVault);
server.start();

final VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999")
.token("mock_token").build();
final Vault vault = Vault.create(vaultConfig);
final LogicalResponse response = vault.withRetries(5, 100).logical()
.write("secret/hello", new HashMap<String, Object>() {{
put("value", "world");
}});
assertEquals(3, response.getRetries());

VaultTestUtils.shutdownMockVault(server);
}

@Test
public void testNoRetries_Read_404() throws Exception {
final RetriesMockVault retriesMockVault = new RetriesMockVault(1, 404, 404,
"{\"errors\":[\"Not found\"]}");
final Server server = VaultTestUtils.initHttpMockVault(retriesMockVault);
server.start();

final VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999")
.token("mock_token").engineVersion(1).build();
final Vault vault = Vault.create(vaultConfig);
final LogicalResponse response = vault.withRetries(5, 100).logical().read("secret/hello");
assertEquals(0, response.getRetries());
assertEquals(404, response.getRestResponse().getStatus());

VaultTestUtils.shutdownMockVault(server);
}

@Test
public void testNoRetries_Write_400() throws Exception {
final RetriesMockVault retriesMockVault = new RetriesMockVault(1, 400, 400,
"{\"errors\":[\"Bad request\"]}");
final Server server = VaultTestUtils.initHttpMockVault(retriesMockVault);
server.start();

final VaultConfig vaultConfig = new VaultConfig().address("http://127.0.0.1:8999")
.token("mock_token").build();
final Vault vault = Vault.create(vaultConfig);
final LogicalResponse response = vault.withRetries(5, 100).logical()
.write("secret/hello", new HashMap<String, Object>() {{
put("value", "world");
}});
assertEquals(0, response.getRetries());
assertEquals(400, response.getRestResponse().getStatus());

VaultTestUtils.shutdownMockVault(server);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
* <ol>
* <li>
* <code>RetriesMockVault</code> responds with HTTP 500 status codes to a designated number of requests (which
* <code>RetriesMockVault</code> responds with a specified HTTP status code to a designated number of requests (which
* can be zero). This can be used to test retry logic.
* </li>
* <li>
Expand Down Expand Up @@ -46,11 +46,18 @@ public class RetriesMockVault extends MockVault {

private final int mockStatus;
private final String mockResponse;
private final int failureStatus;
private int failureCount;

public RetriesMockVault(final int failureCount, final int mockStatus,
final String mockResponse) {
this(failureCount, 500, mockStatus, mockResponse);
}

public RetriesMockVault(final int failureCount, final int failureStatus,
final int mockStatus, final String mockResponse) {
this.failureCount = failureCount;
this.failureStatus = failureStatus;
this.mockStatus = mockStatus;
this.mockResponse = mockResponse;
}
Expand All @@ -66,8 +73,8 @@ public void handle(
baseRequest.setHandled(true);
if (failureCount > 0) {
failureCount = failureCount - 1;
response.setStatus(500);
System.out.println("RetriesMockVault is sending an HTTP 500 code, to cause a retry...");
response.setStatus(failureStatus);
System.out.println("RetriesMockVault is sending an HTTP " + failureStatus + " code, to trigger retry logic...");
} else {
System.out.println("RetriesMockVault is sending an HTTP " + mockStatus
+ " code, with expected success payload...");
Expand Down
Loading