mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 01:06:27 +00:00
Accept healthy instances in list of active instances
Fixes GH #79581 Healthy instances have a nil Reason associated with their target health, so without this, actualIDs ends up as empty (well, without healthy instance IDs in it, anyway). As a result, any instances not present in the instances parameter are perceived to be already out of the target group, and are thus never deregistered. Add tests for node registration/deregistration Make sure that when EnsureLoadBalancer is called with a new set of nodes, old members of the target group are deregistered, and new members in the new set are registered Tests GH #79581 Address golint grievances Run gazelle to update AWS cloud provider dependencies Fix typecheck error
This commit is contained in:
parent
6e38a0f46e
commit
a59a91d415
@ -86,13 +86,16 @@ go_test(
|
|||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||||
"//staging/src/k8s.io/cloud-provider/volume:go_default_library",
|
"//staging/src/k8s.io/cloud-provider/volume:go_default_library",
|
||||||
"//vendor/github.com/aws/aws-sdk-go/aws:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/aws:go_default_library",
|
||||||
|
"//vendor/github.com/aws/aws-sdk-go/aws/awserr:go_default_library",
|
||||||
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library",
|
||||||
"//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library",
|
"//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library",
|
||||||
|
"//vendor/github.com/aws/aws-sdk-go/service/elbv2:go_default_library",
|
||||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||||
"//vendor/github.com/stretchr/testify/mock:go_default_library",
|
"//vendor/github.com/stretchr/testify/mock:go_default_library",
|
||||||
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
"//vendor/github.com/stretchr/testify/require:go_default_library",
|
||||||
|
@ -603,7 +603,9 @@ func (c *Cloud) ensureTargetGroup(targetGroup *elbv2.TargetGroup, serviceName ty
|
|||||||
}
|
}
|
||||||
actualIDs := []string{}
|
actualIDs := []string{}
|
||||||
for _, healthDescription := range healthResponse.TargetHealthDescriptions {
|
for _, healthDescription := range healthResponse.TargetHealthDescriptions {
|
||||||
if healthDescription.TargetHealth.Reason != nil {
|
if aws.StringValue(healthDescription.TargetHealth.State) == elbv2.TargetHealthStateEnumHealthy {
|
||||||
|
actualIDs = append(actualIDs, *healthDescription.Target.Id)
|
||||||
|
} else if healthDescription.TargetHealth.Reason != nil {
|
||||||
switch aws.StringValue(healthDescription.TargetHealth.Reason) {
|
switch aws.StringValue(healthDescription.TargetHealth.Reason) {
|
||||||
case elbv2.TargetHealthReasonEnumTargetDeregistrationInProgress:
|
case elbv2.TargetHealthReasonEnumTargetDeregistrationInProgress:
|
||||||
// We don't need to count this instance in service if it is
|
// We don't need to count this instance in service if it is
|
||||||
|
@ -22,21 +22,25 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
"github.com/aws/aws-sdk-go/service/elb"
|
"github.com/aws/aws-sdk-go/service/elb"
|
||||||
|
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
@ -1708,7 +1712,6 @@ func TestAddLoadBalancerTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEnsureLoadBalancerHealthCheck(t *testing.T) {
|
func TestEnsureLoadBalancerHealthCheck(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
annotations map[string]string
|
annotations map[string]string
|
||||||
@ -1974,6 +1977,579 @@ func informerNotSynced() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MockedFakeELBV2 struct {
|
||||||
|
LoadBalancers []*elbv2.LoadBalancer
|
||||||
|
TargetGroups []*elbv2.TargetGroup
|
||||||
|
Listeners []*elbv2.Listener
|
||||||
|
|
||||||
|
// keys on all of these maps are ARNs
|
||||||
|
LoadBalancerAttributes map[string]map[string]string
|
||||||
|
Tags map[string][]elbv2.Tag
|
||||||
|
RegisteredInstances map[string][]string // value is list of instance IDs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) AddTags(request *elbv2.AddTagsInput) (*elbv2.AddTagsOutput, error) {
|
||||||
|
for _, arn := range request.ResourceArns {
|
||||||
|
for _, tag := range request.Tags {
|
||||||
|
m.Tags[aws.StringValue(arn)] = append(m.Tags[aws.StringValue(arn)], *tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.AddTagsOutput{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) CreateLoadBalancer(request *elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error) {
|
||||||
|
accountID := 123456789
|
||||||
|
arn := fmt.Sprintf("arn:aws:elasticloadbalancing:us-east-1:%d:loadbalancer/net/%x/%x",
|
||||||
|
accountID,
|
||||||
|
rand.Uint64(),
|
||||||
|
rand.Uint32())
|
||||||
|
|
||||||
|
newLB := &elbv2.LoadBalancer{
|
||||||
|
LoadBalancerArn: aws.String(arn),
|
||||||
|
LoadBalancerName: request.Name,
|
||||||
|
Type: aws.String(elbv2.LoadBalancerTypeEnumNetwork),
|
||||||
|
VpcId: aws.String("vpc-abc123def456abc78"),
|
||||||
|
}
|
||||||
|
m.LoadBalancers = append(m.LoadBalancers, newLB)
|
||||||
|
|
||||||
|
return &elbv2.CreateLoadBalancerOutput{
|
||||||
|
LoadBalancers: []*elbv2.LoadBalancer{newLB},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeLoadBalancers(request *elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) {
|
||||||
|
findMeNames := make(map[string]bool)
|
||||||
|
for _, name := range request.Names {
|
||||||
|
findMeNames[aws.StringValue(name)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
findMeARNs := make(map[string]bool)
|
||||||
|
for _, arn := range request.LoadBalancerArns {
|
||||||
|
findMeARNs[aws.StringValue(arn)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result := []*elbv2.LoadBalancer{}
|
||||||
|
|
||||||
|
for _, lb := range m.LoadBalancers {
|
||||||
|
if _, present := findMeNames[aws.StringValue(lb.LoadBalancerName)]; present {
|
||||||
|
result = append(result, lb)
|
||||||
|
delete(findMeNames, aws.StringValue(lb.LoadBalancerName))
|
||||||
|
} else if _, present := findMeARNs[aws.StringValue(lb.LoadBalancerArn)]; present {
|
||||||
|
result = append(result, lb)
|
||||||
|
delete(findMeARNs, aws.StringValue(lb.LoadBalancerArn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(findMeNames) > 0 || len(findMeARNs) > 0 {
|
||||||
|
return nil, awserr.New(elbv2.ErrCodeLoadBalancerNotFoundException, "not found", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.DescribeLoadBalancersOutput{
|
||||||
|
LoadBalancers: result,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DeleteLoadBalancer(*elbv2.DeleteLoadBalancerInput) (*elbv2.DeleteLoadBalancerOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) ModifyLoadBalancerAttributes(request *elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error) {
|
||||||
|
attrMap, present := m.LoadBalancerAttributes[aws.StringValue(request.LoadBalancerArn)]
|
||||||
|
|
||||||
|
if !present {
|
||||||
|
attrMap = make(map[string]string)
|
||||||
|
m.LoadBalancerAttributes[aws.StringValue(request.LoadBalancerArn)] = attrMap
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range request.Attributes {
|
||||||
|
attrMap[aws.StringValue(attr.Key)] = aws.StringValue(attr.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.ModifyLoadBalancerAttributesOutput{
|
||||||
|
Attributes: request.Attributes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeLoadBalancerAttributes(request *elbv2.DescribeLoadBalancerAttributesInput) (*elbv2.DescribeLoadBalancerAttributesOutput, error) {
|
||||||
|
attrs := []*elbv2.LoadBalancerAttribute{}
|
||||||
|
|
||||||
|
if lbAttrs, present := m.LoadBalancerAttributes[aws.StringValue(request.LoadBalancerArn)]; present {
|
||||||
|
for key, value := range lbAttrs {
|
||||||
|
attrs = append(attrs, &elbv2.LoadBalancerAttribute{
|
||||||
|
Key: aws.String(key),
|
||||||
|
Value: aws.String(value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.DescribeLoadBalancerAttributesOutput{
|
||||||
|
Attributes: attrs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) CreateTargetGroup(request *elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error) {
|
||||||
|
accountID := 123456789
|
||||||
|
arn := fmt.Sprintf("arn:aws:elasticloadbalancing:us-east-1:%d:targetgroup/%x/%x",
|
||||||
|
accountID,
|
||||||
|
rand.Uint64(),
|
||||||
|
rand.Uint32())
|
||||||
|
|
||||||
|
newTG := &elbv2.TargetGroup{
|
||||||
|
TargetGroupArn: aws.String(arn),
|
||||||
|
TargetGroupName: request.Name,
|
||||||
|
Port: request.Port,
|
||||||
|
Protocol: request.Protocol,
|
||||||
|
}
|
||||||
|
|
||||||
|
m.TargetGroups = append(m.TargetGroups, newTG)
|
||||||
|
|
||||||
|
return &elbv2.CreateTargetGroupOutput{
|
||||||
|
TargetGroups: []*elbv2.TargetGroup{newTG},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeTargetGroups(request *elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error) {
|
||||||
|
var targetGroups []*elbv2.TargetGroup
|
||||||
|
|
||||||
|
if request.LoadBalancerArn != nil {
|
||||||
|
targetGroups = []*elbv2.TargetGroup{}
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
for _, lbArn := range tg.LoadBalancerArns {
|
||||||
|
if aws.StringValue(lbArn) == aws.StringValue(request.LoadBalancerArn) {
|
||||||
|
targetGroups = append(targetGroups, tg)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(request.Names) != 0 {
|
||||||
|
targetGroups = []*elbv2.TargetGroup{}
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
for _, name := range request.Names {
|
||||||
|
if aws.StringValue(tg.TargetGroupName) == aws.StringValue(name) {
|
||||||
|
targetGroups = append(targetGroups, tg)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if len(request.TargetGroupArns) != 0 {
|
||||||
|
targetGroups = []*elbv2.TargetGroup{}
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
for _, arn := range request.TargetGroupArns {
|
||||||
|
if aws.StringValue(tg.TargetGroupArn) == aws.StringValue(arn) {
|
||||||
|
targetGroups = append(targetGroups, tg)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
targetGroups = m.TargetGroups
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.DescribeTargetGroupsOutput{
|
||||||
|
TargetGroups: targetGroups,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) ModifyTargetGroup(request *elbv2.ModifyTargetGroupInput) (*elbv2.ModifyTargetGroupOutput, error) {
|
||||||
|
var matchingTargetGroup *elbv2.TargetGroup
|
||||||
|
dirtyGroups := []*elbv2.TargetGroup{}
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
if aws.StringValue(tg.TargetGroupArn) == aws.StringValue(request.TargetGroupArn) {
|
||||||
|
matchingTargetGroup = tg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchingTargetGroup != nil {
|
||||||
|
dirtyGroups = append(dirtyGroups, matchingTargetGroup)
|
||||||
|
|
||||||
|
if request.HealthCheckEnabled != nil {
|
||||||
|
matchingTargetGroup.HealthCheckEnabled = request.HealthCheckEnabled
|
||||||
|
}
|
||||||
|
if request.HealthCheckIntervalSeconds != nil {
|
||||||
|
matchingTargetGroup.HealthCheckIntervalSeconds = request.HealthCheckIntervalSeconds
|
||||||
|
}
|
||||||
|
if request.HealthCheckPath != nil {
|
||||||
|
matchingTargetGroup.HealthCheckPath = request.HealthCheckPath
|
||||||
|
}
|
||||||
|
if request.HealthCheckPort != nil {
|
||||||
|
matchingTargetGroup.HealthCheckPort = request.HealthCheckPort
|
||||||
|
}
|
||||||
|
if request.HealthCheckProtocol != nil {
|
||||||
|
matchingTargetGroup.HealthCheckProtocol = request.HealthCheckProtocol
|
||||||
|
}
|
||||||
|
if request.HealthCheckTimeoutSeconds != nil {
|
||||||
|
matchingTargetGroup.HealthCheckTimeoutSeconds = request.HealthCheckTimeoutSeconds
|
||||||
|
}
|
||||||
|
if request.HealthyThresholdCount != nil {
|
||||||
|
matchingTargetGroup.HealthyThresholdCount = request.HealthyThresholdCount
|
||||||
|
}
|
||||||
|
if request.Matcher != nil {
|
||||||
|
matchingTargetGroup.Matcher = request.Matcher
|
||||||
|
}
|
||||||
|
if request.UnhealthyThresholdCount != nil {
|
||||||
|
matchingTargetGroup.UnhealthyThresholdCount = request.UnhealthyThresholdCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.ModifyTargetGroupOutput{
|
||||||
|
TargetGroups: dirtyGroups,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DeleteTargetGroup(request *elbv2.DeleteTargetGroupInput) (*elbv2.DeleteTargetGroupOutput, error) {
|
||||||
|
newTargetGroups := []*elbv2.TargetGroup{}
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
if aws.StringValue(tg.TargetGroupArn) != aws.StringValue(request.TargetGroupArn) {
|
||||||
|
newTargetGroups = append(newTargetGroups, tg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.TargetGroups = newTargetGroups
|
||||||
|
|
||||||
|
delete(m.RegisteredInstances, aws.StringValue(request.TargetGroupArn))
|
||||||
|
|
||||||
|
return &elbv2.DeleteTargetGroupOutput{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeTargetHealth(request *elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error) {
|
||||||
|
healthDescriptions := []*elbv2.TargetHealthDescription{}
|
||||||
|
|
||||||
|
var matchingTargetGroup *elbv2.TargetGroup
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
if aws.StringValue(tg.TargetGroupArn) == aws.StringValue(request.TargetGroupArn) {
|
||||||
|
matchingTargetGroup = tg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if registeredTargets, present := m.RegisteredInstances[aws.StringValue(request.TargetGroupArn)]; present {
|
||||||
|
for _, target := range registeredTargets {
|
||||||
|
healthDescriptions = append(healthDescriptions, &elbv2.TargetHealthDescription{
|
||||||
|
HealthCheckPort: matchingTargetGroup.HealthCheckPort,
|
||||||
|
Target: &elbv2.TargetDescription{
|
||||||
|
Id: aws.String(target),
|
||||||
|
Port: matchingTargetGroup.Port,
|
||||||
|
},
|
||||||
|
TargetHealth: &elbv2.TargetHealth{
|
||||||
|
State: aws.String("healthy"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.DescribeTargetHealthOutput{
|
||||||
|
TargetHealthDescriptions: healthDescriptions,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeTargetGroupAttributes(*elbv2.DescribeTargetGroupAttributesInput) (*elbv2.DescribeTargetGroupAttributesOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) ModifyTargetGroupAttributes(*elbv2.ModifyTargetGroupAttributesInput) (*elbv2.ModifyTargetGroupAttributesOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) RegisterTargets(request *elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error) {
|
||||||
|
arn := aws.StringValue(request.TargetGroupArn)
|
||||||
|
alreadyExists := make(map[string]bool)
|
||||||
|
for _, targetID := range m.RegisteredInstances[arn] {
|
||||||
|
alreadyExists[targetID] = true
|
||||||
|
}
|
||||||
|
for _, target := range request.Targets {
|
||||||
|
if !alreadyExists[aws.StringValue(target.Id)] {
|
||||||
|
m.RegisteredInstances[arn] = append(m.RegisteredInstances[arn], aws.StringValue(target.Id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &elbv2.RegisterTargetsOutput{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DeregisterTargets(request *elbv2.DeregisterTargetsInput) (*elbv2.DeregisterTargetsOutput, error) {
|
||||||
|
removeMe := make(map[string]bool)
|
||||||
|
|
||||||
|
for _, target := range request.Targets {
|
||||||
|
removeMe[aws.StringValue(target.Id)] = true
|
||||||
|
}
|
||||||
|
newRegisteredInstancesForArn := []string{}
|
||||||
|
for _, targetID := range m.RegisteredInstances[aws.StringValue(request.TargetGroupArn)] {
|
||||||
|
if !removeMe[targetID] {
|
||||||
|
newRegisteredInstancesForArn = append(newRegisteredInstancesForArn, targetID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.RegisteredInstances[aws.StringValue(request.TargetGroupArn)] = newRegisteredInstancesForArn
|
||||||
|
|
||||||
|
return &elbv2.DeregisterTargetsOutput{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) CreateListener(request *elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error) {
|
||||||
|
accountID := 123456789
|
||||||
|
arn := fmt.Sprintf("arn:aws:elasticloadbalancing:us-east-1:%d:listener/net/%x/%x/%x",
|
||||||
|
accountID,
|
||||||
|
rand.Uint64(),
|
||||||
|
rand.Uint32(),
|
||||||
|
rand.Uint32())
|
||||||
|
|
||||||
|
newListener := &elbv2.Listener{
|
||||||
|
ListenerArn: aws.String(arn),
|
||||||
|
Port: request.Port,
|
||||||
|
Protocol: request.Protocol,
|
||||||
|
DefaultActions: request.DefaultActions,
|
||||||
|
LoadBalancerArn: request.LoadBalancerArn,
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Listeners = append(m.Listeners, newListener)
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
for _, action := range request.DefaultActions {
|
||||||
|
if aws.StringValue(action.TargetGroupArn) == aws.StringValue(tg.TargetGroupArn) {
|
||||||
|
tg.LoadBalancerArns = append(tg.LoadBalancerArns, request.LoadBalancerArn)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.CreateListenerOutput{
|
||||||
|
Listeners: []*elbv2.Listener{newListener},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DescribeListeners(request *elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) {
|
||||||
|
if len(request.ListenerArns) == 0 && request.LoadBalancerArn == nil {
|
||||||
|
return &elbv2.DescribeListenersOutput{
|
||||||
|
Listeners: m.Listeners,
|
||||||
|
}, nil
|
||||||
|
} else if len(request.ListenerArns) == 0 {
|
||||||
|
listeners := []*elbv2.Listener{}
|
||||||
|
|
||||||
|
for _, lb := range m.Listeners {
|
||||||
|
if aws.StringValue(lb.LoadBalancerArn) == aws.StringValue(request.LoadBalancerArn) {
|
||||||
|
listeners = append(listeners, lb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.DescribeListenersOutput{
|
||||||
|
Listeners: listeners,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) DeleteListener(*elbv2.DeleteListenerInput) (*elbv2.DeleteListenerOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) ModifyListener(request *elbv2.ModifyListenerInput) (*elbv2.ModifyListenerOutput, error) {
|
||||||
|
modifiedListeners := []*elbv2.Listener{}
|
||||||
|
|
||||||
|
for _, listener := range m.Listeners {
|
||||||
|
if aws.StringValue(listener.ListenerArn) == aws.StringValue(request.ListenerArn) {
|
||||||
|
if request.DefaultActions != nil {
|
||||||
|
// for each old action, find the corresponding target group, and remove the listener's LB ARN from its list
|
||||||
|
for _, action := range listener.DefaultActions {
|
||||||
|
var targetGroupForAction *elbv2.TargetGroup
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
if aws.StringValue(action.TargetGroupArn) == aws.StringValue(tg.TargetGroupArn) {
|
||||||
|
targetGroupForAction = tg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetGroupForAction != nil {
|
||||||
|
newLoadBalancerARNs := []*string{}
|
||||||
|
for _, lbArn := range targetGroupForAction.LoadBalancerArns {
|
||||||
|
if aws.StringValue(lbArn) != aws.StringValue(listener.LoadBalancerArn) {
|
||||||
|
newLoadBalancerARNs = append(newLoadBalancerARNs, lbArn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
targetGroupForAction.LoadBalancerArns = newLoadBalancerARNs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.DefaultActions = request.DefaultActions
|
||||||
|
|
||||||
|
// for each new action, add the listener's LB ARN to that action's target groups' lists
|
||||||
|
for _, action := range request.DefaultActions {
|
||||||
|
var targetGroupForAction *elbv2.TargetGroup
|
||||||
|
|
||||||
|
for _, tg := range m.TargetGroups {
|
||||||
|
if aws.StringValue(action.TargetGroupArn) == aws.StringValue(tg.TargetGroupArn) {
|
||||||
|
targetGroupForAction = tg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetGroupForAction != nil {
|
||||||
|
targetGroupForAction.LoadBalancerArns = append(targetGroupForAction.LoadBalancerArns, listener.LoadBalancerArn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if request.Port != nil {
|
||||||
|
listener.Port = request.Port
|
||||||
|
}
|
||||||
|
if request.Protocol != nil {
|
||||||
|
listener.Protocol = request.Protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedListeners = append(modifiedListeners, listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elbv2.ModifyListenerOutput{
|
||||||
|
Listeners: modifiedListeners,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeELBV2) WaitUntilLoadBalancersDeleted(*elbv2.DescribeLoadBalancersInput) error {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockedFakeEC2) maybeExpectDescribeSecurityGroups(clusterID, groupName string) {
|
||||||
|
tags := []*ec2.Tag{
|
||||||
|
{Key: aws.String(TagNameKubernetesClusterLegacy), Value: aws.String(clusterID)},
|
||||||
|
{Key: aws.String(fmt.Sprintf("%s%s", TagNameKubernetesClusterPrefix, clusterID)), Value: aws.String(ResourceLifecycleOwned)},
|
||||||
|
}
|
||||||
|
|
||||||
|
m.On("DescribeSecurityGroups", &ec2.DescribeSecurityGroupsInput{Filters: []*ec2.Filter{
|
||||||
|
newEc2Filter("group-name", groupName),
|
||||||
|
newEc2Filter("vpc-id", ""),
|
||||||
|
}}).Maybe().Return([]*ec2.SecurityGroup{{Tags: tags}})
|
||||||
|
|
||||||
|
m.On("DescribeSecurityGroups", &ec2.DescribeSecurityGroupsInput{}).Maybe().Return([]*ec2.SecurityGroup{{Tags: tags}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNLBNodeRegistration(t *testing.T) {
|
||||||
|
awsServices := newMockedFakeAWSServices(TestClusterID)
|
||||||
|
awsServices.elbv2 = &MockedFakeELBV2{Tags: make(map[string][]elbv2.Tag), RegisteredInstances: make(map[string][]string), LoadBalancerAttributes: make(map[string]map[string]string)}
|
||||||
|
c, _ := newAWSCloud(CloudConfig{}, awsServices)
|
||||||
|
|
||||||
|
awsServices.ec2.(*MockedFakeEC2).Subnets = []*ec2.Subnet{
|
||||||
|
{
|
||||||
|
AvailabilityZone: aws.String("us-west-2a"),
|
||||||
|
SubnetId: aws.String("subnet-abc123de"),
|
||||||
|
Tags: []*ec2.Tag{
|
||||||
|
{
|
||||||
|
Key: aws.String(c.tagging.clusterTagKey()),
|
||||||
|
Value: aws.String("owned"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
awsServices.ec2.(*MockedFakeEC2).RouteTables = []*ec2.RouteTable{
|
||||||
|
{
|
||||||
|
Associations: []*ec2.RouteTableAssociation{
|
||||||
|
{
|
||||||
|
Main: aws.Bool(true),
|
||||||
|
RouteTableAssociationId: aws.String("rtbassoc-abc123def456abc78"),
|
||||||
|
RouteTableId: aws.String("rtb-abc123def456abc78"),
|
||||||
|
SubnetId: aws.String("subnet-abc123de"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RouteTableId: aws.String("rtb-abc123def456abc78"),
|
||||||
|
Routes: []*ec2.Route{
|
||||||
|
{
|
||||||
|
DestinationCidrBlock: aws.String("0.0.0.0/0"),
|
||||||
|
GatewayId: aws.String("igw-abc123def456abc78"),
|
||||||
|
State: aws.String("active"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
awsServices.ec2.(*MockedFakeEC2).maybeExpectDescribeSecurityGroups(TestClusterID, "k8s-elb-aid")
|
||||||
|
|
||||||
|
nodes := []*v1.Node{makeNamedNode(awsServices, 0, "a"), makeNamedNode(awsServices, 1, "b"), makeNamedNode(awsServices, 2, "c")}
|
||||||
|
|
||||||
|
fauxService := &v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "myservice",
|
||||||
|
UID: "id",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"service.beta.kubernetes.io/aws-load-balancer-type": "nlb",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
Name: "http",
|
||||||
|
Port: 8080,
|
||||||
|
NodePort: 31173,
|
||||||
|
TargetPort: intstr.FromInt(31173),
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SessionAffinity: v1.ServiceAffinityNone,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := c.EnsureLoadBalancer(context.TODO(), TestClusterName, fauxService, nodes)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EnsureLoadBalancer returned an error: %v", err)
|
||||||
|
}
|
||||||
|
for _, instances := range awsServices.elbv2.(*MockedFakeELBV2).RegisteredInstances {
|
||||||
|
if len(instances) != 3 {
|
||||||
|
t.Errorf("Expected 3 nodes registered with target group, saw %d", len(instances))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.EnsureLoadBalancer(context.TODO(), TestClusterName, fauxService, nodes[:2])
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EnsureLoadBalancer returned an error: %v", err)
|
||||||
|
}
|
||||||
|
for _, instances := range awsServices.elbv2.(*MockedFakeELBV2).RegisteredInstances {
|
||||||
|
if len(instances) != 2 {
|
||||||
|
t.Errorf("Expected 2 nodes registered with target group, saw %d", len(instances))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.EnsureLoadBalancer(context.TODO(), TestClusterName, fauxService, nodes)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EnsureLoadBalancer returned an error: %v", err)
|
||||||
|
}
|
||||||
|
for _, instances := range awsServices.elbv2.(*MockedFakeELBV2).RegisteredInstances {
|
||||||
|
if len(instances) != 3 {
|
||||||
|
t.Errorf("Expected 3 nodes registered with target group, saw %d", len(instances))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeNamedNode(s *FakeAWSServices, offset int, name string) *v1.Node {
|
||||||
|
instanceID := fmt.Sprintf("i-%x", int64(0x02bce90670bb0c7cd)+int64(offset))
|
||||||
|
instance := &ec2.Instance{}
|
||||||
|
instance.InstanceId = aws.String(instanceID)
|
||||||
|
instance.Placement = &ec2.Placement{
|
||||||
|
AvailabilityZone: aws.String("us-east-1c"),
|
||||||
|
}
|
||||||
|
instance.PrivateDnsName = aws.String(fmt.Sprintf("ip-172-20-0-%d.ec2.internal", 101+offset))
|
||||||
|
instance.PrivateIpAddress = aws.String(fmt.Sprintf("192.168.0.%d", 1+offset))
|
||||||
|
|
||||||
|
var tag ec2.Tag
|
||||||
|
tag.Key = aws.String(TagNameKubernetesClusterLegacy)
|
||||||
|
tag.Value = aws.String(TestClusterID)
|
||||||
|
instance.Tags = []*ec2.Tag{&tag}
|
||||||
|
|
||||||
|
s.instances = append(s.instances, instance)
|
||||||
|
|
||||||
|
testProviderID := "aws:///us-east-1c/" + instanceID
|
||||||
|
return &v1.Node{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Spec: v1.NodeSpec{
|
||||||
|
ProviderID: testProviderID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newMockedFakeAWSServices(id string) *FakeAWSServices {
|
func newMockedFakeAWSServices(id string) *FakeAWSServices {
|
||||||
s := NewFakeAWSServices(id)
|
s := NewFakeAWSServices(id)
|
||||||
s.ec2 = &MockedFakeEC2{FakeEC2Impl: s.ec2.(*FakeEC2Impl)}
|
s.ec2 = &MockedFakeEC2{FakeEC2Impl: s.ec2.(*FakeEC2Impl)}
|
||||||
|
Loading…
Reference in New Issue
Block a user