Skip to content
This repository has been archived by the owner on Jan 25, 2023. It is now read-only.

Commit

Permalink
Merge pull request #92 from hashicorp/test/enterprise-install
Browse files Browse the repository at this point in the history
Add test for Vault Enterprise install
  • Loading branch information
Etiene authored Aug 30, 2018
2 parents c7b782b + 28212b8 commit 43d5e86
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 12 deletions.
10 changes: 5 additions & 5 deletions examples/vault-consul-ami/vault-consul.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"variables": {
"aws_region": "us-east-1",
"vault_version": "0.10.4",
"consul_module_version": "v0.3.7",
"consul_module_version": "v0.3.10",
"consul_version": "1.2.2",
"consul_download_url": "",
"vault_download_url": "",
"consul_download_url": "{{env `CONSUL_DOWNLOAD_URL`}}",
"vault_download_url": "{{env `VAULT_DOWNLOAD_URL`}}",
"github_oauth_token": "{{env `GITHUB_OAUTH_TOKEN`}}",
"ca_public_key_path": null,
"tls_public_key_path": null,
Expand Down Expand Up @@ -59,7 +59,7 @@
},{
"type": "shell",
"inline": [
"if [[ -n '{{user `vault_download_url`}}' ]]; then",
"if test -n \"{{user `vault_download_url`}}\"; then",
" /tmp/terraform-aws-vault/modules/install-vault/install-vault --download-url {{user `vault_download_url`}};",
"else",
" /tmp/terraform-aws-vault/modules/install-vault/install-vault --version {{user `vault_version`}};",
Expand Down Expand Up @@ -104,7 +104,7 @@
"type": "shell",
"inline": [
"git clone --branch {{user `consul_module_version`}} https://{{user `github_oauth_token`}}@github.com/hashicorp/terraform-aws-consul.git /tmp/terraform-aws-consul",
"if [[ -n '{{user `consul_download_url`}}' ]]; then",
"if test -n \"{{user `consul_download_url`}}\"; then",
" /tmp/terraform-aws-consul/modules/install-consul/install-consul --download-url {{user `consul_download_url`}};",
"else",
" /tmp/terraform-aws-consul/modules/install-consul/install-consul --version {{user `consul_version`}};",
Expand Down
10 changes: 8 additions & 2 deletions modules/install-vault/install-vault
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ function fetch_binary {
download_url="https://releases.hashicorp.com/vault/${version}/vault_${version}_linux_amd64.zip"
fi

log_info "Downloading Vault from $download_url to $DOWNLOAD_PACKAGE_PATH"
log_info "Downloading Vault to $DOWNLOAD_PACKAGE_PATH"
curl -o "$DOWNLOAD_PACKAGE_PATH" "$download_url" --location --silent --fail --show-error
}

Expand Down Expand Up @@ -296,7 +296,13 @@ function install {
install_binary "$path" "$user"
configure_mlock

log_info "Vault install complete!"

if command -v vault; then
log_info "Vault install complete!"
else
log_info "Could not find vault command. Aborting.";
exit 1;
fi
}

install "$@"
29 changes: 25 additions & 4 deletions test/terratest_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package test

import (
"testing"

"github.com/gruntwork-io/terratest/modules/packer"
"github.com/gruntwork-io/terratest/modules/test-structure"
)
Expand All @@ -10,25 +11,45 @@ const AMI_VAR_AWS_REGION = "aws_region"
const AMI_VAR_CA_PUBLIC_KEY = "ca_public_key_path"
const AMI_VAR_TLS_PUBLIC_KEY = "tls_public_key_path"
const AMI_VAR_TLS_PRIVATE_KEY = "tls_private_key_path"
const AMI_VAR_VAULT_DOWNLOAD_URL = "VAULT_DOWNLOAD_URL"

const SAVED_TLS_CERT = "TlsCert"

// Use Packer to build the AMI in the given packer template, with the given build name, and return the AMI's ID
func buildAmi(t *testing.T, packerTemplatePath string, packerBuildName string, tlsCert TlsCert, awsRegion string) string {
options := &packer.Options{
Template: packerTemplatePath,
Only: packerBuildName,
Only: packerBuildName,
Vars: map[string]string{
AMI_VAR_AWS_REGION: awsRegion,
AMI_VAR_CA_PUBLIC_KEY: tlsCert.CAPublicKeyPath,
AMI_VAR_TLS_PUBLIC_KEY: tlsCert.PublicKeyPath,
AMI_VAR_AWS_REGION: awsRegion,
AMI_VAR_CA_PUBLIC_KEY: tlsCert.CAPublicKeyPath,
AMI_VAR_TLS_PUBLIC_KEY: tlsCert.PublicKeyPath,
AMI_VAR_TLS_PRIVATE_KEY: tlsCert.PrivateKeyPath,
},
}

return packer.BuildAmi(t, options)
}

// Use Packer to build the AMI in the given packer template, with the given build name, and return the AMI's ID
func buildAmiWithDownloadEnv(t *testing.T, packerTemplatePath string, packerBuildName string, tlsCert TlsCert, awsRegion string, vaultDownloadUrl string) string {
options := &packer.Options{
Template: packerTemplatePath,
Only: packerBuildName,
Vars: map[string]string{
AMI_VAR_AWS_REGION: awsRegion,
AMI_VAR_CA_PUBLIC_KEY: tlsCert.CAPublicKeyPath,
AMI_VAR_TLS_PUBLIC_KEY: tlsCert.PublicKeyPath,
AMI_VAR_TLS_PRIVATE_KEY: tlsCert.PrivateKeyPath,
},
Env: map[string]string{
AMI_VAR_VAULT_DOWNLOAD_URL: vaultDownloadUrl,
},
}

return packer.BuildAmi(t, options)
}

func saveTlsCert(t *testing.T, testFolder string, tlsCert TlsCert) {
test_structure.SaveTestData(t, test_structure.FormatTestDataPath(testFolder, SAVED_TLS_CERT), tlsCert)
}
Expand Down
27 changes: 27 additions & 0 deletions test/vault_cluster_enterprise_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package test

import (
"os"
"testing"
)

func TestVaultClusterEnterpriseWithUbuntuAmi(t *testing.T) {
t.Parallel()
runVaultEnterpriseClusterTest(t, "ubuntu16-ami", "ubuntu", getUrlFromEnv(t))
}

func TestVaultClusterEnterpriseWithAmazonLinuxAmi(t *testing.T) {
t.Parallel()
runVaultEnterpriseClusterTest(t, "amazon-linux-ami", "ec2-user", getUrlFromEnv(t))
}

// To test this on circle ci you need a url set as an environment variable, VAULT_AMI_TEMPLATE_VAR_DOWNLOAD_URL
// which you would also have to set locally if you want to run this test locally.
// The reason is to prevent the actual url from being visible on code and logs
func getUrlFromEnv(t *testing.T) string {
url := os.Getenv("VAULT_AMI_TEMPLATE_VAR_DOWNLOAD_URL")
if url == "" {
t.Fatalf("Please set the environment variable VAULT_AMI_TEMPLATE_VAR_DOWNLOAD_URL.\n")
}
return url
}
106 changes: 105 additions & 1 deletion test/vault_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const (
// 3. Deploy that AMI using the example Terraform code
// 4. SSH to a Vault node and initialize the Vault cluster
// 5. SSH to each Vault node and unseal it
// 5. SSH to a Vault node and make sure you can communicate with the nodes via Consul-managed DNS
// 6. SSH to a Vault node and make sure you can communicate with the nodes via Consul-managed DNS
func runVaultPrivateClusterTest(t *testing.T, packerBuildName string, sshUserName string) {
examplesDir := test_structure.CopyTerraformFolderToTemp(t, REPO_ROOT, VAULT_CLUSTER_PRIVATE_PATH)

Expand Down Expand Up @@ -333,6 +333,82 @@ func runVaultWithS3BackendClusterTest(t *testing.T, packerBuildName string, sshU
})
}

// Test the Vault enterprise cluster example by:
//
// 1. Copy the code in this repo to a temp folder so tests on the Terraform code can run in parallel without the
// state files overwriting each other.
// 2. Build the AMI in the vault-consul-ami example with the given build name and the enterprise package
// 3. Deploy that AMI using the example Terraform code
// 4. SSH to a Vault node and initialize the Vault cluster
// 5. SSH to each Vault node and unseal it
// 6. SSH to a Vault node and make sure you can communicate with the nodes via Consul-managed DNS
// 7. SSH to a Vault node and check if Vault enterprise is installed properly
func runVaultEnterpriseClusterTest(t *testing.T, packerBuildName string, sshUserName string, vaultDownloadUrl string) {
examplesDir := test_structure.CopyTerraformFolderToTemp(t, REPO_ROOT, VAULT_CLUSTER_PRIVATE_PATH)

defer test_structure.RunTestStage(t, "teardown", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, examplesDir)
terraform.Destroy(t, terraformOptions)

amiId := test_structure.LoadAmiId(t, examplesDir)
awsRegion := test_structure.LoadString(t, examplesDir, SAVED_AWS_REGION)
aws.DeleteAmi(t, awsRegion, amiId)

keyPair := test_structure.LoadEc2KeyPair(t, examplesDir)
aws.DeleteEC2KeyPair(t, keyPair)

tlsCert := loadTlsCert(t, examplesDir)
cleanupTlsCertFiles(tlsCert)
})

test_structure.RunTestStage(t, "setup_ami", func() {
awsRegion := aws.GetRandomRegion(t, nil, nil)
test_structure.SaveString(t, examplesDir, SAVED_AWS_REGION, awsRegion)

tlsCert := generateSelfSignedTlsCert(t)
saveTlsCert(t, examplesDir, tlsCert)

amiId := buildAmiWithDownloadEnv(t, AMI_EXAMPLE_PATH, packerBuildName, tlsCert, awsRegion, vaultDownloadUrl)
test_structure.SaveAmiId(t, examplesDir, amiId)
})

test_structure.RunTestStage(t, "deploy", func() {
uniqueId := random.UniqueId()
amiId := test_structure.LoadAmiId(t, examplesDir)
awsRegion := test_structure.LoadString(t, examplesDir, SAVED_AWS_REGION)

keyPair := aws.CreateAndImportEC2KeyPair(t, awsRegion, uniqueId)
test_structure.SaveEc2KeyPair(t, examplesDir, keyPair)

terraformOptions := &terraform.Options{
TerraformDir: examplesDir,
Vars: map[string]interface{}{
VAR_AMI_ID: amiId,
VAR_VAULT_CLUSTER_NAME: fmt.Sprintf("vault-test-%s", uniqueId),
VAR_CONSUL_CLUSTER_NAME: fmt.Sprintf("consul-test-%s", uniqueId),
VAR_CONSUL_CLUSTER_TAG_KEY: fmt.Sprintf("consul-test-%s", uniqueId),
VAR_SSH_KEY_NAME: keyPair.Name,
},
EnvVars: map[string]string{
ENV_VAR_AWS_REGION: awsRegion,
},
}
test_structure.SaveTerraformOptions(t, examplesDir, terraformOptions)

terraform.InitAndApply(t, terraformOptions)
})

test_structure.RunTestStage(t, "validate", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, examplesDir)
awsRegion := test_structure.LoadString(t, examplesDir, SAVED_AWS_REGION)
keyPair := test_structure.LoadEc2KeyPair(t, examplesDir)

cluster := initializeAndUnsealVaultCluster(t, OUTPUT_VAULT_CLUSTER_ASG_NAME, sshUserName, terraformOptions, awsRegion, keyPair)
testVaultUsesConsulForDns(t, cluster)
checkEnterpriseInstall(t, OUTPUT_VAULT_CLUSTER_ASG_NAME, sshUserName, terraformOptions, awsRegion, keyPair)
})
}

