diff --git a/test/integration/BUILD b/test/integration/BUILD index 2b77bb78b94..393f5c83694 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -75,6 +75,7 @@ filegroup( "//test/integration/scheduler:all-srcs", "//test/integration/scheduler_perf:all-srcs", "//test/integration/secrets:all-srcs", + "//test/integration/service:all-srcs", "//test/integration/serviceaccount:all-srcs", "//test/integration/serving:all-srcs", "//test/integration/statefulset:all-srcs", diff --git a/test/integration/service/BUILD b/test/integration/service/BUILD new file mode 100644 index 00000000000..50e9785918b --- /dev/null +++ b/test/integration/service/BUILD @@ -0,0 +1,35 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "go_default_test", + srcs = [ + "loadbalancer_test.go", + "main_test.go", + ], + tags = ["integration"], + deps = [ + "//pkg/features:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", + "//staging/src/k8s.io/client-go/rest:go_default_library", + "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", + "//test/integration/framework:go_default_library", + "//vendor/k8s.io/utils/pointer:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/test/integration/service/loadbalancer_test.go b/test/integration/service/loadbalancer_test.go new file mode 100644 index 00000000000..1a1a7916a3f --- /dev/null +++ b/test/integration/service/loadbalancer_test.go @@ -0,0 +1,151 @@ +/* +Copyright 2020 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 service + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilfeature "k8s.io/apiserver/pkg/util/feature" + clientset "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + featuregatetesting "k8s.io/component-base/featuregate/testing" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/test/integration/framework" + utilpointer "k8s.io/utils/pointer" +) + +// Test_ServiceLoadBalancerAllocateNodePorts tests that a Service with spec.allocateLoadBalancerNodePorts=false +// does not allocate node ports for the Service. +func Test_ServiceLoadBalancerDisableAllocateNodePorts(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)() + + masterConfig := framework.NewIntegrationTestMasterConfig() + _, server, closeFn := framework.RunAMaster(masterConfig) + defer closeFn() + + config := restclient.Config{Host: server.URL} + client, err := clientset.NewForConfig(&config) + if err != nil { + t.Fatalf("Error creating clientset: %v", err) + } + + ns := framework.CreateTestingNamespace("test-service-allocate-node-ports", server, t) + defer framework.DeleteTestingNamespace(ns, server, t) + + service := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-123", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(false), + Ports: []corev1.ServicePort{{ + Port: int32(80), + }}, + Selector: map[string]string{ + "foo": "bar", + }, + }, + } + + service, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Error creating test service: %v", err) + } + + foundNodePorts := false + for _, port := range service.Spec.Ports { + if port.NodePort > 0 { + foundNodePorts = true + } + } + + if foundNodePorts { + t.Error("found node ports when none was expected") + } +} + +// Test_ServiceLoadBalancerSwitchToDeallocatedNodePorts test that switching a Service +// to spec.allocateLoadBalancerNodePorts=false, does not de-allocate existing node ports. +func Test_ServiceLoadBalancerEnableThenDisableAllocatedNodePorts(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, true)() + + masterConfig := framework.NewIntegrationTestMasterConfig() + _, server, closeFn := framework.RunAMaster(masterConfig) + defer closeFn() + + config := restclient.Config{Host: server.URL} + client, err := clientset.NewForConfig(&config) + if err != nil { + t.Fatalf("Error creating clientset: %v", err) + } + + ns := framework.CreateTestingNamespace("test-service-deallocate-node-ports", server, t) + defer framework.DeleteTestingNamespace(ns, server, t) + + service := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-123", + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeLoadBalancer, + AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(true), + Ports: []corev1.ServicePort{{ + Port: int32(80), + }}, + Selector: map[string]string{ + "foo": "bar", + }, + }, + } + + service, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Error creating test service: %v", err) + } + + foundNodePorts := false + for _, port := range service.Spec.Ports { + if port.NodePort > 0 { + foundNodePorts = true + } + } + + if !foundNodePorts { + t.Error("expected node ports but found none") + } + + service.Spec.AllocateLoadBalancerNodePorts = utilpointer.BoolPtr(false) + service, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), service, metav1.UpdateOptions{}) + if err != nil { + t.Fatalf("Error updating test service: %v", err) + } + + foundNodePorts = false + for _, port := range service.Spec.Ports { + if port.NodePort > 0 { + foundNodePorts = true + } + } + + if !foundNodePorts { + t.Error("node ports were unexpectedly deallocated") + } +} diff --git a/test/integration/service/main_test.go b/test/integration/service/main_test.go new file mode 100644 index 00000000000..969ba0e4f4a --- /dev/null +++ b/test/integration/service/main_test.go @@ -0,0 +1,27 @@ +/* +Copyright 2020 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 service + +import ( + "testing" + + "k8s.io/kubernetes/test/integration/framework" +) + +func TestMain(m *testing.M) { + framework.EtcdMain(m.Run) +}