Skip to content

Commit 1251970

Browse files
authored
feat: add service.beta.kubernetes.io/scw-loadbalancer-pn-ids annotation (#188)
1 parent ccf654a commit 1251970

File tree

3 files changed

+104
-42
lines changed

3 files changed

+104
-42
lines changed

docs/loadbalancer-annotations.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,16 @@ The accepted values are "Proxy" and "VIP". Please refer to this article for more
226226
<https://kubernetes.io/blog/2023/12/18/kubernetes-1-29-feature-loadbalancer-ip-mode-alpha/>.
227227
When proxy-protocol is enabled on ALL the ports of the service, the ipMode
228228
is automatically set to "Proxy". You can use this annotation to override this.
229+
230+
### `service.beta.kubernetes.io/scw-loadbalancer-pn-ids`
231+
232+
This is the annotation to configure the Private Networks
233+
that will be attached to the load balancer. It is possible to provide a single
234+
Private Network ID, or a comma delimited list of Private Network IDs.
235+
If this annotation is not set or empty, the load balancer will be attached
236+
to the Private Network specified in the `PN_ID` environment variable.
237+
This annotation is ignored when `service.beta.kubernetes.io/scw-loadbalancer-externally-managed` is enabled.
238+
239+
The possible formats are:
240+
- `<pn-id>`: will attach a single Private Network to the LB.
241+
- `<pn-id>,<pn-id>`: will attach the two Private Networks to the LB.

scaleway/loadbalancers.go

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -589,48 +589,8 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
589589
return err
590590
}
591591

592-
if l.pnID != "" {
593-
respPN, err := l.api.ListLBPrivateNetworks(&scwlb.ZonedAPIListLBPrivateNetworksRequest{
594-
Zone: loadbalancer.Zone,
595-
LBID: loadbalancer.ID,
596-
})
597-
if err != nil {
598-
return fmt.Errorf("error listing private networks of load balancer %s: %v", loadbalancer.ID, err)
599-
}
600-
601-
var pnNIC *scwlb.PrivateNetwork
602-
for _, pNIC := range respPN.PrivateNetwork {
603-
if pNIC.PrivateNetworkID == l.pnID {
604-
pnNIC = pNIC
605-
continue
606-
}
607-
608-
// this PN should not be attached to this loadbalancer
609-
if !lbExternallyManaged {
610-
klog.V(3).Infof("detach extra private network %s from load balancer %s", pNIC.PrivateNetworkID, loadbalancer.ID)
611-
err = l.api.DetachPrivateNetwork(&scwlb.ZonedAPIDetachPrivateNetworkRequest{
612-
Zone: loadbalancer.Zone,
613-
LBID: loadbalancer.ID,
614-
PrivateNetworkID: pNIC.PrivateNetworkID,
615-
})
616-
if err != nil {
617-
return fmt.Errorf("unable to detach unmatched private network %s from %s: %v", pNIC.PrivateNetworkID, loadbalancer.ID, err)
618-
}
619-
}
620-
}
621-
622-
if pnNIC == nil {
623-
klog.V(3).Infof("attach private network %s to load balancer %s", l.pnID, loadbalancer.ID)
624-
_, err = l.api.AttachPrivateNetwork(&scwlb.ZonedAPIAttachPrivateNetworkRequest{
625-
Zone: loadbalancer.Zone,
626-
LBID: loadbalancer.ID,
627-
PrivateNetworkID: l.pnID,
628-
DHCPConfig: &scwlb.PrivateNetworkDHCPConfig{},
629-
})
630-
if err != nil {
631-
return fmt.Errorf("unable to attach private network %s on %s: %v", l.pnID, loadbalancer.ID, err)
632-
}
633-
}
592+
if err := l.attachPrivateNetworks(loadbalancer, service, lbExternallyManaged); err != nil {
593+
return fmt.Errorf("failed to attach private networks: %w", err)
634594
}
635595

636596
var targetIPs []string
@@ -819,6 +779,74 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
819779
return nil
820780
}
821781

