Skip to content

Commit a1c1036

Browse files
guyguy333jtherin
authored andcommitted
lb: introduce service.beta.kubernetes.io/scw-loadbalancer-target-node-labels
Signed-off-by: Guillaume Delbergue <[email protected]>
1 parent 0f0b1d8 commit a1c1036

File tree

1 file changed

+67
-2
lines changed

1 file changed

+67
-2
lines changed

scaleway/loadbalancers.go

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,18 @@ const (
148148
// (for instance "80,443")
149149
serviceAnnotationLoadBalancerProtocolHTTP = "service.beta.kubernetes.io/scw-loadbalancer-protocol-http"
150150

151-
// serviceAnnotationLoadBalancerCertificateIDs is the annotation to choose the the certificate IDS to associate
151+
// serviceAnnotationLoadBalancerCertificateIDs is the annotation to choose the certificate IDS to associate
152152
// with this LoadBalancer.
153153
// The possible format are:
154154
// "<certificate-id>": will use this certificate for all frontends
155155
// "<certificate-id>,<certificate-id>" will use these certificates for all frontends
156156
// "<port1>:<certificate1-id>,<certificate2-id>;<port2>,<port3>:<certificate3-id>" will use certificate 1 and 2 for frontend with port port1
157157
// and certificate3 for frotend with port port2 and port3
158158
serviceAnnotationLoadBalancerCertificateIDs = "service.beta.kubernetes.io/scw-loadbalancer-certificate-ids"
159+
160+
// serviceAnnotationLoadBalancerTargetNodeLabels is the annotation to target nodes with specific label(s)
161+
// Expected format: "Key1=Val1,Key2=Val2"
162+
serviceAnnotationLoadBalancerTargetNodeLabels = "service.beta.kubernetes.io/scw-loadbalancer-target-node-labels"
159163
)
160164

161165
const MaxEntriesPerACL = 60
@@ -276,6 +280,8 @@ func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName stri
276280
return nil, LoadBalancerNotReady
277281
}
278282

283+
nodes = filterNodes(service, nodes)
284+
279285
err = l.updateLoadBalancer(ctx, lb, service, nodes)
280286
if err != nil {
281287
klog.Errorf("error updating loadbalancer for service %s: %v", service.Name, err)
@@ -342,7 +348,6 @@ func (l *loadbalancers) EnsureLoadBalancerDeleted(ctx context.Context, clusterNa
342348
return l.deleteLoadBalancer(ctx, lb, service)
343349
}
344350

345-
//
346351
func (l *loadbalancers) deleteLoadBalancer(ctx context.Context, lb *scwlb.LB, service *v1.Service) error {
347352
// remove loadbalancer annotation
348353
if err := l.unannotateAndPatch(service); err != nil {
@@ -1737,3 +1742,63 @@ func getHTTPSHealthCheck(service *v1.Service, nodePort int32) (*scwlb.HealthChec
17371742
URI: uri,
17381743
}, nil
17391744
}
1745+
1746+
// Original version: https://github.com/kubernetes/legacy-cloud-providers/blob/1aa918bf227e52af6f8feb3fa065dabff251a0a3/aws/aws_loadbalancer.go#L117
1747+
func getKeyValueFromAnnotation(annotation string) map[string]string {
1748+
additionalTags := make(map[string]string)
1749+
additionalTagsList := strings.TrimSpace(annotation)
1750+
1751+
// Break up list of "Key1=Val,Key2=Val2"
1752+
tagList := strings.Split(additionalTagsList, ",")
1753+
1754+
// Break up "Key=Val"
1755+
for _, tagSet := range tagList {
1756+
tag := strings.Split(strings.TrimSpace(tagSet), "=")
1757+
1758+
// Accept "Key=val" or "Key=" or just "Key"
1759+
if len(tag) >= 2 && len(tag[0]) != 0 {
1760+
// There is a key and a value, so save it
1761+
additionalTags[tag[0]] = tag[1]
1762+
} else if len(tag) == 1 && len(tag[0]) != 0 {
1763+
// Just "Key"
1764+
additionalTags[tag[0]] = ""
1765+
}
1766+
}
1767+
1768+
return additionalTags
1769+
}
1770+
1771+
// Original version: https://github.com/kubernetes/legacy-cloud-providers/blob/1aa918bf227e52af6f8feb3fa065dabff251a0a3/aws/aws_loadbalancer.go#L1631
1772+
func filterNodes(service *v1.Service, nodes []*v1.Node) []*v1.Node {
1773+
nodeLabels, ok := service.Annotations[serviceAnnotationLoadBalancerTargetNodeLabels]
1774+
if !ok {
1775+
return nodes
1776+
}
1777+
1778+
targetNodeLabels := getKeyValueFromAnnotation(nodeLabels)
1779+
1780+
if len(targetNodeLabels) == 0 {
1781+
return nodes
1782+
}
1783+
1784+
targetNodes := make([]*v1.Node, 0, len(nodes))
1785+
1786+
for _, node := range nodes {
1787+
if node.Labels != nil && len(node.Labels) > 0 {
1788+
allFiltersMatch := true
1789+
1790+
for targetLabelKey, targetLabelValue := range targetNodeLabels {
1791+
if nodeLabelValue, ok := node.Labels[targetLabelKey]; !ok || (nodeLabelValue != targetLabelValue && targetLabelValue != "") {
1792+
allFiltersMatch = false
1793+
break
1794+
}
1795+
}
1796+
1797+
if allFiltersMatch {
1798+
targetNodes = append(targetNodes, node)
1799+
}
1800+
}
1801+
}
1802+
1803+
return targetNodes
1804+
}

0 commit comments

Comments
 (0)