// Initialize the Vault cluster and unseal each of the nodes by connecting to them over SSH and executing Vault
// commands. The reason we use SSH rather than using the Vault client remotely is we want to verify that the
// self-signed TLS certificate is properly configured on each server so when you're on that server, you don't
Expand Down Expand Up @@ -598,3 +674,31 @@ func checkStatus(t *testing.T, host ssh.Host, expectedStatus VaultStatus) (strin
return "", fmt.Errorf("Expected status code %d for host %s, but got %d", int(expectedStatus), host.Hostname, status)
}
}

// Check if the enterprise version of consul and vault is installed
func checkEnterpriseInstall(t *testing.T, asgNameOutputVar string, sshUserName string, terratestOptions *terraform.Options, awsRegion string, keyPair *aws.Ec2Keypair) {
asgName := terraform.OutputRequired(t, terratestOptions, asgNameOutputVar)
nodeIpAddresses := getIpAddressesOfAsgInstances(t, asgName, awsRegion)

host := ssh.Host{
Hostname: nodeIpAddresses[0],
SshUserName: sshUserName,
SshKeyPair: keyPair.KeyPair,
}

maxRetries := 10
sleepBetweenRetries := 10 * time.Second

output := retry.DoWithRetry(t, "Check Enterprise Install", maxRetries, sleepBetweenRetries, func() (string, error) {
out, err := ssh.CheckSshCommandE(t, host, "vault --version")
if err != nil {
return "", fmt.Errorf("Error running vault command: %s\n", err)
}

return out, nil
})

if !strings.Contains(output, "+ent") {
t.Fatalf("This vault package is not the enterprise version.\n")
}
}

0 comments on commit 43d5e86

Please sign in to comment.