From de5859f7ced541cb3d0b683d430d8f71afef7120 Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 4 Mar 2020 11:09:48 +1300 Subject: [PATCH 1/5] Add Endpoints resource lifecycle test --- test/e2e/network/service.go | 93 +++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 42db66cfe38..9eab091a874 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -19,6 +19,7 @@ package network import ( "bytes" "context" + "encoding/json" "errors" "fmt" "math/rand" @@ -37,6 +38,7 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" @@ -2679,6 +2681,97 @@ var _ = SIGDescribe("Services", func() { framework.ExpectEqual(foundSvc, true, "could not find service 'kubernetes' in service list in all namespaces") }) + + ginkgo.It("should test the lifecycle of an Endpoint", func() { + ns := f.Namespace.Name + testServiceName := "testservice" + + ginkgo.By("creating a service") + _, err := f.ClientSet.CoreV1().Services(ns).Create(context.TODO(), &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: testServiceName, + Namespace: ns, + Labels: map[string]string{ + "testservice-static": "true", + }, + }, + Spec: v1.ServiceSpec{ + Type: "ClusterIP", + Ports: []v1.ServicePort{{ + Port: 80, + TargetPort: intstr.FromInt(80), + Protocol: v1.ProtocolTCP, + }}, + Selector: map[string]string{ + "testservice-static": "true", + }, + }, + }, metav1.CreateOptions{}) + framework.ExpectNoError(err, "failed to create service") + + // setup a watch for the Service + serviceWatchTimeoutSeconds := int64(60) + serviceWatch, err := f.ClientSet.CoreV1().Services(ns).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "testservice-static=true", TimeoutSeconds: &serviceWatchTimeoutSeconds}) + framework.ExpectNoError(err, "Failed to setup watch on newly created Service") + serviceWatchChan := serviceWatch.ResultChan() + ginkgo.By("waiting for available Service") + for event := range serviceWatchChan { + svc, ok := event.Object.(*v1.Service) + framework.ExpectEqual(ok, true, "Unable to convert type of Service watch event") + if svc.Spec.ClusterIP != "" { + break + } + } + + ginkgo.By("listing all Endpoints") + endpointsList, err := f.ClientSet.CoreV1().Endpoints("").List(context.TODO(), metav1.ListOptions{LabelSelector: "testservice-static=true"}) + framework.ExpectNoError(err, "failed to list Endpoints") + foundEndpointService := false + var foundEndpoint v1.Endpoints + for _, endpoint := range endpointsList.Items { + if endpoint.ObjectMeta.Name == testServiceName && endpoint.ObjectMeta.Namespace == ns { + foundEndpointService = true + foundEndpoint = endpoint + break + } + } + framework.ExpectEqual(foundEndpointService, true, "unable to find Endpoint Service in list of Endpoints") + + ginkgo.By("updating the Endpoint") + foundEndpoint.ObjectMeta.Labels["testservice"] = "first-modification" + _, err = f.ClientSet.CoreV1().Endpoints(ns).Update(context.TODO(), &foundEndpoint, metav1.UpdateOptions{}) + framework.ExpectNoError(err, "failed to update Endpoint with new label") + + ginkgo.By("fetching the Endpoint") + _, err = f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testServiceName, metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch Endpoint") + framework.ExpectEqual(foundEndpoint.ObjectMeta.Labels["testservice"], "first-modification", "label not patched") + + endpointPatch, err := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]string{ + "testservice": "second-modification", + }, + }, + }) + framework.ExpectNoError(err, "failed to marshal JSON for Event patch") + ginkgo.By("patching the Endpoint") + _, err = f.ClientSet.CoreV1().Endpoints(ns).Patch(context.TODO(), testServiceName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) + framework.ExpectNoError(err, "failed to patch Endpoint") + + ginkgo.By("fetching the Endpoint") + _, err = f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testServiceName, metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch Endpoint") + framework.ExpectEqual(foundEndpoint.ObjectMeta.Labels["testservice"], "first-modification", "failed to patch Endpoint with Label") + + ginkgo.By("deleting the Endpoint by Collection") + err = f.ClientSet.CoreV1().Endpoints(ns).DeleteCollection(context.TODO(), &metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "testservice-static=true"}) + framework.ExpectNoError(err, "failed to delete Endpoint by Collection") + + ginkgo.By("deleting the Service") + err = f.ClientSet.CoreV1().Services(ns).Delete(context.TODO(), testServiceName, &metav1.DeleteOptions{}) + framework.ExpectNoError(err, "failed to delete Service") + }) }) // TODO: Get rid of [DisabledForLargeClusters] tag when issue #56138 is fixed. From be382a812cace699eccc660083b58618d21d027c Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 4 Mar 2020 14:24:02 +1300 Subject: [PATCH 2/5] Update test to create endpoint, patch addresses and ports for endpoint, ensure watch for DELETED --- test/e2e/network/service.go | 93 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 9eab091a874..50a5d063fc6 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -2684,52 +2684,49 @@ var _ = SIGDescribe("Services", func() { ginkgo.It("should test the lifecycle of an Endpoint", func() { ns := f.Namespace.Name - testServiceName := "testservice" + testEndpointName := "testservice" - ginkgo.By("creating a service") - _, err := f.ClientSet.CoreV1().Services(ns).Create(context.TODO(), &v1.Service{ + ginkgo.By("creating an Endpoint") + _, err := f.ClientSet.CoreV1().Endpoints(ns).Create(context.TODO(), &v1.Endpoints{ ObjectMeta: metav1.ObjectMeta{ - Name: testServiceName, + Name: testEndpointName, Namespace: ns, Labels: map[string]string{ - "testservice-static": "true", + "testendpoint-static": "true", }, }, - Spec: v1.ServiceSpec{ - Type: "ClusterIP", - Ports: []v1.ServicePort{{ - Port: 80, - TargetPort: intstr.FromInt(80), - Protocol: v1.ProtocolTCP, + Subsets: []v1.EndpointSubset{{ + Addresses: []v1.EndpointAddress{{ + IP: "10.0.0.24", }}, - Selector: map[string]string{ - "testservice-static": "true", - }, - }, + Ports: []v1.EndpointPort{{ + Name: "http", + Port: 80, + Protocol: v1.ProtocolTCP, + }}, + }}, }, metav1.CreateOptions{}) - framework.ExpectNoError(err, "failed to create service") + framework.ExpectNoError(err, "failed to create Endpoint") - // setup a watch for the Service - serviceWatchTimeoutSeconds := int64(60) - serviceWatch, err := f.ClientSet.CoreV1().Services(ns).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "testservice-static=true", TimeoutSeconds: &serviceWatchTimeoutSeconds}) - framework.ExpectNoError(err, "Failed to setup watch on newly created Service") - serviceWatchChan := serviceWatch.ResultChan() - ginkgo.By("waiting for available Service") - for event := range serviceWatchChan { - svc, ok := event.Object.(*v1.Service) - framework.ExpectEqual(ok, true, "Unable to convert type of Service watch event") - if svc.Spec.ClusterIP != "" { + // setup a watch for the Endpoint + endpointWatchTimeoutSeconds := int64(60) + endpointWatch, err := f.ClientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "testendpoint-static=true", TimeoutSeconds: &endpointWatchTimeoutSeconds}) + framework.ExpectNoError(err, "failed to setup watch on newly created Endpoint") + endpointWatchChan := endpointWatch.ResultChan() + ginkgo.By("waiting for available Endpoint") + for event := range endpointWatchChan { + if event.Type == "ADDED" { break } } ginkgo.By("listing all Endpoints") - endpointsList, err := f.ClientSet.CoreV1().Endpoints("").List(context.TODO(), metav1.ListOptions{LabelSelector: "testservice-static=true"}) + endpointsList, err := f.ClientSet.CoreV1().Endpoints("").List(context.TODO(), metav1.ListOptions{LabelSelector: "testendpoint-static=true"}) framework.ExpectNoError(err, "failed to list Endpoints") foundEndpointService := false var foundEndpoint v1.Endpoints for _, endpoint := range endpointsList.Items { - if endpoint.ObjectMeta.Name == testServiceName && endpoint.ObjectMeta.Namespace == ns { + if endpoint.ObjectMeta.Name == testEndpointName && endpoint.ObjectMeta.Namespace == ns { foundEndpointService = true foundEndpoint = endpoint break @@ -2743,7 +2740,7 @@ var _ = SIGDescribe("Services", func() { framework.ExpectNoError(err, "failed to update Endpoint with new label") ginkgo.By("fetching the Endpoint") - _, err = f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testServiceName, metav1.GetOptions{}) + _, err = f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testEndpointName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to fetch Endpoint") framework.ExpectEqual(foundEndpoint.ObjectMeta.Labels["testservice"], "first-modification", "label not patched") @@ -2753,24 +2750,48 @@ var _ = SIGDescribe("Services", func() { "testservice": "second-modification", }, }, + "subsets": []map[string]interface{}{ + { + "addresses": []map[string]string{ + { + "ip": "10.0.0.25", + }, + }, + "ports": []map[string]interface{}{ + { + "name": "http-test", + "port": int32(8080), + }, + }, + }, + }, }) framework.ExpectNoError(err, "failed to marshal JSON for Event patch") ginkgo.By("patching the Endpoint") - _, err = f.ClientSet.CoreV1().Endpoints(ns).Patch(context.TODO(), testServiceName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) + _, err = f.ClientSet.CoreV1().Endpoints(ns).Patch(context.TODO(), testEndpointName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch Endpoint") ginkgo.By("fetching the Endpoint") - _, err = f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testServiceName, metav1.GetOptions{}) + endpoint, err := f.ClientSet.CoreV1().Endpoints(ns).Get(context.TODO(), testEndpointName, metav1.GetOptions{}) framework.ExpectNoError(err, "failed to fetch Endpoint") - framework.ExpectEqual(foundEndpoint.ObjectMeta.Labels["testservice"], "first-modification", "failed to patch Endpoint with Label") + framework.ExpectEqual(endpoint.ObjectMeta.Labels["testservice"], "second-modification", "failed to patch Endpoint with Label") + endpointSubsetOne := endpoint.Subsets[0] + endpointSubsetOneAddresses := endpointSubsetOne.Addresses[0] + endpointSubsetOnePorts := endpointSubsetOne.Ports[0] + framework.ExpectEqual(endpointSubsetOneAddresses.IP, "10.0.0.25", "failed to patch Endpoint") + framework.ExpectEqual(endpointSubsetOnePorts.Name, "http-test", "failed to patch Endpoint") + framework.ExpectEqual(endpointSubsetOnePorts.Port, int32(8080), "failed to patch Endpoint") ginkgo.By("deleting the Endpoint by Collection") - err = f.ClientSet.CoreV1().Endpoints(ns).DeleteCollection(context.TODO(), &metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "testservice-static=true"}) + err = f.ClientSet.CoreV1().Endpoints(ns).DeleteCollection(context.TODO(), &metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "testendpoint-static=true"}) framework.ExpectNoError(err, "failed to delete Endpoint by Collection") - ginkgo.By("deleting the Service") - err = f.ClientSet.CoreV1().Services(ns).Delete(context.TODO(), testServiceName, &metav1.DeleteOptions{}) - framework.ExpectNoError(err, "failed to delete Service") + ginkgo.By("waiting for Endpoint deletion") + for event := range endpointWatchChan { + if event.Type == "DELETED" { + break + } + } }) }) From bf4f46b9faaeb60bcc1c48285be794e14dde4284 Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Thu, 5 Mar 2020 10:24:25 +1300 Subject: [PATCH 3/5] Adjust endpoint watch timeout to 180 --- test/e2e/network/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 50a5d063fc6..e86725bd191 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -2709,7 +2709,7 @@ var _ = SIGDescribe("Services", func() { framework.ExpectNoError(err, "failed to create Endpoint") // setup a watch for the Endpoint - endpointWatchTimeoutSeconds := int64(60) + endpointWatchTimeoutSeconds := int64(180) endpointWatch, err := f.ClientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "testendpoint-static=true", TimeoutSeconds: &endpointWatchTimeoutSeconds}) framework.ExpectNoError(err, "failed to setup watch on newly created Endpoint") endpointWatchChan := endpointWatch.ResultChan() From 58c532b9685e5ae00b852712d9c60e844a82f1ad Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 25 Mar 2020 11:05:40 +1300 Subject: [PATCH 4/5] Update name of watchEvent and comment on timeout for watch --- test/e2e/network/service.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index e86725bd191..53ea25b6b64 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -2708,14 +2708,15 @@ var _ = SIGDescribe("Services", func() { }, metav1.CreateOptions{}) framework.ExpectNoError(err, "failed to create Endpoint") - // setup a watch for the Endpoint + // set up a watch for the Endpoint + // this timeout was chosen as there was timeout failure from the CI endpointWatchTimeoutSeconds := int64(180) endpointWatch, err := f.ClientSet.CoreV1().Endpoints(ns).Watch(context.TODO(), metav1.ListOptions{LabelSelector: "testendpoint-static=true", TimeoutSeconds: &endpointWatchTimeoutSeconds}) framework.ExpectNoError(err, "failed to setup watch on newly created Endpoint") endpointWatchChan := endpointWatch.ResultChan() ginkgo.By("waiting for available Endpoint") - for event := range endpointWatchChan { - if event.Type == "ADDED" { + for watchEvent := range endpointWatchChan { + if watchEvent.Type == "ADDED" { break } } @@ -2766,7 +2767,7 @@ var _ = SIGDescribe("Services", func() { }, }, }) - framework.ExpectNoError(err, "failed to marshal JSON for Event patch") + framework.ExpectNoError(err, "failed to marshal JSON for WatchEvent patch") ginkgo.By("patching the Endpoint") _, err = f.ClientSet.CoreV1().Endpoints(ns).Patch(context.TODO(), testEndpointName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) framework.ExpectNoError(err, "failed to patch Endpoint") @@ -2787,8 +2788,8 @@ var _ = SIGDescribe("Services", func() { framework.ExpectNoError(err, "failed to delete Endpoint by Collection") ginkgo.By("waiting for Endpoint deletion") - for event := range endpointWatchChan { - if event.Type == "DELETED" { + for watchEvent := range endpointWatchChan { + if watchEvent.Type == "DELETED" { break } } From f64d348505eee3fc184b5e2fb0193ebb4944129f Mon Sep 17 00:00:00 2001 From: Caleb Woodbine Date: Wed, 25 Mar 2020 11:22:31 +1300 Subject: [PATCH 5/5] Update DeleteOptions --- test/e2e/network/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 53ea25b6b64..850ed008c87 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -2784,7 +2784,7 @@ var _ = SIGDescribe("Services", func() { framework.ExpectEqual(endpointSubsetOnePorts.Port, int32(8080), "failed to patch Endpoint") ginkgo.By("deleting the Endpoint by Collection") - err = f.ClientSet.CoreV1().Endpoints(ns).DeleteCollection(context.TODO(), &metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "testendpoint-static=true"}) + err = f.ClientSet.CoreV1().Endpoints(ns).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "testendpoint-static=true"}) framework.ExpectNoError(err, "failed to delete Endpoint by Collection") ginkgo.By("waiting for Endpoint deletion")