Skip to content

Commit

Permalink
EFS functional test
Browse files Browse the repository at this point in the history
  • Loading branch information
sparrc committed Oct 24, 2019
1 parent 440c88c commit 7a40418
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"family": "ecsftest-task-efs-volume",
"containerDefinitions": [
{
"name": "task-efs-vol-read",
"image": "127.0.0.1:51670/busybox:latest",
"cpu": 10,
"command": ["sh", "-c", "while true; do sleep 1; [ -f /ecs/success ] && if grep -q 'can you read me' /ecs/success; then exit 42; fi done"],
"memory": 256,
"memoryReservation": 128,
"mountPoints": [
{
"sourceVolume": "task-efs-shared",
"containerPath": "/ecs/"
}
]
}
],
"volumes":[
{
"name": "task-efs-shared",
"host": null,
"dockerVolumeConfiguration" : {
"scope": "shared",
"autoprovision": true,
"driver": "local",
"labels": {
"mylabels": "test"
},
"driverOpts": {
"type": "nfs",
"device": ":/",
"o": "addr=FILESYSTEM_ID.efs.TEST_REGION.amazonaws.com,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"family": "ecsftest-task-efs-volume",
"containerDefinitions": [
{
"name": "task-efs-vol-write",
"image": "127.0.0.1:51670/busybox:latest",
"cpu": 10,
"command": ["sh", "-c", "echo 'can you read me'> /ecs/success; [ -f /ecs/success ] && exit 42 || exit 1"],
"memory": 256,
"memoryReservation": 128,
"mountPoints": [
{
"sourceVolume": "task-efs-shared",
"containerPath": "/ecs/"
}
]
}
],
"volumes":[
{
"name": "task-efs-shared",
"host": null,
"dockerVolumeConfiguration" : {
"scope": "shared",
"autoprovision": true,
"driver": "local",
"labels": {
"mylabels": "test"
},
"driverOpts": {
"type": "nfs",
"device": ":/",
"o": "addr=FILESYSTEM_ID.efs.TEST_REGION.amazonaws.com,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"
}
}
}
]
}
116 changes: 113 additions & 3 deletions agent/functional_tests/tests/functionaltests_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,11 @@ func TestASMSecretsARN(t *testing.T) {
assert.Equal(t, 42, exitCode, fmt.Sprintf("Expected exit code of 42; got %d", exitCode))
}

// TestRunEFSVolumeTask TODO
// TestRunEFSVolumeTask does the following:
// 1. creates an EFS filesystem with a mount target.
// 2. spins up a task to mount and write to the filesystem.
// 3. spins up a task to mount and read from the filesystem.
// 4. TODO: do this via EFSVolumeConfiguration instead of via NFS/Docker.
func TestRunEFSVolumeTask(t *testing.T) {
if os.Getenv("TEST_DISABLE_EXECUTION_ROLE") == "true" {
t.Skip("TEST_DISABLE_EXECUTION_ROLE was set to true")
Expand All @@ -1370,11 +1374,117 @@ func TestRunEFSVolumeTask(t *testing.T) {
t.Skip("Skip TestSSMSecretsEncryptedParameter in China partition")
}

_ = efs.New(session.New(), aws.NewConfig().WithRegion(*ECS.Config.Region))
_ = &efs.CreateFileSystemInput{}
agent := RunAgent(t, nil)
defer agent.Cleanup()

fsID := createEFSFileSystem(t)

// start writer task first
overrides := map[string]string{
"FILESYSTEM_ID": fsID,
"TEST_REGION": *ECS.Config.Region,
}
wTask, err := agent.StartTaskWithTaskDefinitionOverrides(t, "task-efs-vol-write", overrides)
require.NoError(t, err, "Register task definition failed")
// Wait for the first task to create the volume
wErr := wTask.WaitStopped(waitTaskStateChangeDuration)
require.NoError(t, wErr, "Error waiting for task to transition to STOPPED")
wExitCode, ok := wTask.ContainerExitcode("task-efs-vol-write")
require.True(t, ok, "Error code for container [task-efs-vol-write] not found, check the logs")
assert.Equal(t, 42, wExitCode, fmt.Sprintf("Expected exit code of 42; got %d", wExitCode))

// then reader task try to read from the volume
rTask, err := agent.StartTaskWithTaskDefinitionOverrides(t, "task-efs-vol-read", overrides)
require.NoError(t, err, "Register task definition failed")

rErr := rTask.WaitStopped(waitTaskStateChangeDuration)
require.NoError(t, rErr, "Error waiting for task to transition to STOPPED")
rExitCode, ok := rTask.ContainerExitcode("task-efs-vol-read")
require.True(t, ok, "Error code for container [task-efs-vol-read] not found, check the logs")
assert.Equal(t, 42, rExitCode, fmt.Sprintf("Expected exit code of 42; got %d", rExitCode))
return
}

// createEFSFileSystem creates an EFS file system with the given creation token.
// If the FS has already been created, it gets the fileSystemId and returns it.
// If it has not been created, then it creates it an waits for it to become "available",
// then creates a mount target with the instance's default subnet ID.
func createEFSFileSystem(t *testing.T) string {
creationToken := uuid.New()
efsClient := efs.New(session.New(), aws.NewConfig().WithRegion(*ECS.Config.Region))
fs, err := efsClient.CreateFileSystem(&efs.CreateFileSystemInput{
CreationToken: aws.String(creationToken),
})
require.NoError(t, err, "Error creating EFS filesystem")
defer deleteEFSFileSystem(*fs.FileSystemId, efsClient)

// Wait for filesystem to be "available"
for true {
out, err := efsClient.DescribeFileSystems(&efs.DescribeFileSystemsInput{
CreationToken: aws.String(creationToken),
})
require.NoError(t, err, "Unexpected error from DescribeFileSystems: %s", err)
if *out.FileSystems[0].LifeCycleState == efs.LifeCycleStateAvailable {
break
}
time.Sleep(time.Second)
}

// create mount target
subnetID, err := GetSubnetID()
require.NoError(t, err, "Could not get the instance's subnet ID")
mt, err := efsClient.CreateMountTarget(&efs.CreateMountTargetInput{
FileSystemId: fs.FileSystemId,
SubnetId: aws.String(subnetID),
})
require.NoError(t, err, "Error creating filesystem's mount target")
// Wait for mount target to be "available"
for true {
out, err := efsClient.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: mt.MountTargetId,
})
require.NoError(t, err, "Unexpected error from DescribeMountTargets: %s", err)
if *out.MountTargets[0].LifeCycleState == efs.LifeCycleStateAvailable {
break
}
time.Sleep(time.Second)
}
defer deleteEFSMountTarget(*mt.MountTargetId, efsClient)

return *fs.FileSystemId
}

func deleteEFSFileSystem(fsID string, efsClient *efs.EFS) {
_, err := efsClient.DeleteFileSystem(&efs.DeleteFileSystemInput{
FileSystemId: aws.String(fsID),
})
if err != nil {
fmt.Printf("Cleanup ERROR, deleting file system: %s\n", err)
}
}

func deleteEFSMountTarget(mtID string, efsClient *efs.EFS) {
_, err := efsClient.DeleteMountTarget(&efs.DeleteMountTargetInput{
MountTargetId: aws.String(mtID),
})
if err != nil {
fmt.Printf("Cleanup ERROR, deleting mount target: %s\n", err)
}
// wait for mount target to be "deleted" (or just disappear)
for true {
out, err := efsClient.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(mtID),
})
if err != nil {
return
}
if *out.MountTargets[0].LifeCycleState == efs.LifeCycleStateDeleted {
return
}
time.Sleep(time.Second)
}
}

