diff --git a/test/conformance/testdata/conformance.yaml b/test/conformance/testdata/conformance.yaml index b059483d071..52847989f96 100755 --- a/test/conformance/testdata/conformance.yaml +++ b/test/conformance/testdata/conformance.yaml @@ -1643,6 +1643,19 @@ The event is deleted and MUST NOT show up when listing all events. release: v1.25 file: test/e2e/instrumentation/core_events.go +- testname: kubernetes.default Endpoints and EndpointSlices + codename: '[sig-network] API Server should have Endpoints and EndpointSlices pointing + to API Server [Conformance]' + description: The "kubernetes.default" service MUST have Endpoints and EndpointSlices + pointing to each API server instance. + release: v1.21 + file: test/e2e/network/apiserver.go +- testname: Kubernetes Service + codename: '[sig-network] API Server should provide secure master service [Conformance]' + description: By default when a kubernetes cluster is running there MUST be a 'kubernetes' + service running in the cluster. + release: v1.9 + file: test/e2e/network/apiserver.go - testname: DNS, cluster codename: '[sig-network] DNS should provide /etc/hosts entries for the cluster [Conformance]' description: When a Pod is created, the pod MUST be able to resolve cluster dns @@ -1717,13 +1730,6 @@ for a Service that matches no pods. release: v1.21 file: test/e2e/network/endpointslice.go -- testname: kubernetes.default Endpoints and EndpointSlices - codename: '[sig-network] EndpointSlice should have Endpoints and EndpointSlices - pointing to API Server [Conformance]' - description: The "kubernetes.default" service MUST have Endpoints and EndpointSlices - pointing to each API server instance. - release: v1.21 - file: test/e2e/network/endpointslice.go - testname: EndpointSlice, multiple IPs, multiple ports codename: '[sig-network] EndpointSlice should support a Service with multiple endpoint IPs specified in multiple EndpointSlices [Conformance]' @@ -1760,6 +1766,15 @@ update, and delete actions. release: v1.21 file: test/e2e/network/endpointslicemirroring.go +- testname: Endpoint resource lifecycle + codename: '[sig-network] Endpoints should test the lifecycle of an Endpoint [Conformance]' + description: Create an endpoint, the endpoint MUST exist. The endpoint is updated + with a new label, a check after the update MUST find the changes. The endpoint + is then patched with a new IPv4 address and port, a check after the patch MUST + the changes. The endpoint is deleted by its label, a watch listens for the deleted + watch event. + release: v1.19 + file: test/e2e/network/endpoints.go - testname: Scheduling, HostPort matching and HostIP and Protocol not-matching codename: '[sig-network] HostPort validates that there is no conflict between pods with same hostPort but different hostIP and protocol [LinuxOnly] [Conformance]' @@ -2032,12 +2047,6 @@ Windows does not support session affinity.' release: v1.19 file: test/e2e/network/service.go -- testname: Kubernetes Service - codename: '[sig-network] Services should provide secure master service [Conformance]' - description: By default when a kubernetes cluster is running there MUST be a 'kubernetes' - service running in the cluster. - release: v1.9 - file: test/e2e/network/service.go - testname: Service, endpoints codename: '[sig-network] Services should serve a basic endpoint from pods [Conformance]' description: Create a service with a endpoint without any Pods, the service MUST @@ -2069,15 +2078,6 @@ Pod and the service must now have empty set of endpoints. release: v1.9 file: test/e2e/network/service.go -- testname: Endpoint resource lifecycle - codename: '[sig-network] Services should test the lifecycle of an Endpoint [Conformance]' - description: Create an endpoint, the endpoint MUST exist. The endpoint is updated - with a new label, a check after the update MUST find the changes. The endpoint - is then patched with a new IPv4 address and port, a check after the patch MUST - the changes. The endpoint is deleted by it's label, a watch listens for the deleted - watch event. - release: v1.19 - file: test/e2e/network/service.go - testname: ConfigMap, from environment field with various prefixes codename: '[sig-node] ConfigMap should be consumable as environment variable names with various prefixes [Conformance]' diff --git a/test/e2e/network/apiserver.go b/test/e2e/network/apiserver.go new file mode 100644 index 00000000000..682cfef43af --- /dev/null +++ b/test/e2e/network/apiserver.go @@ -0,0 +1,140 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package network + +import ( + "context" + + v1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + clientset "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/network/common" + admissionapi "k8s.io/pod-security-admission/api" + + "github.com/onsi/ginkgo/v2" +) + +var _ = common.SIGDescribe("API Server", func() { + f := framework.NewDefaultFramework("apiserver") + f.NamespacePodSecurityLevel = admissionapi.LevelBaseline + + var cs clientset.Interface + + ginkgo.BeforeEach(func() { + cs = f.ClientSet + }) + + /* + Release: v1.9 + Testname: Kubernetes Service + Description: By default when a kubernetes cluster is running there MUST be a 'kubernetes' service running in the cluster. + */ + framework.ConformanceIt("should provide secure master service", func(ctx context.Context) { + _, err := cs.CoreV1().Services(metav1.NamespaceDefault).Get(ctx, "kubernetes", metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch the service object for the service named kubernetes") + }) + + /* + Release: v1.21 + Testname: kubernetes.default Endpoints and EndpointSlices + Description: The "kubernetes.default" service MUST have Endpoints and EndpointSlices pointing to each API server instance. + */ + framework.ConformanceIt("should have Endpoints and EndpointSlices pointing to API Server", func(ctx context.Context) { + namespace := "default" + name := "kubernetes" + // verify "kubernetes.default" service exist + _, err := cs.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) + framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" Service resource on \"default\" namespace") + + // verify Endpoints for the API servers exist + endpoints, err := cs.CoreV1().Endpoints(namespace).Get(ctx, name, metav1.GetOptions{}) + framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" Endpoint resource on \"default\" namespace") + if len(endpoints.Subsets) == 0 { + framework.Failf("Expected at least 1 subset in endpoints, got %d: %#v", len(endpoints.Subsets), endpoints.Subsets) + } + // verify EndpointSlices for the API servers exist + endpointSliceList, err := cs.DiscoveryV1().EndpointSlices(namespace).List(ctx, metav1.ListOptions{ + LabelSelector: "kubernetes.io/service-name=" + name, + }) + framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" EndpointSlice resource on \"default\" namespace") + if len(endpointSliceList.Items) == 0 { + framework.Failf("Expected at least 1 EndpointSlice, got %d: %#v", len(endpoints.Subsets), endpoints.Subsets) + } + + if !endpointSlicesEqual(endpoints, endpointSliceList) { + framework.Failf("Expected EndpointSlice to have same addresses and port as Endpoints, got %#v: %#v", endpoints, endpointSliceList) + } + + }) +}) + +// endpointSlicesEqual compare if the Endpoint and the EndpointSliceList contains the same endpoints values +// as in addresses and ports, considering Ready and Unready addresses +func endpointSlicesEqual(endpoints *v1.Endpoints, endpointSliceList *discoveryv1.EndpointSliceList) bool { + // get the apiserver endpoint addresses + epAddresses := sets.NewString() + epPorts := sets.NewInt32() + for _, subset := range endpoints.Subsets { + for _, addr := range subset.Addresses { + epAddresses.Insert(addr.IP) + } + for _, addr := range subset.NotReadyAddresses { + epAddresses.Insert(addr.IP) + } + for _, port := range subset.Ports { + epPorts.Insert(port.Port) + } + } + framework.Logf("Endpoints addresses: %v , ports: %v", epAddresses.List(), epPorts.List()) + + // Endpoints are single stack, and must match the primary IP family of the Service kubernetes.default + // However, EndpointSlices can be IPv4 or IPv6, we can only compare the Slices that match the same IP family + // framework.TestContext.ClusterIsIPv6() reports the IP family of the kubernetes.default service + var addrType discoveryv1.AddressType + if framework.TestContext.ClusterIsIPv6() { + addrType = discoveryv1.AddressTypeIPv6 + } else { + addrType = discoveryv1.AddressTypeIPv4 + } + + // get the apiserver addresses from the endpoint slice list + sliceAddresses := sets.NewString() + slicePorts := sets.NewInt32() + for _, slice := range endpointSliceList.Items { + if slice.AddressType != addrType { + framework.Logf("Skipping slice %s: wanted %s family, got %s", slice.Name, addrType, slice.AddressType) + continue + } + for _, s := range slice.Endpoints { + sliceAddresses.Insert(s.Addresses...) + } + for _, ports := range slice.Ports { + if ports.Port != nil { + slicePorts.Insert(*ports.Port) + } + } + } + + framework.Logf("EndpointSlices addresses: %v , ports: %v", sliceAddresses.List(), slicePorts.List()) + if sliceAddresses.Equal(epAddresses) && slicePorts.Equal(epPorts) { + return true + } + return false +} diff --git a/test/e2e/network/endpoints.go b/test/e2e/network/endpoints.go new file mode 100644 index 00000000000..bbd9fb7df15 --- /dev/null +++ b/test/e2e/network/endpoints.go @@ -0,0 +1,229 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package network + +import ( + "context" + "encoding/json" + "time" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/resourceversion" + watch "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/tools/cache" + watchtools "k8s.io/client-go/tools/watch" + apimachineryutils "k8s.io/kubernetes/test/e2e/common/apimachinery" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/network/common" + admissionapi "k8s.io/pod-security-admission/api" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" +) + +var _ = common.SIGDescribe("Endpoints", func() { + f := framework.NewDefaultFramework("endpoints") + f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged + + /* + Release: v1.19 + Testname: Endpoint resource lifecycle + Description: Create an endpoint, the endpoint MUST exist. + The endpoint is updated with a new label, a check after the update MUST find the changes. + The endpoint is then patched with a new IPv4 address and port, a check after the patch MUST the changes. + The endpoint is deleted by its label, a watch listens for the deleted watch event. + */ + framework.ConformanceIt("should test the lifecycle of an Endpoint", func(ctx context.Context) { + testNamespaceName := f.Namespace.Name + testEndpointName := "testservice" + testEndpoints := v1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: testEndpointName, + Labels: map[string]string{ + "test-endpoint-static": "true", + }, + }, + Subsets: []v1.EndpointSubset{{ + Addresses: []v1.EndpointAddress{{ + IP: "10.0.0.24", + }}, + Ports: []v1.EndpointPort{{ + Name: "http", + Port: 80, + Protocol: v1.ProtocolTCP, + }}, + }}, + } + w := &cache.ListWatch{ + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + options.LabelSelector = "test-endpoint-static=true" + return f.ClientSet.CoreV1().Endpoints(testNamespaceName).Watch(ctx, options) + }, + } + endpointsList, err := f.ClientSet.CoreV1().Endpoints("").List(ctx, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) + framework.ExpectNoError(err, "failed to list Endpoints") + + ginkgo.By("creating an Endpoint") + createdEP, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Create(ctx, &testEndpoints, metav1.CreateOptions{}) + framework.ExpectNoError(err, "failed to create Endpoint") + gomega.Expect(createdEP).To(apimachineryutils.HaveValidResourceVersion()) + ginkgo.By("waiting for available Endpoint") + ctxUntil, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + _, err = watchtools.Until(ctxUntil, endpointsList.ResourceVersion, w, func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Added: + if endpoints, ok := event.Object.(*v1.Endpoints); ok { + found := endpoints.ObjectMeta.Name == endpoints.Name && + endpoints.Labels["test-endpoint-static"] == "true" + return found, nil + } + default: + framework.Logf("observed event type %v", event.Type) + } + return false, nil + }) + framework.ExpectNoError(err, "failed to see %v event", watch.Added) + + ginkgo.By("listing all Endpoints") + endpointsList, err = f.ClientSet.CoreV1().Endpoints("").List(ctx, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) + framework.ExpectNoError(err, "failed to list Endpoints") + eventFound := false + var foundEndpoint v1.Endpoints + for _, endpoint := range endpointsList.Items { + if endpoint.ObjectMeta.Name == testEndpointName && endpoint.ObjectMeta.Namespace == testNamespaceName { + eventFound = true + foundEndpoint = endpoint + break + } + } + if !eventFound { + framework.Fail("unable to find Endpoint Service in list of Endpoints") + } + + ginkgo.By("updating the Endpoint") + foundEndpoint.ObjectMeta.Labels["test-service"] = "updated" + _, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Update(ctx, &foundEndpoint, metav1.UpdateOptions{}) + framework.ExpectNoError(err, "failed to update Endpoint with new label") + + ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) + defer cancel() + _, err = watchtools.Until(ctxUntil, endpointsList.ResourceVersion, w, func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Modified: + if endpoints, ok := event.Object.(*v1.Endpoints); ok { + found := endpoints.ObjectMeta.Name == endpoints.Name && + endpoints.Labels["test-endpoint-static"] == "true" + return found, nil + } + default: + framework.Logf("observed event type %v", event.Type) + } + return false, nil + }) + framework.ExpectNoError(err, "failed to see %v event", watch.Modified) + + ginkgo.By("fetching the Endpoint") + endpoints, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch Endpoint") + gomega.Expect(foundEndpoint.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("test-service", "updated"), "failed to update Endpoint %v in namespace %v label not updated", testEndpointName, testNamespaceName) + + endpointPatch, err := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]string{ + "test-service": "patched", + }, + }, + "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 WatchEvent patch") + ginkgo.By("patching the Endpoint") + patchedEP, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Patch(ctx, testEndpointName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) + framework.ExpectNoError(err, "failed to patch Endpoint") + gomega.Expect(resourceversion.CompareResourceVersion(createdEP.ResourceVersion, patchedEP.ResourceVersion)).To(gomega.BeNumerically("==", -1), "patched object should have a larger resource version") + + ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) + defer cancel() + _, err = watchtools.Until(ctxUntil, endpoints.ResourceVersion, w, func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Modified: + if endpoints, ok := event.Object.(*v1.Endpoints); ok { + found := endpoints.ObjectMeta.Name == endpoints.Name && + endpoints.Labels["test-endpoint-static"] == "true" + return found, nil + } + default: + framework.Logf("observed event type %v", event.Type) + } + return false, nil + }) + framework.ExpectNoError(err, "failed to see %v event", watch.Modified) + + ginkgo.By("fetching the Endpoint") + endpoints, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) + framework.ExpectNoError(err, "failed to fetch Endpoint") + gomega.Expect(endpoints.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("test-service", "patched"), "failed to patch Endpoint with Label") + endpointSubsetOne := endpoints.Subsets[0] + endpointSubsetOneAddresses := endpointSubsetOne.Addresses[0] + endpointSubsetOnePorts := endpointSubsetOne.Ports[0] + gomega.Expect(endpointSubsetOneAddresses.IP).To(gomega.Equal("10.0.0.25"), "failed to patch Endpoint") + gomega.Expect(endpointSubsetOnePorts.Name).To(gomega.Equal("http-test"), "failed to patch Endpoint") + gomega.Expect(endpointSubsetOnePorts.Port).To(gomega.Equal(int32(8080)), "failed to patch Endpoint") + + ginkgo.By("deleting the Endpoint by Collection") + err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) + framework.ExpectNoError(err, "failed to delete Endpoint by Collection") + + ginkgo.By("waiting for Endpoint deletion") + ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) + defer cancel() + _, err = watchtools.Until(ctxUntil, endpoints.ResourceVersion, w, func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Deleted: + if endpoints, ok := event.Object.(*v1.Endpoints); ok { + found := endpoints.ObjectMeta.Name == endpoints.Name && + endpoints.Labels["test-endpoint-static"] == "true" + return found, nil + } + default: + framework.Logf("observed event type %v", event.Type) + } + return false, nil + }) + framework.ExpectNoError(err, "failed to see %v event", watch.Deleted) + + ginkgo.By("fetching the Endpoint") + _, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) + gomega.Expect(err).To(gomega.HaveOccurred(), "should not be able to fetch Endpoint") + }) +}) diff --git a/test/e2e/network/endpointslice.go b/test/e2e/network/endpointslice.go index 463fa0cb08e..400257b7f82 100644 --- a/test/e2e/network/endpointslice.go +++ b/test/e2e/network/endpointslice.go @@ -59,39 +59,6 @@ var _ = common.SIGDescribe("EndpointSlice", func() { podClient = e2epod.NewPodClient(f) }) - /* - Release: v1.21 - Testname: kubernetes.default Endpoints and EndpointSlices - Description: The "kubernetes.default" service MUST have Endpoints and EndpointSlices pointing to each API server instance. - */ - framework.ConformanceIt("should have Endpoints and EndpointSlices pointing to API Server", func(ctx context.Context) { - namespace := "default" - name := "kubernetes" - // verify "kubernetes.default" service exist - _, err := cs.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) - framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" Service resource on \"default\" namespace") - - // verify Endpoints for the API servers exist - endpoints, err := cs.CoreV1().Endpoints(namespace).Get(ctx, name, metav1.GetOptions{}) - framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" Endpoint resource on \"default\" namespace") - if len(endpoints.Subsets) == 0 { - framework.Failf("Expected at least 1 subset in endpoints, got %d: %#v", len(endpoints.Subsets), endpoints.Subsets) - } - // verify EndpointSlices for the API servers exist - endpointSliceList, err := cs.DiscoveryV1().EndpointSlices(namespace).List(ctx, metav1.ListOptions{ - LabelSelector: "kubernetes.io/service-name=" + name, - }) - framework.ExpectNoError(err, "error obtaining API server \"kubernetes\" EndpointSlice resource on \"default\" namespace") - if len(endpointSliceList.Items) == 0 { - framework.Failf("Expected at least 1 EndpointSlice, got %d: %#v", len(endpoints.Subsets), endpoints.Subsets) - } - - if !endpointSlicesEqual(endpoints, endpointSliceList) { - framework.Failf("Expected EndpointSlice to have same addresses and port as Endpoints, got %#v: %#v", endpoints, endpointSliceList) - } - - }) - /* Release: v1.21 Testname: EndpointSlice, "empty" Service @@ -1017,57 +984,3 @@ func ensurePodTargetRef(pod *v1.Pod, targetRef *v1.ObjectReference) { framework.Failf("Expected TargetRef.UID to be %s, got %s", pod.UID, targetRef.UID) } } - -// endpointSlicesEqual compare if the Endpoint and the EndpointSliceList contains the same endpoints values -// as in addresses and ports, considering Ready and Unready addresses -func endpointSlicesEqual(endpoints *v1.Endpoints, endpointSliceList *discoveryv1.EndpointSliceList) bool { - // get the apiserver endpoint addresses - epAddresses := sets.NewString() - epPorts := sets.NewInt32() - for _, subset := range endpoints.Subsets { - for _, addr := range subset.Addresses { - epAddresses.Insert(addr.IP) - } - for _, addr := range subset.NotReadyAddresses { - epAddresses.Insert(addr.IP) - } - for _, port := range subset.Ports { - epPorts.Insert(port.Port) - } - } - framework.Logf("Endpoints addresses: %v , ports: %v", epAddresses.List(), epPorts.List()) - - // Endpoints are single stack, and must match the primary IP family of the Service kubernetes.default - // However, EndpointSlices can be IPv4 or IPv6, we can only compare the Slices that match the same IP family - // framework.TestContext.ClusterIsIPv6() reports the IP family of the kubernetes.default service - var addrType discoveryv1.AddressType - if framework.TestContext.ClusterIsIPv6() { - addrType = discoveryv1.AddressTypeIPv6 - } else { - addrType = discoveryv1.AddressTypeIPv4 - } - - // get the apiserver addresses from the endpoint slice list - sliceAddresses := sets.NewString() - slicePorts := sets.NewInt32() - for _, slice := range endpointSliceList.Items { - if slice.AddressType != addrType { - framework.Logf("Skipping slice %s: wanted %s family, got %s", slice.Name, addrType, slice.AddressType) - continue - } - for _, s := range slice.Endpoints { - sliceAddresses.Insert(s.Addresses...) - } - for _, ports := range slice.Ports { - if ports.Port != nil { - slicePorts.Insert(*ports.Port) - } - } - } - - framework.Logf("EndpointSlices addresses: %v , ports: %v", sliceAddresses.List(), slicePorts.List()) - if sliceAddresses.Equal(epAddresses) && slicePorts.Equal(epPorts) { - return true - } - return false -} diff --git a/test/e2e/network/service.go b/test/e2e/network/service.go index 8d30ebe885f..58708f11eb8 100644 --- a/test/e2e/network/service.go +++ b/test/e2e/network/service.go @@ -724,16 +724,6 @@ var _ = common.SIGDescribe("Services", func() { // TODO: We get coverage of TCP/UDP and multi-port services through the DNS test. We should have a simpler test for multi-port TCP here. - /* - Release: v1.9 - Testname: Kubernetes Service - Description: By default when a kubernetes cluster is running there MUST be a 'kubernetes' service running in the cluster. - */ - framework.ConformanceIt("should provide secure master service", func(ctx context.Context) { - _, err := cs.CoreV1().Services(metav1.NamespaceDefault).Get(ctx, "kubernetes", metav1.GetOptions{}) - framework.ExpectNoError(err, "failed to fetch the service object for the service named kubernetes") - }) - /* Release: v1.9 Testname: Service, endpoints @@ -3244,192 +3234,6 @@ var _ = common.SIGDescribe("Services", func() { } }) - /* - Release: v1.19 - Testname: Endpoint resource lifecycle - Description: Create an endpoint, the endpoint MUST exist. - The endpoint is updated with a new label, a check after the update MUST find the changes. - The endpoint is then patched with a new IPv4 address and port, a check after the patch MUST the changes. - The endpoint is deleted by it's label, a watch listens for the deleted watch event. - */ - framework.ConformanceIt("should test the lifecycle of an Endpoint", func(ctx context.Context) { - testNamespaceName := f.Namespace.Name - testEndpointName := "testservice" - testEndpoints := v1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: testEndpointName, - Labels: map[string]string{ - "test-endpoint-static": "true", - }, - }, - Subsets: []v1.EndpointSubset{{ - Addresses: []v1.EndpointAddress{{ - IP: "10.0.0.24", - }}, - Ports: []v1.EndpointPort{{ - Name: "http", - Port: 80, - Protocol: v1.ProtocolTCP, - }}, - }}, - } - w := &cache.ListWatch{ - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - options.LabelSelector = "test-endpoint-static=true" - return f.ClientSet.CoreV1().Endpoints(testNamespaceName).Watch(ctx, options) - }, - } - endpointsList, err := f.ClientSet.CoreV1().Endpoints("").List(ctx, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) - framework.ExpectNoError(err, "failed to list Endpoints") - - ginkgo.By("creating an Endpoint") - createdEP, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Create(ctx, &testEndpoints, metav1.CreateOptions{}) - framework.ExpectNoError(err, "failed to create Endpoint") - gomega.Expect(createdEP).To(apimachineryutils.HaveValidResourceVersion()) - ginkgo.By("waiting for available Endpoint") - ctxUntil, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - _, err = watchtools.Until(ctxUntil, endpointsList.ResourceVersion, w, func(event watch.Event) (bool, error) { - switch event.Type { - case watch.Added: - if endpoints, ok := event.Object.(*v1.Endpoints); ok { - found := endpoints.ObjectMeta.Name == endpoints.Name && - endpoints.Labels["test-endpoint-static"] == "true" - return found, nil - } - default: - framework.Logf("observed event type %v", event.Type) - } - return false, nil - }) - framework.ExpectNoError(err, "failed to see %v event", watch.Added) - - ginkgo.By("listing all Endpoints") - endpointsList, err = f.ClientSet.CoreV1().Endpoints("").List(ctx, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) - framework.ExpectNoError(err, "failed to list Endpoints") - eventFound := false - var foundEndpoint v1.Endpoints - for _, endpoint := range endpointsList.Items { - if endpoint.ObjectMeta.Name == testEndpointName && endpoint.ObjectMeta.Namespace == testNamespaceName { - eventFound = true - foundEndpoint = endpoint - break - } - } - if !eventFound { - framework.Fail("unable to find Endpoint Service in list of Endpoints") - } - - ginkgo.By("updating the Endpoint") - foundEndpoint.ObjectMeta.Labels["test-service"] = "updated" - _, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Update(ctx, &foundEndpoint, metav1.UpdateOptions{}) - framework.ExpectNoError(err, "failed to update Endpoint with new label") - - ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) - defer cancel() - _, err = watchtools.Until(ctxUntil, endpointsList.ResourceVersion, w, func(event watch.Event) (bool, error) { - switch event.Type { - case watch.Modified: - if endpoints, ok := event.Object.(*v1.Endpoints); ok { - found := endpoints.ObjectMeta.Name == endpoints.Name && - endpoints.Labels["test-endpoint-static"] == "true" - return found, nil - } - default: - framework.Logf("observed event type %v", event.Type) - } - return false, nil - }) - framework.ExpectNoError(err, "failed to see %v event", watch.Modified) - - ginkgo.By("fetching the Endpoint") - endpoints, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) - framework.ExpectNoError(err, "failed to fetch Endpoint") - gomega.Expect(foundEndpoint.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("test-service", "updated"), "failed to update Endpoint %v in namespace %v label not updated", testEndpointName, testNamespaceName) - - endpointPatch, err := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": map[string]string{ - "test-service": "patched", - }, - }, - "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 WatchEvent patch") - ginkgo.By("patching the Endpoint") - patchedEP, err := f.ClientSet.CoreV1().Endpoints(testNamespaceName).Patch(ctx, testEndpointName, types.StrategicMergePatchType, []byte(endpointPatch), metav1.PatchOptions{}) - framework.ExpectNoError(err, "failed to patch Endpoint") - gomega.Expect(resourceversion.CompareResourceVersion(createdEP.ResourceVersion, patchedEP.ResourceVersion)).To(gomega.BeNumerically("==", -1), "patched object should have a larger resource version") - - ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) - defer cancel() - _, err = watchtools.Until(ctxUntil, endpoints.ResourceVersion, w, func(event watch.Event) (bool, error) { - switch event.Type { - case watch.Modified: - if endpoints, ok := event.Object.(*v1.Endpoints); ok { - found := endpoints.ObjectMeta.Name == endpoints.Name && - endpoints.Labels["test-endpoint-static"] == "true" - return found, nil - } - default: - framework.Logf("observed event type %v", event.Type) - } - return false, nil - }) - framework.ExpectNoError(err, "failed to see %v event", watch.Modified) - - ginkgo.By("fetching the Endpoint") - endpoints, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) - framework.ExpectNoError(err, "failed to fetch Endpoint") - gomega.Expect(endpoints.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("test-service", "patched"), "failed to patch Endpoint with Label") - endpointSubsetOne := endpoints.Subsets[0] - endpointSubsetOneAddresses := endpointSubsetOne.Addresses[0] - endpointSubsetOnePorts := endpointSubsetOne.Ports[0] - gomega.Expect(endpointSubsetOneAddresses.IP).To(gomega.Equal("10.0.0.25"), "failed to patch Endpoint") - gomega.Expect(endpointSubsetOnePorts.Name).To(gomega.Equal("http-test"), "failed to patch Endpoint") - gomega.Expect(endpointSubsetOnePorts.Port).To(gomega.Equal(int32(8080)), "failed to patch Endpoint") - - ginkgo.By("deleting the Endpoint by Collection") - err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "test-endpoint-static=true"}) - framework.ExpectNoError(err, "failed to delete Endpoint by Collection") - - ginkgo.By("waiting for Endpoint deletion") - ctxUntil, cancel = context.WithTimeout(ctx, 30*time.Second) - defer cancel() - _, err = watchtools.Until(ctxUntil, endpoints.ResourceVersion, w, func(event watch.Event) (bool, error) { - switch event.Type { - case watch.Deleted: - if endpoints, ok := event.Object.(*v1.Endpoints); ok { - found := endpoints.ObjectMeta.Name == endpoints.Name && - endpoints.Labels["test-endpoint-static"] == "true" - return found, nil - } - default: - framework.Logf("observed event type %v", event.Type) - } - return false, nil - }) - framework.ExpectNoError(err, "failed to see %v event", watch.Deleted) - - ginkgo.By("fetching the Endpoint") - _, err = f.ClientSet.CoreV1().Endpoints(testNamespaceName).Get(ctx, testEndpointName, metav1.GetOptions{}) - gomega.Expect(err).To(gomega.HaveOccurred(), "should not be able to fetch Endpoint") - }) - /* Release: v1.21 Testname: Service, complete ServiceStatus lifecycle