c876462eb0
If the ECS cluster has > 100 tasks, passing them to ecs.DescribeTasksRequest() will result in the AWS API returning errors. This patch breaks them into chunks of at most 100, and calls DescribeTasks for each chunk. We also return early in case ListTasks returns no values; this prevents DescribeTasks from throwing HTTP errors.
349 lines
7.8 KiB
Go
349 lines
7.8 KiB
Go
package provider
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/service/ec2"
|
|
"github.com/aws/aws-sdk-go/service/ecs"
|
|
)
|
|
|
|
func makeEcsInstance(containerDef *ecs.ContainerDefinition) ecsInstance {
|
|
container := &ecs.Container{
|
|
Name: containerDef.Name,
|
|
NetworkBindings: make([]*ecs.NetworkBinding, len(containerDef.PortMappings)),
|
|
}
|
|
|
|
for i, pm := range containerDef.PortMappings {
|
|
container.NetworkBindings[i] = &ecs.NetworkBinding{
|
|
HostPort: pm.HostPort,
|
|
ContainerPort: pm.ContainerPort,
|
|
Protocol: pm.Protocol,
|
|
BindIP: aws.String("0.0.0.0"),
|
|
}
|
|
}
|
|
|
|
return ecsInstance{
|
|
Name: "foo-http",
|
|
ID: "123456789abc",
|
|
task: &ecs.Task{
|
|
Containers: []*ecs.Container{container},
|
|
},
|
|
taskDefinition: &ecs.TaskDefinition{
|
|
ContainerDefinitions: []*ecs.ContainerDefinition{containerDef},
|
|
},
|
|
container: container,
|
|
containerDefinition: containerDef,
|
|
machine: &ec2.Instance{
|
|
PrivateIpAddress: aws.String("10.0.0.0"),
|
|
State: &ec2.InstanceState{
|
|
Name: aws.String(ec2.InstanceStateNameRunning),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func simpleEcsInstance(labels map[string]*string) ecsInstance {
|
|
return makeEcsInstance(&ecs.ContainerDefinition{
|
|
Name: aws.String("http"),
|
|
PortMappings: []*ecs.PortMapping{{
|
|
HostPort: aws.Int64(80),
|
|
ContainerPort: aws.Int64(80),
|
|
Protocol: aws.String("tcp"),
|
|
}},
|
|
DockerLabels: labels,
|
|
})
|
|
}
|
|
|
|
func TestEcsProtocol(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "http",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: "https",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.protocol": aws.String("https"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.Protocol()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsHost(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "10.0.0.0",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.Host()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsPort(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "80",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.Port()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsWeight(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "0",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: "10",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.weight": aws.String("10"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.Weight()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsPassHostHeader(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "true",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: "false",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.frontend.passHostHeader": aws.String("false"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.PassHostHeader()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsPriority(t *testing.T) {
|
|
cases := []struct {
|
|
expected string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: "0",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: "10",
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.frontend.priority": aws.String("10"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.Priority()
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEcsEntryPoints(t *testing.T) {
|
|
cases := []struct {
|
|
expected []string
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: []string{},
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: []string{"http"},
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.frontend.entryPoints": aws.String("http"),
|
|
}),
|
|
},
|
|
{
|
|
expected: []string{"http", "https"},
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.frontend.entryPoints": aws.String("http,https"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
value := c.instanceInfo.EntryPoints()
|
|
if !reflect.DeepEqual(value, c.expected) {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFilterInstance(t *testing.T) {
|
|
|
|
nilPrivateIP := simpleEcsInstance(map[string]*string{})
|
|
nilPrivateIP.machine.PrivateIpAddress = nil
|
|
|
|
nilMachine := simpleEcsInstance(map[string]*string{})
|
|
nilMachine.machine = nil
|
|
|
|
nilMachineState := simpleEcsInstance(map[string]*string{})
|
|
nilMachineState.machine.State = nil
|
|
|
|
nilMachineStateName := simpleEcsInstance(map[string]*string{})
|
|
nilMachineStateName.machine.State.Name = nil
|
|
|
|
invalidMachineState := simpleEcsInstance(map[string]*string{})
|
|
invalidMachineState.machine.State.Name = aws.String(ec2.InstanceStateNameStopped)
|
|
|
|
cases := []struct {
|
|
expected bool
|
|
exposedByDefault bool
|
|
instanceInfo ecsInstance
|
|
}{
|
|
{
|
|
expected: true,
|
|
exposedByDefault: true,
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: false,
|
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.enable": aws.String("false"),
|
|
}),
|
|
},
|
|
{
|
|
expected: true,
|
|
exposedByDefault: false,
|
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
|
"traefik.enable": aws.String("true"),
|
|
}),
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: nilPrivateIP,
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: nilMachine,
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: nilMachineState,
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: nilMachineStateName,
|
|
},
|
|
{
|
|
expected: false,
|
|
exposedByDefault: true,
|
|
instanceInfo: invalidMachineState,
|
|
},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
provider := &ECS{
|
|
ExposedByDefault: c.exposedByDefault,
|
|
}
|
|
value := provider.filterInstance(c.instanceInfo)
|
|
if value != c.expected {
|
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTaskChunking(t *testing.T) {
|
|
provider := &ECS{}
|
|
|
|
testval := "a"
|
|
cases := []struct {
|
|
count int
|
|
expectedLengths []int
|
|
}{
|
|
{0, []int(nil)},
|
|
{1, []int{1}},
|
|
{99, []int{99}},
|
|
{100, []int{100}},
|
|
{101, []int{100, 1}},
|
|
{199, []int{100, 99}},
|
|
{200, []int{100, 100}},
|
|
{201, []int{100, 100, 1}},
|
|
{555, []int{100, 100, 100, 100, 100, 55}},
|
|
{1001, []int{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1}},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
var tasks []*string
|
|
for v := 0; v < c.count; v++ {
|
|
tasks = append(tasks, &testval)
|
|
}
|
|
|
|
out := provider.chunkedTaskArns(tasks)
|
|
var outCount []int
|
|
|
|
for _, el := range out {
|
|
outCount = append(outCount, len(el))
|
|
}
|
|
|
|
if !reflect.DeepEqual(outCount, c.expectedLengths) {
|
|
t.Errorf("Chunking %d elements, expected %#v, got %#v", c.count, c.expectedLengths, outCount)
|
|
}
|
|
}
|
|
}
|