* refact(e2e): Move cleanup steps into each test The migration test needed to create some resources, but doesn't care about cleaning up because the test would take care of spinning down the docker container that it's using. To maintain flexibility going forward, we'll establish that tests are responsible for cleaning up (rather than the methods they use) * refact(e2e): Use new env var for skip check Currently, the e2e tests use the E2E_PASSWORD_AUTH_METHOD_ID environment variable to determine if the test should be skipped. However, the new migration test does not require a pre-existing boundary cluster and would not have this environment variable. As a result, we needed an alternative way to check if an e2e test should be skipped when running tests in ci. * refact(e2e): Create more common boundary methods * fix(e2e): Set to string value Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
268 lines
9.5 KiB
Go
268 lines
9.5 KiB
Go
package aws_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
"github.com/hashicorp/boundary/api/hostcatalogs"
|
|
"github.com/hashicorp/boundary/api/hosts"
|
|
"github.com/hashicorp/boundary/api/hostsets"
|
|
"github.com/hashicorp/boundary/api/scopes"
|
|
"github.com/hashicorp/boundary/testing/internal/e2e"
|
|
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
|
"github.com/kelseyhightower/envconfig"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
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"` // 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"`
|
|
}
|
|
|
|
func loadConfig() (*config, error) {
|
|
var c config
|
|
err := envconfig.Process("", &c)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &c, err
|
|
}
|
|
|
|
// TestCliCreateAwsDynamicHostCatalog 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 TestCliCreateAwsDynamicHostCatalog(t *testing.T) {
|
|
e2e.MaybeSkipTest(t)
|
|
c, err := loadConfig()
|
|
require.NoError(t, err)
|
|
|
|
ctx := context.Background()
|
|
boundary.AuthenticateAdminCli(t, ctx)
|
|
newOrgId := boundary.CreateNewOrgCli(t, ctx)
|
|
t.Cleanup(func() {
|
|
ctx := context.Background()
|
|
boundary.AuthenticateAdminCli(t, ctx)
|
|
output := e2e.RunCommand(ctx, "boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgId))
|
|
require.NoError(t, output.Err, string(output.Stderr))
|
|
})
|
|
newProjectId := boundary.CreateNewProjectCli(t, ctx, newOrgId)
|
|
newHostCatalogId := boundary.CreateNewAwsHostCatalogCli(t, ctx, newProjectId, c.AwsAccessKeyId, c.AwsSecretAccessKey)
|
|
|
|
// Set up a host set
|
|
newHostSetId1 := boundary.CreateNewAwsHostSetCli(t, ctx, newHostCatalogId, c.AwsHostSetFilter1)
|
|
actualHostSetCount1 := boundary.WaitForHostsInHostSetCli(t, ctx, newHostSetId1)
|
|
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")
|
|
|
|
// Set up another host set
|
|
newHostSetId2 := boundary.CreateNewAwsHostSetCli(t, ctx, newHostCatalogId, c.AwsHostSetFilter2)
|
|
actualHostSetCount2 := boundary.WaitForHostsInHostSetCli(t, ctx, newHostSetId2)
|
|
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")
|
|
|
|
// Get list of all hosts from host catalog
|
|
t.Logf("Looking for items in the host catalog...")
|
|
var actualHostCatalogCount int
|
|
err = backoff.RetryNotify(
|
|
func() error {
|
|
output := e2e.RunCommand(ctx, "boundary",
|
|
e2e.WithArgs("hosts", "list", "-host-catalog-id", newHostCatalogId, "-format", "json"),
|
|
)
|
|
if output.Err != nil {
|
|
return backoff.Permanent(errors.New(string(output.Stderr)))
|
|
}
|
|
|
|
var hostCatalogListResult hostcatalogs.HostCatalogListResult
|
|
err := json.Unmarshal(output.Stdout, &hostCatalogListResult)
|
|
if err != nil {
|
|
return backoff.Permanent(err)
|
|
}
|
|
|
|
actualHostCatalogCount = len(hostCatalogListResult.Items)
|
|
if actualHostCatalogCount == 0 {
|
|
return errors.New("No items are appearing in the host catalog")
|
|
}
|
|
|
|
t.Logf("Found %d host(s)", actualHostCatalogCount)
|
|
return nil
|
|
},
|
|
backoff.WithMaxRetries(backoff.NewConstantBackOff(3*time.Second), 5),
|
|
func(err error, td time.Duration) {
|
|
t.Logf("%s. Retrying...", err.Error())
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
expectedHostCatalogCount := expectedHostSetCount1 + expectedHostSetCount2
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expectedHostCatalogCount, actualHostCatalogCount, "Numbers of hosts in host catalog did not match expected amount")
|
|
|
|
// Create target
|
|
newTargetId := boundary.CreateNewTargetCli(t, ctx, newProjectId, c.TargetPort)
|
|
boundary.AddHostSourceToTargetCli(t, ctx, newTargetId, newHostSetId1)
|
|
|
|
// Connect to target
|
|
output := e2e.RunCommand(ctx, "boundary",
|
|
e2e.WithArgs(
|
|
"connect",
|
|
"-target-id", newTargetId,
|
|
"-exec", "/usr/bin/ssh", "--",
|
|
"-l", c.TargetSshUser,
|
|
"-i", c.TargetSshKeyPath,
|
|
"-o", "UserKnownHostsFile=/dev/null",
|
|
"-o", "StrictHostKeyChecking=no",
|
|
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
|
"-p", "{{boundary.port}}", // this is provided by boundary
|
|
"{{boundary.ip}}",
|
|
"hostname", "-i",
|
|
),
|
|
)
|
|
require.NoError(t, output.Err, string(output.Stderr))
|
|
|
|
parts := strings.Fields(string(output.Stdout))
|
|
hostIp := parts[len(parts)-1]
|
|
t.Log("Successfully connected to the target")
|
|
|
|
// Check if connected host exists in the host set
|
|
hostIpInList := false
|
|
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, targetIps1))
|
|
}
|
|
|
|
// TestApiCreateAwsDynamicHostCatalog uses the 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 TestApiCreateAwsDynamicHostCatalog(t *testing.T) {
|
|
e2e.MaybeSkipTest(t)
|
|
c, err := loadConfig()
|
|
require.NoError(t, err)
|
|
|
|
client, err := boundary.NewApiClient()
|
|
require.NoError(t, err)
|
|
ctx := context.Background()
|
|
|
|
newOrgId := boundary.CreateNewOrgApi(t, ctx, client)
|
|
t.Cleanup(func() {
|
|
scopeClient := scopes.NewClient(client)
|
|
_, err := scopeClient.Delete(ctx, newOrgId)
|
|
require.NoError(t, err)
|
|
})
|
|
newProjectId := boundary.CreateNewProjectApi(t, ctx, client, newOrgId)
|
|
|
|
// Create a dynamic host catalog
|
|
hcClient := hostcatalogs.NewClient(client)
|
|
newHostCatalogResult, err := hcClient.Create(ctx, "plugin", newProjectId,
|
|
hostcatalogs.WithName("e2e Automated Test Host Catalog"),
|
|
hostcatalogs.WithPluginName("aws"),
|
|
hostcatalogs.WithAttributes(map[string]any{
|
|
"disable_credential_rotation": true,
|
|
"region": "us-east-1",
|
|
}),
|
|
hostcatalogs.WithSecrets(map[string]any{
|
|
"access_key_id": c.AwsAccessKeyId,
|
|
"secret_access_key": c.AwsSecretAccessKey,
|
|
}),
|
|
)
|
|
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,
|
|
hostsets.WithAttributes(map[string]any{
|
|
"filters": c.AwsHostSetFilter1,
|
|
}),
|
|
hostsets.WithName("e2e Automated Test Host Set"),
|
|
)
|
|
require.NoError(t, err)
|
|
newHostSetId := newHostSetResult.Item.Id
|
|
t.Logf("Created Host Set: %s", newHostSetId)
|
|
|
|
// Get list of hosts in host set
|
|
// Retry is needed here since it can take a few tries before hosts start appearing
|
|
t.Logf("Looking for items in the host set...")
|
|
var actualHostSetCount int
|
|
err = backoff.RetryNotify(
|
|
func() error {
|
|
hostSetReadResult, err := hsClient.Read(ctx, newHostSetId)
|
|
if err != nil {
|
|
return backoff.Permanent(err)
|
|
}
|
|
|
|
actualHostSetCount = len(hostSetReadResult.Item.HostIds)
|
|
if actualHostSetCount == 0 {
|
|
return errors.New("No items are appearing in the host set")
|
|
}
|
|
|
|
t.Logf("Found %d hosts", actualHostSetCount)
|
|
return nil
|
|
},
|
|
backoff.WithMaxRetries(backoff.NewConstantBackOff(3*time.Second), 5),
|
|
func(err error, td time.Duration) {
|
|
t.Logf("%s. Retrying...", err.Error())
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
t.Log("Successfully found items in the host set")
|
|
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")
|
|
|
|
// Get list of all hosts from host catalog
|
|
// Retry is needed here since it can take a few tries before hosts start appearing
|
|
t.Logf("Looking for items in the host catalog...")
|
|
var actualHostCatalogCount int
|
|
hClient := hosts.NewClient(client)
|
|
err = backoff.RetryNotify(
|
|
func() error {
|
|
hostListResult, err := hClient.List(ctx, newHostCatalogId)
|
|
if err != nil {
|
|
return backoff.Permanent(err)
|
|
}
|
|
|
|
actualHostCatalogCount = len(hostListResult.Items)
|
|
if actualHostCatalogCount == 0 {
|
|
return errors.New("No items are appearing in the host catalog")
|
|
}
|
|
|
|
t.Logf("Found %d hosts", actualHostCatalogCount)
|
|
return nil
|
|
},
|
|
backoff.WithMaxRetries(backoff.NewConstantBackOff(3*time.Second), 5),
|
|
func(err error, td time.Duration) {
|
|
t.Logf("%s. Retrying...", err.Error())
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
t.Log("Successfully found items in the host catalog")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, actualHostCatalogCount, expectedHostSetCount, "Numbers of hosts in host catalog did not match expected amount")
|
|
}
|