Skip to content

Commit 10b709d

Browse files
committed
feat(lb): implement ConnectionRateLimit, EnableAccessLogs and EnableHTTP3
Signed-off-by: Aurelien GASTON <[email protected]>
1 parent c17d3d0 commit 10b709d

File tree

3 files changed

+421
-20
lines changed

3 files changed

+421
-20
lines changed

scaleway/loadbalancers.go

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,11 +1025,32 @@ func servicePortToFrontend(service *v1.Service, loadbalancer *scwlb.LB, port v1.
10251025
return nil, fmt.Errorf("error getting certificate IDs for loadbalancer %s: %v", loadbalancer.ID, err)
10261026
}
10271027

1028+
connectionRateLimit, err := getConnectionRateLimit(service)
1029+
if err != nil {
1030+
return nil, fmt.Errorf("error getting %s annotation for loadbalancer %s: %v",
1031+
serviceAnnotationLoadBalancerConnectionRateLimit, loadbalancer.ID, err)
1032+
}
1033+
1034+
enableAccessLogs, err := getEnableAccessLogs(service)
1035+
if err != nil {
1036+
return nil, fmt.Errorf("error getting %s annotation for loadbalancer %s: %v",
1037+
serviceAnnotationLoadBalancerEnableAccessLogs, loadbalancer.ID, err)
1038+
}
1039+
1040+
enableHTTP3, err := getEnableHTTP3(service)
1041+
if err != nil {
1042+
return nil, fmt.Errorf("error getting %s annotation for loadbalancer %s: %v",
1043+
serviceAnnotationLoadBalancerEnableHTTP3, loadbalancer.ID, err)
1044+
}
1045+
10281046
return &scwlb.Frontend{
1029-
Name: fmt.Sprintf("%s_tcp_%d", string(service.UID), port.Port),
1030-
InboundPort: port.Port,
1031-
TimeoutClient: &timeoutClient,
1032-
CertificateIDs: certificateIDs,
1047+
Name: fmt.Sprintf("%s_tcp_%d", string(service.UID), port.Port),
1048+
InboundPort: port.Port,
1049+
TimeoutClient: &timeoutClient,
1050+
ConnectionRateLimit: connectionRateLimit,
1051+
CertificateIDs: certificateIDs,
1052+
EnableAccessLogs: enableAccessLogs,
1053+
EnableHTTP3: enableHTTP3,
10331054
}, nil
10341055
}
10351056

@@ -1281,6 +1302,21 @@ func frontendEquals(got, want *scwlb.Frontend) bool {
12811302
return false
12821303
}
12831304

1305+
if !uint32PtrEqual(got.ConnectionRateLimit, want.ConnectionRateLimit) {
1306+
klog.V(3).Infof("frontend.ConnectionRateLimit: %s - %s", ptrUint32ToString(got.ConnectionRateLimit), ptrUint32ToString(want.ConnectionRateLimit))
1307+
return false
1308+
}
1309+
1310+
if got.EnableAccessLogs != want.EnableAccessLogs {
1311+
klog.V(3).Infof("frontend.EnableAccessLogs: %t - %t", got.EnableAccessLogs, want.EnableAccessLogs)
1312+
return false
1313+
}
1314+
1315+
if got.EnableHTTP3 != want.EnableHTTP3 {
1316+
klog.V(3).Infof("frontend.EnableHTTP3: %t - %t", got.EnableHTTP3, want.EnableHTTP3)
1317+
return false
1318+
}
1319+
12841320
return true
12851321
}
12861322

