Fix 400 bad request on AWS ECS API

This commit is contained in:
Michael 2018-07-17 12:26:03 +02:00 committed by Traefiker Bot
parent a953d3ad89
commit ff2e2d5026
2 changed files with 140 additions and 32 deletions

View file

@ -347,43 +347,47 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
}
}
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
ContainerInstances: containerInstancesArns,
Cluster: clusterName,
})
if err != nil {
log.Errorf("Unable to describe container instances: %s", err)
return nil, err
}
for _, container := range resp.ContainerInstances {
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
instanceArns = append(instanceArns, container.Ec2InstanceId)
}
if len(instanceArns) > 0 {
input := &ec2.DescribeInstancesInput{
InstanceIds: instanceArns,
}
err = client.ec2.DescribeInstancesPagesWithContext(ctx, input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
if len(page.Reservations) > 0 {
for _, r := range page.Reservations {
for _, i := range r.Instances {
if i.InstanceId != nil {
ec2Instances[instanceIds[aws.StringValue(i.InstanceId)]] = i
}
}
}
}
return !lastPage
for _, arns := range p.chunkIDs(containerInstancesArns) {
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
ContainerInstances: arns,
Cluster: clusterName,
})
if err != nil {
log.Errorf("Unable to describe instances: %s", err)
log.Errorf("Unable to describe container instances: %v", err)
return nil, err
}
for _, container := range resp.ContainerInstances {
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
instanceArns = append(instanceArns, container.Ec2InstanceId)
}
}
if len(instanceArns) > 0 {
for _, ids := range p.chunkIDs(instanceArns) {
input := &ec2.DescribeInstancesInput{
InstanceIds: ids,
}
err := client.ec2.DescribeInstancesPagesWithContext(ctx, input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
if len(page.Reservations) > 0 {
for _, r := range page.Reservations {
for _, i := range r.Instances {
if i.InstanceId != nil {
ec2Instances[instanceIds[aws.StringValue(i.InstanceId)]] = i
}
}
}
}
return !lastPage
})
if err != nil {
log.Errorf("Unable to describe instances [%s]: %v", err)
return nil, err
}
}
}
return ec2Instances, nil
@ -414,3 +418,19 @@ func (p *Provider) loadECSConfig(ctx context.Context, client *awsClient) (*types
return p.buildConfiguration(instances)
}
// chunkIDs ECS expects no more than 100 parameters be passed to a API call;
// thus, pack each string into an array capped at 100 elements
func (p *Provider) chunkIDs(ids []*string) [][]*string {
var chuncked [][]*string
for i := 0; i < len(ids); i += 100 {
sliceEnd := -1
if i+100 < len(ids) {
sliceEnd = i + 100
} else {
sliceEnd = len(ids)
}
chuncked = append(chuncked, ids[i:sliceEnd])
}
return chuncked
}

88
provider/ecs/ecs_test.go Normal file
View file

@ -0,0 +1,88 @@
package ecs
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/stretchr/testify/assert"
)
func TestChunkIDs(t *testing.T) {
provider := &Provider{}
testCases := []struct {
desc string
count int
expected []int
}{
{
desc: "0 element",
count: 0,
expected: []int(nil),
},
{
desc: "1 element",
count: 1,
expected: []int{1},
},
{
desc: "99 elements, 1 chunk",
count: 99,
expected: []int{99},
},
{
desc: "100 elements, 1 chunk",
count: 100,
expected: []int{100},
},
{
desc: "101 elements, 2 chunks",
count: 101,
expected: []int{100, 1},
},
{
desc: "199 elements, 2 chunks",
count: 199,
expected: []int{100, 99},
},
{
desc: "200 elements, 2 chunks",
count: 200,
expected: []int{100, 100},
},
{
desc: "201 elements, 3 chunks",
count: 201,
expected: []int{100, 100, 1},
},
{
desc: "555 elements, 5 chunks",
count: 555,
expected: []int{100, 100, 100, 100, 100, 55},
},
{
desc: "1001 elements, 11 chunks",
count: 1001,
expected: []int{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var IDs []*string
for v := 0; v < test.count; v++ {
IDs = append(IDs, aws.String("a"))
}
var outCount []int
for _, el := range provider.chunkIDs(IDs) {
outCount = append(outCount, len(el))
}
assert.Equal(t, test.expected, outCount)
})
}
}