Skip to content

Commit

Permalink
test(e2e): Add test with scp operations (#3812)
Browse files Browse the repository at this point in the history
* chore(e2e): Allow ssh to targets to assist with debugging

* test(e2e): Add test with scp operations

* CR: Use io.CopyN to optimize memory allocation

This mitigates the need to allocate a 256K string
  • Loading branch information
moduli authored Oct 10, 2023
1 parent 43ae625 commit 578d870
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
18 changes: 18 additions & 0 deletions enos/modules/aws_target/main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

terraform {
required_providers {
enos = {
source = "app.terraform.io/hashicorp-qti/enos"
}
}
}

variable "vpc_id" {}
variable "ami_id" {}
variable "subnet_ids" {}
Expand All @@ -18,6 +26,8 @@ variable "ingress_cidr" {
default = ["10.0.0.0/8"]
}

data "enos_environment" "current" {}

resource "aws_security_group" "boundary_target" {
name_prefix = "boundary-target-sg"
description = "SSH and boundary Traffic"
Expand All @@ -31,6 +41,14 @@ resource "aws_security_group" "boundary_target" {
cidr_blocks = var.ingress_cidr
}

ingress {
description = "SSH to the instance"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = flatten([formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses)])
}

egress {
from_port = 0
to_port = 0
Expand Down
155 changes: 155 additions & 0 deletions testing/internal/e2e/tests/base/target_tcp_connect_scp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package base_test

import (
"context"
"crypto/rand"
"fmt"
"io"
"os"
"strings"
"testing"

"github.com/hashicorp/boundary/internal/target"
"github.com/hashicorp/boundary/testing/internal/e2e"
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
"github.com/stretchr/testify/require"
)

// TestCliTcpTargetConnectTargetAndScp connects to a target and validates scp
// operations by uploading and downloading a file to a host and verifies that
// checksums match
func TestCliTcpTargetConnectTargetAndScp(t *testing.T) {
e2e.MaybeSkipTest(t)
c, err := loadTestConfig()
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)
newTargetId := boundary.CreateNewTargetCli(
t,
ctx,
newProjectId,
c.TargetPort,
target.WithAddress(c.TargetAddress),
)

// Start a session
ctxCancel, cancel := context.WithCancel(context.Background())
port := "12345"
cmdChan := make(chan *e2e.CommandResult)
go func() {
t.Log("Starting session...")
cmdChan <- e2e.RunCommand(ctxCancel, "boundary",
e2e.WithArgs(
"connect",
"-target-id", newTargetId,
"-listen-port", port,
"-format", "json",
),
)
}()
t.Cleanup(cancel)

boundary.WaitForSessionCli(t, ctx, newProjectId)

// Create file to scp
testDir := t.TempDir()
t.Log("Creating text file...")
fileSource := fmt.Sprintf("%s/%s_src.txt", testDir, t.Name())
f, err := os.Create(fileSource)
require.NoError(t, err)
io.CopyN(f, rand.Reader, 256000)

fi, err := f.Stat()
require.NoError(t, err)
require.Greater(t, fi.Size(), int64(16000), "Generated file is not larger than 16K")

output := e2e.RunCommand(ctx, "cksum", e2e.WithArgs(fileSource))
require.NoError(t, output.Err, string(output.Stderr))
parts := strings.Fields(string(output.Stdout))
cksumSource := parts[0]

// Copy file to host
t.Log("Copying file to host...")
fileUpload := fmt.Sprintf("/tmp/%s_upload.txt", t.Name())
output = e2e.RunCommand(ctx, "scp",
e2e.WithArgs(
"-i", c.TargetSshKeyPath,
"-P", port,
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no",
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
fileSource,
fmt.Sprintf("%s@localhost:%s", c.TargetSshUser, fileUpload),
),
)
require.NoError(t, output.Err, string(output.Stderr))

// Validate checksum
output = e2e.RunCommand(ctx, "ssh",
e2e.WithArgs(
"localhost",
"-p", port,
"-l", c.TargetSshUser,
"-i", c.TargetSshKeyPath,
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no",
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
fmt.Sprintf("cksum %s", fileUpload),
),
)
require.NoError(t, output.Err, string(output.Stderr))
parts = strings.Fields(string(output.Stdout))
cksumUpload := parts[0]
require.Equal(t, cksumSource, cksumUpload, "Checksum of uploaded file does not match source")

// Read file on host
t.Log("Reading file on host...")
output = e2e.RunCommand(ctx, "ssh",
e2e.WithArgs(
"localhost",
"-p", port,
"-l", c.TargetSshUser,
"-i", c.TargetSshKeyPath,
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no",
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
fmt.Sprintf("cat %s", fileUpload),
),
)
require.NoError(t, output.Err, string(output.Stderr))

// Download file from host
t.Log("Downloading file from host...")
fileDownload := fmt.Sprintf("%s/%s_download.txt", testDir, t.Name())
output = e2e.RunCommand(ctx, "scp",
e2e.WithArgs(
"-i", c.TargetSshKeyPath,
"-P", port,
"-o", "UserKnownHostsFile=/dev/null",
"-o", "StrictHostKeyChecking=no",
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
fmt.Sprintf("%s@localhost:%s", c.TargetSshUser, fileUpload),
fileDownload,
),
)
require.NoError(t, output.Err, string(output.Stderr))

// Validate checksum
output = e2e.RunCommand(ctx, "cksum", e2e.WithArgs(fileDownload))
require.NoError(t, output.Err, string(output.Stderr))
parts = strings.Fields(string(output.Stdout))
cksumDownload := parts[0]
require.Equal(t, cksumSource, cksumDownload, "Checksum of downloaded file does not match source")
}

0 comments on commit 578d870

Please sign in to comment.