diff --git a/Makefile b/Makefile index a6044e691..9260618d1 100644 --- a/Makefile +++ b/Makefile @@ -358,7 +358,7 @@ unitest_tests: -@rm -rf $(UNITEST_OUTPUT) -@mkdir -p $(UNITEST_OUTPUT) @echo "run unitest tests" - $(ROOT_DIR)/tools/golang/ginkgo.sh \ + sudo $(ROOT_DIR)/tools/golang/ginkgo.sh \ --cover --coverprofile=./coverage.out --covermode set \ --json-report unitestreport.json \ -randomize-suites -randomize-all --keep-going --timeout=1h -p --slow-spec-threshold=120s \ diff --git a/charts/crds/egressgateway.spidernet.io_egresstunnels.yaml b/charts/crds/egressgateway.spidernet.io_egresstunnels.yaml index 2b899530d..843669427 100644 --- a/charts/crds/egressgateway.spidernet.io_egresstunnels.yaml +++ b/charts/crds/egressgateway.spidernet.io_egresstunnels.yaml @@ -9,7 +9,7 @@ spec: group: egressgateway.spidernet.io names: categories: - - egressnode + - egresstunnel kind: EgressTunnel listKind: EgressTunnelList plural: egresstunnels diff --git a/pkg/agent/police.go b/pkg/agent/police.go index 6d29cfc56..024dd2ecf 100644 --- a/pkg/agent/police.go +++ b/pkg/agent/police.go @@ -487,16 +487,6 @@ func parseMark(mark string) (uint32, error) { return i32, nil } -func parseMarkToInt(mark string) (int, error) { - tmp := strings.ReplaceAll(mark, "0x", "") - i64, err := strconv.ParseInt(tmp, 16, 32) - if err != nil { - return 0, err - } - i32 := int(i64) - return i32, nil -} - func (r *policeReconciler) buildPolicyRule(policyName string, mark uint32, version uint8, isIgnoreInternalCIDR bool) *iptables.Rule { tmp := "v4-" ignoreInternalCIDRName := EgressClusterCIDRIPv4 diff --git a/pkg/agent/police_test.go b/pkg/agent/police_test.go deleted file mode 100644 index cf061bea2..000000000 --- a/pkg/agent/police_test.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2022 Authors of spidernet-io -// SPDX-License-Identifier: Apache-2.0 - -package agent diff --git a/pkg/agent/vxlan.go b/pkg/agent/vxlan.go index 0dbbe53f3..b23f7caab 100644 --- a/pkg/agent/vxlan.go +++ b/pkg/agent/vxlan.go @@ -6,6 +6,7 @@ package agent import ( "context" "fmt" + "strconv" "net" "strings" @@ -185,7 +186,7 @@ func (r *vxlanReconciler) updateEgressNodeStatus(node *egressv1.EgressTunnel, ve ctx := context.Background() err = r.client.Get(ctx, types.NamespacedName{Name: r.cfg.NodeName}, node) if err != nil { - if !errors.IsNotFound(err) { + if errors.IsNotFound(err) { return nil } return err @@ -283,11 +284,7 @@ func (r *vxlanReconciler) parseVTEP(status egressv1.EgressNodeStatus) *vxlan.Pee if !ready { return nil } - return &vxlan.Peer{ - IPv4: ipv4, - IPv6: ipv6, - MAC: mac, - } + return &vxlan.Peer{IPv4: ipv4, IPv6: ipv6, MAC: mac} } func (r *vxlanReconciler) version() int { @@ -423,6 +420,16 @@ func (r *vxlanReconciler) ensureRoute() error { return nil } +func parseMarkToInt(mark string) (int, error) { + tmp := strings.ReplaceAll(mark, "0x", "") + i64, err := strconv.ParseInt(tmp, 16, 32) + if err != nil { + return 0, err + } + i32 := int(i64) + return i32, nil +} + func newEgressNodeController(mgr manager.Manager, cfg *config.Config, log logr.Logger) error { ruleRoute := route.NewRuleRoute(log) diff --git a/pkg/agent/vxlan/vxlan_test.go b/pkg/agent/vxlan/vxlan_test.go index 9dc6541f9..f0db2122a 100644 --- a/pkg/agent/vxlan/vxlan_test.go +++ b/pkg/agent/vxlan/vxlan_test.go @@ -89,3 +89,33 @@ func TestDiffLink(t *testing.T) { }) } } + +func TestVxlan(t *testing.T) { + device := New() + mac, err := net.ParseMAC("66:bf:c7:47:5c:14") + if err != nil { + t.Fatal(err) + } + + ipv6, ipv6Net, err := net.ParseCIDR("fd01::1/120") + if err != nil { + t.Fatal(err) + } + + ipv4Net := &net.IPNet{ + IP: []byte{10, 6, 1, 21}, + Mask: []byte{255, 255, 255, 0}, + } + + ipv6Net = &net.IPNet{ + IP: ipv6, + Mask: ipv6Net.Mask, + } + + err = device.EnsureLink("egress", + 101, 3456, mac, 0, + ipv4Net, nil, true) + if err != nil { + t.Fatal(err) + } +} diff --git a/pkg/agent/vxlan_test.go b/pkg/agent/vxlan_test.go deleted file mode 100644 index f2070aa2f..000000000 --- a/pkg/agent/vxlan_test.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2022 Authors of spidernet-io -// SPDX-License-Identifier: Apache-2.0 - -package agent - -import ( - "context" - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/vishvananda/netlink" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/spidernet-io/egressgateway/pkg/agent/route" - "github.com/spidernet-io/egressgateway/pkg/agent/vxlan" - "github.com/spidernet-io/egressgateway/pkg/config" - egressv1 "github.com/spidernet-io/egressgateway/pkg/k8s/apis/v1beta1" - "github.com/spidernet-io/egressgateway/pkg/logger" - "github.com/spidernet-io/egressgateway/pkg/schema" - "github.com/spidernet-io/egressgateway/pkg/utils" -) - -type TestCaseVXLAN struct { - initialObjects []client.Object - reqs []TestReqVXLAN - config *config.Config -} - -type TestReqVXLAN struct { - nn types.NamespacedName - expErr bool - expRequeue bool -} - -func TestReconcilerEgressNode(t *testing.T) { - cases := map[string]TestCaseVXLAN{ - //"caseAddEgressNode": caseAddEgressNode(), - } - - getParent := vxlan.GetParentByDefaultRoute(vxlan.NetLink{ - RouteListFiltered: netlink.RouteListFiltered, - LinkByIndex: netlink.LinkByIndex, - AddrList: netlink.AddrList, - LinkByName: netlink.LinkByName, - }) - - for name, c := range cases { - log := logger.NewLogger(logger.Config{Level: 1}) - - t.Run(name, func(t *testing.T) { - builder := fake.NewClientBuilder() - builder.WithScheme(schema.GetScheme()) - builder.WithObjects(c.initialObjects...) - ctx := context.Background() - ruleRoute := route.NewRuleRoute(log) - reconciler := vxlanReconciler{ - client: builder.Build(), - log: log, - cfg: c.config, - getParent: getParent, - ruleRoute: ruleRoute, - ruleRouteCache: utils.NewSyncMap[string, []net.IP](), - } - - for _, req := range c.reqs { - res, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: req.nn}) - if !req.expErr { - assert.NoError(t, err) - } - assert.Equal(t, req.expRequeue, res.Requeue) - } - }) - } -} - -func caseAddEgressNode() TestCaseVXLAN { - - _, ipn, err := net.ParseCIDR("192.168.100.1/24") - if err != nil { - panic(err) - } - - cfg := &config.Config{ - EnvConfig: config.EnvConfig{ - NodeName: "workstation1", - }, - FileConfig: config.FileConfig{ - EnableIPv4: true, - EnableIPv6: false, - - TunnelIPv4Net: ipn, - TunnelIPv6Net: nil, - }, - } - - return TestCaseVXLAN{ - initialObjects: []client.Object{ - &egressv1.EgressTunnel{ - ObjectMeta: metav1.ObjectMeta{Name: "workstation1"}, - Spec: egressv1.EgressNodeSpec{}, - Status: egressv1.EgressNodeStatus{}, - }, - }, - reqs: []TestReqVXLAN{ - { - nn: types.NamespacedName{ - Namespace: "EgressTunnel/", - Name: "workstation1", - }, - expErr: false, - expRequeue: false, - }, - }, - config: cfg, - } -} diff --git a/pkg/controller/egress_cluster_info.go b/pkg/controller/egress_cluster_info.go index f1c9dc6d1..0dd311fda 100644 --- a/pkg/controller/egress_cluster_info.go +++ b/pkg/controller/egress_cluster_info.go @@ -6,6 +6,7 @@ package controller import ( "context" "fmt" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" "strings" "sync" @@ -144,11 +145,11 @@ func (r *eciReconciler) reconcileCalicoIPPool(ctx context.Context, req reconcile log.Info("update event") // check if cidr about ippools changed - isv4Cidr, err := utils.IsIPv4Cidr(ippool.Spec.CIDR) + isv4Cidr, err := ip.IsIPv4Cidr(ippool.Spec.CIDR) if err != nil { return reconcile.Result{Requeue: true}, err } - isv6Cidr, err := utils.IsIPv6Cidr(ippool.Spec.CIDR) + isv6Cidr, err := ip.IsIPv6Cidr(ippool.Spec.CIDR) if err != nil { return reconcile.Result{Requeue: true}, err } @@ -547,11 +548,11 @@ func getCidr(pod *corev1.Pod, param string) (ipv4Range, ipv6Range []string, err // get cidr ipRanges := strings.Split(ipRange, ",") if len(ipRanges) == 1 { - if isV4, _ := utils.IsIPv4Cidr(ipRanges[0]); isV4 { + if isV4, _ := ip.IsIPv4Cidr(ipRanges[0]); isV4 { ipv4Range = ipRanges ipv6Range = []string{} } - if isV6, _ := utils.IsIPv6Cidr(ipRanges[0]); isV6 { + if isV6, _ := ip.IsIPv6Cidr(ipRanges[0]); isV6 { ipv6Range = ipRanges ipv4Range = []string{} diff --git a/pkg/controller/webhook/validate.go b/pkg/controller/webhook/validate.go index c0327bc9b..40759674d 100644 --- a/pkg/controller/webhook/validate.go +++ b/pkg/controller/webhook/validate.go @@ -105,7 +105,7 @@ func ValidateHook(client client.Client, cfg *config.Config) *webhook.Admission { } if req.Operation == v1.Create { - if cfg.FileConfig.EnableIPv4 && cfg.FileConfig.EnableIPv6 { + if cfg.FileConfig.EnableIPv4 || cfg.FileConfig.EnableIPv6 { if ok, err := checkEIP(client, ctx, *egp); !ok { return webhook.Denied(err.Error()) } @@ -161,7 +161,7 @@ func checkEIP(client client.Client, ctx context.Context, egp egressv1.EgressPoli return true, nil } -// ValidateHook ValidateHook +// MutateHook MutateHook func MutateHook(client client.Client, cfg *config.Config) *webhook.Admission { return &webhook.Admission{ Handler: admission.HandlerFunc(func(ctx context.Context, req webhook.AdmissionRequest) webhook.AdmissionResponse { diff --git a/pkg/controller/webhook/validate_test.go b/pkg/controller/webhook/validate_test.go index ce2a0db24..ab9f87973 100644 --- a/pkg/controller/webhook/validate_test.go +++ b/pkg/controller/webhook/validate_test.go @@ -81,43 +81,105 @@ func TestValidateEgressGateway(t *testing.T) { } } -func TestValidateEgressGatewayPolicy(t *testing.T) { +func TestValidateEgressPolicy(t *testing.T) { ctx := context.Background() cases := map[string]struct { existingResources []runtime.Object - destSubnet []string + spec v1beta1.EgressPolicySpec expAllow bool expErrMessage string }{ "case, valid": { existingResources: nil, - destSubnet: []string{ - "192.168.1.1/24", - "1.1.1.1/32", - "10.0.6.1/16", - "fd00::21/112", + spec: v1beta1.EgressPolicySpec{ + EgressGatewayName: "test", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: false, + IPv4: "", + IPv6: "", + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, + DestSubnet: []string{ + "192.168.1.1/24", + "1.1.1.1/32", + "10.0.6.1/16", + "fd00::21/112", + }, }, expAllow: true, }, "case1, not valid": { existingResources: nil, - destSubnet: []string{ - "1.1.1.1", + spec: v1beta1.EgressPolicySpec{ + EgressGatewayName: "test", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: false, + IPv4: "", + IPv6: "", + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, + DestSubnet: []string{ + "1.1.1.1", + }, }, expAllow: false, }, "case2, not valid": { existingResources: nil, - destSubnet: []string{ - "1.1.1.1999/24", + spec: v1beta1.EgressPolicySpec{ + EgressGatewayName: "test", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: false, + IPv4: "", + IPv6: "", + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, + DestSubnet: []string{ + "1.1.1.1999/24", + }, }, expAllow: false, }, "case3, not valid": { existingResources: nil, - destSubnet: []string{ - "---", + spec: v1beta1.EgressPolicySpec{ + EgressGatewayName: "test", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: false, + IPv4: "", + IPv6: "", + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, + DestSubnet: []string{ + "---", + }, + }, + expAllow: false, + }, + "case3, empty EgressGatewayName": { + existingResources: nil, + spec: v1beta1.EgressPolicySpec{ + EgressGatewayName: "", + EgressIP: v1beta1.EgressIP{}, + AppliedTo: v1beta1.AppliedTo{}, + DestSubnet: []string{}, }, expAllow: false, }, @@ -129,20 +191,7 @@ func TestValidateEgressGatewayPolicy(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "policy", }, - Spec: v1beta1.EgressPolicySpec{ - EgressGatewayName: "test", - EgressIP: v1beta1.EgressIP{ - UseNodeIP: false, - IPv4: "", - IPv6: "", - }, - AppliedTo: v1beta1.AppliedTo{ - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test"}, - }, - }, - DestSubnet: c.destSubnet, - }, + Spec: c.spec, } marshalledRequestObject, err := json.Marshal(policy) @@ -180,6 +229,162 @@ func TestValidateEgressGatewayPolicy(t *testing.T) { } } +func TestUpdateEgressPolicy(t *testing.T) { + ctx := context.Background() + + cases := map[string]struct { + existingResources []runtime.Object + old v1beta1.EgressPolicySpec + new v1beta1.EgressPolicySpec + expAllow bool + expErrMessage string + }{ + "test change ipv4": { + existingResources: nil, + old: v1beta1.EgressPolicySpec{ + EgressGatewayName: "a", + EgressIP: v1beta1.EgressIP{ + IPv4: "10.6.1.21", + IPv6: "", + UseNodeIP: false, + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + Priority: 0, + }, + new: v1beta1.EgressPolicySpec{ + EgressGatewayName: "a", + EgressIP: v1beta1.EgressIP{ + IPv4: "10.6.1.22", + IPv6: "", + UseNodeIP: false, + AllocatorPolicy: "", + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + Priority: 0, + }, + expAllow: false, + expErrMessage: "", + }, + "change useNodeIP": { + existingResources: nil, + old: v1beta1.EgressPolicySpec{ + EgressGatewayName: "a", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: true, + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + }, + new: v1beta1.EgressPolicySpec{ + EgressGatewayName: "a", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: false, + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + }, + expAllow: false, + expErrMessage: "", + }, + "change egress gateway name": { + existingResources: nil, + old: v1beta1.EgressPolicySpec{ + EgressGatewayName: "a", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: true, + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + }, + new: v1beta1.EgressPolicySpec{ + EgressGatewayName: "b", + EgressIP: v1beta1.EgressIP{ + UseNodeIP: true, + }, + AppliedTo: v1beta1.AppliedTo{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + }, DestSubnet: nil, + }, + expAllow: false, + expErrMessage: "", + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + oldPolicy := &v1beta1.EgressPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "policy", + }, + Spec: c.old, + } + + newPolicy := &v1beta1.EgressPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "policy", + }, + Spec: c.new, + } + + oldObj, err := json.Marshal(oldPolicy) + assert.NoError(t, err) + + newObj, err := json.Marshal(newPolicy) + assert.NoError(t, err) + + builder := fake.NewClientBuilder() + builder.WithScheme(schema.GetScheme()) + cli := builder.Build() + conf := &config.Config{ + FileConfig: config.FileConfig{ + EnableIPv4: true, + EnableIPv6: true, + }, + } + + validator := ValidateHook(cli, conf) + resp := validator.Handle(ctx, admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Name: oldPolicy.Name, + Kind: metav1.GroupVersionKind{ + Kind: "EgressPolicy", + }, + Operation: admissionv1.Update, + OldObject: runtime.RawExtension{ + Raw: oldObj, + }, + Object: runtime.RawExtension{ + Raw: newObj, + }, + }, + }) + + assert.Equal(t, c.expAllow, resp.Allowed) + if c.expErrMessage != "" { + assert.Equal(t, c.expErrMessage, resp.AdmissionResponse.Result.Message) + } + }) + } +} + func TestValidateEgressNode(t *testing.T) { ctx := context.Background() diff --git a/pkg/egressgateway/egress_gateway.go b/pkg/egressgateway/egress_gateway.go index e4b5a4080..f493b8e2b 100644 --- a/pkg/egressgateway/egress_gateway.go +++ b/pkg/egressgateway/egress_gateway.go @@ -6,6 +6,7 @@ package egressgateway import ( "context" "fmt" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" "math/rand" "net" "time" @@ -657,10 +658,10 @@ func (r egnReconciler) allocatorEIP(selEipLolicy string, nodeName string, pi pol var useIpv4s []net.IP var useIpv4sByNode []net.IP - ipv4Ranges, _ := utils.MergeIPRanges(constant.IPv4, eg.Spec.Ippools.IPv4) + ipv4Ranges, _ := ip.MergeIPRanges(constant.IPv4, eg.Spec.Ippools.IPv4) perIpv4 = pi.ipv4 if len(perIpv4) != 0 { - result, err := utils.IsIPIncludedRange(constant.IPv4, perIpv4, ipv4Ranges) + result, err := ip.IsIPIncludedRange(constant.IPv4, perIpv4, ipv4Ranges) if err != nil { return "", "", err } @@ -676,8 +677,8 @@ func (r egnReconciler) allocatorEIP(selEipLolicy string, nodeName string, pi pol } } - ipv4s, _ := utils.ParseIPRanges(constant.IPv4, ipv4Ranges) - freeIpv4s := utils.IPsDiffSet(ipv4s, useIpv4s, false) + ipv4s, _ := ip.ParseIPRanges(constant.IPv4, ipv4Ranges) + freeIpv4s := ip.IPsDiffSet(ipv4s, useIpv4s, false) if len(freeIpv4s) == 0 { for _, node := range eg.Status.NodeList { @@ -709,11 +710,11 @@ func (r egnReconciler) allocatorEIP(selEipLolicy string, nodeName string, pi pol var useIpv6s []net.IP var useIpv6sByNode []net.IP - ipv6Ranges, _ := utils.MergeIPRanges(constant.IPv6, eg.Spec.Ippools.IPv6) + ipv6Ranges, _ := ip.MergeIPRanges(constant.IPv6, eg.Spec.Ippools.IPv6) perIpv6 = pi.ipv6 if len(perIpv6) != 0 { - result, err := utils.IsIPIncludedRange(constant.IPv6, perIpv6, ipv6Ranges) + result, err := ip.IsIPIncludedRange(constant.IPv6, perIpv6, ipv6Ranges) if err != nil { return "", "", err } @@ -729,8 +730,8 @@ func (r egnReconciler) allocatorEIP(selEipLolicy string, nodeName string, pi pol } } - ipv6s, _ := utils.ParseIPRanges(constant.IPv6, ipv6Ranges) - freeIpv6s := utils.IPsDiffSet(ipv6s, useIpv6s, false) + ipv6s, _ := ip.ParseIPRanges(constant.IPv6, ipv6Ranges) + freeIpv6s := ip.IPsDiffSet(ipv6s, useIpv6s, false) if len(freeIpv6s) == 0 { for _, node := range eg.Status.NodeList { diff --git a/pkg/egressgateway/egress_gateway_webhook.go b/pkg/egressgateway/egress_gateway_webhook.go index 3f08eda54..c25cb2493 100644 --- a/pkg/egressgateway/egress_gateway_webhook.go +++ b/pkg/egressgateway/egress_gateway_webhook.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" "math/rand" "net" "time" @@ -21,7 +22,6 @@ import ( "github.com/spidernet-io/egressgateway/pkg/config" "github.com/spidernet-io/egressgateway/pkg/constant" egress "github.com/spidernet-io/egressgateway/pkg/k8s/apis/v1beta1" - "github.com/spidernet-io/egressgateway/pkg/utils" ) type EgressGatewayWebhook struct { @@ -62,18 +62,18 @@ func (egw *EgressGatewayWebhook) EgressGatewayValidate(ctx context.Context, req // Checking the number of IPV4 and IPV6 addresses var ipv4s, ipv6s []net.IP - ipv4Ranges, err := utils.MergeIPRanges(constant.IPv4, newEg.Spec.Ippools.IPv4) + ipv4Ranges, err := ip.MergeIPRanges(constant.IPv4, newEg.Spec.Ippools.IPv4) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check IP: %v", err)) } - ipv6Ranges, _ := utils.MergeIPRanges(constant.IPv6, newEg.Spec.Ippools.IPv6) + ipv6Ranges, _ := ip.MergeIPRanges(constant.IPv6, newEg.Spec.Ippools.IPv6) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check IP: %v", err)) } if egw.Config.FileConfig.EnableIPv4 { - ipv4s, err = utils.ParseIPRanges(constant.IPv4, ipv4Ranges) + ipv4s, err = ip.ParseIPRanges(constant.IPv4, ipv4Ranges) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check IP: %v", err)) } @@ -84,7 +84,7 @@ func (egw *EgressGatewayWebhook) EgressGatewayValidate(ctx context.Context, req } if egw.Config.FileConfig.EnableIPv6 { - ipv6s, err = utils.ParseIPRanges(constant.IPv6, ipv6Ranges) + ipv6s, err = ip.ParseIPRanges(constant.IPv6, ipv6Ranges) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check IP: %v", err)) } @@ -111,7 +111,7 @@ func (egw *EgressGatewayWebhook) EgressGatewayValidate(ctx context.Context, req // Check whether the IP address to be deleted has been allocated for _, item := range eg.Status.NodeList { for _, eip := range item.Eips { - result, err := utils.IsIPIncludedRange(constant.IPv4, eip.IPv4, ipv4Ranges) + result, err := ip.IsIPIncludedRange(constant.IPv4, eip.IPv4, ipv4Ranges) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check IP: %v", err)) } @@ -124,7 +124,7 @@ func (egw *EgressGatewayWebhook) EgressGatewayValidate(ctx context.Context, req // Check the defaultEIP if len(newEg.Spec.Ippools.Ipv4DefaultEIP) != 0 { - result, err := utils.IsIPIncludedRange(constant.IPv4, newEg.Spec.Ippools.Ipv4DefaultEIP, ipv4Ranges) + result, err := ip.IsIPIncludedRange(constant.IPv4, newEg.Spec.Ippools.Ipv4DefaultEIP, ipv4Ranges) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check Ipv4DefaultEIP: %v", err)) } @@ -134,7 +134,7 @@ func (egw *EgressGatewayWebhook) EgressGatewayValidate(ctx context.Context, req } if len(newEg.Spec.Ippools.Ipv6DefaultEIP) != 0 { - result, err := utils.IsIPIncludedRange(constant.IPv6, newEg.Spec.Ippools.Ipv6DefaultEIP, ipv6Ranges) + result, err := ip.IsIPIncludedRange(constant.IPv6, newEg.Spec.Ippools.Ipv6DefaultEIP, ipv6Ranges) if err != nil { return webhook.Denied(fmt.Sprintf("Failed to check Ipv6DefaultEIP: %v", err)) } @@ -160,12 +160,12 @@ func (egw *EgressGatewayWebhook) EgressGatewayMutate(ctx context.Context, req we if egw.Config.FileConfig.EnableIPv4 { if len(eg.Spec.Ippools.Ipv4DefaultEIP) == 0 && len(eg.Spec.Ippools.IPv4) != 0 { - ipv4Ranges, err := utils.MergeIPRanges(constant.IPv4, eg.Spec.Ippools.IPv4) + ipv4Ranges, err := ip.MergeIPRanges(constant.IPv4, eg.Spec.Ippools.IPv4) if err != nil { return webhook.Denied(fmt.Sprintf("ippools.ipv4 format error: %v", err)) } - ipv4s, _ := utils.ParseIPRanges(constant.IPv4, ipv4Ranges) + ipv4s, _ := ip.ParseIPRanges(constant.IPv4, ipv4Ranges) if len(ipv4s) != 0 { patch = append(patch, patchOperation{ Op: "add", @@ -181,12 +181,12 @@ func (egw *EgressGatewayWebhook) EgressGatewayMutate(ctx context.Context, req we if egw.Config.FileConfig.EnableIPv6 { if len(eg.Spec.Ippools.Ipv6DefaultEIP) == 0 && len(eg.Spec.Ippools.IPv6) != 0 { - ipv6Ranges, err := utils.MergeIPRanges(constant.IPv6, eg.Spec.Ippools.IPv6) + ipv6Ranges, err := ip.MergeIPRanges(constant.IPv6, eg.Spec.Ippools.IPv6) if err != nil { return webhook.Denied(fmt.Sprintf("ippools.ipv6 format error: %v", err)) } - ipv6s, _ := utils.ParseIPRanges(constant.IPv6, ipv6Ranges) + ipv6s, _ := ip.ParseIPRanges(constant.IPv6, ipv6Ranges) if len(ipv6s) != 0 { patch = append(patch, patchOperation{ Op: "add", diff --git a/pkg/k8s/apis/v1beta1/egressnode_types.go b/pkg/k8s/apis/v1beta1/egressnode_types.go index 56640a830..25bdb680a 100644 --- a/pkg/k8s/apis/v1beta1/egressnode_types.go +++ b/pkg/k8s/apis/v1beta1/egressnode_types.go @@ -17,7 +17,7 @@ type EgressTunnelList struct { } // EgressTunnel represents an egress tunnel -// +kubebuilder:resource:categories={egressnode},path="egresstunnels",singular="egresstunnel",scope="Cluster",shortName={egt} +// +kubebuilder:resource:categories={egresstunnel},path="egresstunnels",singular="egresstunnel",scope="Cluster",shortName={egt} // +kubebuilder:printcolumn:JSONPath=".status.tunnel.mac",description="tunnelMac",name="tunnelMac",type=string // +kubebuilder:printcolumn:JSONPath=".status.tunnel.ipv4",description="tunnelIPv4",name="tunnelIPv4",type=string // +kubebuilder:printcolumn:JSONPath=".status.tunnel.ipv6",description="tunnelIPv6",name="tunnelIPv6",type=string diff --git a/pkg/utils/errors.go b/pkg/utils/ip/errors.go similarity index 59% rename from pkg/utils/errors.go rename to pkg/utils/ip/errors.go index 27321da15..27d6570d9 100644 --- a/pkg/utils/errors.go +++ b/pkg/utils/ip/errors.go @@ -1,15 +1,12 @@ // Copyright 2022 Authors of spidernet-io // SPDX-License-Identifier: Apache-2.0 -package utils +package ip import "errors" var ( ErrInvalidIPVersion = errors.New("invalid IP version") ErrInvalidIPRangeFormat = errors.New("invalid IP range format") - ErrInvalidIPFormat = errors.New("invalid IP format") - ErrInvalidCIDRFormat = errors.New("invalid CIDR format") - ErrInvalidRouteFormat = errors.New("invalid route format") ErrInvalidIP = errors.New("invalid IP") ) diff --git a/pkg/utils/ip.go b/pkg/utils/ip/ip.go similarity index 91% rename from pkg/utils/ip.go rename to pkg/utils/ip/ip.go index ae9fae7ca..2bbca0de6 100644 --- a/pkg/utils/ip.go +++ b/pkg/utils/ip/ip.go @@ -1,7 +1,7 @@ // Copyright 2022 Authors of spidernet-io // SPDX-License-Identifier: Apache-2.0 -package utils +package ip import ( "bytes" @@ -58,8 +58,7 @@ func IsIPVersion(version constant.IPVersion) error { func GetIPV4V6(ips []string) (IPV4s, IPV6s []string, err error) { for _, ip := range ips { if net.ParseIP(ip) == nil { - err = fmt.Errorf(constant.InvalidIPFormat) - return nil, nil, err + return nil, nil, ErrInvalidIP } if isIPv4, _ := IsIPv4(ip); isIPv4 { IPV4s = append(IPV4s, ip) @@ -73,21 +72,23 @@ func GetIPV4V6(ips []string) (IPV4s, IPV6s []string, err error) { func GetIPV4V6Cidr(ipCidrs []string) (IPV4Cidrs, IPV6Cidrs []string, err error) { for _, ipCidr := range ipCidrs { - isIPv4Cidr, err := IsIPv4Cidr(ipCidr) - if err != nil { - return nil, nil, err - } - if isIPv4Cidr { - IPV4Cidrs = append(IPV4Cidrs, ipCidr) - continue - } - - isIPv6Cidr, err := IsIPv6Cidr(ipCidr) - if err != nil { - return nil, nil, err - } - if isIPv6Cidr { - IPV6Cidrs = append(IPV6Cidrs, ipCidr) + if strings.Contains(ipCidr, ".") { + isIPv4Cidr, err := IsIPv4Cidr(ipCidr) + if err != nil { + return nil, nil, err + } + if isIPv4Cidr { + IPV4Cidrs = append(IPV4Cidrs, ipCidr) + continue + } + } else { + isIPv6Cidr, err := IsIPv6Cidr(ipCidr) + if err != nil { + return nil, nil, err + } + if isIPv6Cidr { + IPV6Cidrs = append(IPV6Cidrs, ipCidr) + } } } return @@ -105,6 +106,9 @@ func IsSameIPs(a, b []string) (bool, error) { if err != nil { return false, err } + if len(sortedA) != len(sortedB) { + return false, nil + } for i := range sortedA { if sortedA[i] != sortedB[i] { @@ -189,25 +193,27 @@ func SortIPCidrs(ips []string) ([]string, error) { } func IsIPv4Cidr(cidr string) (bool, error) { - netIP, _, err := net.ParseCIDR(cidr) + _, ipnet, err := net.ParseCIDR(cidr) if err != nil { return false, err } - if netIP.To4() != nil { - return true, nil + verified := ipnet.IP.To4() != nil && ipnet.Mask != nil && len(ipnet.Mask) == net.IPv4len + if !verified { + return false, fmt.Errorf("%s is invalid IPv4 CIDR", cidr) } - return false, nil + return true, nil } func IsIPv6Cidr(cidr string) (bool, error) { - netIP, _, err := net.ParseCIDR(cidr) + _, ipnet, err := net.ParseCIDR(cidr) if err != nil { return false, err } - if netIP.To4() == nil { - return true, nil + verified := ipnet.IP.To16() != nil && ipnet.Mask != nil && len(ipnet.Mask) == net.IPv6len + if !verified { + return false, fmt.Errorf("%s is invalid IPv6 CIDR", cidr) } - return false, nil + return true, nil } // IPsDiffSet calculates the difference set of two IP address slices. diff --git a/pkg/utils/ip/ip_test.go b/pkg/utils/ip/ip_test.go new file mode 100644 index 000000000..cbdaf0e47 --- /dev/null +++ b/pkg/utils/ip/ip_test.go @@ -0,0 +1,694 @@ +// Copyright 2022 Authors of spidernet-io +// SPDX-License-Identifier: Apache-2.0 + +package ip_test + +import ( + "github.com/spidernet-io/egressgateway/pkg/constant" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" + "net" + "reflect" + "testing" +) + +func TestCmp(t *testing.T) { + ip1 := net.ParseIP("2001:db8::1") + ip2 := net.ParseIP("2001:db8::2") + ip3 := net.ParseIP("2001:db8::1") + + if ip.Cmp(ip1, ip2) != -1 { + t.Errorf("Cmp(%v, %v) = %d; want -1", ip1, ip2, ip.Cmp(ip1, ip2)) + } + + if ip.Cmp(ip1, ip3) != 0 { + t.Errorf("Cmp(%v, %v) = %d; want 0", ip1, ip3, ip.Cmp(ip1, ip3)) + } + + if ip.Cmp(ip2, ip1) != 1 { + t.Errorf("Cmp(%v, %v) = %d; want 1", ip2, ip1, ip.Cmp(ip2, ip1)) + } +} + +func TestIsIPv6IPRange(t *testing.T) { + tests := []struct { + name string + args string + want bool + }{ + { + name: "empty", + args: "", + want: false, + }, + { + name: "ipv4", + args: "10.6.1.21-10.6.1.22", + want: false, + }, + { + name: "ipv6", + args: "fd00::01-fd00::06", + want: true, + }, + { + name: "ipv6", + args: "fd00::01-fd00::02-fd00::03", + want: false, + }, + { + name: "ipv6", + args: "fd00::01-fd::00", + want: false, + }, + { + name: "ipv6", + args: "fd00::02-fd00::01", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ip.IsIPv6IPRange(tt.args); got != tt.want { + t.Errorf("IsIPv6IPRange() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsIPv4IPRange(t *testing.T) { + tests := []struct { + name string + args string + want bool + }{ + { + name: "empty", + args: "", + want: false, + }, + { + name: "ipv4", + args: "10.6.1.21-10.6.1.22", + want: true, + }, + { + name: "ipv6", + args: "fd00::01-fd00::06", + want: false, + }, + { + name: "ipv6", + args: "10.6.1.22-10.6.1.21", + want: false, + }, + { + name: "ipv6", + args: "10.6.1.21-10.6.1.22-10.6.1.23", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ip.IsIPv4IPRange(tt.args); got != tt.want { + t.Errorf("IsIPv4IPRange() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsIPv4Cidr(t *testing.T) { + tests := []struct { + name string + args string + want bool + wantErr bool + }{ + { + name: "valid IPv4 CIDR", + args: "192.168.0.0/16", + want: true, + wantErr: false, + }, + { + name: "invalid IPv4 CIDR", + args: "192.168.0.0/33", + want: false, + wantErr: true, + }, + { + name: "IPv6 CIDR", + args: "2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", + want: false, + wantErr: true, + }, + { + name: "invalid input format", + args: "92.168.0.0/16/24", + want: false, + wantErr: true, + }, + { + name: "invalid IP address", + args: "256.256.256.256/16", + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsIPv4Cidr(tt.args) + if (err != nil) != tt.wantErr { + t.Errorf("IsIPv4Cidr() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsIPv4Cidr() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsIPv6Cidr(t *testing.T) { + tests := []struct { + name string + args string + want bool + wantErr bool + }{ + { + name: "valid IPv6 CIDR", + args: "2001:0db8:84a3:0000:0000:8a2e:0370:7234/64", + want: true, + wantErr: false, + }, + { + name: "invalid IPv6 CIDR", + args: "2001:0db8:85a3:0000:0000:8a2e:0370:7334/129", + want: false, + wantErr: true, + }, + { + name: "not cidr", + args: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + want: false, + wantErr: true, + }, + { + name: "IPv4 cidr", + args: "192.168.0.0/16", + want: false, + wantErr: true, + }, + { + name: "invalid CIDR", + args: "2001:0db8:85a3:0000:0000:8a2e:0370:7334/abc", + want: false, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsIPv6Cidr(tt.args) + if (err != nil) != tt.wantErr { + t.Errorf("IsIPv6Cidr() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsIPv6Cidr() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsSameIPs(t *testing.T) { + type args struct { + a []string + b []string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "empty", + args: args{ + a: nil, + b: nil, + }, + want: true, + wantErr: false, + }, + { + name: "different lengths", + args: args{ + a: []string{"192.0.2.1", "192.0.2.2"}, + b: []string{"192.0.2.1"}, + }, + want: false, + wantErr: false, + }, + { + name: "same IP", + args: args{ + a: []string{"192.0.2.1", "192.0.2.2", "192.0.2.3"}, + b: []string{"192.0.2.1", "192.0.2.2", "192.0.2.3"}, + }, + want: true, + wantErr: false, + }, + { + name: "same lists, different order", + args: args{ + a: []string{"192.0.2.1", "192.0.2.2", "192.0.2.3"}, + b: []string{"192.0.2.2", "192.0.2.1", "192.0.2.3"}, + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsSameIPs(tt.args.a, tt.args.b) + if (err != nil) != tt.wantErr { + t.Errorf("IsSameIPs() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsSameIPs() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsIPRange(t *testing.T) { + type args struct { + version constant.IPVersion + ipRange string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "ipv4", + args: args{ + version: constant.IPv4, + ipRange: "172.18.40.0-172.18.40.10", + }, + wantErr: false, + }, + { + name: "ipv4", + args: args{ + version: constant.IPv4, + ipRange: "192.168.0.1-192.168.0.10", + }, + wantErr: false, + }, + { + name: "invalid ipv4", + args: args{ + version: constant.IPv4, + ipRange: "172.18.40.0 - 172.18.40.10", + }, + wantErr: true, + }, + { + name: "invalid ipv4", + args: args{ + version: constant.IPv4, + ipRange: "172.18.40.1-2001:db8:a0b:12f0::1", + }, + wantErr: true, + }, + { + name: "invalid version", + args: args{ + version: 0, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ip.IsIPRange(tt.args.version, tt.args.ipRange); (err != nil) != tt.wantErr { + t.Errorf("IsIPRange() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestMergeIPRanges(t *testing.T) { + type args struct { + version constant.IPVersion + ipRanges []string + } + tests := []struct { + name string + args args + want []string + wantErr bool + }{ + { + name: "invalid version", + args: args{ + version: 0, + ipRanges: nil, + }, + wantErr: true, + }, + { + name: "", + args: args{ + version: constant.IPv4, + ipRanges: []string{ + "172.18.40.1-172.18.40.3", + "172.18.40.2-172.18.40.5", + }, + }, + want: []string{ + "172.18.40.1-172.18.40.5", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.MergeIPRanges(tt.args.version, tt.args.ipRanges) + if (err != nil) != tt.wantErr { + t.Errorf("MergeIPRanges() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MergeIPRanges() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetIPV4V6(t *testing.T) { + type args struct { + ips []string + } + tests := []struct { + name string + args args + wantIPV4s []string + wantIPV6s []string + wantErr bool + }{ + { + name: "empty", + args: args{ + ips: nil, + }, + wantIPV4s: nil, + wantIPV6s: nil, + wantErr: false, + }, + { + name: "empty", + args: args{ + ips: []string{""}, + }, + wantIPV4s: nil, + wantIPV6s: nil, + wantErr: true, + }, + { + name: "ipv6-empty", + args: args{ + ips: []string{ + "10.6.1.21", + }, + }, + wantIPV4s: []string{"10.6.1.21"}, + wantIPV6s: nil, + wantErr: false, + }, + { + name: "ipv4-empty", + args: args{ + ips: []string{ + "fd00::1", + }, + }, + wantIPV4s: nil, + wantIPV6s: []string{"fd00::1"}, + wantErr: false, + }, + { + name: "ipv4-ipv6", + args: args{ + ips: []string{ + "10.6.1.21", + "fd00::1", + "10.6.1.22", + "fd00::2", + }, + }, + wantIPV4s: []string{"10.6.1.21", "10.6.1.22"}, + wantIPV6s: []string{"fd00::1", "fd00::2"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotIPV4s, gotIPV6s, err := ip.GetIPV4V6(tt.args.ips) + if (err != nil) != tt.wantErr { + t.Errorf("GetIPV4V6() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotIPV4s, tt.wantIPV4s) { + t.Errorf("GetIPV4V6() gotIPV4s = %v, want %v", gotIPV4s, tt.wantIPV4s) + } + if !reflect.DeepEqual(gotIPV6s, tt.wantIPV6s) { + t.Errorf("GetIPV4V6() gotIPV6s = %v, want %v", gotIPV6s, tt.wantIPV6s) + } + }) + } +} + +func TestIsIPRangeOverlap(t *testing.T) { + type args struct { + version constant.IPVersion + ipRange1 string + ipRange2 string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "invalid version", + args: args{ + version: 0, + }, + wantErr: true, + }, + { + name: "valid ipv4", + args: args{ + version: constant.IPv4, + ipRange1: "10.6.1.1-10.6.1.10", + ipRange2: "10.6.1.11-10.6.1.20", + }, + wantErr: false, + }, + { + name: "invalid range", + args: args{ + version: constant.IPv4, + ipRange1: "10.6.1.1-10.6.1.11", + ipRange2: "10.6.1.10-10.6.1.20", + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsIPRangeOverlap(tt.args.version, tt.args.ipRange1, tt.args.ipRange2) + if (err != nil) != tt.wantErr { + t.Errorf("IsIPRangeOverlap() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsIPRangeOverlap() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsSameIPCidrs(t *testing.T) { + type args struct { + a []string + b []string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "empty", + args: args{ + a: []string{}, + b: []string{}, + }, + want: true, + wantErr: false, + }, + { + name: "not-cidr", + args: args{ + a: []string{"10.6.1.21"}, + b: []string{"10.6.1.21"}, + }, + want: false, + wantErr: true, + }, + { + name: "cidr-32", + args: args{ + a: []string{"10.6.1.21/32"}, + b: []string{"10.6.1.21/32"}, + }, + want: true, + wantErr: false, + }, + { + name: "cidr-ipv6", + args: args{ + a: []string{"fd00::1/120"}, + b: []string{"fd00::2/120"}, + }, + want: true, + wantErr: false, + }, + { + name: "cidr", + args: args{ + a: []string{"fd00::1/120", "10.6.1.21/28"}, + b: []string{"10.6.1.21/28", "fd00::2/120"}, + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsSameIPCidrs(tt.args.a, tt.args.b) + if (err != nil) != tt.wantErr { + t.Errorf("IsSameIPCidrs() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsSameIPCidrs() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIsIPIncludedRange(t *testing.T) { + type args struct { + version constant.IPVersion + ip string + ipRange []string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "invalid-version", + args: args{ + version: 0, + }, + want: false, + wantErr: true, + }, + { + name: "ipv4", + args: args{ + version: constant.IPv4, + ip: "10.6.1.21", + ipRange: []string{ + "10.6.1.21-10.6.1.22", + }, + }, + want: true, + wantErr: false, + }, + { + name: "ipv6", + args: args{ + version: constant.IPv6, + ip: "fd00::1", + ipRange: []string{ + "fd00::1-fd00::10", + }, + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ip.IsIPIncludedRange(tt.args.version, tt.args.ip, tt.args.ipRange) + if (err != nil) != tt.wantErr { + t.Errorf("IsIPIncludedRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("IsIPIncludedRange() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetIPV4V6Cidr(t *testing.T) { + type args struct { + ipCidrs []string + } + tests := []struct { + name string + args args + wantIPV4Cidrs []string + wantIPV6Cidrs []string + wantErr bool + }{ + { + name: "ipv4", + args: args{ + ipCidrs: []string{"10.6.1.0/24", "fd00::/120"}, + }, + wantIPV4Cidrs: []string{"10.6.1.0/24"}, + wantIPV6Cidrs: []string{"fd00::/120"}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotIPV4Cidrs, gotIPV6Cidrs, err := ip.GetIPV4V6Cidr(tt.args.ipCidrs) + if (err != nil) != tt.wantErr { + t.Errorf("GetIPV4V6Cidr() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotIPV4Cidrs, tt.wantIPV4Cidrs) { + t.Errorf("GetIPV4V6Cidr() gotIPV4Cidrs = %v, want %v", gotIPV4Cidrs, tt.wantIPV4Cidrs) + } + if !reflect.DeepEqual(gotIPV6Cidrs, tt.wantIPV6Cidrs) { + t.Errorf("GetIPV4V6Cidr() gotIPV6Cidrs = %v, want %v", gotIPV6Cidrs, tt.wantIPV6Cidrs) + } + }) + } +} diff --git a/pkg/utils/ip_test.go b/pkg/utils/ip_test.go deleted file mode 100644 index d45d9a771..000000000 --- a/pkg/utils/ip_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 Authors of spidernet-io -// SPDX-License-Identifier: Apache-2.0 - -package utils_test - -import ( - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/spidernet-io/egressgateway/pkg/utils" -) - -var _ = Describe("Ip", func() { - Describe("UT GetIPV4V6",Label("GetIPV4V6"), func() { - ipv4:="10.10.0.1" - ipv6:="fddd:10::1" - invalidIPv4:="10.10.1" - - ipv4s:=[]string{ipv4} - ipv6s:=[]string{ipv6} - ips:=[]string{ipv4,ipv6} - - invalidIPs:=[]string{invalidIPv4,ipv6} - - It("UT GetIPV4V6, expect success", func() { - v4, v6, err := utils.GetIPV4V6(ips) - Expect(err).NotTo(HaveOccurred()) - Expect(v4).To(Equal(ipv4s)) - Expect(v6).To(Equal(ipv6s)) - }) - - It("UT GetIPV4V6, invalid ip format", func() { - v4, v6, err := utils.GetIPV4V6(invalidIPs) - Expect(err).To(HaveOccurred()) - Expect(v4).To(BeNil()) - Expect(v6).To(BeNil()) - }) - }) - -}) diff --git a/pkg/utils/node.go b/pkg/utils/node.go index cbaa80b9e..eebf64d67 100644 --- a/pkg/utils/node.go +++ b/pkg/utils/node.go @@ -4,16 +4,17 @@ package utils import ( + "github.com/spidernet-io/egressgateway/pkg/utils/ip" v1 "k8s.io/api/core/v1" ) func GetNodeIP(node *v1.Node) (nodeIPv4, nodeIPv6 string) { for _, addresses := range node.Status.Addresses { if addresses.Type == v1.NodeInternalIP { - if isV4, _ := IsIPv4(addresses.Address); isV4 { + if isV4, _ := ip.IsIPv4(addresses.Address); isV4 { nodeIPv4 = addresses.Address } - if isV6, _ := IsIPv6(addresses.Address); isV6 { + if isV6, _ := ip.IsIPv6(addresses.Address); isV6 { nodeIPv6 = addresses.Address } } diff --git a/pkg/utils/utils_suite_test.go b/pkg/utils/utils_suite_test.go deleted file mode 100644 index e437f4d3e..000000000 --- a/pkg/utils/utils_suite_test.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022 Authors of spidernet-io -// SPDX-License-Identifier: Apache-2.0 - -package utils_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestUtils(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Utils Suite") -} diff --git a/test/e2e/common/calico.go b/test/e2e/common/calico.go index ca8737488..6918c20f7 100644 --- a/test/e2e/common/calico.go +++ b/test/e2e/common/calico.go @@ -8,16 +8,15 @@ import ( "time" . "github.com/onsi/gomega" - "github.com/spidernet-io/e2eframework/framework" + calicov1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - calicov1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1" - - "github.com/spidernet-io/egressgateway/pkg/utils" + "github.com/spidernet-io/e2eframework/framework" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" e "github.com/spidernet-io/egressgateway/test/e2e/err" "github.com/spidernet-io/egressgateway/test/e2e/tools" ) @@ -47,10 +46,10 @@ func GetCalicoIPPoolsCidr(f *framework.Framework) (v4Cidrs, v6Cidrs []string) { v4Cidrs, v6Cidrs = make([]string, 0), make([]string, 0) for _, ippool := range ippools { cidr := ippool.Spec.CIDR - isV4Cidr, err := utils.IsIPv4Cidr(cidr) + isV4Cidr, err := ip.IsIPv4Cidr(cidr) Expect(err).NotTo(HaveOccurred()) - isV6Cidr, err := utils.IsIPv6Cidr(cidr) + isV6Cidr, err := ip.IsIPv6Cidr(cidr) Expect(err).NotTo(HaveOccurred()) if isV4Cidr { diff --git a/test/e2e/common/clusterip.go b/test/e2e/common/clusterip.go index 70410fe94..512d7746e 100644 --- a/test/e2e/common/clusterip.go +++ b/test/e2e/common/clusterip.go @@ -9,8 +9,7 @@ import ( . "github.com/onsi/gomega" "github.com/spidernet-io/e2eframework/framework" - - "github.com/spidernet-io/egressgateway/pkg/utils" + "github.com/spidernet-io/egressgateway/pkg/utils/ip" ) func GetClusterIpCidr(f *framework.Framework) (ipv4s, ipv6s []string) { @@ -27,7 +26,7 @@ func GetClusterIpCidr(f *framework.Framework) (ipv4s, ipv6s []string) { Expect(len(svcSubnetKV)).To(Equal(2)) subnets := strings.Split(svcSubnetKV[1], ",") - ipv4s, ipv6s, err = utils.GetIPV4V6Cidr(subnets) + ipv4s, ipv6s, err = ip.GetIPV4V6Cidr(subnets) Expect(err).NotTo(HaveOccurred()) return ipv4s, ipv6s } diff --git a/test/e2e/common/ip.go b/test/e2e/common/ip.go index e9ef875a1..238bf8827 100644 --- a/test/e2e/common/ip.go +++ b/test/e2e/common/ip.go @@ -6,6 +6,7 @@ package common import ( "context" "fmt" + "math/big" "net" "os/exec" @@ -13,7 +14,7 @@ import ( "time" "github.com/spidernet-io/egressgateway/pkg/constant" - "github.com/spidernet-io/egressgateway/pkg/utils" + iputil "github.com/spidernet-io/egressgateway/pkg/utils/ip" e "github.com/spidernet-io/egressgateway/test/e2e/err" "github.com/spidernet-io/egressgateway/test/e2e/tools" ) @@ -137,7 +138,7 @@ func CheckIPIncluded(version constant.IPVersion, ip string, ips []string) (bool, _, _, err := net.ParseCIDR(item) if err != nil { // item is not cidr - include, err := utils.IsIPIncludedRange(version, ip, []string{item}) + include, err := iputil.IsIPIncludedRange(version, ip, []string{item}) if err != nil { return false, err } diff --git a/test/e2e/common/node.go b/test/e2e/common/node.go index 5af943aeb..c76a9c8fb 100644 --- a/test/e2e/common/node.go +++ b/test/e2e/common/node.go @@ -15,7 +15,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/spidernet-io/e2eframework/framework" - "github.com/spidernet-io/egressgateway/pkg/utils" "github.com/spidernet-io/egressgateway/test/e2e/tools" )