@@ -1609,14 +1645,16 @@ func (l *loadbalancers) updateBackend(service *v1.Service, loadbalancer *scwlb.L
16091645
// createFrontend creates a frontend on the load balancer
16101646
func (l *loadbalancers) createFrontend(service *v1.Service, loadbalancer *scwlb.LB, frontend *scwlb.Frontend, backend *scwlb.Backend) (*scwlb.Frontend, error) {
16111647
f, err := l.api.CreateFrontend(&scwlb.ZonedAPICreateFrontendRequest{
1612-
Zone: loadbalancer.Zone,
1613-
LBID: loadbalancer.ID,
1614-
Name: frontend.Name,
1615-
InboundPort: frontend.InboundPort,
1616-
BackendID: backend.ID,
1617-
TimeoutClient: frontend.TimeoutClient,
1618-
CertificateIDs: &frontend.CertificateIDs,
1619-
EnableHTTP3: frontend.EnableHTTP3,
1648+
Zone: loadbalancer.Zone,
1649+
LBID: loadbalancer.ID,
1650+
Name: frontend.Name,
1651+
InboundPort: frontend.InboundPort,
1652+
BackendID: backend.ID,
1653+
TimeoutClient: frontend.TimeoutClient,
1654+
CertificateIDs: &frontend.CertificateIDs,
1655+
ConnectionRateLimit: frontend.ConnectionRateLimit,
1656+
EnableAccessLogs: frontend.EnableAccessLogs,
1657+
EnableHTTP3: frontend.EnableHTTP3,
16201658
})
16211659

16221660
return f, err
@@ -1625,14 +1663,16 @@ func (l *loadbalancers) createFrontend(service *v1.Service, loadbalancer *scwlb.
16251663
// updateFrontend updates a frontend on the load balancer
16261664
func (l *loadbalancers) updateFrontend(service *v1.Service, loadbalancer *scwlb.LB, frontend *scwlb.Frontend, backend *scwlb.Backend) (*scwlb.Frontend, error) {
16271665
f, err := l.api.UpdateFrontend(&scwlb.ZonedAPIUpdateFrontendRequest{
1628-
Zone: loadbalancer.Zone,
1629-
FrontendID: frontend.ID,
1630-
Name: frontend.Name,
1631-
InboundPort: frontend.InboundPort,
1632-
BackendID: backend.ID,
1633-
TimeoutClient: frontend.TimeoutClient,
1634-
CertificateIDs: &frontend.CertificateIDs,
1635-
EnableHTTP3: frontend.EnableHTTP3,
1666+
Zone: loadbalancer.Zone,
1667+
FrontendID: frontend.ID,
1668+
Name: frontend.Name,
1669+
InboundPort: frontend.InboundPort,
1670+
BackendID: backend.ID,
1671+
TimeoutClient: frontend.TimeoutClient,
1672+
CertificateIDs: &frontend.CertificateIDs,
1673+
ConnectionRateLimit: frontend.ConnectionRateLimit,
1674+
EnableAccessLogs: &frontend.EnableAccessLogs,
1675+
EnableHTTP3: frontend.EnableHTTP3,
16361676
})
16371677

16381678
return f, err
@@ -1696,6 +1736,17 @@ func int32PtrEqual(got, want *int32) bool {
16961736
return *got == *want
16971737
}
16981738

1739+
// uint32PtrEqual returns true if both integers are equal
1740+
func uint32PtrEqual(got, want *uint32) bool {
1741+
if got == nil && want == nil {
1742+
return true
1743+
}
1744+
if got == nil || want == nil {
1745+
return false
1746+
}
1747+
return *got == *want
1748+
}
1749+
16991750
// chunkArray takes an array and split it in chunks of a given size
17001751
func chunkArray(array []string, maxChunkSize int) [][]string {
17011752
result := [][]string{}
@@ -1779,6 +1830,13 @@ func ptrInt32ToString(i *int32) string {
17791830
return fmt.Sprintf("%d", *i)
17801831
}
17811832

1833+
func ptrUint32ToString(i *uint32) string {
1834+
if i == nil {
1835+
return "<nil>"
1836+
}
1837+
return fmt.Sprintf("%d", *i)
1838+
}
1839+
17821840
func ptrBoolToString(b *bool) string {
17831841
if b == nil {
17841842
return "<nil>"

scaleway/loadbalancers_annotations.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ const (
108108
// serviceAnnotationLoadBalancerZone is the zone to create the load balancer
109109
serviceAnnotationLoadBalancerZone = "service.beta.kubernetes.io/scw-loadbalancer-zone"
110110

111+
// serviceAnnotationLoadBalancerConnectionRateLimit is the annotation to set the incoming connection rate limit per second.
112+
// Set to 0 to disable the rate limit
113+
serviceAnnotationLoadBalancerConnectionRateLimit = "service.beta.kubernetes.io/scw-loadbalancer-connection-rate-limit"
114+
115+
// serviceAnnotationLoadBalancerEnableAccessLogs is the annotation to enable access logs for the load balancer.
116+
// The default value is "false". The possible values are "false" or "true".
117+
serviceAnnotationLoadBalancerEnableAccessLogs = "service.beta.kubernetes.io/scw-loadbalancer-enable-access-logs"
118+
119+
// serviceAnnotationLoadBalancerEnableHTTP3 is the annotation to enable HTTP/3 protocol for the load balancer.
120+
// The default value is "false". The possible values are "false" or "true".
121+
serviceAnnotationLoadBalancerEnableHTTP3 = "service.beta.kubernetes.io/scw-loadbalancer-enable-http3"
122+
111123
// serviceAnnotationLoadBalancerTimeoutClient is the maximum client connection inactivity time
112124
// The default value is "10m". The duration are go's time.Duration (ex: "1s", "2m", "4h", ...)
113125
serviceAnnotationLoadBalancerTimeoutClient = "service.beta.kubernetes.io/scw-loadbalancer-timeout-client"
@@ -994,3 +1006,33 @@ func getKeyValueFromAnnotation(annotation string) map[string]string {
9941006

9951007
return additionalTags
9961008
}
1009+
1010+
func getConnectionRateLimit(service *v1.Service) (*uint32, error) {
1011+
connectionRateLimit, ok := service.Annotations[serviceAnnotationLoadBalancerConnectionRateLimit]
1012+
if !ok {
1013+
return nil, nil
1014+
}
1015+
connectionRateLimitInt, err := strconv.Atoi(connectionRateLimit)
1016+
if err != nil {
1017+
klog.Errorf("invalid value for annotation %s", serviceAnnotationLoadBalancerConnectionRateLimit)
1018+
return nil, errLoadBalancerInvalidAnnotation
1019+
}
1020+
connectionRateLimitUint32 := uint32(connectionRateLimitInt)
1021+
return &connectionRateLimitUint32, nil
1022+
}
1023+
1024+
func getEnableAccessLogs(service *v1.Service) (bool, error) {
1025+
enableAccessLogs, ok := service.Annotations[serviceAnnotationLoadBalancerEnableAccessLogs]
1026+
if !ok {
1027+
return false, nil
1028+
}
1029+
return strconv.ParseBool(enableAccessLogs)
1030+
}
1031+
1032+
func getEnableHTTP3(service *v1.Service) (bool, error) {
1033+
enableHTTP3, ok := service.Annotations[serviceAnnotationLoadBalancerEnableHTTP3]
1034+
if !ok {
1035+
return false, nil
1036+
}
1037+
return strconv.ParseBool(enableHTTP3)
1038+
}

0 commit comments

Comments
 (0)