From f85c21079b02134d784b94d225b4308a8c3017bf Mon Sep 17 00:00:00 2001 From: Berkay Tekin Oz Date: Mon, 11 Nov 2024 16:43:49 +0000 Subject: [PATCH] Add tests, adjust enabled state --- src/k8s/pkg/k8sd/app/cluster_util.go | 21 ++++ src/k8s/pkg/k8sd/app/cluster_util_test.go | 120 ++++++++++++++++++++++ src/k8s/pkg/k8sd/app/hooks_start.go | 18 +--- src/k8s/pkg/k8sd/controllers/feature.go | 2 +- 4 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 src/k8s/pkg/k8sd/app/cluster_util_test.go diff --git a/src/k8s/pkg/k8sd/app/cluster_util.go b/src/k8s/pkg/k8sd/app/cluster_util.go index 9255be3e4..2126f9cfd 100644 --- a/src/k8s/pkg/k8sd/app/cluster_util.go +++ b/src/k8s/pkg/k8sd/app/cluster_util.go @@ -3,10 +3,12 @@ package app import ( "context" "fmt" + "net" "github.com/canonical/k8s/pkg/k8sd/setup" "github.com/canonical/k8s/pkg/snap" snaputil "github.com/canonical/k8s/pkg/snap/util" + mctypes "github.com/canonical/microcluster/v3/rest/types" ) func startControlPlaneServices(ctx context.Context, snap snap.Snap, datastore string) error { @@ -58,3 +60,22 @@ func waitApiServerReady(ctx context.Context, snap snap.Snap) error { return nil } + +func DetermineLocalhostAddress(clusterMembers []mctypes.ClusterMember) (string, error) { + // Check if any of the cluster members have an IPv6 address, if so return "::1" + // if one member has an IPv6 address, other members should also have IPv6 interfaces + for _, clusterMember := range clusterMembers { + memberAddress := clusterMember.Address.Addr().String() + nodeIP := net.ParseIP(memberAddress) + if nodeIP == nil { + return "", fmt.Errorf("failed to parse node IP address %q", memberAddress) + } + + if nodeIP.To4() == nil { + return "::1", nil + } + } + + // If no IPv6 addresses are found this means the cluster is IPv4 only + return "127.0.0.1", nil +} diff --git a/src/k8s/pkg/k8sd/app/cluster_util_test.go b/src/k8s/pkg/k8sd/app/cluster_util_test.go new file mode 100644 index 000000000..de0ce326a --- /dev/null +++ b/src/k8s/pkg/k8sd/app/cluster_util_test.go @@ -0,0 +1,120 @@ +package app_test + +import ( + "net/netip" + "testing" + + "github.com/canonical/k8s/pkg/k8sd/app" + mctypes "github.com/canonical/microcluster/v3/rest/types" + . "github.com/onsi/gomega" +) + +func TestDetermineLocalhostAddress(t *testing.T) { + t.Run("IPv4Only", func(t *testing.T) { + g := NewWithT(t) + + mockMembers := []mctypes.ClusterMember{ + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node1", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("10.1.0.1:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node2", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("10.1.0.2:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node3", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("10.1.0.3:1234"), + }, + }, + }, + } + + localhostAddress, err := app.DetermineLocalhostAddress(mockMembers) + + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(localhostAddress).To(Equal("127.0.0.1")) + }) + + t.Run("IPv6Only", func(t *testing.T) { + g := NewWithT(t) + + mockMembers := []mctypes.ClusterMember{ + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node1", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("[fda1:8e75:b6ef::]:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node2", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("[fd51:d664:aca3::]:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node3", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("[fda3:c11d:3cda::]:1234"), + }, + }, + }, + } + + localhostAddress, err := app.DetermineLocalhostAddress(mockMembers) + + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(localhostAddress).To(Equal("::1")) + }) + + t.Run("IPv4_IPv6_Mixed", func(t *testing.T) { + g := NewWithT(t) + + mockMembers := []mctypes.ClusterMember{ + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node1", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("10.1.0.1:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node2", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("[fd51:d664:aca3::]:1234"), + }, + }, + }, + { + ClusterMemberLocal: mctypes.ClusterMemberLocal{ + Name: "node3", + Address: mctypes.AddrPort{ + AddrPort: netip.MustParseAddrPort("10.1.0.3:1234"), + }, + }, + }, + } + + localhostAddress, err := app.DetermineLocalhostAddress(mockMembers) + + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(localhostAddress).To(Equal("::1")) + }) +} diff --git a/src/k8s/pkg/k8sd/app/hooks_start.go b/src/k8s/pkg/k8sd/app/hooks_start.go index cbf228ac0..1f5cecc3e 100644 --- a/src/k8s/pkg/k8sd/app/hooks_start.go +++ b/src/k8s/pkg/k8sd/app/hooks_start.go @@ -5,7 +5,6 @@ import ( "crypto/rsa" "database/sql" "fmt" - "net" "time" "github.com/canonical/k8s/pkg/k8sd/database" @@ -73,21 +72,12 @@ func (a *App) onStart(ctx context.Context, s state.State) error { return "", fmt.Errorf("failed to get cluster members: %w", err) } - // Check if any of the cluster members have an IPv6 address, if so return "::1" - // if one member has an IPv6 address, other members should also have IPv6 interfaces - for _, clusterMember := range clusterMembers { - nodeIP := net.ParseIP(clusterMember.Address.Addr().String()) - if nodeIP == nil { - return "", fmt.Errorf("failed to parse node IP address %q", s.Address().Hostname()) - } - - if nodeIP.To4() == nil { - return "::1", nil - } + localhostAddress, err := DetermineLocalhostAddress(clusterMembers) + if err != nil { + return "", fmt.Errorf("failed to determine localhost address: %w", err) } - // If no IPv6 addresses are found this means the cluster is IPv4 only - return "127.0.0.1", nil + return localhostAddress, nil }, func(ctx context.Context, dnsIP string) error { if err := s.Database().Transaction(ctx, func(ctx context.Context, tx *sql.Tx) error { diff --git a/src/k8s/pkg/k8sd/controllers/feature.go b/src/k8s/pkg/k8sd/controllers/feature.go index 4240b6a39..33589b88e 100644 --- a/src/k8s/pkg/k8sd/controllers/feature.go +++ b/src/k8s/pkg/k8sd/controllers/feature.go @@ -82,7 +82,7 @@ func (c *FeatureController) Run( go c.reconcileLoop(ctx, getClusterConfig, setFeatureStatus, features.Network, c.triggerNetworkCh, c.reconciledNetworkCh, func(cfg types.ClusterConfig) (types.FeatureStatus, error) { localhostAddress, err := getLocalhostAddress() if err != nil { - return types.FeatureStatus{Enabled: cfg.Network.GetEnabled(), Message: "failed to determine the localhost address"}, fmt.Errorf("failed to get localhost address: %w", err) + return types.FeatureStatus{Enabled: false, Message: "failed to determine the localhost address"}, fmt.Errorf("failed to get localhost address: %w", err) } return features.Implementation.ApplyNetwork(ctx, c.snap, localhostAddress, cfg.APIServer, cfg.Network, cfg.Annotations) })