Skip to content

Commit 280f94b

Browse files
authored
[fix] : use updated service status as upstream controller can pass wrong info (linode#410)
* use updated service status as upstream controller can pass stale service object without any status set * fix failing e2e test, address review comments
1 parent df079a2 commit 280f94b

File tree

3 files changed

+211
-50
lines changed

3 files changed

+211
-50
lines changed

cloud/linode/loadbalancers.go

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,14 @@ func (l *loadbalancers) getLatestServiceLoadBalancerStatus(ctx context.Context,
160160
// getNodeBalancerByStatus attempts to get the NodeBalancer from the IP or hostname specified in the
161161
// most recent LoadBalancer status.
162162
func (l *loadbalancers) getNodeBalancerByStatus(ctx context.Context, service *v1.Service) (nb *linodego.NodeBalancer, err error) {
163-
for _, ingress := range service.Status.LoadBalancer.Ingress {
163+
lb := service.Status.LoadBalancer
164+
updatedLb, err := l.getLatestServiceLoadBalancerStatus(ctx, service)
165+
if err != nil {
166+
klog.V(3).Infof("failed to get latest LoadBalancer status for service (%s): %v", getServiceNn(service), err)
167+
} else {
168+
lb = updatedLb
169+
}
170+
for _, ingress := range lb.Ingress {
164171
if ingress.IP != "" {
165172
address, err := netip.ParseAddr(ingress.IP)
166173
if err != nil {
@@ -467,14 +474,19 @@ func (l *loadbalancers) updateNodeBalancer(
467474
klog.Infof("Node %s is excluded from NodeBalancer by annotation, skipping", node.Name)
468475
continue
469476
}
470-
newNodeOpts := l.buildNodeBalancerNodeConfigRebuildOptions(node, port.NodePort, subnetID, newNBCfg.Protocol)
477+
var newNodeOpts *linodego.NodeBalancerConfigRebuildNodeOptions
478+
newNodeOpts, err = l.buildNodeBalancerNodeConfigRebuildOptions(node, port.NodePort, subnetID, newNBCfg.Protocol)
479+
if err != nil {
480+
sentry.CaptureError(ctx, err)
481+
return fmt.Errorf("failed to build NodeBalancer node config options for node %s: %w", node.Name, err)
482+
}
471483
oldNodeID, ok := oldNBNodeIDs[newNodeOpts.Address]
472484
if ok {
473485
newNodeOpts.ID = oldNodeID
474486
} else {
475487
klog.Infof("No preexisting node id for %v found.", newNodeOpts.Address)
476488
}
477-
newNBNodes = append(newNBNodes, newNodeOpts)
489+
newNBNodes = append(newNBNodes, *newNodeOpts)
478490
}
479491
// If there's no existing config, create it
480492
var rebuildOpts linodego.NodeBalancerConfigRebuildOptions
@@ -1033,12 +1045,17 @@ func (l *loadbalancers) buildLoadBalancerRequest(ctx context.Context, clusterNam
10331045
}
10341046
createOpt := config.GetCreateOptions()
10351047

1036-
for _, n := range nodes {
1037-
if _, ok := n.Annotations[annotations.AnnExcludeNodeFromNb]; ok {
1038-
klog.Infof("Node %s is excluded from NodeBalancer by annotation, skipping", n.Name)
1048+
for _, node := range nodes {
1049+
if _, ok := node.Annotations[annotations.AnnExcludeNodeFromNb]; ok {
1050+
klog.Infof("Node %s is excluded from NodeBalancer by annotation, skipping", node.Name)
10391051
continue
10401052
}
1041-
createOpt.Nodes = append(createOpt.Nodes, l.buildNodeBalancerNodeConfigRebuildOptions(n, port.NodePort, subnetID, config.Protocol).NodeBalancerNodeCreateOptions)
1053+
newNodeOpts, err := l.buildNodeBalancerNodeConfigRebuildOptions(node, port.NodePort, subnetID, config.Protocol)
1054+
if err != nil {
1055+
sentry.CaptureError(ctx, err)
1056+
return nil, fmt.Errorf("failed to build NodeBalancer node config options for node %s: %w", node.Name, err)
1057+
}
1058+
createOpt.Nodes = append(createOpt.Nodes, newNodeOpts.NodeBalancerNodeCreateOptions)
10421059
}
10431060

10441061
configs = append(configs, &createOpt)
@@ -1058,10 +1075,14 @@ func coerceString(str string, minLen, maxLen int, padding string) string {
10581075
return str
10591076
}
10601077

1061-
func (l *loadbalancers) buildNodeBalancerNodeConfigRebuildOptions(node *v1.Node, nodePort int32, subnetID int, protocol linodego.ConfigProtocol) linodego.NodeBalancerConfigRebuildNodeOptions {
1062-
nodeOptions := linodego.NodeBalancerConfigRebuildNodeOptions{
1078+
func (l *loadbalancers) buildNodeBalancerNodeConfigRebuildOptions(node *v1.Node, nodePort int32, subnetID int, protocol linodego.ConfigProtocol) (*linodego.NodeBalancerConfigRebuildNodeOptions, error) {
1079+
nodeIP, err := getNodePrivateIP(node, subnetID)
1080+
if err != nil {
1081+
return nil, fmt.Errorf("node %s does not have a private IP address: %w", node.Name, err)
1082+
}
1083+
nodeOptions := &linodego.NodeBalancerConfigRebuildNodeOptions{
10631084
NodeBalancerNodeCreateOptions: linodego.NodeBalancerNodeCreateOptions{
1064-
Address: fmt.Sprintf("%v:%v", getNodePrivateIP(node, subnetID), nodePort),
1085+
Address: fmt.Sprintf("%v:%v", nodeIP, nodePort),
10651086
// NodeBalancer backends must be 3-32 chars in length
10661087
// If < 3 chars, pad node name with "node-" prefix
10671088
Label: coerceString(node.Name, 3, 32, "node-"),
@@ -1075,7 +1096,7 @@ func (l *loadbalancers) buildNodeBalancerNodeConfigRebuildOptions(node *v1.Node,
10751096
if subnetID != 0 {
10761097
nodeOptions.SubnetID = subnetID
10771098
}
1078-
return nodeOptions
1099+
return nodeOptions, nil
10791100
}
10801101

10811102
func (l *loadbalancers) retrieveKubeClient() error {
@@ -1204,20 +1225,23 @@ func getPortConfigAnnotation(service *v1.Service, port int) (portConfigAnnotatio
12041225
// For services outside of VPC, it will use linode specific private IP address
12051226
// Backend IP can be overwritten to the one specified using AnnLinodeNodePrivateIP
12061227
// annotation over the NodeInternalIP.
1207-
func getNodePrivateIP(node *v1.Node, subnetID int) string {
1228+
func getNodePrivateIP(node *v1.Node, subnetID int) (string, error) {
12081229
if subnetID == 0 {
12091230
if address, exists := node.Annotations[annotations.AnnLinodeNodePrivateIP]; exists {
1210-
return address
1231+
return address, nil
12111232
}
12121233
}
12131234

12141235
klog.Infof("Node %s, assigned IP addresses: %v", node.Name, node.Status.Addresses)
12151236
for _, addr := range node.Status.Addresses {
12161237
if addr.Type == v1.NodeInternalIP {
1217-
return addr.Address
1238+
return addr.Address, nil
12181239
}
12191240
}
1220-
return ""
1241+
1242+
// If no private/internal IP is found, return error.
1243+
klog.V(4).Infof("No internal IP found for node %s", node.Name)
1244+
return "", fmt.Errorf("no internal IP found for node %s", node.Name)
12211245
}
12221246

12231247
func getTLSCertInfo(ctx context.Context, kubeClient kubernetes.Interface, namespace string, config portConfig) (string, string, error) {

0 commit comments

Comments
 (0)