Skip to content

Commit

Permalink
Add unit tests for Calico network k8sd feature (#647)
Browse files Browse the repository at this point in the history
* Add unit tests for calico k8sd network feature

* Remove t.Helper from cilium tests
  • Loading branch information
HomayoonAlimohammadi authored Sep 4, 2024
1 parent 11d088a commit 1b51ba7
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 27 deletions.
8 changes: 4 additions & 4 deletions src/k8s/pkg/k8sd/features/calico/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

var (
// chartCalico represents manifests to deploy Calico.
chartCalico = helm.InstallableChart{
// ChartCalico represents manifests to deploy Calico.
ChartCalico = helm.InstallableChart{
Name: "ck-network",
Namespace: "tigera-operator",
ManifestPath: filepath.Join("charts", "tigera-operator-v3.28.0.tgz"),
Expand All @@ -21,8 +21,8 @@ var (

// calicoImageRepo represents the repo to fetch the calico images.
calicoImageRepo = "ghcr.io/canonical/k8s-snap/calico"
// calicoTag represents the tag to use for the calico images.
calicoTag = "v3.28.0"
// CalicoTag represents the tag to use for the calico images.
CalicoTag = "v3.28.0"

// tigeraOperatorImage represents the image to fetch for calico.
tigeraOperatorImage = "tigera/operator"
Expand Down
28 changes: 14 additions & 14 deletions src/k8s/pkg/k8sd/features/calico/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
)

const (
enabledMsg = "enabled"
disabledMsg = "disabled"
EnabledMsg = "enabled"
DisabledMsg = "disabled"
deployFailedMsgTmpl = "Failed to deploy Calico, the error was: %v"
deleteFailedMsgTmpl = "Failed to delete Calico, the error was: %v"
)
Expand All @@ -27,19 +27,19 @@ func ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network, annota
m := snap.HelmClient()

if !cfg.GetEnabled() {
if _, err := m.Apply(ctx, chartCalico, helm.StateDeleted, nil); err != nil {
if _, err := m.Apply(ctx, ChartCalico, helm.StateDeleted, nil); err != nil {
err = fmt.Errorf("failed to uninstall network: %w", err)
return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Version: CalicoTag,
Message: fmt.Sprintf(deleteFailedMsgTmpl, err),
}, err
}

return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Message: disabledMsg,
Version: CalicoTag,
Message: DisabledMsg,
}, nil
}

Expand All @@ -48,18 +48,18 @@ func ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network, annota
err = fmt.Errorf("failed to parse annotations: %w", err)
return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Version: CalicoTag,
Message: fmt.Sprintf(deployFailedMsgTmpl, err),
}, err
}

podIpPools := []map[string]any{}
ipv4PodCIDR, ipv6PodCIDR, err := utils.ParseCIDRs(cfg.GetPodCIDR())
if err != nil {
err = fmt.Errorf("invalid pod cidr: %v", err)
err = fmt.Errorf("invalid pod cidr: %w", err)
return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Version: CalicoTag,
Message: fmt.Sprintf(deployFailedMsgTmpl, err),
}, err
}
Expand All @@ -84,7 +84,7 @@ func ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network, annota
err = fmt.Errorf("invalid service cidr: %v", err)
return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Version: CalicoTag,
Message: fmt.Sprintf(deployFailedMsgTmpl, err),
}, err
}
Expand Down Expand Up @@ -127,18 +127,18 @@ func ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network, annota
"serviceCIDRs": serviceCIDRs,
}

if _, err := m.Apply(ctx, chartCalico, helm.StatePresent, values); err != nil {
if _, err := m.Apply(ctx, ChartCalico, helm.StatePresent, values); err != nil {
err = fmt.Errorf("failed to enable network: %w", err)
return types.FeatureStatus{
Enabled: false,
Version: calicoTag,
Version: CalicoTag,
Message: fmt.Sprintf(deployFailedMsgTmpl, err),
}, err
}

return types.FeatureStatus{
Enabled: true,
Version: calicoTag,
Message: enabledMsg,
Version: CalicoTag,
Message: EnabledMsg,
}, nil
}
222 changes: 222 additions & 0 deletions src/k8s/pkg/k8sd/features/calico/network_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package calico_test