782+
func (l *loadbalancers) attachPrivateNetworks(loadbalancer *scwlb.LB, service *v1.Service, lbExternallyManaged bool) error {
783+
if l.pnID == "" {
784+
return nil
785+
}
786+
787+
// maps pnID => attached
788+
pnIDs := make(map[string]bool)
789+
790+
// Fetch user-specified PrivateNetworkIDs unless LB is externally managed.
791+
if !lbExternallyManaged {
792+
for _, pnID := range getPrivateNetworkIDs(service) {
793+
pnIDs[pnID] = false
794+
}
795+
}
796+
797+
if len(pnIDs) == 0 {
798+
pnIDs[l.pnID] = false
799+
}
800+
801+
respPN, err := l.api.ListLBPrivateNetworks(&scwlb.ZonedAPIListLBPrivateNetworksRequest{
802+
Zone: loadbalancer.Zone,
803+
LBID: loadbalancer.ID,
804+
})
805+
if err != nil {
806+
return fmt.Errorf("error listing private networks of load balancer %s: %v", loadbalancer.ID, err)
807+
}
808+
809+
for _, pNIC := range respPN.PrivateNetwork {
810+
if _, ok := pnIDs[pNIC.PrivateNetworkID]; ok {
811+
// Mark this Private Network as attached.
812+
pnIDs[pNIC.PrivateNetworkID] = true
813+
continue
814+
}
815+
816+
// this PN should not be attached to this loadbalancer
817+
if !lbExternallyManaged {
818+
klog.V(3).Infof("detach extra private network %s from load balancer %s", pNIC.PrivateNetworkID, loadbalancer.ID)
819+
err = l.api.DetachPrivateNetwork(&scwlb.ZonedAPIDetachPrivateNetworkRequest{
820+
Zone: loadbalancer.Zone,
821+
LBID: loadbalancer.ID,
822+
PrivateNetworkID: pNIC.PrivateNetworkID,
823+
})
824+
if err != nil {
825+
return fmt.Errorf("unable to detach unmatched private network %s from %s: %v", pNIC.PrivateNetworkID, loadbalancer.ID, err)
826+
}
827+
}
828+
}
829+
830+
for pnID, attached := range pnIDs {
831+
if attached {
832+
continue
833+
}
834+
835+
klog.V(3).Infof("attach private network %s to load balancer %s", pnID, loadbalancer.ID)
836+
_, err = l.api.AttachPrivateNetwork(&scwlb.ZonedAPIAttachPrivateNetworkRequest{
837+
Zone: loadbalancer.Zone,
838+
LBID: loadbalancer.ID,
839+
PrivateNetworkID: pnID,
840+
DHCPConfig: &scwlb.PrivateNetworkDHCPConfig{},
841+
})
842+
if err != nil {
843+
return fmt.Errorf("unable to attach private network %s on %s: %v", pnID, loadbalancer.ID, err)
844+
}
845+
}
846+
847+
return nil
848+
}
849+
822850
// createPrivateServiceStatus creates a LoadBalancer status for services with private load balancers
823851
func (l *loadbalancers) createPrivateServiceStatus(service *v1.Service, lb *scwlb.LB, ipMode *v1.LoadBalancerIPMode) (*v1.LoadBalancerStatus, error) {
824852
if l.pnID == "" {

scaleway/loadbalancers_annotations.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,18 @@ const (
224224
// When proxy-protocol is enabled on ALL the ports of the service, the ipMode
225225
// is automatically set to "Proxy". You can use this annotation to override this.
226226
serviceAnnotationLoadBalancerIPMode = "service.beta.kubernetes.io/scw-loadbalancer-ip-mode"
227+
228+
// serviceAnnotationPrivateNetworkIDs is the annotation to configure the Private Networks
229+
// that will be attached to the load balancer. It is possible to provide a single
230+
// Private Network ID, or a comma delimited list of Private Network IDs.
231+
// If this annotation is not set or empty, the load balancer will be attached
232+
// to the Private Network specified in the `PN_ID` environment variable.
233+
// This annotation is ignored when service.beta.kubernetes.io/scw-loadbalancer-externally-managed is enabled.
234+
//
235+
// The possible formats are:
236+
// - "<pn-id>": will attach a single Private Network to the LB.
237+
// - "<pn-id>,<pn-id>": will attach the two Private Networks to the LB.
238+
serviceAnnotationPrivateNetworkIDs = "service.beta.kubernetes.io/scw-loadbalancer-pn-ids"
227239
)
228240

229241
func getLoadBalancerID(service *v1.Service) (scw.Zone, string, error) {
@@ -295,6 +307,15 @@ func getIPIDs(service *v1.Service) []string {
295307
return strings.Split(ipIDs, ",")
296308
}
297309

310+
func getPrivateNetworkIDs(service *v1.Service) []string {
311+
pnIDs := service.Annotations[serviceAnnotationPrivateNetworkIDs]
312+
if pnIDs == "" {
313+
return nil
314+
}
315+
316+
return strings.Split(pnIDs, ",")
317+
}
318+
298319
func getSendProxyV2(service *v1.Service, nodePort int32) (scwlb.ProxyProtocol, error) {
299320
sendProxyV2, ok := service.Annotations[serviceAnnotationLoadBalancerSendProxyV2]
300321
if !ok {

0 commit comments

Comments
 (0)