Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/loadbalancer-annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,16 @@ The accepted values are "Proxy" and "VIP". Please refer to this article for more
<https://kubernetes.io/blog/2023/12/18/kubernetes-1-29-feature-loadbalancer-ip-mode-alpha/>.
When proxy-protocol is enabled on ALL the ports of the service, the ipMode
is automatically set to "Proxy". You can use this annotation to override this.

### `service.beta.kubernetes.io/scw-loadbalancer-pn-ids`

This is the annotation to configure the Private Networks
that will be attached to the load balancer. It is possible to provide a single
Private Network ID, or a comma delimited list of Private Network IDs.
If this annotation is not set or empty, the load balancer will be attached
to the Private Network specified in the `PN_ID` environment variable.
This annotation is ignored when `service.beta.kubernetes.io/scw-loadbalancer-externally-managed` is enabled.

The possible formats are:
- `<pn-id>`: will attach a single Private Network to the LB.
- `<pn-id>,<pn-id>`: will attach the two Private Networks to the LB.
112 changes: 70 additions & 42 deletions scaleway/loadbalancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,48 +589,8 @@ func (l *loadbalancers) updateLoadBalancer(ctx context.Context, loadbalancer *sc
return err
}

if l.pnID != "" {
respPN, err := l.api.ListLBPrivateNetworks(&scwlb.ZonedAPIListLBPrivateNetworksRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
})
if err != nil {
return fmt.Errorf("error listing private networks of load balancer %s: %v", loadbalancer.ID, err)
}

var pnNIC *scwlb.PrivateNetwork
for _, pNIC := range respPN.PrivateNetwork {
if pNIC.PrivateNetworkID == l.pnID {
pnNIC = pNIC
continue
}

// this PN should not be attached to this loadbalancer
if !lbExternallyManaged {
klog.V(3).Infof("detach extra private network %s from load balancer %s", pNIC.PrivateNetworkID, loadbalancer.ID)
err = l.api.DetachPrivateNetwork(&scwlb.ZonedAPIDetachPrivateNetworkRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
PrivateNetworkID: pNIC.PrivateNetworkID,
})
if err != nil {
return fmt.Errorf("unable to detach unmatched private network %s from %s: %v", pNIC.PrivateNetworkID, loadbalancer.ID, err)
}
}
}

if pnNIC == nil {
klog.V(3).Infof("attach private network %s to load balancer %s", l.pnID, loadbalancer.ID)
_, err = l.api.AttachPrivateNetwork(&scwlb.ZonedAPIAttachPrivateNetworkRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
PrivateNetworkID: l.pnID,
DHCPConfig: &scwlb.PrivateNetworkDHCPConfig{},
})
if err != nil {
return fmt.Errorf("unable to attach private network %s on %s: %v", l.pnID, loadbalancer.ID, err)
}
}
if err := l.attachPrivateNetworks(loadbalancer, service, lbExternallyManaged); err != nil {
return fmt.Errorf("failed to attach private networks: %w", err)
}

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

func (l *loadbalancers) attachPrivateNetworks(loadbalancer *scwlb.LB, service *v1.Service, lbExternallyManaged bool) error {
if l.pnID == "" {
return nil
}

// maps pnID => attached
pnIDs := make(map[string]bool)

// Fetch user-specified PrivateNetworkIDs unless LB is externally managed.
if !lbExternallyManaged {
for _, pnID := range getPrivateNetworkIDs(service) {
pnIDs[pnID] = false
}
}

if len(pnIDs) == 0 {
pnIDs[l.pnID] = false
}

respPN, err := l.api.ListLBPrivateNetworks(&scwlb.ZonedAPIListLBPrivateNetworksRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
})
if err != nil {
return fmt.Errorf("error listing private networks of load balancer %s: %v", loadbalancer.ID, err)
}

for _, pNIC := range respPN.PrivateNetwork {
if _, ok := pnIDs[pNIC.PrivateNetworkID]; ok {
// Mark this Private Network as attached.
pnIDs[pNIC.PrivateNetworkID] = true
continue
}

// this PN should not be attached to this loadbalancer
if !lbExternallyManaged {
klog.V(3).Infof("detach extra private network %s from load balancer %s", pNIC.PrivateNetworkID, loadbalancer.ID)
err = l.api.DetachPrivateNetwork(&scwlb.ZonedAPIDetachPrivateNetworkRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
PrivateNetworkID: pNIC.PrivateNetworkID,
})
if err != nil {
return fmt.Errorf("unable to detach unmatched private network %s from %s: %v", pNIC.PrivateNetworkID, loadbalancer.ID, err)
}
}
}

for pnID, attached := range pnIDs {
if attached {
continue
}

klog.V(3).Infof("attach private network %s to load balancer %s", pnID, loadbalancer.ID)
_, err = l.api.AttachPrivateNetwork(&scwlb.ZonedAPIAttachPrivateNetworkRequest{
Zone: loadbalancer.Zone,
LBID: loadbalancer.ID,
PrivateNetworkID: pnID,
DHCPConfig: &scwlb.PrivateNetworkDHCPConfig{},
})
if err != nil {
return fmt.Errorf("unable to attach private network %s on %s: %v", pnID, loadbalancer.ID, err)
}
}

return nil
}

// createPrivateServiceStatus creates a LoadBalancer status for services with private load balancers
func (l *loadbalancers) createPrivateServiceStatus(service *v1.Service, lb *scwlb.LB, ipMode *v1.LoadBalancerIPMode) (*v1.LoadBalancerStatus, error) {
if l.pnID == "" {
Expand Down
21 changes: 21 additions & 0 deletions scaleway/loadbalancers_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ const (
// When proxy-protocol is enabled on ALL the ports of the service, the ipMode
// is automatically set to "Proxy". You can use this annotation to override this.
serviceAnnotationLoadBalancerIPMode = "service.beta.kubernetes.io/scw-loadbalancer-ip-mode"

// serviceAnnotationPrivateNetworkIDs is the annotation to configure the Private Networks
// that will be attached to the load balancer. It is possible to provide a single
// Private Network ID, or a comma delimited list of Private Network IDs.
// If this annotation is not set or empty, the load balancer will be attached
// to the Private Network specified in the `PN_ID` environment variable.
// This annotation is ignored when service.beta.kubernetes.io/scw-loadbalancer-externally-managed is enabled.
//
// The possible formats are:
// - "<pn-id>": will attach a single Private Network to the LB.
// - "<pn-id>,<pn-id>": will attach the two Private Networks to the LB.
serviceAnnotationPrivateNetworkIDs = "service.beta.kubernetes.io/scw-loadbalancer-pn-ids"
)

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

func getPrivateNetworkIDs(service *v1.Service) []string {
pnIDs := service.Annotations[serviceAnnotationPrivateNetworkIDs]
if pnIDs == "" {
return nil
}

return strings.Split(pnIDs, ",")
}

func getSendProxyV2(service *v1.Service, nodePort int32) (scwlb.ProxyProtocol, error) {
sendProxyV2, ok := service.Annotations[serviceAnnotationLoadBalancerSendProxyV2]
if !ok {
Expand Down
Loading