diff --git a/pkg/api/endpoints/testing/make.go b/pkg/api/endpoints/testing/make.go new file mode 100644 index 00000000000..0b397c919bf --- /dev/null +++ b/pkg/api/endpoints/testing/make.go @@ -0,0 +1,70 @@ +/* +Copyright 2021 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 testing + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + api "k8s.io/kubernetes/pkg/apis/core" +) + +// Tweak is a function that modifies a Endpoints. +type Tweak func(*api.Endpoints) + +// MakeEndpoints helps construct Endpoints objects (which pass API validation) +// more legibly and tersely than a Go struct definition. +func MakeEndpoints(name string, addrs []api.EndpointAddress, ports []api.EndpointPort, tweaks ...Tweak) *api.Endpoints { + // NOTE: Any field that would be populated by defaulting needs to be + // present and valid here. + eps := &api.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + }, + Subsets: []api.EndpointSubset{{ + Addresses: addrs, + Ports: ports, + }}, + } + + for _, tweak := range tweaks { + tweak(eps) + } + + return eps +} + +// MakeEndpointAddress helps construct EndpointAddress objects which pass API +// validation. +func MakeEndpointAddress(ip string, pod string) api.EndpointAddress { + return api.EndpointAddress{ + IP: ip, + TargetRef: &api.ObjectReference{ + Name: pod, + Namespace: metav1.NamespaceDefault, + }, + } +} + +// MakeEndpointPort helps construct EndpointPort objects which pass API +// validation. +func MakeEndpointPort(name string, port int) api.EndpointPort { + return api.EndpointPort{ + Name: name, + Port: int32(port), + } +} diff --git a/pkg/api/service/testing/make.go b/pkg/api/service/testing/make.go new file mode 100644 index 00000000000..bb4d2b8c761 --- /dev/null +++ b/pkg/api/service/testing/make.go @@ -0,0 +1,142 @@ +/* +Copyright 2021 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 testing + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + + api "k8s.io/kubernetes/pkg/apis/core" +) + +// Tweak is a function that modifies a Service. +type Tweak func(*api.Service) + +// MakeService helps construct Service objects (which pass API validation) more +// legibly and tersely than a Go struct definition. By default this produces +// a ClusterIP service with a single port and a trivial selector. The caller +// can pass any number of tweak functions to further modify the result. +func MakeService(name string, tweaks ...Tweak) *api.Service { + // NOTE: Any field that would be populated by defaulting needs to be + // present and valid here. + svc := &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + }, + Spec: api.ServiceSpec{ + Selector: map[string]string{"k": "v"}, + SessionAffinity: api.ServiceAffinityNone, + }, + } + // Default to ClusterIP + SetTypeClusterIP(svc) + // Default to 1 port + SetPorts(MakeServicePort("", 93, intstr.FromInt(76), api.ProtocolTCP))(svc) + + for _, tweak := range tweaks { + tweak(svc) + } + + return svc +} + +// SetTypeClusterIP sets the service type to ClusterIP and clears other fields. +func SetTypeClusterIP(svc *api.Service) { + svc.Spec.Type = api.ServiceTypeClusterIP + for i := range svc.Spec.Ports { + svc.Spec.Ports[i].NodePort = 0 + } + svc.Spec.ExternalName = "" + svc.Spec.ExternalTrafficPolicy = "" +} + +// SetTypeNodePort sets the service type to NodePort and clears other fields. +func SetTypeNodePort(svc *api.Service) { + svc.Spec.Type = api.ServiceTypeNodePort + svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeCluster + svc.Spec.ExternalName = "" +} + +// SetTypeLoadBalancer sets the service type to LoadBalancer and clears other fields. +func SetTypeLoadBalancer(svc *api.Service) { + svc.Spec.Type = api.ServiceTypeLoadBalancer + svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeCluster + svc.Spec.ExternalName = "" +} + +// SetTypeExternalName sets the service type to ExternalName and clears other fields. +func SetTypeExternalName(svc *api.Service) { + svc.Spec.Type = api.ServiceTypeExternalName + svc.Spec.ExternalName = "example.com" + svc.Spec.ExternalTrafficPolicy = "" + svc.Spec.ClusterIP = "" + svc.Spec.ClusterIPs = nil +} + +// SetPorts sets the service ports list. +func SetPorts(ports ...api.ServicePort) Tweak { + return func(svc *api.Service) { + svc.Spec.Ports = ports + } +} + +// MakeServicePort helps construct ServicePort objects which pass API +// validation. +func MakeServicePort(name string, port int, tgtPort intstr.IntOrString, proto api.Protocol) api.ServicePort { + return api.ServicePort{ + Name: name, + Port: int32(port), + TargetPort: tgtPort, + Protocol: proto, + } +} + +// SetClusterIPs sets the service ClusterIP and ClusterIPs fields. +func SetClusterIPs(ips ...string) Tweak { + return func(svc *api.Service) { + svc.Spec.ClusterIP = ips[0] + svc.Spec.ClusterIPs = ips + } +} + +// SetIPFamilies sets the service IPFamilies field. +func SetIPFamilies(families ...api.IPFamily) Tweak { + return func(svc *api.Service) { + svc.Spec.IPFamilies = families + } +} + +// SetIPFamilyPolicy sets the service IPFamilyPolicy field. +func SetIPFamilyPolicy(policy api.IPFamilyPolicyType) Tweak { + return func(svc *api.Service) { + svc.Spec.IPFamilyPolicy = &policy + } +} + +// SetNodePorts sets the values for each node port, in order. If less values +// are specified than there are ports, the rest are untouched. +func SetNodePorts(values ...int) Tweak { + return func(svc *api.Service) { + for i := range svc.Spec.Ports { + if i >= len(values) { + break + } + svc.Spec.Ports[i].NodePort = int32(values[i]) + } + } +} diff --git a/pkg/registry/core/service/ipallocator/allocator.go b/pkg/registry/core/service/ipallocator/allocator.go index 634569f767a..7e57dc23d5b 100644 --- a/pkg/registry/core/service/ipallocator/allocator.go +++ b/pkg/registry/core/service/ipallocator/allocator.go @@ -35,8 +35,7 @@ type Interface interface { Release(net.IP) error ForEach(func(net.IP)) CIDR() net.IPNet - - // For testing + IPFamily() api.IPFamily Has(ip net.IP) bool } @@ -76,6 +75,8 @@ type Range struct { base *big.Int // max is the maximum size of the usable addresses in the range max int + // family is the IP family of this range + family api.IPFamily alloc allocator.Interface } @@ -85,13 +86,16 @@ func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.Allocator max := utilnet.RangeSize(cidr) base := utilnet.BigForIP(cidr.IP) rangeSpec := cidr.String() + var family api.IPFamily if utilnet.IsIPv6CIDR(cidr) { + family = api.IPv6Protocol // Limit the max size, since the allocator keeps a bitmap of that size. if max > 65536 { max = 65536 } } else { + family = api.IPv4Protocol // Don't use the IPv4 network's broadcast address. max-- } @@ -101,9 +105,10 @@ func NewAllocatorCIDRRange(cidr *net.IPNet, allocatorFactory allocator.Allocator max-- r := Range{ - net: cidr, - base: base, - max: maximum(0, int(max)), + net: cidr, + base: base, + max: maximum(0, int(max)), + family: family, } var err error r.alloc, err = allocatorFactory(r.max, rangeSpec) @@ -219,6 +224,11 @@ func (r *Range) Has(ip net.IP) bool { return r.alloc.Has(offset) } +// IPFamily returns the IP family of this range. +func (r *Range) IPFamily() api.IPFamily { + return r.family +} + // Snapshot saves the current state of the pool. func (r *Range) Snapshot(dst *api.RangeAllocation) error { snapshottable, ok := r.alloc.(allocator.Snapshottable) diff --git a/pkg/registry/core/service/ipallocator/allocator_test.go b/pkg/registry/core/service/ipallocator/allocator_test.go index 63ab5725695..db43f65ef5f 100644 --- a/pkg/registry/core/service/ipallocator/allocator_test.go +++ b/pkg/registry/core/service/ipallocator/allocator_test.go @@ -28,6 +28,7 @@ func TestAllocate(t *testing.T) { testCases := []struct { name string cidr string + family api.IPFamily free int released string outOfRange []string @@ -36,6 +37,7 @@ func TestAllocate(t *testing.T) { { name: "IPv4", cidr: "192.168.1.0/24", + family: api.IPv4Protocol, free: 254, released: "192.168.1.5", outOfRange: []string{ @@ -49,6 +51,7 @@ func TestAllocate(t *testing.T) { { name: "IPv6", cidr: "2001:db8:1::/48", + family: api.IPv6Protocol, free: 65535, released: "2001:db8:1::5", outOfRange: []string{ @@ -79,6 +82,10 @@ func TestAllocate(t *testing.T) { t.Errorf("allocator returned a different cidr") } + if r.IPFamily() != tc.family { + t.Errorf("allocator returned wrong IP family") + } + if f := r.Used(); f != 0 { t.Errorf("Test %s unexpected used %d", tc.name, f) } diff --git a/pkg/registry/core/service/portallocator/allocator.go b/pkg/registry/core/service/portallocator/allocator.go index 13eea2d275e..d344aa894da 100644 --- a/pkg/registry/core/service/portallocator/allocator.go +++ b/pkg/registry/core/service/portallocator/allocator.go @@ -34,8 +34,6 @@ type Interface interface { AllocateNext() (int, error) Release(int) error ForEach(func(int)) - - // For testing Has(int) bool } diff --git a/pkg/registry/core/service/storage/rest.go b/pkg/registry/core/service/storage/rest.go index a2c1a119bfd..5d6102d6295 100644 --- a/pkg/registry/core/service/storage/rest.go +++ b/pkg/registry/core/service/storage/rest.go @@ -612,7 +612,7 @@ func (rs *REST) allocClusterIPs(service *api.Service, toAlloc map[api.IPFamily]s } else { parsedIP := net.ParseIP(ip) if err := allocator.Allocate(parsedIP); err != nil { - el := field.ErrorList{field.Invalid(field.NewPath("spec", "clusterIPs"), service.Spec.ClusterIPs, fmt.Sprintf("failed to allocated ip:%v with error:%v", ip, err))} + el := field.ErrorList{field.Invalid(field.NewPath("spec", "clusterIPs"), service.Spec.ClusterIPs, fmt.Sprintf("failed to allocate IP %v: %v", ip, err))} return allocated, errors.NewInvalid(api.Kind("Service"), service.Name, el) } allocated[family] = ip diff --git a/pkg/registry/core/service/storage/rest_test.go b/pkg/registry/core/service/storage/rest_test.go index cff1830607a..fcd41b5ec68 100644 --- a/pkg/registry/core/service/storage/rest_test.go +++ b/pkg/registry/core/service/storage/rest_test.go @@ -18,9 +18,10 @@ package storage import ( "context" + "fmt" "net" "reflect" - "strings" + "sort" "testing" "k8s.io/apimachinery/pkg/api/errors" @@ -36,26 +37,21 @@ import ( "k8s.io/apiserver/pkg/registry/rest" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" "k8s.io/apiserver/pkg/util/dryrun" - + utilfeature "k8s.io/apiserver/pkg/util/feature" + featuregatetesting "k8s.io/component-base/featuregate/testing" + epstest "k8s.io/kubernetes/pkg/api/endpoints/testing" "k8s.io/kubernetes/pkg/api/service" + svctest "k8s.io/kubernetes/pkg/api/service/testing" api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/features" endpointstore "k8s.io/kubernetes/pkg/registry/core/endpoint/storage" podstore "k8s.io/kubernetes/pkg/registry/core/pod/storage" "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" "k8s.io/kubernetes/pkg/registry/core/service/portallocator" "k8s.io/kubernetes/pkg/registry/registrytest" - "sigs.k8s.io/structured-merge-diff/v4/fieldpath" - - utilfeature "k8s.io/apiserver/pkg/util/feature" - featuregatetesting "k8s.io/component-base/featuregate/testing" - "k8s.io/kubernetes/pkg/features" - netutil "k8s.io/utils/net" utilpointer "k8s.io/utils/pointer" -) - -var ( - singleStackIPv4 = []api.IPFamily{api.IPv4Protocol} + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" ) // TODO(wojtek-t): Cleanup this file. @@ -63,16 +59,14 @@ var ( // in a completely different way. We should unify it. type serviceStorage struct { - GottenID string - UpdatedID string - CreatedID string - DeletedID string - Created bool - DeletedImmediately bool - Service *api.Service - OldService *api.Service - ServiceList *api.ServiceList - Err error + Services map[string]*api.Service +} + +func (s *serviceStorage) saveService(svc *api.Service) { + if s.Services == nil { + s.Services = map[string]*api.Service{} + } + s.Services[svc.Name] = svc.DeepCopy() } func (s *serviceStorage) NamespaceScoped() bool { @@ -80,12 +74,18 @@ func (s *serviceStorage) NamespaceScoped() bool { } func (s *serviceStorage) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - s.GottenID = name - return s.Service, s.Err + if s.Services[name] == nil { + return nil, fmt.Errorf("service %q not found", name) + } + return s.Services[name].DeepCopy(), nil } -func (s *serviceStorage) GetService(ctx context.Context, name string, options *metav1.GetOptions) (*api.Service, error) { - return s.Service, s.Err +func getService(getter rest.Getter, ctx context.Context, name string, options *metav1.GetOptions) (*api.Service, error) { + obj, err := getter.Get(ctx, name, options) + if err != nil { + return nil, err + } + return obj.(*api.Service), nil } func (s *serviceStorage) NewList() runtime.Object { @@ -95,22 +95,21 @@ func (s *serviceStorage) NewList() runtime.Object { func (s *serviceStorage) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { ns, _ := genericapirequest.NamespaceFrom(ctx) - // Copy metadata from internal list into result - res := new(api.ServiceList) - res.TypeMeta = s.ServiceList.TypeMeta - res.ListMeta = s.ServiceList.ListMeta + keys := make([]string, 0, len(s.Services)) + for k := range s.Services { + keys = append(keys, k) + } + sort.Strings(keys) - if ns != metav1.NamespaceAll { - for _, service := range s.ServiceList.Items { - if ns == service.Namespace { - res.Items = append(res.Items, service) - } + res := new(api.ServiceList) + for _, k := range keys { + svc := s.Services[k] + if ns == metav1.NamespaceAll || ns == svc.Namespace { + res.Items = append(res.Items, *svc) } - } else { - res.Items = append([]api.Service{}, s.ServiceList.Items...) } - return res, s.Err + return res, nil } func (s *serviceStorage) New() runtime.Object { @@ -119,37 +118,30 @@ func (s *serviceStorage) New() runtime.Object { func (s *serviceStorage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { if dryrun.IsDryRun(options.DryRun) { - return obj, s.Err + return obj, nil } svc := obj.(*api.Service) - s.CreatedID = obj.(metav1.Object).GetName() - s.Service = svc.DeepCopy() + s.saveService(svc) + s.Services[svc.Name].ResourceVersion = "1" - if s.ServiceList == nil { - s.ServiceList = &api.ServiceList{} - } - - s.ServiceList.Items = append(s.ServiceList.Items, *svc) - return svc, s.Err + return s.Services[svc.Name].DeepCopy(), nil } func (s *serviceStorage) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - obj, err := objInfo.UpdatedObject(ctx, s.OldService) + obj, err := objInfo.UpdatedObject(ctx, nil) if err != nil { return nil, false, err } if !dryrun.IsDryRun(options.DryRun) { - s.UpdatedID = name - s.Service = obj.(*api.Service) + s.saveService(obj.(*api.Service)) } - return obj, s.Created, s.Err + return obj, false, nil } func (s *serviceStorage) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { - if !dryrun.IsDryRun(options.DryRun) { - s.DeletedID = name - } - return s.Service, s.DeletedImmediately, s.Err + ret := s.Services[name] + delete(s.Services, name) + return ret, false, nil } func (s *serviceStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) { @@ -173,11 +165,11 @@ func (s *serviceStorage) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Se return nil } -func NewTestREST(t *testing.T, endpoints *api.EndpointsList, ipFamilies []api.IPFamily) (*REST, *serviceStorage, *etcd3testing.EtcdTestServer) { - return NewTestRESTWithPods(t, endpoints, nil, ipFamilies) +func NewTestREST(t *testing.T, ipFamilies []api.IPFamily) (*REST, *etcd3testing.EtcdTestServer) { + return NewTestRESTWithPods(t, nil, nil, ipFamilies) } -func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.PodList, ipFamilies []api.IPFamily) (*REST, *serviceStorage, *etcd3testing.EtcdTestServer) { +func NewTestRESTWithPods(t *testing.T, endpoints []*api.Endpoints, pods []api.Pod, ipFamilies []api.IPFamily) (*REST, *etcd3testing.EtcdTestServer) { etcdStorage, server := registrytest.NewEtcdStorage(t, "") serviceStorage := &serviceStorage{} @@ -191,13 +183,11 @@ func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.P if err != nil { t.Fatalf("unexpected error from REST storage: %v", err) } - if pods != nil && len(pods.Items) > 0 { - ctx := genericapirequest.NewDefaultContext() - for ix := range pods.Items { - key, _ := podStorage.Pod.KeyFunc(ctx, pods.Items[ix].Name) - if err := podStorage.Pod.Storage.Create(ctx, key, &pods.Items[ix], nil, 0, false); err != nil { - t.Fatalf("Couldn't create pod: %v", err) - } + ctx := genericapirequest.NewDefaultContext() + for ix := range pods { + key, _ := podStorage.Pod.KeyFunc(ctx, pods[ix].Name) + if err := podStorage.Pod.Storage.Create(ctx, key, &pods[ix], nil, 0, false); err != nil { + t.Fatalf("Couldn't create pod: %v", err) } } endpointStorage, err := endpointstore.NewREST(generic.RESTOptions{ @@ -208,13 +198,10 @@ func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.P if err != nil { t.Fatalf("unexpected error from REST storage: %v", err) } - if endpoints != nil && len(endpoints.Items) > 0 { - ctx := genericapirequest.NewDefaultContext() - for ix := range endpoints.Items { - key, _ := endpointStorage.KeyFunc(ctx, endpoints.Items[ix].Name) - if err := endpointStorage.Store.Storage.Create(ctx, key, &endpoints.Items[ix], nil, 0, false); err != nil { - t.Fatalf("Couldn't create endpoint: %v", err) - } + for ix := range endpoints { + key, _ := endpointStorage.KeyFunc(ctx, endpoints[ix].Name) + if err := endpointStorage.Store.Storage.Create(ctx, key, endpoints[ix], nil, 0, false); err != nil { + t.Fatalf("Couldn't create endpoint: %v", err) } } @@ -254,7 +241,7 @@ func NewTestRESTWithPods(t *testing.T, endpoints *api.EndpointsList, pods *api.P rest, _ := NewREST(serviceStorage, endpointStorage, podStorage.Pod, rPrimary, rSecondary, portAllocator, nil) - return rest, serviceStorage, server + return rest, server } func makeIPNet(t *testing.T) *net.IPNet { @@ -272,23 +259,23 @@ func makeIPNet6(t *testing.T) *net.IPNet { return net } -func releaseServiceNodePorts(t *testing.T, ctx context.Context, svcName string, rest *REST, registry ServiceStorage) { - obj, err := registry.Get(ctx, svcName, &metav1.GetOptions{}) - if err != nil { - t.Errorf("Unexpected error: %v", err) +func ipIsAllocated(t *testing.T, alloc ipallocator.Interface, ipstr string) bool { + t.Helper() + ip := net.ParseIP(ipstr) + if ip == nil { + t.Errorf("error parsing IP %q", ipstr) + return false } - srv := obj.(*api.Service) - if srv == nil { - t.Fatalf("Failed to find service: %s", svcName) - } - serviceNodePorts := collectServiceNodePorts(srv) - if len(serviceNodePorts) == 0 { - t.Errorf("Failed to find NodePorts of service : %s", srv.Name) - } - for i := range serviceNodePorts { - nodePort := serviceNodePorts[i] - rest.serviceNodePorts.Release(nodePort) + return alloc.Has(ip) +} + +func portIsAllocated(t *testing.T, alloc portallocator.Interface, port int32) bool { + t.Helper() + if port == 0 { + t.Errorf("port is 0") + return false } + return alloc.Has(int(port)) } func TestServiceRegistryCreate(t *testing.T) { @@ -297,88 +284,30 @@ func TestServiceRegistryCreate(t *testing.T) { name string families []api.IPFamily enableDualStack bool - }{ - { - name: "Service IPFamily default cluster dualstack:off", - enableDualStack: false, - families: []api.IPFamily{api.IPv4Protocol}, - - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "Service IPFamily:v4 dualstack off", - enableDualStack: false, - families: []api.IPFamily{api.IPv4Protocol}, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "Service IPFamily:v4 dualstack on", - enableDualStack: true, - families: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "Service IPFamily:v6 dualstack on", - enableDualStack: true, - families: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - } + }{{ + name: "Service IPFamily default cluster dualstack:off", + enableDualStack: false, + families: []api.IPFamily{api.IPv4Protocol}, + svc: svctest.MakeService("foo"), + }, { + name: "Service IPFamily:v4 dualstack off", + enableDualStack: false, + families: []api.IPFamily{api.IPv4Protocol}, + svc: svctest.MakeService("foo", svctest.SetIPFamilies(api.IPv4Protocol)), + }, { + name: "Service IPFamily:v4 dualstack on", + enableDualStack: true, + families: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, + svc: svctest.MakeService("foo", svctest.SetIPFamilies(api.IPv4Protocol)), + }, { + name: "Service IPFamily:v6 dualstack on", + enableDualStack: true, + families: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, + svc: svctest.MakeService("foo", svctest.SetIPFamilies(api.IPv6Protocol)), + }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - storage, registry, server := NewTestREST(t, nil, tc.families) + storage, server := NewTestREST(t, tc.families) defer server.Terminate(t) ctx := genericapirequest.NewDefaultContext() @@ -409,7 +338,7 @@ func TestServiceRegistryCreate(t *testing.T) { t.Errorf("Unexpected ClusterIP: %s", createdService.Spec.ClusterIPs[i]) } } - srv, err := registry.GetService(ctx, tc.svc.Name, &metav1.GetOptions{}) + srv, err := getService(storage, ctx, tc.svc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -421,94 +350,35 @@ func TestServiceRegistryCreate(t *testing.T) { } func TestServiceRegistryCreateDryRun(t *testing.T) { - requireDualStack := api.IPFamilyPolicyRequireDualStack testCases := []struct { name string svc *api.Service enableDualStack bool - }{ - { - name: "v4 service featuregate off", - enableDualStack: false, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "v6 service featuregate on but singlestack", - enableDualStack: true, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "dualstack v4,v6 service", - enableDualStack: true, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4", "2000:0:0:0:0:0:0:1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "dualstack v6,v4 service", - enableDualStack: true, - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - } + }{{ + name: "v4 service featuregate off", + enableDualStack: false, + svc: svctest.MakeService("foo", svctest.SetClusterIPs("1.2.3.4")), + }, { + name: "v6 service featuregate on but singlestack", + enableDualStack: true, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol), + svctest.SetClusterIPs("2000::1")), + }, { + name: "dualstack v4,v6 service", + enableDualStack: true, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetClusterIPs("1.2.3.4", "2000::1")), + }, { + name: "dualstack v6,v4 service", + enableDualStack: true, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + svctest.SetClusterIPs("2000::1", "1.2.3.4")), + }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -518,7 +388,7 @@ func TestServiceRegistryCreateDryRun(t *testing.T) { if tc.enableDualStack { families = append(families, api.IPv6Protocol) } - storage, registry, server := NewTestREST(t, nil, families) + storage, server := NewTestREST(t, families) defer server.Terminate(t) ctx := genericapirequest.NewDefaultContext() @@ -529,235 +399,134 @@ func TestServiceRegistryCreateDryRun(t *testing.T) { for i, family := range tc.svc.Spec.IPFamilies { alloc := storage.serviceIPAllocatorsByFamily[family] - if alloc.Has(net.ParseIP(tc.svc.Spec.ClusterIPs[i])) { + if ipIsAllocated(t, alloc, tc.svc.Spec.ClusterIPs[i]) { t.Errorf("unexpected side effect: ip allocated %v", tc.svc.Spec.ClusterIPs[i]) } } - srv, err := registry.GetService(ctx, tc.svc.Name, &metav1.GetOptions{}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if srv != nil { - t.Errorf("unexpected service found: %v", srv) + _, err = getService(storage, ctx, tc.svc.Name, &metav1.GetOptions{}) + if err == nil { + t.Errorf("expected error") } }) } } func TestDryRunNodePort(t *testing.T) { - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) // Test dry run create request with a node port - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - NodePort: 30010, - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc := svctest.MakeService("foo", svctest.SetTypeNodePort) ctx := genericapirequest.NewDefaultContext() - _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } - if storage.serviceNodePorts.Has(30010) { + createdSvc := obj.(*api.Service) + if createdSvc.Spec.Ports[0].NodePort == 0 { + t.Errorf("expected NodePort value assigned") + } + if portIsAllocated(t, storage.serviceNodePorts, createdSvc.Spec.Ports[0].NodePort) { t.Errorf("unexpected side effect: NodePort allocated") } - srv, err := registry.GetService(ctx, svc.Name, &metav1.GetOptions{}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if srv != nil { - t.Errorf("unexpected service found: %v", srv) + _, err = getService(storage, ctx, svc.Name, &metav1.GetOptions{}) + if err == nil { + // Should get a not-found. + t.Errorf("expected error") } // Test dry run create request with multi node port - svc = &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - NodePort: 30053, - TargetPort: intstr.FromInt(6503), - Protocol: api.ProtocolTCP, - }, - { - Name: "port-udp", - Port: 53, - NodePort: 30053, - TargetPort: intstr.FromInt(6503), - Protocol: api.ProtocolUDP, - }, - }, - }, - } + svc = svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6503), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6503), api.ProtocolUDP)), + svctest.SetNodePorts(30053, 30053)) expectNodePorts := collectServiceNodePorts(svc) - createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) + obj, err = storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } - createdService := createdSvc.(*api.Service) - serviceNodePorts := collectServiceNodePorts(createdService) - if !reflect.DeepEqual(serviceNodePorts, expectNodePorts) { - t.Errorf("Expected %v, but got %v", expectNodePorts, serviceNodePorts) + createdSvc = obj.(*api.Service) + actualNodePorts := collectServiceNodePorts(createdSvc) + if !reflect.DeepEqual(actualNodePorts, expectNodePorts) { + t.Errorf("Expected %v, but got %v", expectNodePorts, actualNodePorts) } - if storage.serviceNodePorts.Has(30053) { - t.Errorf("unexpected side effect: NodePort allocated") + for i := range svc.Spec.Ports { + if portIsAllocated(t, storage.serviceNodePorts, svc.Spec.Ports[i].NodePort) { + t.Errorf("unexpected side effect: NodePort allocated") + } } - srv, err = registry.GetService(ctx, svc.Name, &metav1.GetOptions{}) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if srv != nil { - t.Errorf("unexpected service found: %v", srv) + _, err = getService(storage, ctx, svc.Name, &metav1.GetOptions{}) + if err == nil { + // Should get a not-found. + t.Errorf("expected error") } // Test dry run create request with multiple unspecified node ports, // so PortAllocationOperation.AllocateNext() will be called multiple times. - svc = &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-a", - Port: 53, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6503), - }, - { - Name: "port-b", - Port: 54, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6504), - }, - }, - }, - } - createdSvc, err = storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) + svc = svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-a", 53, intstr.FromInt(6503), api.ProtocolTCP), + svctest.MakeServicePort("port-b", 54, intstr.FromInt(6504), api.ProtocolUDP))) + obj, err = storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } - createdService = createdSvc.(*api.Service) - serviceNodePorts = collectServiceNodePorts(createdService) - if len(serviceNodePorts) != 2 { - t.Errorf("Expected service to have 2 ports, but got %v", serviceNodePorts) - } else if serviceNodePorts[0] == serviceNodePorts[1] { - t.Errorf("Expected unique port numbers, but got %v", serviceNodePorts) + createdSvc = obj.(*api.Service) + actualNodePorts = collectServiceNodePorts(createdSvc) + if len(actualNodePorts) != len(svc.Spec.Ports) { + t.Fatalf("Expected service to have %d ports, but got %v", len(svc.Spec.Ports), actualNodePorts) + } + seen := map[int]bool{} + for _, np := range actualNodePorts { + if seen[np] { + t.Errorf("Expected unique port numbers, but got %v", actualNodePorts) + } else { + seen[np] = true + } } } func TestServiceRegistryCreateMultiNodePortsService(t *testing.T) { - - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) testCases := []struct { svc *api.Service name string expectNodePorts []int - }{ - { - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - NodePort: 30053, - TargetPort: intstr.FromInt(6503), - Protocol: api.ProtocolTCP, - }, - { - Name: "port-udp", - Port: 53, - NodePort: 30053, - TargetPort: intstr.FromInt(6503), - Protocol: api.ProtocolUDP, - }, - }, - }, - }, - name: "foo1", - expectNodePorts: []int{30053, 30053}, - }, - { - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo2"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 54, - TargetPort: intstr.FromInt(6504), - Protocol: api.ProtocolTCP, - }, - { - Name: "port-udp", - Port: 54, - NodePort: 30054, - TargetPort: intstr.FromInt(6504), - Protocol: api.ProtocolUDP, - }, - }, - }, - }, - name: "foo2", - expectNodePorts: []int{30054, 30054}, - }, - { - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo3"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 55, - NodePort: 30055, - TargetPort: intstr.FromInt(6505), - Protocol: api.ProtocolTCP, - }, - { - Name: "port-udp", - Port: 55, - NodePort: 30056, - TargetPort: intstr.FromInt(6506), - Protocol: api.ProtocolUDP, - }, - }, - }, - }, - name: "foo3", - expectNodePorts: []int{30055, 30056}, - }, - } + }{{ + svc: svctest.MakeService("foo1", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6503), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6503), api.ProtocolUDP)), + svctest.SetNodePorts(30053, 30053)), + name: "foo1", + expectNodePorts: []int{30053, 30053}, + }, { + svc: svctest.MakeService("foo2", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 54, intstr.FromInt(6504), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 54, intstr.FromInt(6504), api.ProtocolUDP)), + svctest.SetNodePorts(30054, 30054)), + name: "foo2", + expectNodePorts: []int{30054, 30054}, + }, { + svc: svctest.MakeService("foo3", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 55, intstr.FromInt(6505), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 55, intstr.FromInt(6506), api.ProtocolUDP)), + svctest.SetNodePorts(30055, 30056)), + name: "foo3", + expectNodePorts: []int{30055, 30056}, + }} ctx := genericapirequest.NewDefaultContext() for _, test := range testCases { @@ -780,7 +549,7 @@ func TestServiceRegistryCreateMultiNodePortsService(t *testing.T) { if !reflect.DeepEqual(serviceNodePorts, test.expectNodePorts) { t.Errorf("Expected %v, but got %v", test.expectNodePorts, serviceNodePorts) } - srv, err := registry.GetService(ctx, test.name, &metav1.GetOptions{}) + srv, err := getService(storage, ctx, test.name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -796,49 +565,18 @@ func TestServiceRegistryCreateMultiNodePortsService(t *testing.T) { } func TestServiceStorageValidatesCreate(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - failureCases := map[string]api.Service{ - "empty ID": { - ObjectMeta: metav1.ObjectMeta{Name: ""}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - "empty port": { - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Protocol: api.ProtocolTCP, - }}, - }, - }, - "missing targetPort": { - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - }}, - }, - }, + failureCases := map[string]*api.Service{ + "empty ID": svctest.MakeService(""), + "empty port": svctest.MakeService("foo", svctest.SetPorts( + svctest.MakeServicePort("p", 0, intstr.FromInt(80), api.ProtocolTCP))), + "missing targetPort": svctest.MakeService("foo", svctest.SetPorts( + svctest.MakeServicePort("p", 80, intstr.IntOrString{}, api.ProtocolTCP))), } ctx := genericapirequest.NewDefaultContext() for _, failureCase := range failureCases { - c, err := storage.Create(ctx, &failureCase, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + c, err := storage.Create(ctx, failureCase, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if c != nil { t.Errorf("Expected nil object") } @@ -850,22 +588,10 @@ func TestServiceStorageValidatesCreate(t *testing.T) { func TestServiceRegistryUpdate(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, []api.IPFamily{api.IPv4Protocol}) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - _, err := registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - SessionAffinity: api.ServiceAffinityNone, - Selector: map[string]string{"bar": "baz1"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + _, err := storage.Create(ctx, svctest.MakeService("foo"), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("Expected no error: %v", err) } @@ -893,257 +619,129 @@ func TestServiceRegistryUpdate(t *testing.T) { if updatedService.Name != "foo" { t.Errorf("Expected foo, but got %v", updatedService.Name) } - if e, a := "foo", registry.UpdatedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) - } } func TestServiceRegistryUpdateDryRun(t *testing.T) { - ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - obj, err := registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeExternalName, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err := storage.Create(ctx, svctest.MakeService("foo", svctest.SetTypeExternalName), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("Expected no error: %v", err) } svc := obj.(*api.Service) // Test dry run update request external name to node port - updatedSvc, created, err := storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(&api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: svc.Name, - ResourceVersion: svc.ResourceVersion}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - NodePort: 30020, - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) + new1 := svc.DeepCopy() + svctest.SetTypeNodePort(new1) + svctest.SetNodePorts(30001)(new1) // DryRun does not set port values yet + obj, created, err := storage.Update(ctx, new1.Name, rest.DefaultUpdatedObjectInfo(new1), + rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Expected no error: %v", err) } - if updatedSvc == nil { + if obj == nil { t.Errorf("Expected non-nil object") } if created { t.Errorf("expected not created") } - if storage.serviceNodePorts.Has(30020) { + if portIsAllocated(t, storage.serviceNodePorts, new1.Spec.Ports[0].NodePort) { t.Errorf("unexpected side effect: NodePort allocated") } - if e, a := "", registry.UpdatedID; e != a { - t.Errorf("Expected %q, but got %q", e, a) - } // Test dry run update request external name to cluster ip - _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(&api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: svc.Name, - ResourceVersion: svc.ResourceVersion}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) + new2 := svc.DeepCopy() + svctest.SetTypeClusterIP(new2) + svctest.SetClusterIPs("1.2.3.4")(new2) // DryRun does not set IP values yet + _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(new2), + rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Expected no error: %v", err) } - if storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].Has(net.ParseIP("1.2.3.4")) { + if ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily], new2.Spec.ClusterIP) { t.Errorf("unexpected side effect: ip allocated") } // Test dry run update request remove node port - obj, err = storage.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo2", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - ClusterIP: "1.2.3.5", - ClusterIPs: []string{"1.2.3.5"}, - Ports: []api.ServicePort{{ - NodePort: 30020, - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err = storage.Create(ctx, svctest.MakeService("foo2", svctest.SetTypeNodePort, svctest.SetNodePorts(30001)), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("Expected no error: %v", err) } svc = obj.(*api.Service) + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily], svc.Spec.ClusterIP) { + t.Errorf("expected IP to be allocated") + } + if !portIsAllocated(t, storage.serviceNodePorts, svc.Spec.Ports[0].NodePort) { + t.Errorf("expected NodePort to be allocated") + } - _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(&api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: svc.Name, - ResourceVersion: svc.ResourceVersion}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeExternalName, - ExternalName: "foo-svc", - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) + new3 := svc.DeepCopy() + svctest.SetTypeExternalName(new3) + _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(new3), + rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Expected no error: %v", err) } - if !storage.serviceNodePorts.Has(30020) { + if !portIsAllocated(t, storage.serviceNodePorts, svc.Spec.Ports[0].NodePort) { t.Errorf("unexpected side effect: NodePort unallocated") } // Test dry run update request remove cluster ip - obj, err = storage.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo3", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err = storage.Create(ctx, svctest.MakeService("foo3", svctest.SetClusterIPs("1.2.3.4")), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { - t.Fatalf("Expected no error: %v", err) + t.Fatalf("expected no error: %v", err) } svc = obj.(*api.Service) - _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(&api.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: svc.Name, - ResourceVersion: svc.ResourceVersion}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeExternalName, - ExternalName: "foo-svc", - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) + + new4 := svc.DeepCopy() + svctest.SetTypeExternalName(new4) + _, _, err = storage.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(new4), + rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { - t.Fatalf("Expected no error: %v", err) + t.Fatalf("expected no error: %v", err) } - if !storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].Has(net.ParseIP("1.2.3.4")) { + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily], svc.Spec.ClusterIP) { t.Errorf("unexpected side effect: ip unallocated") } } func TestServiceStorageValidatesUpdate(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - }}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - failureCases := map[string]api.Service{ - "empty ID": { - ObjectMeta: metav1.ObjectMeta{Name: ""}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - "invalid selector": { - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"ThisSelectorFailsValidation": "ok"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + _, err := storage.Create(ctx, svctest.MakeService("foo"), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + failureCases := map[string]*api.Service{ + "empty ID": svctest.MakeService(""), + "invalid selector": svctest.MakeService("", func(svc *api.Service) { + svc.Spec.Selector = map[string]string{"ThisSelectorFailsValidation": "ok"} + }), } for _, failureCase := range failureCases { - c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(&failureCase), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(failureCase), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + if err == nil { + t.Errorf("expected error") + } if c != nil || created { t.Errorf("Expected nil object or created false") } - if !errors.IsInvalid(err) { - t.Errorf("Expected to get an invalid resource error, got %v", err) - } } } -func TestServiceRegistryExternalService(t *testing.T) { +func TestServiceRegistryLoadBalancerService(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc := svctest.MakeService("foo", svctest.SetTypeLoadBalancer) _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Errorf("Failed to create service: %#v", err) } - srv, err := registry.GetService(ctx, svc.Name, &metav1.GetOptions{}) + srv, err := getService(storage, ctx, svc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -1154,142 +752,53 @@ func TestServiceRegistryExternalService(t *testing.T) { if len(serviceNodePorts) == 0 { t.Errorf("Failed to find NodePorts of service : %s", srv.Name) } - for i := range serviceNodePorts { - nodePort := serviceNodePorts[i] - // Release the node port at the end of the test case. - storage.serviceNodePorts.Release(nodePort) - } } + func TestAllocateLoadBalancerNodePorts(t *testing.T) { + setAlloc := func(val bool) svctest.Tweak { + return func(s *api.Service) { + s.Spec.AllocateLoadBalancerNodePorts = utilpointer.BoolPtr(val) + } + } + testcases := []struct { name string svc *api.Service expectNodePorts bool allocateNodePortGate bool expectError bool - }{ - { - name: "allocate nil, gate on", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-nil"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: nil, - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: true, - allocateNodePortGate: true, - expectError: true, - }, - { - name: "allocate false, gate on", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-false"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(false), - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: false, - allocateNodePortGate: true, - }, - { - name: "allocate true, gate on", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-true"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(true), - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: true, - allocateNodePortGate: true, - }, - { - name: "allocate nil, gate off", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-false"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: nil, - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: true, - allocateNodePortGate: false, - }, - { - name: "allocate false, gate off", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-false"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(false), - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: true, - allocateNodePortGate: false, - }, - { - name: "allocate true, gate off", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "alloc-true"}, - Spec: api.ServiceSpec{ - AllocateLoadBalancerNodePorts: utilpointer.BoolPtr(true), - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectNodePorts: true, - allocateNodePortGate: false, - }, - } + }{{ + name: "allocate false, gate on", + svc: svctest.MakeService("alloc-false", svctest.SetTypeLoadBalancer, setAlloc(false)), + expectNodePorts: false, + allocateNodePortGate: true, + }, { + name: "allocate true, gate on", + svc: svctest.MakeService("alloc-true", svctest.SetTypeLoadBalancer, setAlloc(true)), + expectNodePorts: true, + allocateNodePortGate: true, + }, { + name: "allocate nil, gate off", + svc: svctest.MakeService("alloc-nil", svctest.SetTypeLoadBalancer), + expectNodePorts: true, + allocateNodePortGate: false, + }, { + name: "allocate false, gate off", + svc: svctest.MakeService("alloc-false", svctest.SetTypeLoadBalancer, setAlloc(false)), + expectNodePorts: true, + allocateNodePortGate: false, + }, { + name: "allocate true, gate off", + svc: svctest.MakeService("alloc-true", svctest.SetTypeLoadBalancer, setAlloc(true)), + expectNodePorts: true, + allocateNodePortGate: false, + }} for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { ctx := genericapirequest.NewDefaultContext() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLBNodePortControl, tc.allocateNodePortGate)() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) _, err := storage.Create(ctx, tc.svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) @@ -1299,7 +808,7 @@ func TestAllocateLoadBalancerNodePorts(t *testing.T) { } t.Errorf("%s; Failed to create service: %#v", tc.name, err) } - srv, err := registry.GetService(ctx, tc.svc.Name, &metav1.GetOptions{}) + srv, err := getService(storage, ctx, tc.svc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("%s; Unexpected error: %v", tc.name, err) } @@ -1310,94 +819,64 @@ func TestAllocateLoadBalancerNodePorts(t *testing.T) { if (len(serviceNodePorts) != 0) != tc.expectNodePorts { t.Errorf("%s; Allocated NodePorts not as expected", tc.name) } - - for i := range serviceNodePorts { - nodePort := serviceNodePorts[i] - // Release the node port at the end of the test case. - storage.serviceNodePorts.Release(nodePort) - } }) } } func TestServiceRegistryDelete(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - }}, - }, + svc := svctest.MakeService("foo") + _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) } - registry.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - storage.Delete(ctx, svc.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) - if e, a := "foo", registry.DeletedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) + _, _, err = storage.Delete(ctx, svc.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) } } func TestServiceRegistryDeleteDryRun(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) // Test dry run delete request with cluster ip - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } - _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + svc := svctest.MakeService("foo") + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("Expected no error: %v", err) } + createdSvc := obj.(*api.Service) + if createdSvc.Spec.ClusterIP == "" { + t.Fatalf("expected ClusterIP to be set") + } + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily], createdSvc.Spec.ClusterIP) { + t.Errorf("expected ClusterIP to be allocated") + } _, _, err = storage.Delete(ctx, svc.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{DryRun: []string{metav1.DryRunAll}}) if err != nil { t.Fatalf("Expected no error: %v", err) } - if e, a := "", registry.DeletedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - if !storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].Has(net.ParseIP("1.2.3.4")) { + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily], createdSvc.Spec.ClusterIP) { t.Errorf("unexpected side effect: ip unallocated") } // Test dry run delete request with node port - svc = &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo2"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - NodePort: 30030, - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } - _, err = storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + svc = svctest.MakeService("foo2", svctest.SetTypeNodePort) + obj, err = storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("Expected no error: %v", err) } + createdSvc = obj.(*api.Service) + if createdSvc.Spec.Ports[0].NodePort == 0 { + t.Fatalf("expected NodePort to be set") + } + if !portIsAllocated(t, storage.serviceNodePorts, createdSvc.Spec.Ports[0].NodePort) { + t.Errorf("expected NodePort to be allocated") + } isValidClusterIPFields(t, storage, svc, svc) @@ -1405,10 +884,7 @@ func TestServiceRegistryDeleteDryRun(t *testing.T) { if err != nil { t.Fatalf("Expected no error: %v", err) } - if e, a := "", registry.DeletedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - if !storage.serviceNodePorts.Has(30030) { + if !portIsAllocated(t, storage.serviceNodePorts, createdSvc.Spec.Ports[0].NodePort) { t.Errorf("unexpected side effect: NodePort unallocated") } } @@ -1418,27 +894,13 @@ func TestDualStackServiceRegistryDeleteDryRun(t *testing.T) { // dry run for non dualstack defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, true)() - dualstack_storage, dualstack_registry, dualstack_server := NewTestREST(t, nil, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) + dualstack_storage, dualstack_server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) defer dualstack_server.Terminate(t) - requireDualStack := api.IPFamilyPolicyRequireDualStack // Test dry run delete request with cluster ip - dualstack_svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + dualstack_svc := svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1", "1.2.3.4")) _, err := dualstack_storage.Create(ctx, dualstack_svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { @@ -1449,69 +911,46 @@ func TestDualStackServiceRegistryDeleteDryRun(t *testing.T) { if err != nil { t.Fatalf("Expected no error: %v", err) } - if e, a := "", dualstack_registry.DeletedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) - } for i, family := range dualstack_svc.Spec.IPFamilies { - if !dualstack_storage.serviceIPAllocatorsByFamily[family].Has(net.ParseIP(dualstack_svc.Spec.ClusterIPs[i])) { + if !ipIsAllocated(t, dualstack_storage.serviceIPAllocatorsByFamily[family], dualstack_svc.Spec.ClusterIPs[i]) { t.Errorf("unexpected side effect: ip unallocated %v", dualstack_svc.Spec.ClusterIPs[i]) } } } -func TestServiceRegistryDeleteExternal(t *testing.T) { +func TestServiceRegistryDeleteExternalName(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - }}, - }, + svc := svctest.MakeService("foo", svctest.SetTypeExternalName) + _, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) } - registry.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - storage.Delete(ctx, svc.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) - if e, a := "foo", registry.DeletedID; e != a { - t.Errorf("Expected %v, but got %v", e, a) + _, _, err = storage.Delete(ctx, svc.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) + if err != nil { + t.Fatalf("Expected no error: %v", err) } } -func TestServiceRegistryUpdateExternalService(t *testing.T) { +func TestServiceRegistryUpdateLoadBalancerService(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - // Create non-external load balancer. - svc1 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } - if _, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { + // Create non-loadbalancer. + svc1 := svctest.MakeService("foo") + obj, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { t.Fatalf("Unexpected error: %v", err) } - // Modify load balancer to be external. - svc2 := svc1.DeepCopy() + // Modify to be loadbalancer. + svc2 := obj.(*api.Service).DeepCopy() svc2.Spec.Type = api.ServiceTypeLoadBalancer if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil { t.Fatalf("Unexpected error: %v", err) } - defer releaseServiceNodePorts(t, ctx, svc2.Name, storage, registry) // Change port. svc3 := svc2.DeepCopy() @@ -1521,38 +960,24 @@ func TestServiceRegistryUpdateExternalService(t *testing.T) { } } -func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) { +func TestServiceRegistryUpdateMultiPortLoadBalancerService(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - // Create external load balancer. - svc1 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Name: "p", - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }, { - Name: "q", - Port: 8086, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(8086), - }}, - }, - } - if _, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { + // Create load balancer. + svc1 := svctest.MakeService("foo", + svctest.SetTypeLoadBalancer, + svctest.SetPorts( + svctest.MakeServicePort("p", 6502, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("q", 8086, intstr.FromInt(8086), api.ProtocolTCP))) + obj, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { t.Fatalf("Unexpected error: %v", err) } - defer releaseServiceNodePorts(t, ctx, svc1.Name, storage, registry) // Modify ports - svc2 := svc1.DeepCopy() + svc2 := obj.(*api.Service).DeepCopy() svc2.Spec.Ports[1].Port = 8088 if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil { t.Fatalf("Unexpected error: %v", err) @@ -1561,273 +986,186 @@ func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) { func TestServiceRegistryGet(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - storage.Get(ctx, "foo", &metav1.GetOptions{}) - if e, a := "foo", registry.GottenID; e != a { + _, err := storage.Create(ctx, svctest.MakeService("foo"), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("error creating service: %v", err) + } + obj, _ := storage.Get(ctx, "foo", &metav1.GetOptions{}) + svc := obj.(*api.Service) + if e, a := "foo", svc.Name; e != a { t.Errorf("Expected %v, but got %v", e, a) } } -func TestServiceRegistryResourceLocation(t *testing.T) { - ctx := genericapirequest.NewDefaultContext() - endpoints := &api.EndpointsList{ - Items: []api.Endpoints{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "bad", - Namespace: metav1.NamespaceDefault, - }, - Subsets: []api.EndpointSubset{{ - Addresses: []api.EndpointAddress{ - {IP: "1.2.3.4", TargetRef: &api.ObjectReference{Name: "foo", Namespace: "doesn't exist"}}, - {IP: "1.2.3.4", TargetRef: &api.ObjectReference{Name: "doesn't exist", Namespace: metav1.NamespaceDefault}}, - {IP: "23.2.3.4", TargetRef: &api.ObjectReference{Name: "foo", Namespace: metav1.NamespaceDefault}}, - }, - Ports: []api.EndpointPort{{Name: "", Port: 80}, {Name: "p", Port: 93}}, - }}, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: metav1.NamespaceDefault, - }, - Subsets: []api.EndpointSubset{{ - Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &api.ObjectReference{Name: "foo", Namespace: metav1.NamespaceDefault}}}, - Ports: []api.EndpointPort{{Name: "", Port: 80}, {Name: "p", Port: 93}}, - }}, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo-second-ip", - Namespace: metav1.NamespaceDefault, - }, - Subsets: []api.EndpointSubset{{ - Addresses: []api.EndpointAddress{{IP: "2001:db7::", TargetRef: &api.ObjectReference{Name: "foo", Namespace: metav1.NamespaceDefault}}}, - Ports: []api.EndpointPort{{Name: "", Port: 80}, {Name: "p", Port: 93}}, - }}, - }, +// this is local because it's not fully fleshed out enough for general use. +func makePod(name string, ips ...string) api.Pod { + p := api.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: metav1.NamespaceDefault, + }, + Spec: api.PodSpec{ + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSDefault, + Containers: []api.Container{{Name: "ctr", Image: "img", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePolicy: api.TerminationMessageReadFile}}, + }, + Status: api.PodStatus{ + PodIPs: []api.PodIP{}, }, } - pods := &api.PodList{ - Items: []api.Pod{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: metav1.NamespaceDefault, - }, - Spec: api.PodSpec{ - RestartPolicy: "Always", - DNSPolicy: "Default", - Containers: []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, - Status: api.PodStatus{ - PodIPs: []api.PodIP{{IP: "1.2.3.4"}, {IP: "2001:db7::"}}, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: metav1.NamespaceDefault, - }, - Spec: api.PodSpec{ - RestartPolicy: "Always", - DNSPolicy: "Default", - Containers: []api.Container{{Name: "bar", Image: "test", ImagePullPolicy: api.PullIfNotPresent, TerminationMessagePolicy: api.TerminationMessageReadFile}}, - }, - Status: api.PodStatus{ - PodIPs: []api.PodIP{{IP: "1.2.3.5"}, {IP: "2001:db8::"}}, - }, - }, - }, - } - storage, registry, server := NewTestRESTWithPods(t, endpoints, pods, singleStackIPv4) - defer server.Terminate(t) - for _, name := range []string{"foo", "bad"} { - registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: name}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Ports: []api.ServicePort{ - // Service port 9393 should route to endpoint port "p", which is port 93 - {Name: "p", Port: 9393, TargetPort: intstr.FromString("p")}, - // Service port 93 should route to unnamed endpoint port, which is port 80 - // This is to test that the service port definition is used when determining resource location - {Name: "", Port: 93, TargetPort: intstr.FromInt(80)}, - }, + for _, ip := range ips { + p.Status.PodIPs = append(p.Status.PodIPs, api.PodIP{IP: ip}) + } + + return p +} + +func TestServiceRegistryResourceLocation(t *testing.T) { + pods := []api.Pod{ + makePod("unnamed", "1.2.3.4", "1.2.3.5"), + makePod("named", "1.2.3.6", "1.2.3.7"), + makePod("no-endpoints", "9.9.9.9"), // to prove this does not get chosen + } + + endpoints := []*api.Endpoints{ + epstest.MakeEndpoints("unnamed", + []api.EndpointAddress{ + epstest.MakeEndpointAddress("1.2.3.4", "unnamed"), }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + []api.EndpointPort{ + epstest.MakeEndpointPort("", 80), + }), + epstest.MakeEndpoints("unnamed2", + []api.EndpointAddress{ + epstest.MakeEndpointAddress("1.2.3.5", "unnamed"), + }, + []api.EndpointPort{ + epstest.MakeEndpointPort("", 80), + }), + epstest.MakeEndpoints("named", + []api.EndpointAddress{ + epstest.MakeEndpointAddress("1.2.3.6", "named"), + }, + []api.EndpointPort{ + epstest.MakeEndpointPort("p", 80), + epstest.MakeEndpointPort("q", 81), + }), + epstest.MakeEndpoints("no-endpoints", nil, nil), // to prove this does not get chosen + } + + storage, server := NewTestRESTWithPods(t, endpoints, pods, []api.IPFamily{api.IPv4Protocol}) + defer server.Terminate(t) + + ctx := genericapirequest.NewDefaultContext() + for _, name := range []string{"unnamed", "unnamed2", "no-endpoints"} { + _, err := storage.Create(ctx, + svctest.MakeService(name, svctest.SetPorts( + svctest.MakeServicePort("", 93, intstr.FromInt(80), api.ProtocolTCP))), + rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error creating service %q: %v", name, err) + } + + } + _, err := storage.Create(ctx, + svctest.MakeService("named", svctest.SetPorts( + svctest.MakeServicePort("p", 93, intstr.FromInt(80), api.ProtocolTCP), + svctest.MakeServicePort("q", 76, intstr.FromInt(81), api.ProtocolTCP))), + rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error creating service %q: %v", "named", err) } redirector := rest.Redirector(storage) - // Test a simple id. - location, _, err := redirector.ResourceLocation(ctx, "foo") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//1.2.3.4:80", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a simple id (using second ip). - location, _, err = redirector.ResourceLocation(ctx, "foo-second-ip") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//[2001:db7::]:80", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port. - location, _, err = redirector.ResourceLocation(ctx, "foo:p") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//1.2.3.4:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port (using second ip). - location, _, err = redirector.ResourceLocation(ctx, "foo-second-ip:p") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//[2001:db7::]:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port number (service port 93 -> target port 80) - location, _, err = redirector.ResourceLocation(ctx, "foo:93") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//1.2.3.4:80", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port number (service port 93 -> target port 80, using second ip) - location, _, err = redirector.ResourceLocation(ctx, "foo-second-ip:93") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//[2001:db7::]:80", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port number (service port 9393 -> target port "p" -> endpoint port 93) - location, _, err = redirector.ResourceLocation(ctx, "foo:9393") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//1.2.3.4:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a name + port number (service port 9393 -> target port "p" -> endpoint port 93, using second ip) - location, _, err = redirector.ResourceLocation(ctx, "foo-second-ip:9393") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "//[2001:db7::]:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a scheme + name + port. - location, _, err = redirector.ResourceLocation(ctx, "https:foo:p") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "https://1.2.3.4:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a scheme + name + port (using second ip). - location, _, err = redirector.ResourceLocation(ctx, "https:foo-second-ip:p") - if err != nil { - t.Errorf("Unexpected error: %v", err) - } - if location == nil { - t.Errorf("Unexpected nil: %v", location) - } - if e, a := "https://[2001:db7::]:93", location.String(); e != a { - t.Errorf("Expected %v, but got %v", e, a) - } - - // Test a non-existent name + port. - _, _, err = redirector.ResourceLocation(ctx, "foo:q") - if err == nil { - t.Errorf("Unexpected nil error") - } - - // Test a non-existent name + port (using second ip). - _, _, err = redirector.ResourceLocation(ctx, "foo-second-ip:q") - if err == nil { - t.Errorf("Unexpected nil error") - } - - // Test error path - if _, _, err = redirector.ResourceLocation(ctx, "bar"); err == nil { - t.Errorf("unexpected nil error") - } - - // Test a simple id. - _, _, err = redirector.ResourceLocation(ctx, "bad") - if err == nil { - t.Errorf("Unexpected nil error") + cases := []struct { + query string + err bool + expect string + }{{ + query: "unnamed", + expect: "//1.2.3.4:80", + }, { + query: "unnamed:", + expect: "//1.2.3.4:80", + }, { + query: "unnamed:93", + expect: "//1.2.3.4:80", + }, { + query: "http:unnamed:", + expect: "http://1.2.3.4:80", + }, { + query: "http:unnamed:93", + expect: "http://1.2.3.4:80", + }, { + query: "unnamed:80", + err: true, + }, { + query: "unnamed2", + expect: "//1.2.3.5:80", + }, { + query: "named:p", + expect: "//1.2.3.6:80", + }, { + query: "named:q", + expect: "//1.2.3.6:81", + }, { + query: "named:93", + expect: "//1.2.3.6:80", + }, { + query: "named:76", + expect: "//1.2.3.6:81", + }, { + query: "http:named:p", + expect: "http://1.2.3.6:80", + }, { + query: "http:named:q", + expect: "http://1.2.3.6:81", + }, { + query: "named:bad", + err: true, + }, { + query: "no-endpoints", + err: true, + }, { + query: "non-existent", + err: true, + }} + for _, tc := range cases { + t.Run(tc.query, func(t *testing.T) { + location, _, err := redirector.ResourceLocation(ctx, tc.query) + if tc.err == false && err != nil { + t.Fatalf("unexpected error: %v", err) + } + if tc.err == true && err == nil { + t.Fatalf("unexpected success") + } + if !tc.err { + if location == nil { + t.Errorf("unexpected location: %v", location) + } + if e, a := tc.expect, location.String(); e != a { + t.Errorf("expected %q, but got %q", e, a) + } + } + }) } } func TestServiceRegistryList(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - registry.Create(ctx, &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo2", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar2": "baz2"}, - }, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - registry.ServiceList.ResourceVersion = "1" + _, err := storage.Create(ctx, svctest.MakeService("foo"), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + _, err = storage.Create(ctx, svctest.MakeService("foo2"), rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } s, _ := storage.List(ctx, nil) sl := s.(*api.ServiceList) if len(sl.Items) != 2 { @@ -1839,173 +1177,112 @@ func TestServiceRegistryList(t *testing.T) { if e, a := "foo2", sl.Items[1].Name; e != a { t.Errorf("Expected %v, but got %v", e, a) } - if sl.ResourceVersion != "1" { - t.Errorf("Unexpected resource version: %#v", sl) - } } func TestServiceRegistryIPAllocation(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc1 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc1 := svctest.MakeService("foo") ctx := genericapirequest.NewDefaultContext() - createdSvc1, _ := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - createdService1 := createdSvc1.(*api.Service) - if createdService1.Name != "foo" { - t.Errorf("Expected foo, but got %v", createdService1.Name) + obj, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("error creating service: %v", err) } - if !makeIPNet(t).Contains(net.ParseIP(createdService1.Spec.ClusterIPs[0])) { - t.Errorf("Unexpected ClusterIP: %s", createdService1.Spec.ClusterIPs[0]) + createdSvc1 := obj.(*api.Service) + if createdSvc1.Name != "foo" { + t.Errorf("Expected foo, but got %v", createdSvc1.Name) + } + if !makeIPNet(t).Contains(net.ParseIP(createdSvc1.Spec.ClusterIPs[0])) { + t.Errorf("Unexpected ClusterIP: %s", createdSvc1.Spec.ClusterIPs[0]) } - svc2 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }} + svc2 := svctest.MakeService("bar") ctx = genericapirequest.NewDefaultContext() - createdSvc2, _ := storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - createdService2 := createdSvc2.(*api.Service) - if createdService2.Name != "bar" { - t.Errorf("Expected bar, but got %v", createdService2.Name) + obj, err = storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("error creating service: %v", err) } - if !makeIPNet(t).Contains(net.ParseIP(createdService2.Spec.ClusterIPs[0])) { - t.Errorf("Unexpected ClusterIP: %s", createdService2.Spec.ClusterIPs[0]) + createdSvc2 := obj.(*api.Service) + if createdSvc2.Name != "bar" { + t.Errorf("Expected bar, but got %v", createdSvc2.Name) + } + if !makeIPNet(t).Contains(net.ParseIP(createdSvc2.Spec.ClusterIPs[0])) { + t.Errorf("Unexpected ClusterIP: %s", createdSvc2.Spec.ClusterIPs[0]) } testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"} - testIP := "" + testIP := "not-an-ip" for _, ip := range testIPs { - if !storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].(*ipallocator.Range).Has(net.ParseIP(ip)) { + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].(*ipallocator.Range), ip) { testIP = ip break } } - svc3 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "quux"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - ClusterIP: testIP, - ClusterIPs: []string{testIP}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc3 := svctest.MakeService("qux", svctest.SetClusterIPs(testIP)) ctx = genericapirequest.NewDefaultContext() - createdSvc3, err := storage.Create(ctx, svc3, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err = storage.Create(ctx, svc3, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatal(err) } - createdService3 := createdSvc3.(*api.Service) - if createdService3.Spec.ClusterIPs[0] != testIP { // specific IP - t.Errorf("Unexpected ClusterIP: %s", createdService3.Spec.ClusterIPs[0]) + createdSvc3 := obj.(*api.Service) + if createdSvc3.Spec.ClusterIPs[0] != testIP { // specific IP + t.Errorf("Unexpected ClusterIP: %s", createdSvc3.Spec.ClusterIPs[0]) } } func TestServiceRegistryIPReallocation(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc1 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc1 := svctest.MakeService("foo") ctx := genericapirequest.NewDefaultContext() - createdSvc1, _ := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - createdService1 := createdSvc1.(*api.Service) - if createdService1.Name != "foo" { - t.Errorf("Expected foo, but got %v", createdService1.Name) + obj, err := storage.Create(ctx, svc1, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("error creating service: %v", err) } - if !makeIPNet(t).Contains(net.ParseIP(createdService1.Spec.ClusterIPs[0])) { - t.Errorf("Unexpected ClusterIP: %s", createdService1.Spec.ClusterIPs[0]) + createdSvc1 := obj.(*api.Service) + if createdSvc1.Name != "foo" { + t.Errorf("Expected foo, but got %v", createdSvc1.Name) + } + if !makeIPNet(t).Contains(net.ParseIP(createdSvc1.Spec.ClusterIPs[0])) { + t.Errorf("Unexpected ClusterIP: %s", createdSvc1.Spec.ClusterIPs[0]) } - _, _, err := storage.Delete(ctx, createdService1.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) + _, _, err = storage.Delete(ctx, createdSvc1.Name, rest.ValidateAllObjectFunc, &metav1.DeleteOptions{}) if err != nil { t.Errorf("Unexpected error deleting service: %v", err) } - svc2 := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "bar"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc2 := svctest.MakeService("bar", svctest.SetClusterIPs(svc1.Spec.ClusterIP)) ctx = genericapirequest.NewDefaultContext() - createdSvc2, _ := storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - createdService2 := createdSvc2.(*api.Service) - if createdService2.Name != "bar" { - t.Errorf("Expected bar, but got %v", createdService2.Name) + obj, err = storage.Create(ctx, svc2, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("error creating service: %v", err) } - if !makeIPNet(t).Contains(net.ParseIP(createdService2.Spec.ClusterIPs[0])) { - t.Errorf("Unexpected ClusterIP: %s", createdService2.Spec.ClusterIPs[0]) + createdSvc2 := obj.(*api.Service) + if createdSvc2.Name != "bar" { + t.Errorf("Expected bar, but got %v", createdSvc2.Name) + } + if !makeIPNet(t).Contains(net.ParseIP(createdSvc2.Spec.ClusterIPs[0])) { + t.Errorf("Unexpected ClusterIP: %s", createdSvc2.Spec.ClusterIPs[0]) } } func TestServiceRegistryIPUpdate(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc := svctest.MakeService("foo") ctx := genericapirequest.NewDefaultContext() - createdSvc, _ := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } createdService := createdSvc.(*api.Service) - if createdService.Spec.Ports[0].Port != 6502 { - t.Errorf("Expected port 6502, but got %v", createdService.Spec.Ports[0].Port) + if createdService.Spec.Ports[0].Port != svc.Spec.Ports[0].Port { + t.Errorf("Expected port %d, but got %v", svc.Spec.Ports[0].Port, createdService.Spec.Ports[0].Port) } if !makeIPNet(t).Contains(net.ParseIP(createdService.Spec.ClusterIPs[0])) { t.Errorf("Unexpected ClusterIP: %s", createdService.Spec.ClusterIPs[0]) @@ -2026,7 +1303,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) { testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"} testIP := "" for _, ip := range testIPs { - if !storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].(*ipallocator.Range).Has(net.ParseIP(ip)) { + if !ipIsAllocated(t, storage.serviceIPAllocatorsByFamily[storage.defaultServiceIPFamily].(*ipallocator.Range), ip) { testIP = ip break } @@ -2037,39 +1314,26 @@ func TestServiceRegistryIPUpdate(t *testing.T) { update.Spec.ClusterIP = testIP update.Spec.ClusterIPs[0] = testIP - _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) + _, _, err = storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) if err == nil || !errors.IsInvalid(err) { t.Errorf("Unexpected error type: %v", err) } } func TestServiceRegistryIPLoadBalancer(t *testing.T) { - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - } + svc := svctest.MakeService("foo", svctest.SetTypeLoadBalancer) ctx := genericapirequest.NewDefaultContext() createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if createdSvc == nil || err != nil { t.Errorf("Unexpected failure creating service %v", err) } - defer releaseServiceNodePorts(t, ctx, svc.Name, storage, registry) createdService := createdSvc.(*api.Service) - if createdService.Spec.Ports[0].Port != 6502 { - t.Errorf("Expected port 6502, but got %v", createdService.Spec.Ports[0].Port) + if createdService.Spec.Ports[0].Port != svc.Spec.Ports[0].Port { + t.Errorf("Expected port %d, but got %v", svc.Spec.Ports[0].Port, createdService.Spec.Ports[0].Port) } if !makeIPNet(t).Contains(net.ParseIP(createdService.Spec.ClusterIPs[0])) { t.Errorf("Unexpected ClusterIP: %s", createdService.Spec.ClusterIPs[0]) @@ -2083,61 +1347,27 @@ func TestServiceRegistryIPLoadBalancer(t *testing.T) { } } -func TestUpdateServiceWithConflictingNamespace(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) - defer server.Terminate(t) - service := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "not-default"}, - } - - ctx := genericapirequest.NewDefaultContext() - obj, created, err := storage.Update(ctx, service.Name, rest.DefaultUpdatedObjectInfo(service), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}) - if obj != nil || created { - t.Error("Expected a nil object, but we got a value or created was true") - } - if err == nil { - t.Errorf("Expected an error, but we didn't get one") - } else if strings.Index(err.Error(), "Service.Namespace does not match the provided context") == -1 { - t.Errorf("Expected 'Service.Namespace does not match the provided context' error, got '%s'", err.Error()) - } -} - // Validate allocation of a nodePort when ExternalTrafficPolicy is set to Local // and type is LoadBalancer. func TestServiceRegistryExternalTrafficHealthCheckNodePortAllocation(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "external-lb-esipp"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal, - }, - } - createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if createdSvc == nil || err != nil { + svc := svctest.MakeService("external-lb-esipp", svctest.SetTypeLoadBalancer, func(s *api.Service) { + s.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal + }) + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if obj == nil || err != nil { t.Errorf("Unexpected failure creating service %v", err) } - defer releaseServiceNodePorts(t, ctx, svc.Name, storage, registry) - createdService := createdSvc.(*api.Service) - if !service.NeedsHealthCheck(createdService) { + createdSvc := obj.(*api.Service) + if !service.NeedsHealthCheck(createdSvc) { t.Errorf("Expecting health check needed, returned health check not needed instead") } - port := createdService.Spec.HealthCheckNodePort + port := createdSvc.Spec.HealthCheckNodePort if port == 0 { t.Errorf("Failed to allocate health check node port and set the HealthCheckNodePort") - } else { - // Release the health check node port at the end of the test case. - storage.serviceNodePorts.Release(int(port)) } } @@ -2145,71 +1375,44 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortAllocation(t *testing. // and type is LoadBalancer. func TestServiceRegistryExternalTrafficHealthCheckNodePortUserAllocation(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "external-lb-esipp"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - // hard-code NodePort to make sure it doesn't conflict with the healthport. - // TODO: remove this once http://issue.k8s.io/93922 fixes auto-allocation conflicting with user-specified health check ports - NodePort: 30500, - }}, - ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal, - HealthCheckNodePort: 30501, - }, - } - createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if createdSvc == nil || err != nil { + svc := svctest.MakeService("external-lb-esipp", svctest.SetTypeLoadBalancer, func(s *api.Service) { + // hard-code NodePort to make sure it doesn't conflict with the healthport. + // TODO: remove this once http://issue.k8s.io/93922 fixes auto-allocation conflicting with user-specified health check ports + s.Spec.Ports[0].NodePort = 30500 + s.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal + s.Spec.HealthCheckNodePort = 30501 + }) + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if obj == nil || err != nil { t.Fatalf("Unexpected failure creating service :%v", err) } - defer releaseServiceNodePorts(t, ctx, svc.Name, storage, registry) - createdService := createdSvc.(*api.Service) - if !service.NeedsHealthCheck(createdService) { + createdSvc := obj.(*api.Service) + if !service.NeedsHealthCheck(createdSvc) { t.Errorf("Expecting health check needed, returned health check not needed instead") } - port := createdService.Spec.HealthCheckNodePort + port := createdSvc.Spec.HealthCheckNodePort if port == 0 { t.Errorf("Failed to allocate health check node port and set the HealthCheckNodePort") } if port != 30501 { t.Errorf("Failed to allocate requested nodePort expected %d, got %d", 30501, port) } - if port != 0 { - // Release the health check node port at the end of the test case. - storage.serviceNodePorts.Release(int(port)) - } } // Validate that the service creation fails when the requested port number is -1. func TestServiceRegistryExternalTrafficHealthCheckNodePortNegative(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "external-lb-esipp"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeLocal, - HealthCheckNodePort: int32(-1), - }, - } - createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if createdSvc == nil || err != nil { + svc := svctest.MakeService("external-lb-esipp", svctest.SetTypeLoadBalancer, func(s *api.Service) { + s.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal + s.Spec.HealthCheckNodePort = int32(-1) + }) + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if obj == nil || err != nil { return } t.Errorf("Unexpected creation of service with invalid HealthCheckNodePort specified") @@ -2218,46 +1421,28 @@ func TestServiceRegistryExternalTrafficHealthCheckNodePortNegative(t *testing.T) // Validate that the health check nodePort is not allocated when ExternalTrafficPolicy is set to Global. func TestServiceRegistryExternalTrafficGlobal(t *testing.T) { ctx := genericapirequest.NewDefaultContext() - storage, registry, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) - svc := &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "external-lb-esipp"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeLoadBalancer, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - ExternalTrafficPolicy: api.ServiceExternalTrafficPolicyTypeCluster, - }, - } - createdSvc, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if createdSvc == nil || err != nil { + svc := svctest.MakeService("external-lb-esipp", svctest.SetTypeLoadBalancer, func(s *api.Service) { + s.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeCluster + }) + obj, err := storage.Create(ctx, svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if obj == nil || err != nil { t.Errorf("Unexpected failure creating service %v", err) } - defer releaseServiceNodePorts(t, ctx, svc.Name, storage, registry) - createdService := createdSvc.(*api.Service) - if service.NeedsHealthCheck(createdService) { + createdSvc := obj.(*api.Service) + if service.NeedsHealthCheck(createdSvc) { t.Errorf("Expecting health check not needed, returned health check needed instead") } // Make sure the service does not have the health check node port allocated - port := createdService.Spec.HealthCheckNodePort + port := createdSvc.Spec.HealthCheckNodePort if port != 0 { - // Release the health check node port at the end of the test case. - storage.serviceNodePorts.Release(int(port)) t.Errorf("Unexpected allocation of health check node port: %v", port) } } func TestInitClusterIP(t *testing.T) { - singleStack := api.IPFamilyPolicySingleStack - requireDualStack := api.IPFamilyPolicyRequireDualStack - preferDualStack := api.IPFamilyPolicyPreferDualStack - testCases := []struct { name string svc *api.Service @@ -2267,347 +1452,141 @@ func TestInitClusterIP(t *testing.T) { expectError bool expectedCountIPs int expectedClusterIPs []string - }{ - { - name: "Allocate single stack ClusterIP (v4)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - enableDualStackAllocator: false, - expectError: false, - preAllocateClusterIPs: nil, - expectedCountIPs: 1, - }, - { - name: "Allocate single ClusterIP (v6)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - preAllocateClusterIPs: nil, - expectedCountIPs: 1, - }, - { - name: "Allocate specified ClusterIP (v4)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - preAllocateClusterIPs: nil, - expectedCountIPs: 1, - expectedClusterIPs: []string{"1.2.3.4"}, - }, - { - name: "Allocate specified ClusterIP-v6", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1"}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 1, - expectedClusterIPs: []string{"2000:0:0:0:0:0:0:1"}, - }, - { - name: "Allocate dual stack - on a non dual stack ", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &preferDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: false, - expectedCountIPs: 1, - }, - { - name: "Allocate dual stack - upgrade - v4, v6", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &preferDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 2, - }, - { - name: "Allocate dual stack - upgrade - v4, v6 - specific first IP", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &preferDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 2, - expectedClusterIPs: []string{"1.2.3.4"}, - }, - { - name: "Allocate dual stack - upgrade - v6, v4", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &preferDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 2, - }, - { - name: "Allocate dual stack - v4, v6 - specific ips", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &requireDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4", "2000:0:0:0:0:0:0:1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 2, - expectedClusterIPs: []string{"1.2.3.4", "2000:0:0:0:0:0:0:1"}, - }, - { - name: "Allocate dual stack - upgrade - v6, v4 - specific ips", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &requireDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: true, - expectedCountIPs: 2, - expectedClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - }, - { - name: "Shouldn't allocate ClusterIP", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "None", - ClusterIPs: []string{api.ClusterIPNone}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: false, - enableDualStackAllocator: false, - expectedCountIPs: 0, - }, - { - name: "single stack, ip is pre allocated (ipv4)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &singleStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "1.2.3.4", - ClusterIPs: []string{"1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: true, - enableDualStackAllocator: false, - expectedCountIPs: 0, - preAllocateClusterIPs: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, - }, - - { - name: "single stack, ip is pre allocated (ipv6)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &singleStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000:0:0:0:0:0:0:1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: true, - enableDualStackAllocator: true, // ipv6 allocator is always the second one during test - expectedCountIPs: 0, - preAllocateClusterIPs: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, - }, - { - name: "Allocate dual stack - upgrade - v6, v4 - specific ips (first ip can't be allocated)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &requireDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: true, - enableDualStackAllocator: true, - expectedCountIPs: 0, - preAllocateClusterIPs: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, - }, - { - name: "Allocate dual stack - upgrade - v6, v4 - specific ips (second ip can't be allocated)", - svc: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - IPFamilyPolicy: &requireDualStack, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - ClusterIP: "2000:0:0:0:0:0:0:1", - ClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectError: true, - enableDualStackAllocator: true, - expectedCountIPs: 0, - preAllocateClusterIPs: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, - }, - } + }{{ + name: "Allocate single stack ClusterIP (v4)", + svc: svctest.MakeService("foo"), + enableDualStackAllocator: false, + expectError: false, + preAllocateClusterIPs: nil, + expectedCountIPs: 1, + }, { + name: "Allocate single ClusterIP (v6)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol)), + expectError: false, + enableDualStackAllocator: true, + preAllocateClusterIPs: nil, + expectedCountIPs: 1, + }, { + name: "Allocate specified ClusterIP (v4)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("1.2.3.4")), + expectError: false, + enableDualStackAllocator: true, + preAllocateClusterIPs: nil, + expectedCountIPs: 1, + expectedClusterIPs: []string{"1.2.3.4"}, + }, { + name: "Allocate specified ClusterIP-v6", + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1")), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 1, + expectedClusterIPs: []string{"2000:0:0:0:0:0:0:1"}, + }, { + name: "Allocate dual stack - on a non dual stack ", + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol)), + expectError: false, + enableDualStackAllocator: false, + expectedCountIPs: 1, + }, { + name: "Allocate dual stack - upgrade - v4, v6", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv4Protocol)), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 2, + }, { + name: "Allocate dual stack - upgrade - v4, v6 - specific first IP", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("1.2.3.4")), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 2, + expectedClusterIPs: []string{"1.2.3.4"}, + }, { + name: "Allocate dual stack - upgrade - v6, v4", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv6Protocol)), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 2, + }, { + name: "Allocate dual stack - v4, v6 - specific ips", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetClusterIPs("1.2.3.4", "2000:0:0:0:0:0:0:1")), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 2, + expectedClusterIPs: []string{"1.2.3.4", "2000:0:0:0:0:0:0:1"}, + }, { + name: "Allocate dual stack - upgrade - v6, v4 - specific ips", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1", "1.2.3.4")), + expectError: false, + enableDualStackAllocator: true, + expectedCountIPs: 2, + expectedClusterIPs: []string{"2000:0:0:0:0:0:0:1", "1.2.3.4"}, + }, { + name: "Shouldn't allocate ClusterIP", + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None")), + expectError: false, + enableDualStackAllocator: false, + expectedCountIPs: 0, + }, { + name: "single stack, ip is pre allocated (ipv4)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("1.2.3.4")), + expectError: true, + enableDualStackAllocator: false, + expectedCountIPs: 0, + preAllocateClusterIPs: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, + }, { + name: "single stack, ip is pre allocated (ipv6)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack), + svctest.SetIPFamilies(api.IPv6Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1")), + expectError: true, + enableDualStackAllocator: true, // ipv6 allocator is always the second one during test + expectedCountIPs: 0, + preAllocateClusterIPs: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, + }, { + name: "Allocate dual stack - upgrade - v6, v4 - specific ips (first ip can't be allocated)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1", "1.2.3.4")), + expectError: true, + enableDualStackAllocator: true, + expectedCountIPs: 0, + preAllocateClusterIPs: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, + }, { + name: "Allocate dual stack - upgrade - v6, v4 - specific ips (second ip can't be allocated)", + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + svctest.SetClusterIPs("2000:0:0:0:0:0:0:1", "1.2.3.4")), + expectError: true, + enableDualStackAllocator: true, + expectedCountIPs: 0, + preAllocateClusterIPs: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, + }} for _, test := range testCases { t.Run(test.name, func(t *testing.T) { @@ -2618,7 +1597,7 @@ func TestInitClusterIP(t *testing.T) { if test.enableDualStackAllocator { families = append(families, api.IPv6Protocol) } - storage, _, server := NewTestREST(t, nil, families) + storage, server := NewTestREST(t, families) defer server.Terminate(t) copySvc := test.svc.DeepCopy() @@ -2657,8 +1636,7 @@ func TestInitClusterIP(t *testing.T) { family = api.IPv6Protocol } allocator := storage.serviceIPAllocatorsByFamily[family] - // has retruns true if it was allocated *sigh*.. - if !allocator.Has(net.ParseIP(ip)) { + if !ipIsAllocated(t, allocator, ip) { t.Fatalf("expected ip:%v to be allocated by %v allocator. it was not", ip, family) } } @@ -2706,161 +1684,63 @@ func TestInitClusterIP(t *testing.T) { } func TestInitNodePorts(t *testing.T) { - storage, _, server := NewTestREST(t, nil, []api.IPFamily{api.IPv4Protocol}) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) nodePortOp := portallocator.StartOperation(storage.serviceNodePorts, false) - defer nodePortOp.Finish() testCases := []struct { name string service *api.Service expectSpecifiedNodePorts []int - }{ - { - name: "Service doesn't have specified NodePort", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{}, - }, - { - name: "Service has one specified NodePort", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }}, - }, - }, - expectSpecifiedNodePorts: []int{30053}, - }, - { - name: "Service has two same ports with different protocols and specifies same NodePorts", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30054, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30054, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30054, 30054}, - }, - { - name: "Service has two same ports with different protocols and specifies different NodePorts", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30055, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30056, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30055, 30056}, - }, - { - name: "Service has two different ports with different protocols and specifies different NodePorts", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30057, - }, - { - Name: "port-udp", - Port: 54, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30058, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30057, 30058}, - }, - { - name: "Service has two same ports with different protocols but only specifies one NodePort", - service: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30059, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30059, 30059}, - }, - } + }{{ + name: "Service doesn't have specified NodePort", + service: svctest.MakeService("foo", svctest.SetTypeNodePort), + expectSpecifiedNodePorts: []int{}, + }, { + name: "Service has one specified NodePort", + service: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + expectSpecifiedNodePorts: []int{30053}, + }, { + name: "Service has two same ports with different protocols and specifies same NodePorts", + service: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30054, 30054)), + expectSpecifiedNodePorts: []int{30054, 30054}, + }, { + name: "Service has two same ports with different protocols and specifies different NodePorts", + service: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30055, 30056)), + expectSpecifiedNodePorts: []int{30055, 30056}, + }, { + name: "Service has two different ports with different protocols and specifies different NodePorts", + service: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 54, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30057, 30058)), + expectSpecifiedNodePorts: []int{30057, 30058}, + }, { + name: "Service has two same ports with different protocols but only specifies one NodePort", + service: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30059)), + expectSpecifiedNodePorts: []int{30059, 30059}, + }} for _, test := range testCases { err := initNodePorts(test.service, nodePortOp) @@ -2888,249 +1768,94 @@ func TestInitNodePorts(t *testing.T) { } func TestUpdateNodePorts(t *testing.T) { - storage, _, server := NewTestREST(t, nil, singleStackIPv4) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol}) defer server.Terminate(t) nodePortOp := portallocator.StartOperation(storage.serviceNodePorts, false) - defer nodePortOp.Finish() testCases := []struct { name string oldService *api.Service newService *api.Service expectSpecifiedNodePorts []int - }{ - { - name: "Old service and new service have the same NodePort", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - NodePort: 30053, - }}, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - NodePort: 30053, - }}, - }, - }, - expectSpecifiedNodePorts: []int{30053}, - }, - { - name: "Old service has more NodePorts than new service has", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30053, - }, - }, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30053}, - }, - { - name: "Change protocol of ServicePort without changing NodePort", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - }, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30053, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30053}, - }, - { - name: "Should allocate NodePort when changing service type to NodePort", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - expectSpecifiedNodePorts: []int{}, - }, - { - name: "Add new ServicePort with a different protocol without changing port numbers", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - }, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30053, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30053, 30053}, - }, - { - name: "Change service type from ClusterIP to NodePort with same NodePort number but different protocols", - oldService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 53, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - newService: &api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo"}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeNodePort, - Ports: []api.ServicePort{ - { - Name: "port-tcp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolTCP, - NodePort: 30053, - }, - { - Name: "port-udp", - Port: 53, - TargetPort: intstr.FromInt(6502), - Protocol: api.ProtocolUDP, - NodePort: 30053, - }, - }, - }, - }, - expectSpecifiedNodePorts: []int{30053, 30053}, - }, - } + }{{ + name: "Old service and new service have the same NodePort", + oldService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("", 6502, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("", 6502, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + expectSpecifiedNodePorts: []int{30053}, + }, { + name: "Old service has more NodePorts than new service has", + oldService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30053, 30053)), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + expectSpecifiedNodePorts: []int{30053}, + }, { + name: "Change protocol of ServicePort without changing NodePort", + oldService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30053)), + expectSpecifiedNodePorts: []int{30053}, + }, { + name: "Should allocate NodePort when changing service type to NodePort", + oldService: svctest.MakeService("foo", + svctest.SetTypeClusterIP, + svctest.SetPorts( + svctest.MakeServicePort("", 6502, intstr.FromInt(6502), api.ProtocolUDP))), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("", 6502, intstr.FromInt(6502), api.ProtocolUDP))), + expectSpecifiedNodePorts: []int{}, + }, { + name: "Add new ServicePort with a different protocol without changing port numbers", + oldService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP)), + svctest.SetNodePorts(30053)), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30053, 30053)), + expectSpecifiedNodePorts: []int{30053, 30053}, + }, { + name: "Change service type from ClusterIP to NodePort with same NodePort number but different protocols", + oldService: svctest.MakeService("foo", + svctest.SetTypeClusterIP, + svctest.SetPorts( + svctest.MakeServicePort("", 53, intstr.FromInt(6502), api.ProtocolTCP))), + newService: svctest.MakeService("foo", + svctest.SetTypeNodePort, + svctest.SetPorts( + svctest.MakeServicePort("port-tcp", 53, intstr.FromInt(6502), api.ProtocolTCP), + svctest.MakeServicePort("port-udp", 53, intstr.FromInt(6502), api.ProtocolUDP)), + svctest.SetNodePorts(30053, 30053)), + expectSpecifiedNodePorts: []int{30053, 30053}, + }} for _, test := range testCases { err := updateNodePorts(test.oldService, test.newService, nodePortOp) @@ -3168,230 +1893,129 @@ func TestServiceUpgrade(t *testing.T) { enableDualStackGate bool allocateIPsBeforeUpdate map[api.IPFamily]string expectUpgradeError bool - svc api.Service - }{ - { - name: "normal, no upgrade needed", - enableDualStackAllocator: false, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: false, + svc *api.Service + }{{ + name: "normal, no upgrade needed", + enableDualStackAllocator: false, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: false, - updateFunc: func(s *api.Service) { - s.Spec.Selector = map[string]string{"bar": "baz2"} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "error, no upgrade (has single allocator)", - enableDualStackAllocator: false, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: true, - - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "upgrade to v4,6", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: false, - - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "upgrade to v4,6 (specific ip)", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: false, - - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "2000:0:0:0:0:0:0:1") - s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "upgrade to v4,6 (specific ip) - fail, ip is not available", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, - expectUpgradeError: true, - - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "2000:0:0:0:0:0:0:1") - s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + updateFunc: func(s *api.Service) { + s.Spec.Selector = map[string]string{"bar": "baz2"} }, - { - name: "upgrade to v6,4", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: false, + svc: svctest.MakeService("foo"), + }, { + name: "error, no upgrade (has single allocator)", + enableDualStackAllocator: false, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: true, - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} }, - { - name: "upgrade to v6,4 (specific ip)", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: nil, - expectUpgradeError: false, + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol} + }), + }, { + name: "upgrade to v4,6", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: false, - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "1.2.3.4") - s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} }, - { - name: "upgrade to v6,4 (specific ip) - fail ip is already allocated", - enableDualStackAllocator: true, - enableDualStackGate: true, - allocateIPsBeforeUpdate: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, - expectUpgradeError: true, + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol} + }), + }, { + name: "upgrade to v4,6 (specific ip)", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: false, - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &requireDualStack - s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "1.2.3.4") - s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "2000:0:0:0:0:0:0:1") + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} }, - } + + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol} + }), + }, { + name: "upgrade to v4,6 (specific ip) - fail, ip is not available", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: map[api.IPFamily]string{api.IPv6Protocol: "2000:0:0:0:0:0:0:1"}, + expectUpgradeError: true, + + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "2000:0:0:0:0:0:0:1") + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} + }, + + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol} + }), + }, { + name: "upgrade to v6,4", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: false, + + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} + }, + + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol} + }), + }, { + name: "upgrade to v6,4 (specific ip)", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: nil, + expectUpgradeError: false, + + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "1.2.3.4") + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} + }, + + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol} + }), + }, { + name: "upgrade to v6,4 (specific ip) - fail ip is already allocated", + enableDualStackAllocator: true, + enableDualStackGate: true, + allocateIPsBeforeUpdate: map[api.IPFamily]string{api.IPv4Protocol: "1.2.3.4"}, + expectUpgradeError: true, + + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requireDualStack + s.Spec.ClusterIPs = append(s.Spec.ClusterIPs, "1.2.3.4") + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol} + }, + + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilies = []api.IPFamily{api.IPv6Protocol} + }), + }} for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { @@ -3399,11 +2023,11 @@ func TestServiceUpgrade(t *testing.T) { if testCase.enableDualStackAllocator { families = append(families, api.IPv6Protocol) } - storage, _, server := NewTestREST(t, nil, families) + storage, server := NewTestREST(t, families) defer server.Terminate(t) defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, testCase.enableDualStackGate)() - obj, err := storage.Create(ctx, &testCase.svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err := storage.Create(ctx, testCase.svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("error is unexpected: %v", err) } @@ -3456,8 +2080,7 @@ func TestServiceUpgrade(t *testing.T) { for i, family := range updatedSvc.Spec.IPFamilies { ip := updatedSvc.Spec.ClusterIPs[i] allocator := storage.serviceIPAllocatorsByFamily[family] - // has retruns true if it was allocated *sigh*.. - if !allocator.Has(net.ParseIP(ip)) { + if !ipIsAllocated(t, allocator, ip) { t.Fatalf("expected ip:%v to be allocated by %v allocator. it was not", ip, family) } } @@ -3475,123 +2098,72 @@ func TestServiceDowngrade(t *testing.T) { enableDualStackAllocator bool enableDualStackGate bool expectDowngradeError bool - svc api.Service - }{ - { - name: "normal, no downgrade needed. single stack => single stack", - enableDualStackAllocator: true, - enableDualStackGate: true, - expectDowngradeError: false, + svc *api.Service + }{{ + name: "normal, no downgrade needed. single stack => single stack", + enableDualStackAllocator: true, + enableDualStackGate: true, + expectDowngradeError: false, - updateFunc: func(s *api.Service) { s.Spec.Selector = map[string]string{"bar": "baz2"} }, + updateFunc: func(s *api.Service) { s.Spec.Selector = map[string]string{"bar": "baz2"} }, - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requiredDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - { - name: "normal, no downgrade needed. dual stack => dual stack", - enableDualStackAllocator: true, - enableDualStackGate: true, - expectDowngradeError: false, + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requiredDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol} + }), + }, { + name: "normal, no downgrade needed. dual stack => dual stack", + enableDualStackAllocator: true, + enableDualStackGate: true, + expectDowngradeError: false, - updateFunc: func(s *api.Service) { s.Spec.Selector = map[string]string{"bar": "baz2"} }, + updateFunc: func(s *api.Service) { s.Spec.Selector = map[string]string{"bar": "baz2"} }, - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requiredDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requiredDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} + }), + }, { + name: "normal, downgrade v4,v6 => v4", + enableDualStackAllocator: true, + enableDualStackGate: true, + expectDowngradeError: false, + + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &singleStack + s.Spec.ClusterIPs = s.Spec.ClusterIPs[0:1] + s.Spec.IPFamilies = s.Spec.IPFamilies[0:1] }, - { - name: "normal, downgrade v4,v6 => v4", - enableDualStackAllocator: true, - enableDualStackGate: true, - expectDowngradeError: false, + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requiredDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} + }), + }, { + name: "normal, downgrade v6,v4 => v6", + enableDualStackAllocator: true, + enableDualStackGate: true, + expectDowngradeError: false, - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &singleStack - s.Spec.ClusterIPs = s.Spec.ClusterIPs[0:1] - s.Spec.IPFamilies = s.Spec.IPFamilies[0:1] - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requiredDualStack, - - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, + updateFunc: func(s *api.Service) { + s.Spec.IPFamilyPolicy = &singleStack + s.Spec.ClusterIPs = s.Spec.ClusterIPs[0:1] + s.Spec.IPFamilies = s.Spec.IPFamilies[0:1] }, - { - name: "normal, downgrade v6,v4 => v6", - enableDualStackAllocator: true, - enableDualStackGate: true, - expectDowngradeError: false, - updateFunc: func(s *api.Service) { - s.Spec.IPFamilyPolicy = &singleStack - s.Spec.ClusterIPs = s.Spec.ClusterIPs[0:1] - s.Spec.IPFamilies = s.Spec.IPFamilies[0:1] - }, - - svc: api.Service{ - ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: metav1.NamespaceDefault}, - Spec: api.ServiceSpec{ - Selector: map[string]string{"bar": "baz"}, - SessionAffinity: api.ServiceAffinityNone, - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requiredDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - Ports: []api.ServicePort{{ - Port: 6502, - Protocol: api.ProtocolTCP, - TargetPort: intstr.FromInt(6502), - }}, - }, - }, - }, - } + svc: svctest.MakeService("foo", func(s *api.Service) { + s.Spec.IPFamilyPolicy = &requiredDualStack + s.Spec.IPFamilies = []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol} + }), + }} for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - storage, _, server := NewTestREST(t, nil, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) defer server.Terminate(t) defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, testCase.enableDualStackGate)() - obj, err := storage.Create(ctx, &testCase.svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + obj, err := storage.Create(ctx, testCase.svc, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) if err != nil { t.Fatalf("error is unexpected: %v", err) } @@ -3641,7 +2213,7 @@ func TestServiceDowngrade(t *testing.T) { releasedIPFamily := copySvc.Spec.IPFamilies[1] allocator := storage.serviceIPAllocatorsByFamily[releasedIPFamily] - if allocator.Has(net.ParseIP(releasedIP)) { + if ipIsAllocated(t, allocator, releasedIP) { t.Fatalf("expected ip:%v to be released by %v allocator. it was not", releasedIP, releasedIPFamily) } } @@ -3685,7 +2257,7 @@ func TestDefaultingValidation(t *testing.T) { name string modifyRest func(rest *REST) oldSvc *api.Service - svc api.Service + svc *api.Service expectedIPFamilyPolicy *api.IPFamilyPolicyType expectedIPFamilies []api.IPFamily @@ -3695,25 +2267,17 @@ func TestDefaultingValidation(t *testing.T) { // cluster configured as single stack v4 //////////////////////////// { - name: "[singlestack:v4] set: externalname on a single stack - v4", - modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeExternalName, - }, - }, + name: "[singlestack:v4] set: externalname on a single stack - v4", + modifyRest: fnMakeSingleStackIPv4Allocator, + svc: svctest.MakeService("foo", svctest.SetTypeExternalName), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: false, }, { - name: "[singlestack:v4] set: nothing", - modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - }, - }, + name: "[singlestack:v4] set: nothing", + modifyRest: fnMakeSingleStackIPv4Allocator, + svc: svctest.MakeService("foo"), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3722,12 +2286,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: v4Cluster IPSet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3735,12 +2295,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: v4IPFamilySet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3748,13 +2304,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: v4IPFamilySet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4"), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3762,12 +2314,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: PreferDualStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3775,13 +2323,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: PreferDualStack + v4ClusterIPSet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3789,14 +2333,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: PreferDualStack + v4ClusterIPSet + v4FamilySet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3804,12 +2344,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: v6IPSet", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3817,12 +2353,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: v6IPFamily", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3830,12 +2362,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: RequireDualStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3843,13 +2371,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: RequireDualStack + family", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3858,13 +2382,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: selectorless, families are ignored", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -3872,12 +2393,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: selectorless, no families", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -3885,13 +2403,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: selectorless, user selected", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -3899,13 +2414,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: selectorless, user set to preferDualStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -3914,14 +2426,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: multifamily set to preferDualStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3929,14 +2436,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: multifamily set to singleStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3944,14 +2446,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: mult clusterips set to preferDualStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3959,14 +2456,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v4] set: multi clusterips set to singleStack", modifyRest: fnMakeSingleStackIPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -3976,25 +2468,17 @@ func TestDefaultingValidation(t *testing.T) { // cluster configured as single stack v6 //////////////////////////// { - name: "[singlestack:v6] set: externalname on a single stack - v4", - modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeExternalName, - }, - }, + name: "[singlestack:v6] set: externalname on a single stack - v4", + modifyRest: fnMakeSingleStackIPv6Allocator, + svc: svctest.MakeService("foo", svctest.SetTypeExternalName), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: false, }, { - name: "[singlestack:v6] set: nothing", - modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - }, - }, + name: "[singlestack:v6] set: nothing", + modifyRest: fnMakeSingleStackIPv6Allocator, + svc: svctest.MakeService("foo"), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4002,12 +2486,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: v6Cluster IPSet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4015,12 +2495,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: v4IPFamilySet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4028,13 +2504,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: v6IPFamilySet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1"), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4042,12 +2514,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: PreferDualStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4055,13 +2523,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: PreferDualStack + v6ClusterIPSet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4069,14 +2533,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: PreferDualStack + v6ClusterIPSet + v6FamilySet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv6Protocol), + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4084,12 +2544,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: v4IPSet", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.10")), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4097,12 +2553,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: v4IPFamily", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4110,12 +2562,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: RequireDualStack (on single stack ipv6 cluster)", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4123,13 +2571,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: RequireDualStack + family (on single stack ipv6 cluster)", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4139,13 +2583,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: selectorless, families are ignored", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4153,12 +2594,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: selectorless, no families", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - ClusterIPs: []string{"None"}, - Type: api.ServiceTypeClusterIP, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4166,13 +2604,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: selectorless, user selected", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4180,13 +2615,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: selectorless, user set to preferDualStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4195,14 +2627,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: multifamily set to preferDualStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4210,14 +2637,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: multifamily set to singleStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4225,14 +2647,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: mult clusterips set to preferDualStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4240,14 +2657,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[singlestack:v6] set: multi clusterips set to singleStack", modifyRest: fnMakeSingleStackIPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4257,25 +2669,17 @@ func TestDefaultingValidation(t *testing.T) { // cluster configured as dual stack v4,6 //////////////////////////// { - name: "[dualstack:v4,v6] set: externalname on a dual stack - v4,v6", - modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeExternalName, - }, - }, + name: "[dualstack:v4,v6] set: externalname on a dual stack - v4,v6", + modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, + svc: svctest.MakeService("foo", svctest.SetTypeExternalName), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: false, }, { - name: "[dualstack:v4,v6] set: nothing", - modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - }, - }, + name: "[dualstack:v4,v6] set: nothing", + modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, + svc: svctest.MakeService("foo"), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4284,12 +2688,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v4ClusterIPSet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4297,12 +2697,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v4IPFamilySet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4310,13 +2706,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v4IPFamilySet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4"), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4324,12 +2716,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v6ClusterIPSet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4337,12 +2725,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v6IPFamilySet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4350,13 +2734,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: v6IPFamilySet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1"), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4365,12 +2745,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: PreferDualStack.", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4378,13 +2754,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: PreferDualStack + v4ClusterIPSet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4392,14 +2764,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: PreferDualStack + v4ClusterIPSet + v4FamilySet", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4408,12 +2776,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4421,13 +2785,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + family v4", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4435,13 +2795,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + family v6", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4450,14 +2806,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + family +ip v4", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10"), + svctest.SetIPFamilies(api.IPv4Protocol)), // expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, @@ -4466,14 +2818,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + family +ip v6", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1"), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4481,13 +2829,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + ip v6", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4495,13 +2839,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + ip v4", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4509,13 +2849,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + ips", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10", "2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10", "2000::1")), // expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, @@ -4524,13 +2860,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + ips", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1", "10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1", "10.0.0.10")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4538,14 +2870,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: RequireDualStack + ips + families v6,v4", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1", "10.0.0.10"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1", "10.0.0.10"), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4553,14 +2881,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ips + families v4,v6", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10", "2000::1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10", "2000::1"), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4568,12 +2892,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,v6] set: selectorless, no families", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4581,13 +2902,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: selectorless, user selected", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4595,13 +2912,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: selectorless, user set to prefer", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4610,14 +2923,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[duakstack:v4,6] set: multifamily set to preferDualStack", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4625,14 +2933,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: multifamily set to singleStack", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4640,14 +2943,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: mult clusterips set to preferDualStack", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4655,14 +2953,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: multi clusterips set to singleStack", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -4672,25 +2965,17 @@ func TestDefaultingValidation(t *testing.T) { // cluster configured as dual stack v6,4 //////////////////////////// { - name: "[dualstack:v6,v4] set: externalname on a dual stack - v6,v4", - modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeExternalName, - }, - }, + name: "[dualstack:v6,v4] set: externalname on a dual stack - v6,v4", + modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, + svc: svctest.MakeService("foo", svctest.SetTypeExternalName), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: false, }, { - name: "[dualstack:v6,v4] set: nothing", - modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - }, - }, + name: "[dualstack:v6,v4] set: nothing", + modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, + svc: svctest.MakeService("foo"), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4698,12 +2983,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v4ClusterIPSet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4711,12 +2992,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v4IPFamilySet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol)), // expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, @@ -4725,13 +3002,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v4IPFamilySet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"10.0.0.4"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("10.0.0.4"), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -4739,12 +3012,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v6ClusterIPSet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4752,12 +3021,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v6IPFamilySet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4765,13 +3030,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: v6IPFamilySet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"2000::1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("2000::1"), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, expectError: false, @@ -4780,12 +3041,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: PreferDualStack.", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4793,13 +3050,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: PreferDualStack + v4ClusterIPSet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4807,14 +3060,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: PreferDualStack + v4ClusterIPSet + v4FamilySet", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &preferDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - ClusterIPs: []string{"10.0.0.4"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetClusterIPs("10.0.0.4")), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4823,12 +3072,8 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4836,13 +3081,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + family v4", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4850,13 +3091,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + family v6", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4864,14 +3101,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + family +ip v4", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10"), + svctest.SetIPFamilies(api.IPv4Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4879,14 +3112,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + family +ip v6", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1"), + svctest.SetIPFamilies(api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4894,13 +3123,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ip v6", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4908,13 +3133,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ip v4", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4922,13 +3143,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ip v4", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4936,13 +3153,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ips", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10", "2000::1"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10", "2000::1")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4950,13 +3163,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ips", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1", "10.0.0.10"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1", "10.0.0.10")), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4964,14 +3173,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ips + families v6,v4", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"2000::1", "10.0.0.10"}, - IPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("2000::1", "10.0.0.10"), + svctest.SetIPFamilies(api.IPv6Protocol, api.IPv4Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -4979,14 +3184,10 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: RequireDualStack + ips + families v4,v6", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - IPFamilyPolicy: &requireDualStack, - ClusterIPs: []string{"10.0.0.10", "2000::1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack), + svctest.SetClusterIPs("10.0.0.10", "2000::1"), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -4994,12 +3195,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: selectorless, no families", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + func(s *api.Service) { s.Spec.Selector = nil }), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, expectError: false, @@ -5007,13 +3205,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: selectorless, user selected", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol}, @@ -5022,13 +3216,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,v4] set: selectorless, user set to prefer", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"None"}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("None"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv6Protocol, api.IPv4Protocol}, @@ -5038,14 +3228,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[duakstack:v6,5] set: multifamily set to preferDualStack", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -5053,14 +3238,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v4,6] set: multifamily set to singleStack", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -5068,14 +3248,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,4] set: mult clusterips set to preferDualStack", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -5083,14 +3258,9 @@ func TestDefaultingValidation(t *testing.T) { { name: "[dualstack:v6,4] set: multi clusterips set to singleStack", modifyRest: fnMakeDualStackStackIPv6IPv4Allocator, - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: nil, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: nil, expectedIPFamilies: nil, expectError: true, @@ -5102,23 +3272,15 @@ func TestDefaultingValidation(t *testing.T) { { name: "unchanged preferDualStack-1-ClusterUpgraded", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - oldSvc: &api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + oldSvc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1"), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1"), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -5127,23 +3289,15 @@ func TestDefaultingValidation(t *testing.T) { { name: "unchanged preferDualStack-2-ClusterDowngraded", modifyRest: fnMakeSingleStackIPv4Allocator, - oldSvc: &api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + oldSvc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), expectedIPFamilyPolicy: &preferDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -5152,23 +3306,14 @@ func TestDefaultingValidation(t *testing.T) { { name: "changed preferDualStack-1 (cluster upgraded)", modifyRest: fnMakeDualStackStackIPv4IPv6Allocator, - oldSvc: &api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + oldSvc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1"), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: nil, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - IPFamilyPolicy: &requireDualStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyRequireDualStack)), expectedIPFamilyPolicy: &requireDualStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, expectError: false, @@ -5177,23 +3322,15 @@ func TestDefaultingValidation(t *testing.T) { { name: "changed preferDualStack-2-ClusterDowngraded", modifyRest: fnMakeSingleStackIPv4Allocator, - oldSvc: &api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1", "2001::1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}, - IPFamilyPolicy: &preferDualStack, - }, - }, + oldSvc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1", "2001::1"), + svctest.SetIPFamilies(api.IPv4Protocol, api.IPv6Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicyPreferDualStack)), - svc: api.Service{ - Spec: api.ServiceSpec{ - Type: api.ServiceTypeClusterIP, - ClusterIPs: []string{"1.1.1.1"}, - IPFamilies: []api.IPFamily{api.IPv4Protocol}, - IPFamilyPolicy: &singleStack, - }, - }, + svc: svctest.MakeService("foo", + svctest.SetClusterIPs("1.1.1.1"), + svctest.SetIPFamilies(api.IPv4Protocol), + svctest.SetIPFamilyPolicy(api.IPFamilyPolicySingleStack)), expectedIPFamilyPolicy: &singleStack, expectedIPFamilies: []api.IPFamily{api.IPv4Protocol}, expectError: false, @@ -5203,7 +3340,7 @@ func TestDefaultingValidation(t *testing.T) { // This func only runs when feature gate is on defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, true)() - storage, _, server := NewTestREST(t, nil, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) + storage, server := NewTestREST(t, []api.IPFamily{api.IPv4Protocol, api.IPv6Protocol}) defer server.Terminate(t) for _, testCase := range testCases { @@ -5216,7 +3353,7 @@ func TestDefaultingValidation(t *testing.T) { testCase.modifyRest(storage) } - err := storage.tryDefaultValidateServiceClusterIPFields(testCase.oldSvc, &testCase.svc) + err := storage.tryDefaultValidateServiceClusterIPFields(testCase.oldSvc, testCase.svc) if err != nil && !testCase.expectError { t.Fatalf("error %v was not expected", err) } diff --git a/pkg/registry/core/service/storage/storage.go b/pkg/registry/core/service/storage/storage.go index 0e706bea01d..2ec4bd64389 100644 --- a/pkg/registry/core/service/storage/storage.go +++ b/pkg/registry/core/service/storage/storage.go @@ -45,7 +45,7 @@ type GenericREST struct { secondaryFamily *api.IPFamily } -// NewREST returns a RESTStorage object that will work against services. +// NewGenericREST returns a RESTStorage object that will work against services. func NewGenericREST(optsGetter generic.RESTOptionsGetter, serviceCIDR net.IPNet, hasSecondary bool) (*GenericREST, *StatusREST, error) { strategy, _ := registry.StrategyForServiceCIDRs(serviceCIDR, hasSecondary)