// Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package utils import ( "io/ioutil" "os" "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ecs" "github.com/docker/libcompose/yaml" "github.com/stretchr/testify/assert" ) func TestReadECSParams(t *testing.T) { ecsParamsString := `version: 1 task_definition: ecs_network_mode: host task_role_arn: arn:aws:iam::123456789012:role/my_role` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { assert.Equal(t, "1", ecsParams.Version, "Expected version to match") taskDef := ecsParams.TaskDefinition assert.Equal(t, "host", taskDef.NetworkMode, "Expected network mode to match") assert.Equal(t, "arn:aws:iam::123456789012:role/my_role", taskDef.TaskRoleArn, "Expected task role ARN to match") // Should still populate other fields with empty values assert.Empty(t, taskDef.ExecutionRole) awsvpcConfig := ecsParams.RunParams.NetworkConfiguration.AwsVpcConfiguration assert.Empty(t, awsvpcConfig.Subnets) assert.Empty(t, awsvpcConfig.SecurityGroups) } } func TestReadECSParams_FileDoesNotExist(t *testing.T) { _, err := ReadECSParams("nonexistant.yml") assert.Error(t, err) } func TestReadECSParams_NoFile(t *testing.T) { ecsParams, err := ReadECSParams("") if assert.NoError(t, err) { assert.Nil(t, ecsParams) } } func TestReadECSParams_WithServices(t *testing.T) { ecsParamsString := `version: 1 task_definition: ecs_network_mode: host task_role_arn: arn:aws:iam::123456789012:role/my_role services: log_router: firelens_configuration: type: fluentbit options: enable-ecs-log-metadata: "true" mysql: essential: false cpu_shares: 100 mem_limit: 524288000 mem_reservation: 500mb wordpress: essential: true depends_on: - container_name: mysql condition: STARTED - container_name: log_router condition: STARTED repository_credentials: credentials_parameter: arn:aws:secretsmanager:1234567890:secret:test-RT4iv logging: secret_options: - value_from: arn:aws:ssm:eu-west-1:111111111111:parameter/mysecrets/dbpassword name: DB_PASSWORD - value_from: /mysecrets/dbusername name: DB_USERNAME secrets: - value_from: arn:aws:ssm:eu-west-1:111111111111:parameter/mysecrets/dbpassword name: DB_PASSWORD - value_from: /mysecrets/dbusername name: DB_USERNAME` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskDef := ecsParams.TaskDefinition assert.Equal(t, "host", ecsParams.TaskDefinition.NetworkMode, "Expected NetworkMode to match") assert.Equal(t, "arn:aws:iam::123456789012:role/my_role", taskDef.TaskRoleArn, "Expected TaskRoleArn to match") containerDefs := taskDef.ContainerDefinitions assert.Equal(t, 3, len(containerDefs), "Expected 3 containers") mysql := containerDefs["mysql"] wordpress := containerDefs["wordpress"] log_router := containerDefs["log_router"] assert.False(t, mysql.Essential, "Expected container to not be essential") assert.Equal(t, int64(100), mysql.Cpu) assert.Equal(t, yaml.MemStringorInt(524288000), mysql.Memory) assert.Equal(t, yaml.MemStringorInt(524288000), mysql.MemoryReservation) assert.True(t, wordpress.Essential, "Expected container to be essential") assert.Equal(t, "arn:aws:secretsmanager:1234567890:secret:test-RT4iv", wordpress.RepositoryCredentials.CredentialsParameter, "Expected CredentialsParameter to match") expectedSecrets := []Secret{ Secret{ ValueFrom: "arn:aws:ssm:eu-west-1:111111111111:parameter/mysecrets/dbpassword", Name: "DB_PASSWORD", }, Secret{ ValueFrom: "/mysecrets/dbusername", Name: "DB_USERNAME", }, } assert.ElementsMatch(t, expectedSecrets, wordpress.Secrets, "Expected secrets to match") assert.ElementsMatch(t, expectedSecrets, wordpress.Logging.SecretOptions, "Expected secrets to match") expectedContainerDependencies := []ContainerDependency { ContainerDependency { ContainerName: "mysql", Condition: "STARTED", }, ContainerDependency { ContainerName: "log_router", Condition: "STARTED", }, } assert.ElementsMatch(t, expectedContainerDependencies, wordpress.ContainerDependencies, "Expected container dependiencies to match") assert.Equal(t, "fluentbit", log_router.FirelensConfiguration.Type, "Except firelens_configuration type to be fluentbit") assert.Equal(t, "true", log_router.FirelensConfiguration.Options["enable-ecs-log-metadata"], "Expected Firelens 'enable-ecs-log-metadata' to be 'true'") } } func TestReadECSParams_WithRunParams(t *testing.T) { ecsParamsString := `version: 1 task_definition: ecs_network_mode: awsvpc run_params: network_configuration: awsvpc_configuration: subnets: [subnet-feedface, subnet-deadbeef] security_groups: - sg-bafff1ed - sg-c0ffeefe` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskDef := ecsParams.TaskDefinition assert.Equal(t, "awsvpc", taskDef.NetworkMode, "Expected network mode to match") awsvpcConfig := ecsParams.RunParams.NetworkConfiguration.AwsVpcConfiguration assert.Equal(t, 2, len(awsvpcConfig.Subnets), "Expected 2 subnets") assert.Equal(t, []string{"subnet-feedface", "subnet-deadbeef"}, awsvpcConfig.Subnets, "Expected subnets to match") assert.Equal(t, 2, len(awsvpcConfig.SecurityGroups), "Expected 2 securityGroups") assert.Equal(t, []string{"sg-bafff1ed", "sg-c0ffeefe"}, awsvpcConfig.SecurityGroups, "Expected security groups to match") assert.Equal(t, AssignPublicIp(""), awsvpcConfig.AssignPublicIp, "Expected AssignPublicIP to be empty") } } // Task Size, Task Execution Role, and Assign Public Ip are required for Fargate tasks func TestReadECSParams_WithFargateRunParams(t *testing.T) { ecsParamsString := `version: 1 task_definition: ecs_network_mode: awsvpc task_execution_role: arn:aws:iam::123456789012:role/fargate_role task_size: mem_limit: 0.5GB cpu_limit: 256 run_params: network_configuration: awsvpc_configuration: subnets: [subnet-feedface, subnet-deadbeef] security_groups: - sg-bafff1ed - sg-c0ffeefe assign_public_ip: ENABLED` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskDef := ecsParams.TaskDefinition assert.Equal(t, "awsvpc", taskDef.NetworkMode, "Expected network mode to match") assert.Equal(t, "arn:aws:iam::123456789012:role/fargate_role", taskDef.ExecutionRole) assert.Equal(t, "0.5GB", taskDef.TaskSize.Memory) assert.Equal(t, "256", taskDef.TaskSize.Cpu) awsvpcConfig := ecsParams.RunParams.NetworkConfiguration.AwsVpcConfiguration assert.Equal(t, 2, len(awsvpcConfig.Subnets), "Expected 2 subnets") assert.Equal(t, []string{"subnet-feedface", "subnet-deadbeef"}, awsvpcConfig.Subnets, "Expected subnets to match") assert.Equal(t, 2, len(awsvpcConfig.SecurityGroups), "Expected 2 securityGroups") assert.Equal(t, []string{"sg-bafff1ed", "sg-c0ffeefe"}, awsvpcConfig.SecurityGroups, "Expected security groups to match") assert.Equal(t, Enabled, awsvpcConfig.AssignPublicIp, "Expected AssignPublicIp to match") } } func TestReadECSParams_WithTaskPlacement(t *testing.T) { ecsParamsString := `version: 1 task_definition: placement_constraints: - type: memberOf expression: attribute:ecs.os-type == linux run_params: task_placement: strategy: - field: memory type: binpack - field: attribute:ecs.availability-zone type: spread constraints: - expression: attribute:ecs.instance-type =~ t2.* type: memberOf - type: distinctInstance` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs fields tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs fields tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") expectedStrategies := []Strategy{ { Field: "memory", Type: ecs.PlacementStrategyTypeBinpack, }, { Field: "attribute:ecs.availability-zone", Type: ecs.PlacementStrategyTypeSpread, }, } expectedConstraints := []Constraint{ { Expression: "attribute:ecs.instance-type =~ t2.*", Type: ecs.PlacementConstraintTypeMemberOf, }, { Type: ecs.PlacementConstraintTypeDistinctInstance, }, } expectedTaskDefConstraints := []Constraint{ { Expression: "attribute:ecs.os-type == linux", Type: ecs.PlacementConstraintTypeMemberOf, }, } ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskPlacement := ecsParams.RunParams.TaskPlacement strategies := taskPlacement.Strategies constraints := taskPlacement.Constraints assert.Len(t, strategies, 2) assert.Len(t, constraints, 2) assert.ElementsMatch(t, expectedStrategies, strategies) assert.ElementsMatch(t, expectedConstraints, constraints) taskDefConstraints := ecsParams.TaskDefinition.PlacementConstraints assert.ElementsMatch(t, expectedTaskDefConstraints, taskDefConstraints) } } func TestReadECSParams_MemoryWithUnits(t *testing.T) { ecsParamsString := `version: 1 task_definition: ecs_network_mode: awsvpc task_size: mem_limit: 0.5GB cpu_limit: 256` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskSize := ecsParams.TaskDefinition.TaskSize assert.Equal(t, "256", taskSize.Cpu, "Expected CPU limit to match") assert.Equal(t, "0.5GB", taskSize.Memory, "Expected Memory limit to match") } } // Task Size must match specific CPU/Memory buckets, but we leave validation to ECS. func TestReadECSParams_WithTaskSize(t *testing.T) { ecsParamsString := `version: 1 task_definition: task_size: mem_limit: 1024 cpu_limit: 256` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskSize := ecsParams.TaskDefinition.TaskSize assert.Equal(t, "256", taskSize.Cpu, "Expected CPU limit to match") assert.Equal(t, "1024", taskSize.Memory, "Expected Memory limit to match") } } func TestReadECSParams_WithPIDandIPC(t *testing.T) { ecsParamsString := `version: 1 task_definition: pid_mode: host ipc_mode: task` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { assert.Equal(t, "host", ecsParams.TaskDefinition.PIDMode, "Expected PIDMode to be set") assert.Equal(t, "task", ecsParams.TaskDefinition.IPCMode, "Expected IPCMode to be set") } } /** ConvertToECSNetworkConfiguration tests **/ func TestConvertToECSNetworkConfiguration(t *testing.T) { taskDef := EcsTaskDef{NetworkMode: "awsvpc"} subnets := []string{"subnet-feedface"} securityGroups := []string{"sg-c0ffeefe"} awsVpconfig := AwsVpcConfiguration{ Subnets: subnets, SecurityGroups: securityGroups, } networkConfig := NetworkConfiguration{ AwsVpcConfiguration: awsVpconfig, } ecsParams := &ECSParams{ TaskDefinition: taskDef, RunParams: RunParams{ NetworkConfiguration: networkConfig, }, } ecsNetworkConfig, err := ConvertToECSNetworkConfiguration(ecsParams) if assert.NoError(t, err) { ecsAwsConfig := ecsNetworkConfig.AwsvpcConfiguration assert.Equal(t, subnets[0], aws.StringValue(ecsAwsConfig.Subnets[0]), "Expected subnets to match") assert.Equal(t, securityGroups[0], aws.StringValue(ecsAwsConfig.SecurityGroups[0]), "Expected securityGroups to match") assert.Nil(t, ecsAwsConfig.AssignPublicIp, "Expected AssignPublicIp to be nil") } } func TestConvertToECSNetworkConfiguration_NoSecurityGroups(t *testing.T) { taskDef := EcsTaskDef{NetworkMode: "awsvpc"} subnets := []string{"subnet-feedface"} awsVpconfig := AwsVpcConfiguration{ Subnets: subnets, } networkConfig := NetworkConfiguration{ AwsVpcConfiguration: awsVpconfig, } ecsParams := &ECSParams{ TaskDefinition: taskDef, RunParams: RunParams{ NetworkConfiguration: networkConfig, }, } ecsNetworkConfig, err := ConvertToECSNetworkConfiguration(ecsParams) if assert.NoError(t, err) { ecsAwsConfig := ecsNetworkConfig.AwsvpcConfiguration assert.Equal(t, subnets[0], aws.StringValue(ecsAwsConfig.Subnets[0]), "Expected subnets to match") assert.Nil(t, ecsAwsConfig.AssignPublicIp, "Expected AssignPublicIp to be nil") } } func TestConvertToECSNetworkConfiguration_ErrorWhenNoSubnets(t *testing.T) { taskDef := EcsTaskDef{NetworkMode: "awsvpc"} subnets := []string{} awsVpconfig := AwsVpcConfiguration{ Subnets: subnets, } networkConfig := NetworkConfiguration{ AwsVpcConfiguration: awsVpconfig, } ecsParams := &ECSParams{ TaskDefinition: taskDef, RunParams: RunParams{ NetworkConfiguration: networkConfig, }, } _, err := ConvertToECSNetworkConfiguration(ecsParams) assert.Error(t, err) } func TestConvertToECSNetworkConfiguration_WhenNoECSParams(t *testing.T) { ecsParams, err := ConvertToECSNetworkConfiguration(nil) if assert.NoError(t, err) { assert.Nil(t, ecsParams) } } func TestConvertToECSNetworkConfiguration_WithAssignPublicIp(t *testing.T) { taskDef := EcsTaskDef{NetworkMode: "awsvpc"} subnets := []string{"subnet-feedface"} awsVpconfig := AwsVpcConfiguration{ Subnets: subnets, AssignPublicIp: Enabled, } networkConfig := NetworkConfiguration{ AwsVpcConfiguration: awsVpconfig, } ecsParams := &ECSParams{ TaskDefinition: taskDef, RunParams: RunParams{ NetworkConfiguration: networkConfig, }, } ecsNetworkConfig, err := ConvertToECSNetworkConfiguration(ecsParams) if assert.NoError(t, err) { ecsAwsConfig := ecsNetworkConfig.AwsvpcConfiguration assert.Equal(t, subnets[0], aws.StringValue(ecsAwsConfig.Subnets[0]), "Expected subnets to match") assert.Equal(t, "ENABLED", aws.StringValue(ecsAwsConfig.AssignPublicIp), "Expected AssignPublicIp to match") } } func TestConvertToECSNetworkConfiguration_NoNetworkConfig(t *testing.T) { taskDef := EcsTaskDef{NetworkMode: "bridge"} ecsParams := &ECSParams{ TaskDefinition: taskDef, } ecsNetworkConfig, err := ConvertToECSNetworkConfiguration(ecsParams) if assert.NoError(t, err) { assert.Nil(t, ecsNetworkConfig, "Expected AssignPublicIp to be nil") } } func TestConvertToECSPlacementConstraints(t *testing.T) { constraint1 := Constraint{ Expression: "attribute:ecs.instance-type =~ t2.*", Type: ecs.PlacementConstraintTypeMemberOf, } constraint2 := Constraint{ Type: ecs.PlacementConstraintTypeDistinctInstance, } constraints := []Constraint{constraint1, constraint2} taskPlacement := TaskPlacement{ Constraints: constraints, } ecsParams := &ECSParams{ RunParams: RunParams{ TaskPlacement: taskPlacement, }, } expectedConstraints := []*ecs.PlacementConstraint{ &ecs.PlacementConstraint{ Expression: aws.String("attribute:ecs.instance-type =~ t2.*"), Type: aws.String(ecs.PlacementConstraintTypeMemberOf), }, &ecs.PlacementConstraint{ Type: aws.String(ecs.PlacementConstraintTypeDistinctInstance), }, } ecsPlacementConstraints, err := ConvertToECSPlacementConstraints(ecsParams) if assert.NoError(t, err) { assert.ElementsMatch(t, expectedConstraints, ecsPlacementConstraints, "Expected placement constraints to match") } } func TestConvertToECSPlacementStrategy(t *testing.T) { strategy1 := Strategy{ Field: "instanceId", Type: ecs.PlacementStrategyTypeBinpack, } strategy2 := Strategy{ Field: "attribute:ecs.availability-zone", Type: ecs.PlacementStrategyTypeSpread, } strategy3 := Strategy{ Type: ecs.PlacementStrategyTypeRandom, } strategy := []Strategy{strategy1, strategy2, strategy3} taskPlacement := TaskPlacement{ Strategies: strategy, } ecsParams := &ECSParams{ RunParams: RunParams{ TaskPlacement: taskPlacement, }, } expectedStrategy := []*ecs.PlacementStrategy{ &ecs.PlacementStrategy{ Field: aws.String("instanceId"), Type: aws.String(ecs.PlacementStrategyTypeBinpack), }, &ecs.PlacementStrategy{ Field: aws.String("attribute:ecs.availability-zone"), Type: aws.String(ecs.PlacementStrategyTypeSpread), }, &ecs.PlacementStrategy{ Type: aws.String(ecs.PlacementStrategyTypeRandom), }, } ecsPlacementStrategy, err := ConvertToECSPlacementStrategy(ecsParams) if assert.NoError(t, err) { assert.ElementsMatch(t, expectedStrategy, ecsPlacementStrategy, "Expected placement strategy to match") } } func TestReadECSParams_WithDockerVolumes(t *testing.T) { ecsParamsString := `version: 1 task_definition: docker_volumes: - name: my_volume scope: shared autoprovision: true driver: doggyromcom driver_opts: pudding: is-engaged-to-marry-Tum-Tum clyde: professes-his-love-at-the-ceremony it: does-not-go-well this: is-not-a-movie labels: pudding: mad clyde: sad life: sucks` expectedVolumes := []DockerVolume{ DockerVolume{ Name: "my_volume", Scope: aws.String("shared"), Autoprovision: aws.Bool(true), Driver: aws.String("doggyromcom"), DriverOptions: map[string]string{ "pudding": "is-engaged-to-marry-Tum-Tum", "clyde": "professes-his-love-at-the-ceremony", "it": "does-not-go-well", "this": "is-not-a-movie", }, Labels: map[string]string{ "pudding": "mad", "clyde": "sad", "life": "sucks", }, }, } content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { volumes := ecsParams.TaskDefinition.DockerVolumes assert.ElementsMatch(t, expectedVolumes, volumes, "Expected volumes to match") } } func TestReadECSParams_WithHealthCheck(t *testing.T) { ecsParamsString := `version: 1 task_definition: services: mysql: healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 1m30s timeout: 10s retries: 3 start_period: 40s wordpress: healthcheck: command: ["CMD-SHELL", "curl -f http://localhost"] interval: 70 timeout: 15 retries: 5 start_period: 40 logstash: healthcheck: test: curl -f http://localhost interval: 10m timeout: 15s retries: 5 start_period: 50 elasticsearch: healthcheck: command: curl http://example.com interval: 10 timeout: 15 retries: 5 start_period: 50s` mysqlExpectedHealthCheck := &HealthCheck{ Test: []string{"CMD", "curl", "-f", "http://localhost"}, Command: nil, Interval: "1m30s", Timeout: "10s", Retries: 3, StartPeriod: "40s", } wordpressExpectedHealthCheck := &HealthCheck{ Command: []string{"CMD-SHELL", "curl -f http://localhost"}, Test: nil, Interval: "70", Timeout: "15", Retries: int64(5), StartPeriod: "40", } logstashExpectedHealthCheck := &HealthCheck{ Test: []string{"curl -f http://localhost"}, Command: nil, Interval: "10m", Timeout: "15s", Retries: 5, StartPeriod: "50", } elasticsearchExpectedHealthCheck := &HealthCheck{ Command: []string{"curl http://example.com"}, Test: nil, Interval: "10", Timeout: "15", Retries: 5, StartPeriod: "50s", } content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { taskDef := ecsParams.TaskDefinition containerDefs := taskDef.ContainerDefinitions assert.Equal(t, 4, len(containerDefs), "Expected 4 containers") mysql := containerDefs["mysql"] wordpress := containerDefs["wordpress"] logstash := containerDefs["logstash"] elasticsearch := containerDefs["elasticsearch"] assert.Equal(t, mysqlExpectedHealthCheck, mysql.HealthCheck) assert.Equal(t, wordpressExpectedHealthCheck, wordpress.HealthCheck) assert.Equal(t, logstashExpectedHealthCheck, logstash.HealthCheck) assert.Equal(t, elasticsearchExpectedHealthCheck, elasticsearch.HealthCheck) } } func TestReadECSParams_WithServiceDiscoveryAllFields(t *testing.T) { ecsParamsString := `version: 1 run_params: service_discovery: container_name: nginx container_port: 80 private_dns_namespace: vpc: vpc-8BAADF00D id: ns-CA15CA15CA15CA15 name: corp description: This is a private namespace public_dns_namespace: id: ns-C0VF3F3 name: amazon.com service_discovery_service: name: mysds description: This is an SDS dns_config: type: A ttl: 60 healthcheck_custom_config: failure_threshold: 1` content := []byte(ecsParamsString) tmpfile, err := ioutil.TempFile("", "ecs-params") assert.NoError(t, err, "Could not create ecs-params tempfile") ecsParamsFileName := tmpfile.Name() defer os.Remove(ecsParamsFileName) _, err = tmpfile.Write(content) assert.NoError(t, err, "Could not write data to ecs-params tempfile") err = tmpfile.Close() assert.NoError(t, err, "Could not close tempfile") ecsParams, err := ReadECSParams(ecsParamsFileName) if assert.NoError(t, err) { serviceDiscovery := ecsParams.RunParams.ServiceDiscovery assert.Equal(t, "nginx", serviceDiscovery.ContainerName, "Expected ContainerName to match") assert.Equal(t, aws.Int64(80), serviceDiscovery.ContainerPort, "Expected ContainerPort to match") assert.Equal(t, "vpc-8BAADF00D", serviceDiscovery.PrivateDNSNamespace.VPC, "Expected VPC to match") assert.Equal(t, "ns-CA15CA15CA15CA15", serviceDiscovery.PrivateDNSNamespace.ID, "Expected private namespace ID to match") assert.Equal(t, "corp", serviceDiscovery.PrivateDNSNamespace.Name, "Expected private namespace Name to match") assert.Equal(t, "This is a private namespace", serviceDiscovery.PrivateDNSNamespace.Description, "Expected private namespace description to match") assert.Equal(t, "ns-C0VF3F3", serviceDiscovery.PublicDNSNamespace.ID, "Expected public namespace ID to match") assert.Equal(t, "amazon.com", serviceDiscovery.PublicDNSNamespace.Name, "Expected public namespace name to match") sds := serviceDiscovery.ServiceDiscoveryService assert.Equal(t, "mysds", sds.Name, "Expected SDS Name to match") assert.Equal(t, "This is an SDS", sds.Description, "Expected SDS Description to match") assert.Equal(t, "A", sds.DNSConfig.Type, "Expected SDS DNSConfig Type to match") assert.Equal(t, aws.Int64(60), sds.DNSConfig.TTL, "Expected SDS DNSConfig TTL to match") assert.Equal(t, aws.Int64(1), sds.HealthCheckCustomConfig.FailureThreshold, "Expected SDS HealthCheckCustomConfig FailureThreshold to match") } } func TestConvertToECSHealthCheck(t *testing.T) { testHealthCheck := &HealthCheck{ Test: []string{"CMD-SHELL", "curl -f http://localhost"}, Command: nil, Interval: "10m", Timeout: "15s", Retries: 5, StartPeriod: "50s", } expected := &ecs.HealthCheck{ Command: aws.StringSlice([]string{"CMD-SHELL", "curl -f http://localhost"}), Interval: aws.Int64(600), Timeout: aws.Int64(15), Retries: aws.Int64(5), StartPeriod: aws.Int64(50), } actual, err := testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, expected, actual, "Expected healthcheck to match") } } func TestConvertToECSHealthCheck_AltFormat(t *testing.T) { testHealthCheck := &HealthCheck{ Command: []string{"CMD-SHELL", "curl -f http://localhost"}, Test: nil, Interval: "600", Timeout: "15", Retries: 5, StartPeriod: "50", } expected := &ecs.HealthCheck{ Command: aws.StringSlice([]string{"CMD-SHELL", "curl -f http://localhost"}), Interval: aws.Int64(600), Timeout: aws.Int64(15), Retries: aws.Int64(5), StartPeriod: aws.Int64(50), } actual, err := testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, expected, actual, "Expected healthcheck to match") } } func TestConvertToECSHealthCheck_PrependForStringCommand(t *testing.T) { testHealthCheck := &HealthCheck{ Command: []string{"curl -f http://localhost"}, } expected := []string{"CMD-SHELL", "curl -f http://localhost"} actual, err := testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, aws.StringSlice(expected), actual.Command, "Expected healthcheck command to match") } // With Test key testHealthCheck = &HealthCheck{ Test: []string{"curl -f http://localhost"}, } actual, err = testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, aws.StringSlice(expected), actual.Command, "Expected healthcheck command to match") } } func TestConvertToECSHealthCheck_ErrorCase_InvalidInterval(t *testing.T) { testHealthCheck := &HealthCheck{ Test: []string{"CMD", "curl", "-f", "http://localhost"}, Command: nil, Interval: "cat", Timeout: "10s", Retries: 3, StartPeriod: "40s", } _, err := testHealthCheck.ConvertToECSHealthCheck() assert.Error(t, err, "Expected error parsing interval field in healthcheck") } func TestConvertToECSHealthCheck_ErrorCase_TestAndCommand(t *testing.T) { testHealthCheck := &HealthCheck{ Test: []string{"CMD", "curl", "-f", "http://localhost"}, Command: []string{"CMD", "curl", "-f", "http://localhost"}, Interval: "5s", Timeout: "10s", Retries: 3, StartPeriod: "40s", } _, err := testHealthCheck.ConvertToECSHealthCheck() assert.Error(t, err, "Expected error reading ecs-params: healthcheck test and command can not both be specified") } func TestConvertToECSHealthCheck_IntFieldsBlank(t *testing.T) { testHealthCheck := &HealthCheck{ Command: []string{"CMD", "curl", "-f", "http://localhost"}, } expected := &ecs.HealthCheck{ Command: aws.StringSlice([]string{"CMD", "curl", "-f", "http://localhost"}), Interval: nil, Timeout: nil, Retries: nil, StartPeriod: nil, } actual, err := testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, expected, actual) } } func TestConvertToECSHealthCheck_TestFieldBlank(t *testing.T) { testHealthCheck := &HealthCheck{ Command: nil, Test: nil, Interval: "", Timeout: "", Retries: 0, StartPeriod: "10", } expected := &ecs.HealthCheck{ Command: nil, Interval: nil, Timeout: nil, Retries: nil, StartPeriod: aws.Int64(10), } actual, err := testHealthCheck.ConvertToECSHealthCheck() if assert.NoError(t, err) { assert.Equal(t, expected, actual) } }