Skip to content

Commit 8b4231d

Browse files
authored
Merge pull request #4794 from nrb/fix-4790
🐛 Don't reconcile security groups on NLBs from older versions of CAPA
2 parents 66bb485 + 23828d5 commit 8b4231d

File tree

2 files changed

+112
-6
lines changed

2 files changed

+112
-6
lines changed

pkg/cloud/services/elb/loadbalancer.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (s *Service) reconcileV2LB(lbSpec *infrav1.AWSLoadBalancerSpec) error {
137137
}
138138

139139
// Reconcile the security groups from the spec and the ones currently attached to the load balancer
140-
if !sets.NewString(lb.SecurityGroupIDs...).Equal(sets.NewString(spec.SecurityGroupIDs...)) {
140+
if shouldReconcileSGs(s.scope, lb, spec.SecurityGroupIDs) {
141141
_, err := s.ELBV2Client.SetSecurityGroups(&elbv2.SetSecurityGroupsInput{
142142
LoadBalancerArn: &lb.ARN,
143143
SecurityGroups: aws.StringSlice(spec.SecurityGroupIDs),
@@ -1534,11 +1534,11 @@ func fromSDKTypeToLB(v *elbv2.LoadBalancer, attrs []*elbv2.LoadBalancerAttribute
15341534
availabilityZones[i] = az.ZoneName
15351535
}
15361536
res := &infrav1.LoadBalancer{
1537-
ARN: aws.StringValue(v.LoadBalancerArn),
1538-
Name: aws.StringValue(v.LoadBalancerName),
1539-
Scheme: infrav1.ELBScheme(aws.StringValue(v.Scheme)),
1540-
SubnetIDs: aws.StringValueSlice(subnetIds),
1541-
// SecurityGroupIDs: aws.StringValueSlice(v.SecurityGroups),
1537+
ARN: aws.StringValue(v.LoadBalancerArn),
1538+
Name: aws.StringValue(v.LoadBalancerName),
1539+
Scheme: infrav1.ELBScheme(aws.StringValue(v.Scheme)),
1540+
SubnetIDs: aws.StringValueSlice(subnetIds),
1541+
SecurityGroupIDs: aws.StringValueSlice(v.SecurityGroups),
15421542
AvailabilityZones: aws.StringValueSlice(availabilityZones),
15431543
DNSName: aws.StringValue(v.DNSName),
15441544
Tags: converters.V2TagsToMap(tags),
@@ -1565,3 +1565,17 @@ func chunkELBs(names []string) [][]string {
15651565
}
15661566
return chunked
15671567
}
1568+
1569+
func shouldReconcileSGs(scope scope.ELBScope, lb *infrav1.LoadBalancer, specSGs []string) bool {
1570+
// Backwards compat: NetworkLoadBalancers were not always capable of having security groups attached.
1571+
// Once created without a security group, the NLB can never have any added.
1572+
// (https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-security-groups.html)
1573+
if lb.LoadBalancerType == infrav1.LoadBalancerTypeNLB && len(lb.SecurityGroupIDs) == 0 {
1574+
scope.Info("Pre-existing NLB %s without security groups, cannot reconcile security groups.", lb.Name)
1575+
return false
1576+
}
1577+
if !sets.NewString(lb.SecurityGroupIDs...).Equal(sets.NewString(specSGs...)) {
1578+
return true
1579+
}
1580+
return true
1581+
}

pkg/cloud/services/elb/loadbalancer_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,96 @@ func TestReconcileV2LB(t *testing.T) {
18471847
}
18481848
},
18491849
},
1850+
{
1851+
name: "ensure NLB without SGs doesn't attempt to add new SGs",
1852+
spec: func(spec infrav1.LoadBalancer) infrav1.LoadBalancer {
1853+
return spec
1854+
},
1855+
awsCluster: func(acl infrav1.AWSCluster) infrav1.AWSCluster {
1856+
acl.Spec.ControlPlaneLoadBalancer.Name = aws.String(elbName)
1857+
acl.Spec.ControlPlaneLoadBalancer.LoadBalancerType = infrav1.LoadBalancerTypeNLB
1858+
acl.Spec.ControlPlaneLoadBalancer.AdditionalSecurityGroups = []string{"sg-001"}
1859+
return acl
1860+
},
1861+
elbV2APIMocks: func(m *mocks.MockELBV2APIMockRecorder) {
1862+
m.DescribeLoadBalancers(gomock.Eq(&elbv2.DescribeLoadBalancersInput{
1863+
Names: aws.StringSlice([]string{elbName}),
1864+
})).
1865+
Return(&elbv2.DescribeLoadBalancersOutput{
1866+
LoadBalancers: []*elbv2.LoadBalancer{
1867+
{
1868+
LoadBalancerArn: aws.String(elbArn),
1869+
LoadBalancerName: aws.String(elbName),
1870+
Scheme: aws.String(string(infrav1.ELBSchemeInternetFacing)),
1871+
AvailabilityZones: []*elbv2.AvailabilityZone{
1872+
{
1873+
SubnetId: aws.String(clusterSubnetID),
1874+
ZoneName: aws.String(az),
1875+
},
1876+
},
1877+
VpcId: aws.String(vpcID),
1878+
},
1879+
},
1880+
}, nil)
1881+
m.ModifyLoadBalancerAttributes(&elbv2.ModifyLoadBalancerAttributesInput{
1882+
LoadBalancerArn: aws.String(elbArn),
1883+
Attributes: []*elbv2.LoadBalancerAttribute{
1884+
{
1885+
Key: aws.String("load_balancing.cross_zone.enabled"),
1886+
Value: aws.String("false"),
1887+
},
1888+
}}).
1889+
Return(&elbv2.ModifyLoadBalancerAttributesOutput{}, nil)
1890+
m.DescribeLoadBalancerAttributes(&elbv2.DescribeLoadBalancerAttributesInput{LoadBalancerArn: aws.String(elbArn)}).Return(
1891+
&elbv2.DescribeLoadBalancerAttributesOutput{
1892+
Attributes: []*elbv2.LoadBalancerAttribute{
1893+
{
1894+
Key: aws.String("load_balancing.cross_zone.enabled"),
1895+
Value: aws.String("false"),
1896+
},
1897+
{
1898+
Key: aws.String(infrav1.ClusterTagKey(clusterName)),
1899+
Value: aws.String(string(infrav1.ResourceLifecycleOwned)),
1900+
},
1901+
},
1902+
},
1903+
nil,
1904+
)
1905+
m.DescribeTags(&elbv2.DescribeTagsInput{ResourceArns: []*string{aws.String(elbArn)}}).Return(
1906+
&elbv2.DescribeTagsOutput{
1907+
TagDescriptions: []*elbv2.TagDescription{
1908+
{
1909+
ResourceArn: aws.String(elbArn),
1910+
Tags: []*elbv2.Tag{
1911+
{
1912+
Key: aws.String(infrav1.ClusterTagKey(clusterName)),
1913+
Value: aws.String(string(infrav1.ResourceLifecycleOwned)),
1914+
},
1915+
},
1916+
},
1917+
},
1918+
},
1919+
nil,
1920+
)
1921+
1922+
// Avoid the need to sort the AddTagsInput.Tags slice
1923+
m.AddTags(gomock.AssignableToTypeOf(&elbv2.AddTagsInput{})).Return(&elbv2.AddTagsOutput{}, nil)
1924+
1925+
m.SetSubnets(&elbv2.SetSubnetsInput{
1926+
LoadBalancerArn: aws.String(elbArn),
1927+
Subnets: []*string{},
1928+
}).Return(&elbv2.SetSubnetsOutput{}, nil)
1929+
},
1930+
check: func(t *testing.T, lb *infrav1.LoadBalancer, err error) {
1931+
t.Helper()
1932+
if err != nil {
1933+
t.Fatalf("did not expect error: %v", err)
1934+
}
1935+
if len(lb.SecurityGroupIDs) != 0 {
1936+
t.Errorf("Expected LB to contain 0 security groups, got %v", len(lb.SecurityGroupIDs))
1937+
}
1938+
},
1939+
},
18501940
}
18511941

18521942
for _, tc := range tests {
@@ -1897,6 +1987,7 @@ func TestReconcileV2LB(t *testing.T) {
18971987
}
18981988
err = s.reconcileV2LB(clusterScope.ControlPlaneLoadBalancer())
18991989
lb := s.scope.Network().APIServerELB
1990+
19001991
tc.check(t, &lb, err)
19011992
})
19021993
}
@@ -2886,6 +2977,7 @@ func TestGetHealthCheckProtocol(t *testing.T) {
28862977
})
28872978
}
28882979
}
2980+
28892981
func setupScheme() (*runtime.Scheme, error) {
28902982
scheme := runtime.NewScheme()
28912983
if err := clusterv1.AddToScheme(scheme); err != nil {

0 commit comments

Comments
 (0)