Skip to content

Commit

Permalink
Put srv in backup is not in zone
Browse files Browse the repository at this point in the history
  • Loading branch information
mlophez committed Sep 20, 2024
1 parent 8757db1 commit 66dc4c5
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pkg/service/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/haproxytech/kubernetes-ingress/pkg/annotations"
"github.com/haproxytech/kubernetes-ingress/pkg/haproxy/api"
"github.com/haproxytech/kubernetes-ingress/pkg/store"
"github.com/haproxytech/kubernetes-ingress/pkg/zone"
)

// HandleHAProxySrvs handles the haproxy backend servers of the corresponding IngressPath (service + port)
Expand Down Expand Up @@ -69,6 +70,10 @@ func (s *Service) updateHAProxySrv(client api.HAProxyClient, srvSlot store.HAPro
if srvSlot.Address != "" {
srv.Address = srvSlot.Address
srv.Maintenance = "disabled"
// Put in backup if cross zone traffic is disabled
if zone.IsBackupEnabledForThisIP(srv.Address) {
srv.Backup = "enabled"
}
}
logger.Tracef("[CONFIG] [BACKEND] [SERVER] backend %s: about to update server in configuration file : models.Server { Name: %s, Port: %d, Address: %s, Maintenance: %s }", s.backend.Name, srv.Name, *srv.Port, srv.Address, srv.Maintenance)
// Update server
Expand Down
76 changes: 76 additions & 0 deletions pkg/zone/zone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package zone

import (
"fmt"
"net"
"os"
"strings"
)

var controllerIP string
var controllerZone string
var zonesInfo string
var zonesCrossEnabled bool = true

func init() {
controllerIP = os.Getenv("POD_IP")
zonesInfo = os.Getenv("ZONES_INFO")
zonesCrossEnabled = !(strings.ToLower(os.Getenv("ZONES_CROSS_TRAFFIC_ENABLED")) == "false")

if controllerIP == "" || zonesInfo == "" {
zonesCrossEnabled = true
return
}

controllerZone = getZoneFromIP(controllerIP, zonesInfo)
}

// This function is used when haproxy configure a server in backend
func IsBackupEnabledForThisIP(address string) bool {
if zonesCrossEnabled || address == "" || address == "127.0.0.1" {
return false
}
srvZone := getZoneFromIP(address, zonesInfo)
return srvZone != controllerZone
}

// Private; Auxiliary functions
func getZoneFromIP(address string, zoneSubnets string) string {
input := strings.ReplaceAll(zoneSubnets, " ", "")
subnetGroups := strings.Split(input, ";")

for _, group := range subnetGroups {
parts := strings.Split(group, ":")
if len(parts) != 2 || parts[1] == "" {
return "unknown"
}

zoneName := parts[0]
subnets := strings.Split(parts[1], ",")

for _, subnet := range subnets {
if ok, _ := isIPInSubnet(address, subnet); ok {
return zoneName
}
}
}

return "unknown"
}

func isIPInSubnet(ipStr, subnetStr string) (bool, error) {
// Parseamos la IP
ip := net.ParseIP(ipStr)
if ip == nil {
return false, fmt.Errorf("IP inválida: %s", ipStr)
}

// Parseamos la subnet (dirección IP + máscara)
_, subnet, err := net.ParseCIDR(subnetStr)
if err != nil {
return false, fmt.Errorf("subred inválida: %s", subnetStr)
}

// Comprobamos si la IP está dentro de la subred
return subnet.Contains(ip), nil
}
66 changes: 66 additions & 0 deletions pkg/zone/zone_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package zone

import (
"testing"
)

func TestGetZoneFromIp(t *testing.T) {
tests := []struct {
name string
address string
zoneSubnets string
expected string
}{
{
name: "IP belongs to eu-south-2a",
address: "192.168.2.1",
zoneSubnets: "eu-south-2a: 192.168.1.0/24, 192.168.2.0/24; eu-south-2b: 192.168.3.0/24",
expected: "eu-south-2a",
},
{
name: "IP belongs to eu-south-2b",
address: "192.168.3.10",
zoneSubnets: "eu-south-2a: 192.168.1.0/24, 192.168.2.0/24; eu-south-2b: 192.168.3.0/24",
expected: "eu-south-2b",
},
{
name: "IP not in any subnet",
address: "10.0.0.1",
zoneSubnets: "eu-south-2a: 192.168.1.0/24, 192.168.2.0/24; eu-south-2b: 192.168.3.0/24",
expected: "unknown",
},
{
name: "Malformed input - no subnet",
address: "192.168.2.1",
zoneSubnets: "eu-south-2a:;eu-south-2b:192.168.2.0/24",
expected: "unknown",
},
{
name: "Malformed input - no subnet",
address: "192.168.2.1",
zoneSubnets: "eu-south-2a;eu-south-2b:192.168.2.0/24",
expected: "unknown",
},
{
name: "IP belongs to overlapping subnets, first match",
address: "192.167.4.10",
zoneSubnets: "eu-south-2a:192.167.4.0/24;eu-south-2b:192.167.4.0/16",
expected: "eu-south-2a",
},
{
name: "Empty Data",
address: "192.167.4.10",
zoneSubnets: " ",
expected: "unknown",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := getZoneFromIP(tt.address, tt.zoneSubnets)
if result != tt.expected {
t.Errorf("expected %s, got %s", tt.expected, result)
}
})
}
}

0 comments on commit 66dc4c5

Please sign in to comment.