// Note: This functional test requires ECS GPU instance which has at least 1 GPU.
func TestRunGPUTask(t *testing.T) {
gpuInstances := []string{"p2", "p3", "g3", "g4dn"}
Expand Down
8 changes: 4 additions & 4 deletions agent/functional_tests/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
"github.com/aws/amazon-ecs-agent/agent/dockerclient/sdkclientfactory"
"github.com/aws/amazon-ecs-agent/agent/ec2"
"github.com/aws/amazon-ecs-agent/agent/ecs_client/model/ecs"
"github.com/aws/amazon-ecs-agent/agent/handlers/v1"
v1 "github.com/aws/amazon-ecs-agent/agent/handlers/v1"
"github.com/aws/amazon-ecs-agent/agent/utils"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
Expand Down Expand Up @@ -275,7 +275,7 @@ func (agent *TestAgent) startAWSVPCTask(taskDefinition string) (*TestTask, error
agent.t.Logf("Task definition: %s", taskDefinition)
// Get the subnet ID, which is a required parameter for starting
// tasks in 'awsvpc' network mode
subnet, err := getSubnetID()
subnet, err := GetSubnetID()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -809,8 +809,8 @@ func AttributesToMap(attributes []*ecs.Attribute) map[string]string {
return attributeMap
}

// getSubnetID gets the subnet id for the instance from ec2 instance metadata
func getSubnetID() (string, error) {
// GetSubnetID gets the subnet id for the instance from ec2 instance metadata
func GetSubnetID() (string, error) {
ec2Metadata := ec2metadata.New(session.Must(session.NewSession()))
mac, err := ec2Metadata.GetMetadata("mac")
if err != nil {
Expand Down

0 comments on commit 7a40418

Please sign in to comment.