From 86dafced1ae163a002d820347b75b98688ac60c1 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Fri, 7 Oct 2022 14:58:10 -0400 Subject: [PATCH 1/7] fix(e2e): Add missing require --- testing/internal/e2e/host/static/statichost_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/internal/e2e/host/static/statichost_test.go b/testing/internal/e2e/host/static/statichost_test.go index e1cc55c37..bd2ab6d44 100644 --- a/testing/internal/e2e/host/static/statichost_test.go +++ b/testing/internal/e2e/host/static/statichost_test.go @@ -216,6 +216,7 @@ func TestCreateTargetApi(t *testing.T) { // Create a target tClient := targets.NewClient(client) targetPort, err := strconv.ParseInt(c.TargetPort, 10, 32) + require.NoError(t, err) newTargetResult, err := tClient.Create(ctx, "tcp", newProjectId, targets.WithName("e2e Automated Test Target"), targets.WithTcpTargetDefaultPort(uint32(targetPort)), From 1361c3cc6d3d7b3e3f109261d0c20749e006650a Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Oct 2022 11:44:01 -0400 Subject: [PATCH 2/7] refact(e2e): Move environment variables into its own file --- testing/internal/e2e/host/static/env.go | 20 +++++++++++++++++++ .../e2e/host/static/statichost_test.go | 18 ----------------- 2 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 testing/internal/e2e/host/static/env.go diff --git a/testing/internal/e2e/host/static/env.go b/testing/internal/e2e/host/static/env.go new file mode 100644 index 000000000..944f97f22 --- /dev/null +++ b/testing/internal/e2e/host/static/env.go @@ -0,0 +1,20 @@ +package static_test + +import "github.com/kelseyhightower/envconfig" + +type config struct { + TargetIp string `envconfig:"E2E_TARGET_IP" required:"true"` // e.g. 192.168.0.1 + TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. /Users/username/key.pem + TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. ubuntu + TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"` +} + +func loadConfig() (*config, error) { + var c config + err := envconfig.Process("", &c) + if err != nil { + return nil, err + } + + return &c, err +} diff --git a/testing/internal/e2e/host/static/statichost_test.go b/testing/internal/e2e/host/static/statichost_test.go index bd2ab6d44..ad012c692 100644 --- a/testing/internal/e2e/host/static/statichost_test.go +++ b/testing/internal/e2e/host/static/statichost_test.go @@ -13,27 +13,9 @@ import ( "github.com/hashicorp/boundary/api/targets" "github.com/hashicorp/boundary/testing/internal/e2e" "github.com/hashicorp/boundary/testing/internal/e2e/boundary" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" ) -type config struct { - TargetIp string `envconfig:"E2E_TARGET_IP" required:"true"` // e.g. 192.168.0.1 - TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. /Users/username/key.pem - TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. ubuntu - TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"` -} - -func loadConfig() (*config, error) { - var c config - err := envconfig.Process("", &c) - if err != nil { - return nil, err - } - - return &c, err -} - // TestConnectTargetCli uses the boundary cli to create a number of supporting objects // to connect to a target. It then attempts to connect to that target and verifies that // the connection was successful. From 5365b2900759832233967fcd656be3fc482ab8b4 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Oct 2022 11:47:19 -0400 Subject: [PATCH 3/7] refact(e2e): Port enos smoke test into e2e test suite This adds a test case to the e2e test suite and unifies where testing is located. --- .github/workflows/enos-run.yml | 1 - enos/enos.hcl | 37 +-- enos/modules/test_smoke/README.md | 5 - enos/modules/test_smoke/main.tf | 140 ---------- enos/templates/connect-target.sh | 24 -- .../e2e/host/static/staticcredential_test.go | 257 ++++++++++++++++++ 6 files changed, 258 insertions(+), 206 deletions(-) delete mode 100644 enos/modules/test_smoke/README.md delete mode 100644 enos/modules/test_smoke/main.tf delete mode 100644 enos/templates/connect-target.sh create mode 100644 testing/internal/e2e/host/static/staticcredential_test.go diff --git a/.github/workflows/enos-run.yml b/.github/workflows/enos-run.yml index ff95d4fe2..9a25d4493 100644 --- a/.github/workflows/enos-run.yml +++ b/.github/workflows/enos-run.yml @@ -25,7 +25,6 @@ jobs: fail-fast: false # don't fail as that can skip required cleanup steps for jobs matrix: include: - - filter: 'integration test:smoke' - filter: 'integration test:cli_ui' - filter: 'e2e_credential_vault' - filter: 'e2e_host_aws' diff --git a/enos/enos.hcl b/enos/enos.hcl index 09b106af1..8cd76d665 100644 --- a/enos/enos.hcl +++ b/enos/enos.hcl @@ -43,7 +43,7 @@ scenario "integration" { matrix { builder = ["local", "crt"] - test = ["smoke", "cli_ui"] + test = ["cli_ui"] } locals { @@ -120,41 +120,6 @@ scenario "integration" { } } - step "launch_smoke_targets" { - skip_step = matrix.test != "smoke" - module = module.target - depends_on = [step.create_base_infra] - - variables { - ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"] - aws_ssh_keypair_name = var.aws_ssh_keypair_name - enos_user = var.enos_user - instance_type = var.target_instance_type - vpc_id = step.create_base_infra.vpc_id - } - } - - step "run_test_smoke" { - skip_step = matrix.test != "smoke" - module = module.test_smoke - depends_on = [step.create_boundary_cluster] - - variables { - alb_boundary_api_addr = step.create_boundary_cluster.alb_boundary_api_addr - auth_login_name = step.create_boundary_cluster.auth_login_name - auth_method_id = step.create_boundary_cluster.auth_method_id - auth_password = step.create_boundary_cluster.auth_password - aws_ssh_private_key_path = local.aws_ssh_private_key_path - boundary_install_dir = local.boundary_install_dir - controller_ips = step.create_boundary_cluster.controller_ips - local_boundary_dir = local.local_boundary_dir - project_scope_id = step.create_boundary_cluster.project_scope_id - target_count = var.target_count - target_id = step.create_boundary_cluster.target_id - target_ips = step.launch_smoke_targets.target_ips - } - } - step "run_test_cli_ui" { skip_step = matrix.test != "cli_ui" module = module.test_cli_ui diff --git a/enos/modules/test_smoke/README.md b/enos/modules/test_smoke/README.md deleted file mode 100644 index 2b824609c..000000000 --- a/enos/modules/test_smoke/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Smoke Test - -This test runs a basic smoke test that gets a Boundary Auth token, creates a -test catalog and host set, adds the "target" node(s) as hosts/targets and -attempts to SSH to a target to verify that it is able. diff --git a/enos/modules/test_smoke/main.tf b/enos/modules/test_smoke/main.tf deleted file mode 100644 index 3f903a3d3..000000000 --- a/enos/modules/test_smoke/main.tf +++ /dev/null @@ -1,140 +0,0 @@ -terraform { - required_providers { - enos = { - source = "app.terraform.io/hashicorp-qti/enos" - } - } -} - -variable "alb_boundary_api_addr" {} -variable "auth_login_name" {} -variable "auth_method_id" {} -variable "auth_password" {} -variable "aws_ssh_private_key_path" {} -variable "boundary_install_dir" {} -variable "controller_ips" {} -variable "local_boundary_dir" {} -variable "project_scope_id" {} -variable "target_count" {} -variable "target_id" {} -variable "target_ips" {} - -resource "enos_local_exec" "local_boundary_version" { - inline = ["${var.local_boundary_dir}/boundary version -format=json"] -} - -resource "enos_remote_exec" "remote_boundary_version" { - inline = ["${var.boundary_install_dir}/boundary version -format=json"] - transport = { - ssh = { - host = var.controller_ips.0 - } - } -} - -locals { - base_environment = { - BOUNDARY_ADDR = var.alb_boundary_api_addr, - BOUNDARY_TOKEN = local.auth_token - } -} - -resource "enos_local_exec" "get_token" { - environment = { - BOUNDARY_ADDR = var.alb_boundary_api_addr, - BOUNDARY_PATH = var.local_boundary_dir, - METHOD_ID = var.auth_method_id, - LOGIN_NAME = var.auth_login_name, - PASSWORD = var.auth_password, - } - scripts = ["${path.module}/../../templates/get-token.sh"] -} - -locals { - auth_token = jsondecode(enos_local_exec.get_token.stdout).item.attributes.token -} - -resource "enos_local_exec" "read_target" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary targets read -id ${var.target_id}"] -} - -resource "enos_local_exec" "create_catalog" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary host-catalogs create static -scope-id=${var.project_scope_id} -name=enos1 -description=test -format=json"] -} - -locals { - catalog_id = jsondecode(enos_local_exec.create_catalog.stdout).item.id -} - -resource "enos_local_exec" "create_static_hosts" { - environment = local.base_environment - for_each = toset([for idx in range(var.target_count) : tostring(idx)]) - inline = ["${var.local_boundary_dir}/boundary hosts create static -name=${var.target_ips[each.value]} -description=${var.target_ips[each.value]} -address=${var.target_ips[each.value]} -host-catalog-id=${local.catalog_id} -format=json"] -} - -locals { - host_ids = [for idx in range(var.target_count) : jsondecode(values(enos_local_exec.create_static_hosts)[idx].stdout).item.id] -} - -resource "enos_local_exec" "create_host_set" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary host-sets create static -name='test-machines' -description='Test machine host set' -host-catalog-id=${local.catalog_id} -format=json"] -} - -locals { - host_set_id = jsondecode(enos_local_exec.create_host_set.stdout).item.id -} - -resource "enos_local_exec" "add_to_host_set" { - environment = local.base_environment - for_each = toset([for idx in range(var.target_count) : tostring(idx)]) - inline = ["${var.local_boundary_dir}/boundary host-sets add-hosts -id=${local.host_set_id} -host=${local.host_ids[each.value]} -format=json"] -} - -resource "enos_local_exec" "create_static_credential_store" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary credential-stores create static -scope-id=${var.project_scope_id} -format=json"] -} - -locals { - credential_store_id = jsondecode(enos_local_exec.create_static_credential_store.stdout).item.id -} - -resource "enos_local_exec" "create_ssh_private_key_credential" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary credentials create ssh-private-key -credential-store-id=${local.credential_store_id} -username=ubuntu -private-key=file://${var.aws_ssh_private_key_path} -format=json"] -} - -locals { - credential_id = jsondecode(enos_local_exec.create_ssh_private_key_credential.stdout).item.id -} - -resource "enos_local_exec" "create_target" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary targets create tcp -name='test target' -description='test target' -default-port=22 -scope-id=${var.project_scope_id} -session-connection-limit='-1' -session-max-seconds=900 -format=json"] -} - -locals { - target_id = jsondecode(enos_local_exec.create_target.stdout).item.id -} - -resource "enos_local_exec" "add_hosts_to_target" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary targets add-host-sources -id=${local.target_id} -host-source=${local.host_set_id} -format=json"] -} - -resource "enos_local_exec" "add_credential_to_target" { - environment = local.base_environment - inline = ["${var.local_boundary_dir}/boundary targets add-credential-sources -id=${local.target_id} -brokered-credential-source=${local.credential_id} -format=json"] -} - -resource "enos_local_exec" "connect_target" { - environment = merge(local.base_environment, - { - BOUNDARY_PATH = var.local_boundary_dir - TARGET_ID = local.target_id - }) - scripts = ["${path.module}/../../templates/connect-target.sh"] -} diff --git a/enos/templates/connect-target.sh b/enos/templates/connect-target.sh deleted file mode 100644 index 41eb3804b..000000000 --- a/enos/templates/connect-target.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -set -e - -function retry { - local retries=$1 - shift - local count=0 - - until "$@"; do - exit=$? - wait=$((2 ** count)) - count=$((count + 1)) - - if [ "$count" -lt "$retries" ]; then - sleep "$wait" - else - return "$exit" - fi - done - - return 0 -} - -retry 10 ${BOUNDARY_PATH}/boundary connect ssh -target-id=${TARGET_ID} -- -o StrictHostKeyChecking=no diff --git a/testing/internal/e2e/host/static/staticcredential_test.go b/testing/internal/e2e/host/static/staticcredential_test.go new file mode 100644 index 000000000..278c3a58b --- /dev/null +++ b/testing/internal/e2e/host/static/staticcredential_test.go @@ -0,0 +1,257 @@ +package static_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + "strconv" + "testing" + + "github.com/hashicorp/boundary/api/credentials" + "github.com/hashicorp/boundary/api/credentialstores" + "github.com/hashicorp/boundary/api/hostcatalogs" + "github.com/hashicorp/boundary/api/hosts" + "github.com/hashicorp/boundary/api/hostsets" + "github.com/hashicorp/boundary/api/targets" + "github.com/hashicorp/boundary/testing/internal/e2e" + "github.com/hashicorp/boundary/testing/internal/e2e/boundary" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestConnectTargetWithStaticCredentialStoreCli uses the boundary cli to create a credential using +// boundary's built-in credential store. The test attaches that credential to a target and attempts +// to connect to that target using those credentials. +func TestConnectTargetWithStaticCredentialStoreCli(t *testing.T) { + e2e.MaybeSkipTest(t) + c, err := loadConfig() + require.NoError(t, err) + + boundary.AuthenticateCli(t) + + // Create an org and project + newOrgId := boundary.CreateNewOrgCli(t) + t.Logf("Created Org Id: %s", newOrgId) + newProjectId := boundary.CreateNewProjectCli(t, newOrgId) + t.Logf("Created Project Id: %s", newProjectId) + + // Create a credential store + output := e2e.RunCommand("boundary", "credential-stores", "create", "static", + "-scope-id", newProjectId, + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newCredentialStoreResult credentialstores.CredentialStoreCreateResult + err = json.Unmarshal(output.Stdout, &newCredentialStoreResult) + require.NoError(t, err) + newCredentialStoreId := newCredentialStoreResult.Item.Id + t.Logf("Created Credential Store: %s", newCredentialStoreId) + + // Create credentials + output = e2e.RunCommand("boundary", "credentials", "create", "ssh-private-key", + "-credential-store-id", newCredentialStoreId, + "-username", c.TargetSshUser, + "-private-key", "file://"+c.TargetSshKeyPath, + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newCredentialsResult credentials.CredentialCreateResult + err = json.Unmarshal(output.Stdout, &newCredentialsResult) + require.NoError(t, err) + newCredentialsId := newCredentialsResult.Item.Id + t.Logf("Created Credentials: %s", newCredentialsId) + + // Create a host catalog + output = e2e.RunCommand("boundary", "host-catalogs", "create", "static", + "-scope-id", newProjectId, + "-name", "e2e Automated Test Host Catalog", + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newHostCatalogResult hostcatalogs.HostCatalogCreateResult + err = json.Unmarshal(output.Stdout, &newHostCatalogResult) + require.NoError(t, err) + newHostCatalogId := newHostCatalogResult.Item.Id + t.Logf("Created Host Catalog: %s", newHostCatalogId) + + // Create a host set and add to catalog + output = e2e.RunCommand("boundary", "host-sets", "create", "static", + "-host-catalog-id", newHostCatalogId, + "-name", "e2e Automated Test Host Set", + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newHostSetResult hostsets.HostSetCreateResult + err = json.Unmarshal(output.Stdout, &newHostSetResult) + require.NoError(t, err) + newHostSetId := newHostSetResult.Item.Id + t.Logf("Created Host Set: %s", newHostSetId) + + // Create a host + output = e2e.RunCommand("boundary", "hosts", "create", "static", + "-host-catalog-id", newHostCatalogId, + "-name", c.TargetIp, + "-address", c.TargetIp, + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newHostResult hosts.HostCreateResult + err = json.Unmarshal(output.Stdout, &newHostResult) + require.NoError(t, err) + newHostId := newHostResult.Item.Id + t.Logf("Created Host: %s", newHostId) + + // Add host to host set + output = e2e.RunCommand("boundary", "host-sets", "add-hosts", "-id", newHostSetId, "-host", newHostId) + require.NoError(t, output.Err, string(output.Stderr)) + + // Create a target + output = e2e.RunCommand("boundary", "targets", "create", "tcp", + "-scope-id", newProjectId, + "-default-port", c.TargetPort, + "-name", "e2e Automated Test Target", + "-format", "json", + ) + require.NoError(t, output.Err, string(output.Stderr)) + var newTargetResult targets.TargetCreateResult + err = json.Unmarshal(output.Stdout, &newTargetResult) + require.NoError(t, err) + newTargetId := newTargetResult.Item.Id + t.Logf("Created Target: %s", newTargetId) + + // Add host set to target + output = e2e.RunCommand("boundary", "targets", "add-host-sources", + "-id", newTargetId, + "-host-source", newHostSetId, + ) + require.NoError(t, output.Err, string(output.Stderr)) + + // Add credentials to target + output = e2e.RunCommand("boundary", "targets", "add-credential-sources", + "-id", newTargetId, + "-brokered-credential-source", newCredentialsId, + ) + require.NoError(t, output.Err, string(output.Stderr)) + + // Get credentials for target + output = e2e.RunCommand("boundary", "targets", "authorize-session", "-id", newTargetId, "-format", "json") + require.NoError(t, output.Err, string(output.Stderr)) + var newSessionAuthorizationResult targets.SessionAuthorizationResult + err = json.Unmarshal(output.Stdout, &newSessionAuthorizationResult) + require.NoError(t, err) + + newSessionAuthorization := newSessionAuthorizationResult.Item + retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"]) + retrievedKey := fmt.Sprintf("%s\n", newSessionAuthorization.Credentials[0].Credential["private_key"]) + assert.Equal(t, c.TargetSshUser, retrievedUser) + + k, err := os.ReadFile(c.TargetSshKeyPath) + require.NoError(t, err) + require.Equal(t, string(k), retrievedKey) + t.Log("Successfully retrieved credentials for target") + + // Connect to target and print host's IP address using retrieved credentials + output = e2e.RunCommand("boundary", "connect", "ssh", + "-target-id", newTargetId, "--", + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking=no", + "-o", "IdentitiesOnly=yes", // forces the use of the provided key + ) + require.NoError(t, output.Err, string(output.Stderr)) + t.Log("Successfully connected to target") +} + +// TestCreateTargetWithStaticCredentialStoreApi uses the boundary go api to create a credential using +// boundary's built-in credential store. The test then attaches that credential to a target. +func TestCreateTargetWithStaticCredentialStoreApi(t *testing.T) { + e2e.MaybeSkipTest(t) + c, err := loadConfig() + require.NoError(t, err) + + // Create boundary api client + client, err := boundary.NewApiClient() + require.NoError(t, err) + ctx := context.Background() + + // Create an org and project + newOrgId := boundary.CreateNewOrgApi(t, ctx, client) + t.Logf("Created Org Id: %s", newOrgId) + newProjectId := boundary.CreateNewProjectApi(t, ctx, client, newOrgId) + t.Logf("Created Project Id: %s", newProjectId) + + // Create a credential store + csClient := credentialstores.NewClient(client) + newCredentialStoreResult, err := csClient.Create(ctx, "static", newProjectId) + require.NoError(t, err) + newCredentialStoreId := newCredentialStoreResult.Item.Id + t.Logf("Created Credential Store: %s", newCredentialStoreId) + + // Create credentials + cClient := credentials.NewClient(client) + k, err := os.ReadFile(c.TargetSshKeyPath) + require.NoError(t, err) + newCredentialsResult, err := cClient.Create(ctx, "ssh_private_key", newCredentialStoreId, + credentials.WithSshPrivateKeyCredentialUsername(c.TargetSshUser), + credentials.WithSshPrivateKeyCredentialPrivateKey(string(k)), + ) + require.NoError(t, err) + newCredentialsId := newCredentialsResult.Item.Id + t.Logf("Created Credentials: %s", newCredentialsId) + + // Create a host catalog + hcClient := hostcatalogs.NewClient(client) + newHostCatalogResult, err := hcClient.Create(ctx, "static", newProjectId, + hostcatalogs.WithName("e2e Automated Test Host Catalog"), + ) + require.NoError(t, err) + newHostCatalogId := newHostCatalogResult.Item.Id + t.Logf("Created Host Catalog: %s", newHostCatalogId) + + // Create a host set and add to catalog + hsClient := hostsets.NewClient(client) + newHostSetResult, err := hsClient.Create(ctx, newHostCatalogId) + require.NoError(t, err) + newHostSetId := newHostSetResult.Item.Id + t.Logf("Created Host Set: %s", newHostSetId) + + // Create a host + hClient := hosts.NewClient(client) + newHostResult, err := hClient.Create(ctx, newHostCatalogId, + hosts.WithName(c.TargetIp), + hosts.WithStaticHostAddress(c.TargetIp), + ) + require.NoError(t, err) + newHostId := newHostResult.Item.Id + t.Logf("Created Host: %s", newHostId) + + // Add host to host set + _, err = hsClient.AddHosts(ctx, newHostSetId, 0, []string{newHostId}, hostsets.WithAutomaticVersioning(true)) + require.NoError(t, err) + + // Create a target + tClient := targets.NewClient(client) + targetPort, err := strconv.ParseInt(c.TargetPort, 10, 32) + require.NoError(t, err) + newTargetResult, err := tClient.Create(ctx, "tcp", newProjectId, + targets.WithName("e2e Automated Test Target"), + targets.WithTcpTargetDefaultPort(uint32(targetPort)), + ) + require.NoError(t, err) + newTargetId := newTargetResult.Item.Id + t.Logf("Created Target: %s", newTargetId) + + // Add host set to target + _, err = tClient.AddHostSources(ctx, newTargetId, 0, + []string{newHostSetId}, + targets.WithAutomaticVersioning(true), + ) + require.NoError(t, err) + + // Add credentials to target + _, err = tClient.AddCredentialSources(ctx, newTargetId, 0, + targets.WithAutomaticVersioning(true), + targets.WithBrokeredCredentialSourceIds([]string{newCredentialsId}), + ) + require.NoError(t, err) +} From 719200612ddcec4bc9a53a85e44ed19baa648cb2 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Oct 2022 14:10:41 -0400 Subject: [PATCH 4/7] refact(e2e): Remove use of AwsHostSetCount env Instead of passing in the number of hosts created for a host set, we can just use the length of the IP addresses to determine that value. --- enos/enos-scenario-e2e-host-aws.hcl | 3 +- enos/modules/test_e2e/main.tf | 12 +++--- testing/internal/e2e/README.md | 3 +- .../e2e/host/aws/dynamichostcatalog_test.go | 39 ++++++++++++------- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/enos/enos-scenario-e2e-host-aws.hcl b/enos/enos-scenario-e2e-host-aws.hcl index e194c29f6..384145096 100644 --- a/enos/enos-scenario-e2e-host-aws.hcl +++ b/enos/enos-scenario-e2e-host-aws.hcl @@ -179,10 +179,9 @@ scenario "e2e_host_aws" { aws_access_key_id = step.iam_setup.access_key_id aws_secret_access_key = step.iam_setup.secret_access_key aws_host_set_filter1 = step.create_tag1_inputs.tag_string - aws_host_set_count1 = 2 aws_host_set_ips1 = step.create_targets_with_tag1.target_ips aws_host_set_filter2 = step.create_tag2_inputs.tag_string - aws_host_set_count2 = 1 + aws_host_set_ips2 = step.create_targets_with_tag2.target_ips } } diff --git a/enos/modules/test_e2e/main.tf b/enos/modules/test_e2e/main.tf index e5bb23be9..437b94c2a 100644 --- a/enos/modules/test_e2e/main.tf +++ b/enos/modules/test_e2e/main.tf @@ -83,16 +83,17 @@ variable "aws_host_set_filter2" { type = string default = "" } -variable "aws_host_set_count2" { - description = "Number of hosts in aws_host_set_filter2" - type = number - default = 0 +variable "aws_host_set_ips2" { + description = "List of IP addresses in aws_host_set_filter2" + type = list(string) + default = [""] } locals { aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path) vault_addr = var.vault_addr != "" ? "http://${var.vault_addr}:8200" : "" aws_host_set_ips1 = jsonencode(var.aws_host_set_ips1) + aws_host_set_ips2 = jsonencode(var.aws_host_set_ips2) } resource "enos_local_exec" "run_e2e_test" { @@ -109,10 +110,9 @@ resource "enos_local_exec" "run_e2e_test" { E2E_AWS_ACCESS_KEY_ID = var.aws_access_key_id, E2E_AWS_SECRET_ACCESS_KEY = var.aws_secret_access_key, E2E_AWS_HOST_SET_FILTER1 = var.aws_host_set_filter1, - E2E_AWS_HOST_SET_COUNT1 = var.aws_host_set_count1, E2E_AWS_HOST_SET_IPS1 = local.aws_host_set_ips1, E2E_AWS_HOST_SET_FILTER2 = var.aws_host_set_filter2, - E2E_AWS_HOST_SET_COUNT2 = var.aws_host_set_count2 + E2E_AWS_HOST_SET_IPS2 = local.aws_host_set_ips2 } inline = ["PATH=\"${var.local_boundary_dir}:$PATH\" go test -v ${var.test_package}"] diff --git a/testing/internal/e2e/README.md b/testing/internal/e2e/README.md index c56e6d3f3..4f89e02cf 100644 --- a/testing/internal/e2e/README.md +++ b/testing/internal/e2e/README.md @@ -49,10 +49,9 @@ export E2E_SSH_USER= # e.g. ubuntu export E2E_AWS_ACCESS_KEY_ID= export E2E_AWS_SECRET_ACCESS_KEY= export E2E_AWS_HOST_SET_FILTER1= # e.g. "tag:testtag=true" -export E2E_AWS_HOST_SET_COUNT1= # e.g. 2 export E2E_AWS_HOST_SET_IPS1= # e.g. "[\"1.2.3.4\", \"2.3.4.5\"]" export E2E_AWS_HOST_SET_FILTER2= # e.g. "tag:testtagtwo=test" -export E2E_AWS_HOST_SET_COUNT2= # e.g. 1 +export E2E_AWS_HOST_SET_IPS2= # e.g. "[\"1.2.3.4\"] export E2E_SSH_KEY_PATH= # e.g. /Users/username/key.pem export E2E_SSH_USER= # e.g. ubuntu diff --git a/testing/internal/e2e/host/aws/dynamichostcatalog_test.go b/testing/internal/e2e/host/aws/dynamichostcatalog_test.go index 1c93cdd0c..819574b1a 100644 --- a/testing/internal/e2e/host/aws/dynamichostcatalog_test.go +++ b/testing/internal/e2e/host/aws/dynamichostcatalog_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "strconv" "strings" "testing" "time" @@ -25,13 +24,12 @@ import ( type config struct { AwsAccessKeyId string `envconfig:"E2E_AWS_ACCESS_KEY_ID" required:"true"` AwsSecretAccessKey string `envconfig:"E2E_AWS_SECRET_ACCESS_KEY" required:"true"` - AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER1" required:"true"` - AwsHostSetCount1 string `envconfig:"E2E_AWS_HOST_SET_COUNT1" required:"true"` - AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS1" required:"true"` - AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` - AwsHostSetCount2 string `envconfig:"E2E_AWS_HOST_SET_COUNT2" required:"true"` - TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. /Users/username/key.pem - TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. ubuntu + AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER1" required:"true"` // e.g. "tag:testtag=true" + AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS1" required:"true"` // e.g. "[\"1.2.3.4\", \"2.3.4.5\"]" + AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` // e.g. "tag:testtagtwo=test" + AwsHostSetIps2 string `envconfig:"E2E_AWS_HOST_SET_IPS2" required:"true"` // e.g. "[\"1.2.3.4\"]" + TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. "/Users/username/key.pem" + TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. "ubuntu" TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"` } @@ -45,6 +43,9 @@ func loadConfig() (*config, error) { return &c, err } +// TestCreateAwsDynamicHostCatalogCli uses the boundary cli to create a host catalog with the AWS +// plugin. The test sets up an AWS dynamic host catalog, creates some host sets, sets up a target to +// one of the host sets, and attempts to connect to the target. func TestCreateAwsDynamicHostCatalogCli(t *testing.T) { e2e.MaybeSkipTest(t) c, err := loadConfig() @@ -123,7 +124,10 @@ func TestCreateAwsDynamicHostCatalogCli(t *testing.T) { }, ) require.NoError(t, err) - expectedHostSetCount1, err := strconv.Atoi(c.AwsHostSetCount1) + + var targetIps1 []string + err = json.Unmarshal([]byte(c.AwsHostSetIps1), &targetIps1) + expectedHostSetCount1 := len(targetIps1) require.NoError(t, err) assert.Equal(t, expectedHostSetCount1, actualHostSetCount1, "Numbers of hosts in host set did not match expected amount") @@ -174,7 +178,9 @@ func TestCreateAwsDynamicHostCatalogCli(t *testing.T) { }, ) require.NoError(t, err) - expectedHostSetCount2, err := strconv.Atoi(c.AwsHostSetCount2) + var targetIps2 []string + err = json.Unmarshal([]byte(c.AwsHostSetIps2), &targetIps2) + expectedHostSetCount2 := len(targetIps2) require.NoError(t, err) assert.Equal(t, expectedHostSetCount2, actualHostSetCount2, "Numbers of hosts in host set did not match expected amount") @@ -257,17 +263,18 @@ func TestCreateAwsDynamicHostCatalogCli(t *testing.T) { t.Log("Successfully connected to the target") // Check if connected host exists in the host set - var targetIps []string - err = json.Unmarshal([]byte(c.AwsHostSetIps1), &targetIps) hostIpInList := false - for _, v := range targetIps { + for _, v := range targetIps1 { if v == hostIp { hostIpInList = true } } - require.True(t, hostIpInList, fmt.Sprintf("Connected host (%s) is not in expected list (%s)", hostIp, targetIps)) + require.True(t, hostIpInList, fmt.Sprintf("Connected host (%s) is not in expected list (%s)", hostIp, targetIps1)) } +// TestCreateAwsDynamicHostCatalogApi uses the boundary go api to create a host catalog with the AWS +// plugin. The test sets up an AWS dynamic host catalog, creates a host set, and sets up a target to +// the host set. func TestCreateAwsDynamicHostCatalogApi(t *testing.T) { e2e.MaybeSkipTest(t) c, err := loadConfig() @@ -340,7 +347,9 @@ func TestCreateAwsDynamicHostCatalogApi(t *testing.T) { ) require.NoError(t, err) t.Log("Successfully found items in the host set") - expectedHostSetCount, err := strconv.Atoi(c.AwsHostSetCount1) + var targetIps []string + err = json.Unmarshal([]byte(c.AwsHostSetIps1), &targetIps) + expectedHostSetCount := len(targetIps) require.NoError(t, err) assert.Equal(t, expectedHostSetCount, actualHostSetCount, "Numbers of hosts in host set did not match expected amount") From f9dfd024ed5f2ceb8959a295a43e070b9e1cbb6a Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Oct 2022 11:56:07 -0400 Subject: [PATCH 5/7] doc(e2e): Add info for adding tests --- testing/internal/e2e/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/testing/internal/e2e/README.md b/testing/internal/e2e/README.md index 4f89e02cf..10de8f516 100644 --- a/testing/internal/e2e/README.md +++ b/testing/internal/e2e/README.md @@ -79,3 +79,31 @@ one can be created. If a new package is created, a new enos scenario would also Enos is comprised of scenarios, where a scenario is the environment you want the tests to operate in. In one scenario, there may be a boundary cluster and a target. Another scenario might involve a boundary cluster and a vault instance. Scenarios can be found in [boundary/enos](../../../enos/) + +To run these tests in CI, the [enos-run.yml](../../../.github/workflows/enos-run.yml) github action +workflow must be updated to include the new scenario (see the `matrix`). + +### Development +To assist with iterating on tests on enos launched infrastructure, you can perform the following... + +Add the following snippet to print out environment variable information +``` +# `c` is the output from `loadConfig()` +s, _ := json.MarshalIndent(c, "", "\t") +log.Printf("%s", s) +``` +Launch an enos scenario +``` +enos scenario launch e2e_{scenario} builder:local +enos scenario output +``` +Take the printed environment variable information and export them into another terminal session +``` +export BOUNDARY_ADDR= +export E2E_PASSWORD_AUTH_METHOD_ID= +... +``` +Run your tests +``` +go test -v {go package} +``` From d8448d2184f1640b5b39e980acc606ff4b225aa4 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Oct 2022 14:11:12 -0400 Subject: [PATCH 6/7] doc(e2e): Fix typo --- testing/internal/e2e/credential/vault/vault_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/internal/e2e/credential/vault/vault_test.go b/testing/internal/e2e/credential/vault/vault_test.go index 498a9f3b6..a5de0d07d 100644 --- a/testing/internal/e2e/credential/vault/vault_test.go +++ b/testing/internal/e2e/credential/vault/vault_test.go @@ -249,7 +249,7 @@ func TestCreateVaultCredentialStoreCli(t *testing.T) { } // TestCreateVaultCredentialStoreApi uses the boundary go api along with the vault cli to -// add secrets management for a target. The test sets up vault as a creential stores and creates +// add secrets management for a target. The test sets up vault as a credential stores and creates // a set of credentials in vault that is attached to a target. func TestCreateVaultCredentialStoreApi(t *testing.T) { e2e.MaybeSkipTest(t) From 0857cbb663429a5733f3cc2037f82821252dc6fa Mon Sep 17 00:00:00 2001 From: Josh Brand Date: Mon, 10 Oct 2022 16:16:42 -0400 Subject: [PATCH 7/7] fix(e2e): Add missing project tags for targets --- enos/modules/target/main.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/enos/modules/target/main.tf b/enos/modules/target/main.tf index 7511bcf48..0af5914ba 100644 --- a/enos/modules/target/main.tf +++ b/enos/modules/target/main.tf @@ -53,6 +53,8 @@ resource "aws_instance" "target" { tags = merge(var.additional_tags, { "Name" : "boundary-target-${count.index}", "Type" : "target", + "Project" : "Enos", + "Project Name" : "qti-enos-boundary", "Environment" : var.environment "Enos User" : var.enos_user, })