import (
"context"
"errors"
"testing"

. "github.com/onsi/gomega"

"github.com/canonical/k8s/pkg/client/helm"
helmmock "github.com/canonical/k8s/pkg/client/helm/mock"
"github.com/canonical/k8s/pkg/k8sd/features/calico"
"github.com/canonical/k8s/pkg/k8sd/types"
snapmock "github.com/canonical/k8s/pkg/snap/mock"
"github.com/canonical/k8s/pkg/utils"
"k8s.io/utils/ptr"
)

// NOTE(hue): status.Message is not checked sometimes to avoid unnecessary complexity

var defaultAnnotations = types.Annotations{
"k8sd/v1alpha1/calico/apiserver-enabled": "true",
"k8sd/v1alpha1/calico/encapsulation-v4": "VXLAN",
"k8sd/v1alpha1/calico/encapsulation-v6": "VXLAN",
"k8sd/v1alpha1/calico/autodetection-v4/firstFound": "true",
"k8sd/v1alpha1/calico/autodetection-v6/firstFound": "true",
}

func TestDisabled(t *testing.T) {
t.Run("HelmApplyFails", func(t *testing.T) {
g := NewWithT(t)

applyErr := errors.New("failed to apply")
helmM := &helmmock.Mock{
ApplyErr: applyErr,
}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(false),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, nil)

g.Expect(err).To(MatchError(applyErr))
g.Expect(status.Enabled).To(BeFalse())
g.Expect(status.Message).To(ContainSubstring(applyErr.Error()))
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(1))

callArgs := helmM.ApplyCalledWith[0]
g.Expect(callArgs.Chart).To(Equal(calico.ChartCalico))
g.Expect(callArgs.State).To(Equal(helm.StateDeleted))
g.Expect(callArgs.Values).To(BeNil())
})
t.Run("Success", func(t *testing.T) {
g := NewWithT(t)

helmM := &helmmock.Mock{}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(false),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, nil)

g.Expect(err).ToNot(HaveOccurred())
g.Expect(status.Enabled).To(BeFalse())
g.Expect(status.Message).To(Equal(calico.DisabledMsg))
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(1))

callArgs := helmM.ApplyCalledWith[0]
g.Expect(callArgs.Chart).To(Equal(calico.ChartCalico))
g.Expect(callArgs.State).To(Equal(helm.StateDeleted))
g.Expect(callArgs.Values).To(BeNil())
})
}

func TestEnabled(t *testing.T) {
t.Run("InvalidPodCIDR", func(t *testing.T) {
g := NewWithT(t)

helmM := &helmmock.Mock{}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(true),
PodCIDR: ptr.To("invalid-cidr"),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, defaultAnnotations)

g.Expect(err).To(HaveOccurred())
g.Expect(status.Enabled).To(BeFalse())
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(0))
})
t.Run("InvalidServiceCIDR", func(t *testing.T) {
g := NewWithT(t)

helmM := &helmmock.Mock{}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(true),
PodCIDR: ptr.To("192.0.2.0/24,2001:db8::/32"),
ServiceCIDR: ptr.To("invalid-cidr"),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, defaultAnnotations)

g.Expect(err).To(HaveOccurred())
g.Expect(status.Enabled).To(BeFalse())
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(0))
})
t.Run("HelmApplyFails", func(t *testing.T) {
g := NewWithT(t)

applyErr := errors.New("failed to apply")
helmM := &helmmock.Mock{
ApplyErr: applyErr,
}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(true),
PodCIDR: ptr.To("192.0.2.0/24,2001:db8::/32"),
ServiceCIDR: ptr.To("192.0.2.0/24,2001:db8::/32"),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, defaultAnnotations)

g.Expect(err).To(MatchError(applyErr))
g.Expect(status.Enabled).To(BeFalse())
g.Expect(status.Message).To(ContainSubstring(applyErr.Error()))
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(1))

