From e97109590322bcc1d035e53d9406965138960dc3 Mon Sep 17 00:00:00 2001 From: jeffy Date: Wed, 22 Mar 2023 11:09:21 +0800 Subject: [PATCH] add vip to webhook e2e (#2525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add vip e2e * Change variable name * Update test/e2e/framework/vip.go Co-authored-by: 张祖建 --------- Co-authored-by: yl4811 Co-authored-by: 张祖建 --- test/e2e/framework/vip.go | 87 ++++++++++++++++++++++++++++++++++++ test/e2e/webhook/e2e_test.go | 1 + test/e2e/webhook/vip/vip.go | 86 +++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) create mode 100644 test/e2e/framework/vip.go create mode 100644 test/e2e/webhook/vip/vip.go diff --git a/test/e2e/framework/vip.go b/test/e2e/framework/vip.go new file mode 100644 index 00000000000..d11f63ce6bf --- /dev/null +++ b/test/e2e/framework/vip.go @@ -0,0 +1,87 @@ +package framework + +import ( + "context" + apiv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1" + v1 "github.com/kubeovn/kube-ovn/pkg/client/clientset/versioned/typed/kubeovn/v1" + "github.com/kubeovn/kube-ovn/pkg/util" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "time" +) + +// VipClient is a struct for vip client. +type VipClient struct { + f *Framework + v1.VipInterface +} + +func (f *Framework) VipClient() *VipClient { + return &VipClient{ + f: f, + VipInterface: f.KubeOVNClientSet.KubeovnV1().Vips(), + } +} + +func (c *VipClient) Get(name string) *apiv1.Vip { + vip, err := c.VipInterface.Get(context.TODO(), name, metav1.GetOptions{}) + ExpectNoError(err) + return vip.DeepCopy() +} + +// Create creates a new vip according to the framework specifications +func (c *VipClient) Create(pn *apiv1.Vip) *apiv1.Vip { + vip, err := c.VipInterface.Create(context.TODO(), pn, metav1.CreateOptions{}) + ExpectNoError(err, "Error creating vip") + return vip.DeepCopy() +} + +// Patch patches the vip +func (c *VipClient) Patch(original, modified *apiv1.Vip, timeout time.Duration) *apiv1.Vip { + patch, err := util.GenerateMergePatchPayload(original, modified) + ExpectNoError(err) + + var patchedVip *apiv1.Vip + err = wait.PollImmediate(2*time.Second, timeout, func() (bool, error) { + p, err := c.VipInterface.Patch(context.TODO(), original.Name, types.MergePatchType, patch, metav1.PatchOptions{}, "") + if err != nil { + return handleWaitingAPIError(err, false, "patch vip %q", original.Name) + } + patchedVip = p + return true, nil + }) + if err == nil { + return patchedVip.DeepCopy() + } + + if IsTimeout(err) { + Failf("timed out while retrying to patch vip %s", original.Name) + } + ExpectNoError(maybeTimeoutError(err, "patching vip %s", original.Name)) + + return nil +} + +// Delete deletes a vip if the vip exists +func (c *VipClient) Delete(name string, options metav1.DeleteOptions) { + err := c.VipInterface.Delete(context.TODO(), name, options) + if err != nil && !apierrors.IsNotFound(err) { + Failf("Failed to delete vip %q: %v", name, err) + } +} + +func MakeVip(name, subnet, v4ip, v6ip string) *apiv1.Vip { + vip := &apiv1.Vip{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: apiv1.VipSpec{ + Subnet: subnet, + V4ip: v4ip, + V6ip: v6ip, + }, + } + return vip +} diff --git a/test/e2e/webhook/e2e_test.go b/test/e2e/webhook/e2e_test.go index 44991b41d6c..0cf1e280f9a 100644 --- a/test/e2e/webhook/e2e_test.go +++ b/test/e2e/webhook/e2e_test.go @@ -16,6 +16,7 @@ import ( // Import tests. _ "github.com/kubeovn/kube-ovn/test/e2e/webhook/pod" _ "github.com/kubeovn/kube-ovn/test/e2e/webhook/subnet" + _ "github.com/kubeovn/kube-ovn/test/e2e/webhook/vip" ) func init() { diff --git a/test/e2e/webhook/vip/vip.go b/test/e2e/webhook/vip/vip.go new file mode 100644 index 00000000000..babebd880ba --- /dev/null +++ b/test/e2e/webhook/vip/vip.go @@ -0,0 +1,86 @@ +package vip + +import ( + "context" + "fmt" + "github.com/kubeovn/kube-ovn/pkg/util" + "github.com/onsi/ginkgo/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "math/big" + + apiv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1" + "github.com/kubeovn/kube-ovn/test/e2e/framework" +) + +var _ = framework.Describe("[group:webhook-vip]", func() { + f := framework.NewDefaultFramework("webhook-vip") + + var vip *apiv1.Vip + var subnet *apiv1.Subnet + var vipClient *framework.VipClient + var subnetClient *framework.SubnetClient + var vipName, subnetName, namespaceName string + var cidr, lastIPv4 string + + ginkgo.BeforeEach(func() { + subnetClient = f.SubnetClient() + subnetName = "subnet-" + framework.RandomSuffix() + cidr = framework.RandomCIDR(f.ClusterIpFamily) + cidrV4, _ := util.SplitStringIP(cidr) + if cidrV4 == "" { + lastIPv4 = "" + } else { + lastIPv4, _ = util.LastIP(cidrV4) + } + + vipClient = f.VipClient() + subnetClient = f.SubnetClient() + vipName = "vip-" + framework.RandomSuffix() + namespaceName = f.Namespace.Name + + ginkgo.By("Creating subnet " + subnetName) + subnet = framework.MakeSubnet(subnetName, "", cidr, "", nil, nil, []string{namespaceName}) + subnet = subnetClient.CreateSync(subnet) + }) + + ginkgo.AfterEach(func() { + ginkgo.By("Deleting vip " + vipName) + vipClient.Delete(vipName, metav1.DeleteOptions{}) + + ginkgo.By("Deleting subnet " + subnetName) + subnetClient.DeleteSync(subnetName) + }) + + framework.ConformanceIt("check create vip with different errors", func() { + ginkgo.By("Creating vip " + vipName) + vip = framework.MakeVip(vipName, "", "", "") + + ginkgo.By("validating subnet") + vip.Spec.Subnet = "" + _, err := vipClient.VipInterface.Create(context.TODO(), vip, metav1.CreateOptions{}) + framework.ExpectError(err, fmt.Errorf("subnet parameter cannot be empty")) + + ginkgo.By("validating wrong subnet") + vip.Spec.Subnet = "abc" + _, err = vipClient.VipInterface.Create(context.TODO(), vip, metav1.CreateOptions{}) + framework.ExpectError(err, fmt.Errorf("Subnet.kubeovn.io \"%s\" not found", vip.Spec.Subnet)) + + ginkgo.By("Validating vip usage with wrong v4ip") + vip.Spec.Subnet = subnetName + vip.Spec.V4ip = "10.10.10.10.10" + _, err = vipClient.VipInterface.Create(context.TODO(), vip, metav1.CreateOptions{}) + framework.ExpectError(err, fmt.Errorf("%s is not a valid ip", vip.Spec.V4ip)) + + ginkgo.By("Validating vip usage with wrong v6ip") + vip.Spec.V4ip = "" + vip.Spec.V6ip = "2001:250:207::eff2::2" + _, err = vipClient.VipInterface.Create(context.TODO(), vip, metav1.CreateOptions{}) + framework.ExpectError(err, fmt.Errorf("%s is not a valid ip", vip.Spec.V6ip)) + + ginkgo.By("validate ip not in subnet cidr") + vip.Spec.V6ip = "" + vip.Spec.V4ip = util.BigInt2Ip(big.NewInt(0).Add(util.Ip2BigInt(lastIPv4), big.NewInt(10))) + _, err = vipClient.VipInterface.Create(context.TODO(), vip, metav1.CreateOptions{}) + framework.ExpectError(err, fmt.Errorf("%s is not in the range of subnet %s", vip.Spec.V4ip, vip.Spec.Subnet)) + }) +})