@@ -115,6 +115,10 @@ const (
115
115
// serviceAnnotationLoadBalancerZone is the zone to create the load balancer
116
116
serviceAnnotationLoadBalancerZone = "service.beta.kubernetes.io/scw-loadbalancer-zone"
117
117
118
+ // serviceAnnotationLoadBalancerTimeoutClient is the maximum client connection inactivity time
119
+ // The default value is "10m". The duration are go's time.Duration (ex: "1s", "2m", "4h", ...)
120
+ serviceAnnotationLoadBalancerTimeoutClient = "service.beta.kubernetes.io/scw-loadbalancer-timeout-client"
121
+
118
122
// serviceAnnotationLoadBalancerTimeoutServer is the maximum server connection inactivity time
119
123
// The default value is "10m". The duration are go's time.Duration (ex: "1s", "2m", "4h", ...)
120
124
serviceAnnotationLoadBalancerTimeoutServer = "service.beta.kubernetes.io/scw-loadbalancer-timeout-server"
@@ -144,14 +148,18 @@ const (
144
148
// (for instance "80,443")
145
149
serviceAnnotationLoadBalancerProtocolHTTP = "service.beta.kubernetes.io/scw-loadbalancer-protocol-http"
146
150
147
- // serviceAnnotationLoadBalancerCertificateIDs is the annotation to choose the the certificate IDS to associate
151
+ // serviceAnnotationLoadBalancerCertificateIDs is the annotation to choose the certificate IDS to associate
148
152
// with this LoadBalancer.
149
153
// The possible format are:
150
154
// "<certificate-id>": will use this certificate for all frontends
151
155
// "<certificate-id>,<certificate-id>" will use these certificates for all frontends
152
156
// "<port1>:<certificate1-id>,<certificate2-id>;<port2>,<port3>:<certificate3-id>" will use certificate 1 and 2 for frontend with port port1
153
157
// and certificate3 for frotend with port port2 and port3
154
158
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"
155
163
)
156
164
157
165
const MaxEntriesPerACL = 60
@@ -272,6 +280,8 @@ func (l *loadbalancers) EnsureLoadBalancer(ctx context.Context, clusterName stri
272
280
return nil , LoadBalancerNotReady
273
281
}
274
282
283
+ nodes = filterNodes (service , nodes )
284
+
275
285
err = l .updateLoadBalancer (ctx , lb , service , nodes )
276
286
if err != nil {
277
287
klog .Errorf ("error updating loadbalancer for service %s: %v" , service .Name , err )
@@ -338,7 +348,6 @@ func (l *loadbalancers) EnsureLoadBalancerDeleted(ctx context.Context, clusterNa
338
348
return l .deleteLoadBalancer (ctx , lb , service )
339
349
}
340
350
341
- //
342
351
func (l * loadbalancers ) deleteLoadBalancer (ctx context.Context , lb * scwlb.LB , service * v1.Service ) error {
343
352
// remove loadbalancer annotation
344
353
if err := l .unannotateAndPatch (service ); err != nil {
@@ -710,6 +719,13 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
710
719
if err != nil {
711
720
return fmt .Errorf ("error getting certificate IDs for loadbalancer %s: %v" , loadbalancer .ID , err )
712
721
}
722
+
723
+ timeoutClient , err := getTimeoutClient (service )
724
+ if err != nil {
725
+ return fmt .Errorf ("error getting %s annotation for loadbalancer %s: %v" ,
726
+ serviceAnnotationLoadBalancerTimeoutClient , loadbalancer .ID , err )
727
+ }
728
+
713
729
// if the frontend exists for the port, update it
714
730
if frontend , ok := portFrontends [port .Port ]; ok {
715
731
_ , err := l .api .UpdateFrontend (& scwlb.ZonedAPIUpdateFrontendRequest {
@@ -718,7 +734,7 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
718
734
Name : frontend .Name ,
719
735
InboundPort : frontend .InboundPort ,
720
736
BackendID : portBackends [port .NodePort ].ID ,
721
- TimeoutClient : frontend . TimeoutClient ,
737
+ TimeoutClient : & timeoutClient ,
722
738
CertificateIDs : scw .StringsPtr (certificateIDs ),
723
739
})
724
740
@@ -729,14 +745,13 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
729
745
730
746
frontendID = frontend .ID
731
747
} else { // if the frontend for this port does not exist, create it
732
- timeoutClient := time .Minute * 10
733
748
resp , err := l .api .CreateFrontend (& scwlb.ZonedAPICreateFrontendRequest {
734
749
Zone : loadbalancer .Zone ,
735
750
LBID : loadbalancer .ID ,
736
751
Name : fmt .Sprintf ("%s_tcp_%d" , string (service .UID ), port .Port ),
737
752
InboundPort : port .Port ,
738
753
BackendID : portBackends [port .NodePort ].ID ,
739
- TimeoutClient : & timeoutClient , // TODO use annotation?
754
+ TimeoutClient : & timeoutClient ,
740
755
CertificateIDs : scw .StringsPtr (certificateIDs ),
741
756
})
742
757
@@ -1330,6 +1345,21 @@ func getProxyProtocol(service *v1.Service, nodePort int32) (scwlb.ProxyProtocol,
1330
1345
return getSendProxyV2 (service , nodePort )
1331
1346
}
1332
1347
1348
+ func getTimeoutClient (service * v1.Service ) (time.Duration , error ) {
1349
+ timeoutClient , ok := service .Annotations [serviceAnnotationLoadBalancerTimeoutClient ]
1350
+ if ! ok {
1351
+ return time .ParseDuration ("10m" )
1352
+ }
1353
+
1354
+ timeoutClientDuration , err := time .ParseDuration (timeoutClient )
1355
+ if err != nil {
1356
+ klog .Errorf ("invalid value for annotation %s" , serviceAnnotationLoadBalancerTimeoutClient )
1357
+ return time .Duration (0 ), errLoadBalancerInvalidAnnotation
1358
+ }
1359
+
1360
+ return timeoutClientDuration , nil
1361
+ }
1362
+
1333
1363
func getTimeoutServer (service * v1.Service ) (time.Duration , error ) {
1334
1364
timeoutServer , ok := service .Annotations [serviceAnnotationLoadBalancerTimeoutServer ]
1335
1365
if ! ok {
@@ -1712,3 +1742,63 @@ func getHTTPSHealthCheck(service *v1.Service, nodePort int32) (*scwlb.HealthChec
1712
1742
URI : uri ,
1713
1743
}, nil
1714
1744
}
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