Skip to content

Commit

Permalink
Add tests, adjust enabled state
Browse files Browse the repository at this point in the history
  • Loading branch information
berkayoz committed Nov 11, 2024
1 parent 4bbb14c commit f85c210
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 15 deletions.
21 changes: 21 additions & 0 deletions src/k8s/pkg/k8sd/app/cluster_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
120 changes: 120 additions & 0 deletions src/k8s/pkg/k8sd/app/cluster_util_test.go
Original file line number Diff line number Diff line change
@@ -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"))
})
}
18 changes: 4 additions & 14 deletions src/k8s/pkg/k8sd/app/hooks_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"crypto/rsa"
"database/sql"
"fmt"
"net"
"time"

"github.com/canonical/k8s/pkg/k8sd/database"
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/k8s/pkg/k8sd/controllers/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
Expand Down

0 comments on commit f85c210

Please sign in to comment.