callArgs := helmM.ApplyCalledWith[0]
g.Expect(callArgs.Chart).To(Equal(calico.ChartCalico))
g.Expect(callArgs.State).To(Equal(helm.StatePresent))
validateValues(t, callArgs.Values, cfg)
})
t.Run("Success", func(t *testing.T) {
g := NewWithT(t)

helmM := &helmmock.Mock{}
snapM := &snapmock.Snap{
Mock: snapmock.Mock{
HelmClient: helmM,
},
}
cfg := types.Network{
Enabled: ptr.To(true),
PodCIDR: ptr.To("192.0.2.0/24,2001:db8::/32"),
ServiceCIDR: ptr.To("192.0.2.0/24,2001:db8::/32"),
}

status, err := calico.ApplyNetwork(context.Background(), snapM, cfg, defaultAnnotations)

g.Expect(err).ToNot(HaveOccurred())
g.Expect(status.Enabled).To(BeTrue())
g.Expect(status.Message).To(Equal(calico.EnabledMsg))
g.Expect(status.Version).To(Equal(calico.CalicoTag))
g.Expect(helmM.ApplyCalledWith).To(HaveLen(1))

callArgs := helmM.ApplyCalledWith[0]
g.Expect(callArgs.Chart).To(Equal(calico.ChartCalico))
g.Expect(callArgs.State).To(Equal(helm.StatePresent))
validateValues(t, callArgs.Values, cfg)
})
}

func validateValues(t *testing.T, values map[string]any, cfg types.Network) {
g := NewWithT(t)

podIPv4CIDR, podIPv6CIDR, err := utils.ParseCIDRs(cfg.GetPodCIDR())
g.Expect(err).ToNot(HaveOccurred())

svcIPv4CIDR, svcIPv6CIDR, err := utils.ParseCIDRs(cfg.GetServiceCIDR())
g.Expect(err).ToNot(HaveOccurred())

// calico network
calicoNetwork := values["installation"].(map[string]any)["calicoNetwork"].(map[string]any)
g.Expect(calicoNetwork["ipPools"].([]map[string]any)).To(ContainElements(map[string]any{
"name": "ipv4-ippool",
"cidr": podIPv4CIDR,
"encapsulation": "VXLAN",
}))
g.Expect(calicoNetwork["ipPools"].([]map[string]any)).To(ContainElements(map[string]any{
"name": "ipv6-ippool",
"cidr": podIPv6CIDR,
"encapsulation": "VXLAN",
}))
g.Expect(calicoNetwork["ipPools"].([]map[string]any)).To(HaveLen(2))
g.Expect(calicoNetwork["nodeAddressAutodetectionV4"].(map[string]any)["firstFound"]).To(Equal(true))
g.Expect(calicoNetwork["nodeAddressAutodetectionV6"].(map[string]any)["firstFound"]).To(Equal(true))

g.Expect(values["apiServer"].(map[string]any)["enabled"]).To(Equal(true))

// service CIDRs
g.Expect(values["serviceCIDRs"].([]string)).To(ContainElements(svcIPv4CIDR, svcIPv6CIDR))
g.Expect(values["serviceCIDRs"].([]string)).To(HaveLen(2))
}
16 changes: 8 additions & 8 deletions src/k8s/pkg/k8sd/features/calico/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ func init() {
// Tigera images
fmt.Sprintf("%s/%s:%s", imageRepo, tigeraOperatorImage, tigeraOperatorVersion),
// Calico images
fmt.Sprintf("%s/apiserver:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/cni:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/csi:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/apiserver:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/cni:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/csi:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/ctl:%s", calicoImageRepo, calicoCtlTag),
fmt.Sprintf("%s/kube-controllers:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/node:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/node-driver-registrar:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/pod2daemon-flexvol:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/typha:%s", calicoImageRepo, calicoTag),
fmt.Sprintf("%s/kube-controllers:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/node:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/node-driver-registrar:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/pod2daemon-flexvol:%s", calicoImageRepo, CalicoTag),
fmt.Sprintf("%s/typha:%s", calicoImageRepo, CalicoTag),
)
}
1 change: 0 additions & 1 deletion src/k8s/pkg/k8sd/features/cilium/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ func TestEnabled(t *testing.T) {
}

func validateValues(t *testing.T, values map[string]any, cfg types.Network, snap snap.Snap) {
t.Helper()
g := NewWithT(t)

ipv4CIDR, ipv6CIDR, err := utils.ParseCIDRs(cfg.GetPodCIDR())
Expand Down

0 comments on commit 1b51ba7

Please sign in to comment.