From 80d38f46ff4aa636b4f86d4bb05b83a0690e5ab8 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 8 Oct 2016 20:48:14 +0200 Subject: [PATCH] Upgrade to Vault 0.6.2. Setup test run with Vault 0.5.3 to 0.6.2, guard tests accessing features available since specific versions. Fixes gh-44. --- .travis.yml | 8 + .../CassandraSecretIntegrationTests.java | 9 +- .../MongoSecretIntegrationTests.java | 7 +- .../databases/VaultConfigCassandraTests.java | 10 +- .../databases/VaultConfigMongoTests.java | 4 + .../RabbitMqSecretIntegrationTests.java | 2 + .../rabbitmq/VaultConfigRabbitMqTests.java | 4 + ...ultConfigCubbyholeAuthenticationTests.java | 10 +- .../cloud/vault/util/PrepareVault.java | 25 ++ .../cloud/vault/util/Version.java | 237 ++++++++++++++++++ src/test/bash/install_vault.sh | 2 +- 11 files changed, 308 insertions(+), 10 deletions(-) create mode 100644 spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Version.java diff --git a/.travis.yml b/.travis.yml index 31b3a2c5..23e56458 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,14 @@ addons: jdk: - oraclejdk8 +env: + matrix: + - VAULT_VER=0.5.2 + - VAULT_VER=0.5.3 + - VAULT_VER=0.6.0 + - VAULT_VER=0.6.1 + - VAULT_VER=0.6.2 + install: - mkdir -p download - test -f download/apache-cassandra-2.2.6-bin.tar.gz || wget http://www-eu.apache.org/dist/cassandra/2.2.6/apache-cassandra-2.2.6-bin.tar.gz -O download/apache-cassandra-2.2.6-bin.tar.gz diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java index 04157239..3bd77be9 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java @@ -20,12 +20,12 @@ import static org.junit.Assume.*; import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecretBackendMetadataFactory.*; import java.net.InetSocketAddress; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; + import org.springframework.cloud.vault.config.VaultConfigOperations; import org.springframework.cloud.vault.config.VaultConfigTemplate; import org.springframework.cloud.vault.config.VaultProperties; @@ -84,9 +84,14 @@ public class CassandraSecretIntegrationTests extends IntegrationTestSupport { String.format("%s/config/connection", cassandra.getBackend()), connection); + Map role = new HashMap<>(); + + role.put("creation_cql", CREATE_USER_AND_GRANT_CQL); + role.put("consistency", "All"); + vaultOperations.write( String.format("%s/roles/%s", cassandra.getBackend(), cassandra.getRole()), - Collections.singletonMap("creation_cql", CREATE_USER_AND_GRANT_CQL)); + role); configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MongoSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MongoSecretIntegrationTests.java index 10674c2e..21637a77 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MongoSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MongoSecretIntegrationTests.java @@ -26,12 +26,14 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; + import org.springframework.cloud.vault.config.VaultConfigOperations; import org.springframework.cloud.vault.config.VaultConfigTemplate; import org.springframework.cloud.vault.config.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.IntegrationTestSupport; import org.springframework.cloud.vault.util.Settings; +import org.springframework.cloud.vault.util.Version; import org.springframework.vault.core.VaultOperations; /** @@ -61,6 +63,7 @@ public class MongoSecretIntegrationTests extends IntegrationTestSupport { public void setUp() throws Exception { assumeTrue(CanConnect.to(new InetSocketAddress(MONGODB_HOST, MONGODB_PORT))); + assumeTrue(prepare().getVersion().isGreaterThanOrEqualTo(Version.parse("0.6.2"))); mongodb.setEnabled(true); mongodb.setRole("readonly"); @@ -88,8 +91,8 @@ public class MongoSecretIntegrationTests extends IntegrationTestSupport { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = configOperations - .read(forDatabase(mongodb)).getData(); + Map secretProperties = configOperations.read(forDatabase(mongodb)) + .getData(); assertThat(secretProperties).containsKeys("spring.data.mongodb.username", "spring.data.mongodb.password"); diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java index c179cf9c..1c69a8a6 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java @@ -20,13 +20,13 @@ import static org.junit.Assume.*; import java.net.InetSocketAddress; import java.sql.SQLException; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; @@ -91,8 +91,12 @@ public class VaultConfigCassandraTests { vaultOperations.write(String.format("%s/config/connection", "cassandra"), connection); - vaultOperations.write("cassandra/roles/readonly", - Collections.singletonMap("creation_cql", CREATE_USER_AND_GRANT_CQL)); + Map role = new HashMap<>(); + + role.put("creation_cql", CREATE_USER_AND_GRANT_CQL); + role.put("consistency", "All"); + + vaultOperations.write("cassandra/roles/readonly", role); } @Value("${spring.data.cassandra.username}") diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMongoTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMongoTests.java index b68c45b5..dfabe455 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMongoTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMongoTests.java @@ -36,6 +36,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.VaultRule; +import org.springframework.cloud.vault.util.Version; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.vault.core.VaultOperations; @@ -77,6 +78,9 @@ public class VaultConfigMongoTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); + assumeTrue(vaultRule.prepare().getVersion() + .isGreaterThanOrEqualTo(Version.parse("0.6.2"))); + if (!vaultRule.prepare().hasSecretBackend("mongodb")) { vaultRule.prepare().mountSecret("mongodb"); } diff --git a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java index be6037b3..1462b9c1 100644 --- a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java @@ -31,6 +31,7 @@ import org.springframework.cloud.vault.config.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.IntegrationTestSupport; import org.springframework.cloud.vault.util.Settings; +import org.springframework.cloud.vault.util.Version; import org.springframework.vault.core.VaultOperations; /** @@ -66,6 +67,7 @@ public class RabbitMqSecretIntegrationTests extends IntegrationTestSupport { assumeTrue(CanConnect .to(new InetSocketAddress(RABBITMQ_HOST, RABBITMQ_HTTP_MANAGEMENT_PORT))); + assumeTrue(prepare().getVersion().isGreaterThanOrEqualTo(Version.parse("0.6.2"))); rabbitmq.setEnabled(true); rabbitmq.setRole("readonly"); diff --git a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java index 1d13576f..6e39a41d 100644 --- a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.VaultRule; +import org.springframework.cloud.vault.util.Version; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.vault.core.VaultOperations; @@ -81,6 +82,9 @@ public class VaultConfigRabbitMqTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); + assumeTrue(vaultRule.prepare().getVersion() + .isGreaterThanOrEqualTo(Version.parse("0.6.2"))); + if (!vaultRule.prepare().hasSecretBackend("rabbitmq")) { vaultRule.prepare().mountSecret("rabbitmq"); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigCubbyholeAuthenticationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigCubbyholeAuthenticationTests.java index 20598ed4..a2fba55b 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigCubbyholeAuthenticationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigCubbyholeAuthenticationTests.java @@ -16,6 +16,7 @@ package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; +import static org.junit.Assume.*; import java.util.Collections; @@ -23,11 +24,13 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.vault.util.VaultRule; +import org.springframework.cloud.vault.util.Version; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -37,8 +40,8 @@ import org.springframework.vault.core.VaultOperations; import org.springframework.vault.support.VaultResponse; /** - * Integration test using config infrastructure with Cubbyhole authentication. In case this - * test should fail because of SSL make sure you run the test within the + * Integration test using config infrastructure with Cubbyhole authentication. In case + * this test should fail because of SSL make sure you run the test within the * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is * referenced with {@code ../work/keystore.jks}. * @@ -56,6 +59,9 @@ public class VaultConfigCubbyholeAuthenticationTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); + assumeTrue(vaultRule.prepare().getVersion() + .isGreaterThanOrEqualTo(Version.parse("0.6.1"))); + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); vaultOperations.write( diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java index 9ae113ae..391f3468 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java @@ -19,8 +19,10 @@ import java.util.Collections; import java.util.Map; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.vault.core.VaultOperations; import org.springframework.vault.core.VaultSysOperations; +import org.springframework.vault.support.VaultHealth; import org.springframework.vault.support.VaultInitializationRequest; import org.springframework.vault.support.VaultInitializationResponse; import org.springframework.vault.support.VaultMount; @@ -153,4 +155,27 @@ public class PrepareVault { public VaultOperations getVaultOperations() { return vaultOperations; } + + /** + * @return Vault version from the health check. Versions beginning from Vault 0.6.2 + * will expose a version number. + */ + public Version getVersion() { + + VaultHealth health = getVaultOperations().opsForSys().health(); + + if (StringUtils.hasText(health.getVersion())) { + + String version = health.getVersion(); + + // Migration code for Vault 0.6.1 + if (version.startsWith("Vault v")) { + version = version.substring(7); + } + + return Version.parse(version); + } + + return Version.parse("0.0.0"); + } } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Version.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Version.java new file mode 100644 index 00000000..a4e60a29 --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Version.java @@ -0,0 +1,237 @@ +/* + * 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.util; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Value object representing Version consisting of major, minor and bugfix part. + * + * @author Mark Paluch + */ +public class Version implements Comparable { + + private static final String VERSION_PARSE_ERROR = "Invalid version string! Could not parse segment %s within %s."; + + private final int major; + + private final int minor; + + private final int bugfix; + + private final int build; + + /** + * Creates a new {@link Version} from the given integer values. At least one value has + * to be given but a maximum of 4. + * + * @param parts must not be {@literal null} or empty. + */ + private Version(int... parts) { + + Assert.notNull(parts); + Assert.isTrue(parts.length > 0 && parts.length < 5); + + this.major = parts[0]; + this.minor = parts.length > 1 ? parts[1] : 0; + this.bugfix = parts.length > 2 ? parts[2] : 0; + this.build = parts.length > 3 ? parts[3] : 0; + + Assert.isTrue(major >= 0, "Major version must be greater or equal zero!"); + Assert.isTrue(minor >= 0, "Minor version must be greater or equal zero!"); + Assert.isTrue(bugfix >= 0, "Bugfix version must be greater or equal zero!"); + Assert.isTrue(build >= 0, "Build version must be greater or equal zero!"); + } + + /** + * Parses the given string representation of a version into a {@link Version} object. + * + * @param version must not be {@literal null} or empty. + * @return + */ + public static Version parse(String version) { + + Assert.hasText(version); + + String[] parts = version.trim().split("\\."); + int[] intParts = new int[parts.length]; + + for (int i = 0; i < parts.length; i++) { + + String input = i == parts.length - 1 ? parts[i].replaceAll("\\D.*", "") + : parts[i]; + + if (StringUtils.hasText(input)) { + try { + intParts[i] = Integer.parseInt(input); + } + catch (IllegalArgumentException o_O) { + throw new IllegalArgumentException( + String.format(VERSION_PARSE_ERROR, input, version), o_O); + } + } + } + + return new Version(intParts); + } + + /** + * Returns whether the current {@link Version} is greater (newer) than the given one. + * + * @param version + * @return + */ + public boolean isGreaterThan(Version version) { + return compareTo(version) > 0; + } + + /** + * Returns whether the current {@link Version} is greater (newer) or the same as the + * given one. + * + * @param version + * @return + */ + public boolean isGreaterThanOrEqualTo(Version version) { + return compareTo(version) >= 0; + } + + /** + * Returns whether the current {@link Version} is the same as the given one. + * + * @param version + * @return + */ + public boolean is(Version version) { + return equals(version); + } + + /** + * Returns whether the current {@link Version} is less (older) than the given one. + * + * @param version + * @return + */ + public boolean isLessThan(Version version) { + return compareTo(version) < 0; + } + + /** + * Returns whether the current {@link Version} is less (older) or equal to the current + * one. + * + * @param version + * @return + */ + public boolean isLessThanOrEqualTo(Version version) { + return compareTo(version) <= 0; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Version that) { + + if (that == null) { + return 1; + } + + if (major != that.major) { + return major - that.major; + } + + if (minor != that.minor) { + return minor - that.minor; + } + + if (bugfix != that.bugfix) { + return bugfix - that.bugfix; + } + + if (build != that.build) { + return build - that.build; + } + + return 0; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (!(obj instanceof Version)) { + return false; + } + + Version that = (Version) obj; + + return this.major == that.major && this.minor == that.minor + && this.bugfix == that.bugfix && this.build == that.build; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + + int result = 17; + result += 31 * major; + result += 31 * minor; + result += 31 * bugfix; + result += 31 * build; + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + + List digits = new ArrayList(); + digits.add(major); + digits.add(minor); + + if (build != 0 || bugfix != 0) { + digits.add(bugfix); + } + + if (build != 0) { + digits.add(build); + } + + return StringUtils.collectionToDelimitedString(digits, "."); + } +} \ No newline at end of file diff --git a/src/test/bash/install_vault.sh b/src/test/bash/install_vault.sh index 07f7f719..b1d911d2 100755 --- a/src/test/bash/install_vault.sh +++ b/src/test/bash/install_vault.sh @@ -6,7 +6,7 @@ ########################################################################### -VAULT_VER="${VAULT_VER:-0.6.1}" +VAULT_VER="${VAULT_VER:-0.6.2}" UNAME=$(uname -s | tr '[:upper:]' '[:lower:]') VAULT_ZIP="vault_${VAULT_VER}_${UNAME}_amd64.zip" IGNORE_CERTS="${IGNORE_CERTS:-no}"