Commit 67724439 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #46623 from sttts/sttts-aggregator-unified-modes

Automatic merge from submit-queue (batch tested with PRs 43505, 45168, 46439, 46677, 46623) aggregator: unify resolver implementation and tests This is https://github.com/kubernetes/kubernetes/pull/45082, but without the port support.
parents 98e5496a c7d9a396
...@@ -18,11 +18,12 @@ go_test( ...@@ -18,11 +18,12 @@ go_test(
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/client-go/listers/core/v1:go_default_library", "//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library", "//vendor/k8s.io/client-go/pkg/api/v1:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
], ],
) )
...@@ -40,6 +41,7 @@ go_library( ...@@ -40,6 +41,7 @@ go_library(
"//vendor/golang.org/x/net/html:go_default_library", "//vendor/golang.org/x/net/html:go_default_library",
"//vendor/golang.org/x/net/html/atom:go_default_library", "//vendor/golang.org/x/net/html/atom:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/third_party/forked/golang/netutil:go_default_library", "//vendor/k8s.io/apimachinery/third_party/forked/golang/netutil:go_default_library",
......
...@@ -24,48 +24,53 @@ import ( ...@@ -24,48 +24,53 @@ import (
"strconv" "strconv"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
utilnet "k8s.io/apimachinery/pkg/util/net"
listersv1 "k8s.io/client-go/listers/core/v1" listersv1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/pkg/api/v1"
"k8s.io/apimachinery/pkg/util/intstr"
) )
// findServicePort finds the service port by name or numerically.
func findServicePort(svc *v1.Service, port intstr.IntOrString) (*v1.ServicePort, error) {
for _, svcPort := range svc.Spec.Ports {
if (port.Type == intstr.Int && int32(svcPort.Port) == port.IntVal) || (port.Type == intstr.String && svcPort.Name == port.StrVal) {
return &svcPort, nil
}
}
return nil, errors.NewServiceUnavailable(fmt.Sprintf("no service port %q found for service %q", port.String(), svc.Name))
}
// ResourceLocation returns a URL to which one can send traffic for the specified service. // ResourceLocation returns a URL to which one can send traffic for the specified service.
func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.EndpointsLister, namespace, id string) (*url.URL, error) { func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.EndpointsLister, namespace, id string) (*url.URL, error) {
// Allow ID as "svcname", "svcname:port", or "scheme:svcname:port". svc, err := services.Services(namespace).Get(id)
svcScheme, svcName, portStr, valid := utilnet.SplitSchemeNamePort(id) if err != nil {
if !valid { return nil, err
return nil, errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id))
} }
// If a port *number* was specified, find the corresponding service port name port := intstr.FromInt(443)
if portNum, err := strconv.ParseInt(portStr, 10, 64); err == nil { svcPort, err := findServicePort(svc, port)
svc, err := services.Services(namespace).Get(svcName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
found := false
for _, svcPort := range svc.Spec.Ports { switch {
if int64(svcPort.Port) == portNum { case svc.Spec.Type == v1.ServiceTypeClusterIP, svc.Spec.Type == v1.ServiceTypeLoadBalancer, svc.Spec.Type == v1.ServiceTypeNodePort:
// use the declared port's name // these are fine
portStr = svcPort.Name default:
found = true return nil, fmt.Errorf("unsupported service type %q", svc.Spec.Type)
break
}
}
if !found {
return nil, errors.NewServiceUnavailable(fmt.Sprintf("no service port %d found for service %q", portNum, svcName))
}
} }
eps, err := endpoints.Endpoints(namespace).Get(svcName) eps, err := endpoints.Endpoints(namespace).Get(svc.Name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(eps.Subsets) == 0 { if len(eps.Subsets) == 0 {
return nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", svcName)) return nil, errors.NewServiceUnavailable(fmt.Sprintf("no endpoints available for service %q", svc.Name))
} }
// Pick a random Subset to start searching from. // Pick a random Subset to start searching from.
ssSeed := rand.Intn(len(eps.Subsets)) ssSeed := rand.Intn(len(eps.Subsets))
// Find a Subset that has the port. // Find a Subset that has the port.
for ssi := 0; ssi < len(eps.Subsets); ssi++ { for ssi := 0; ssi < len(eps.Subsets); ssi++ {
ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)] ss := &eps.Subsets[(ssSeed+ssi)%len(eps.Subsets)]
...@@ -73,12 +78,12 @@ func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.Endpo ...@@ -73,12 +78,12 @@ func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.Endpo
continue continue
} }
for i := range ss.Ports { for i := range ss.Ports {
if ss.Ports[i].Name == portStr { if ss.Ports[i].Name == svcPort.Name {
// Pick a random address. // Pick a random address.
ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP ip := ss.Addresses[rand.Intn(len(ss.Addresses))].IP
port := int(ss.Ports[i].Port) port := int(ss.Ports[i].Port)
return &url.URL{ return &url.URL{
Scheme: svcScheme, Scheme: "https",
Host: net.JoinHostPort(ip, strconv.Itoa(port)), Host: net.JoinHostPort(ip, strconv.Itoa(port)),
}, nil }, nil
} }
...@@ -88,30 +93,35 @@ func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.Endpo ...@@ -88,30 +93,35 @@ func ResolveEndpoint(services listersv1.ServiceLister, endpoints listersv1.Endpo
} }
func ResolveCluster(services listersv1.ServiceLister, namespace, id string) (*url.URL, error) { func ResolveCluster(services listersv1.ServiceLister, namespace, id string) (*url.URL, error) {
if len(id) == 0 { svc, err := services.Services(namespace).Get(id)
return &url.URL{Scheme: "https"}, nil
}
destinationHost := id + "." + namespace + ".svc"
service, err := services.Services(namespace).Get(id)
if err != nil { if err != nil {
return &url.URL{ return nil, err
Scheme: "https",
Host: destinationHost,
}, nil
} }
port := intstr.FromInt(443)
switch { switch {
case svc.Spec.Type == v1.ServiceTypeClusterIP && svc.Spec.ClusterIP == v1.ClusterIPNone:
return nil, fmt.Errorf(`cannot route to service with ClusterIP "None"`)
// use IP from a clusterIP for these service types // use IP from a clusterIP for these service types
case service.Spec.Type == v1.ServiceTypeClusterIP, case svc.Spec.Type == v1.ServiceTypeClusterIP, svc.Spec.Type == v1.ServiceTypeLoadBalancer, svc.Spec.Type == v1.ServiceTypeNodePort:
service.Spec.Type == v1.ServiceTypeNodePort, svcPort, err := findServicePort(svc, port)
service.Spec.Type == v1.ServiceTypeLoadBalancer: if err != nil {
return nil, err
}
return &url.URL{ return &url.URL{
Scheme: "https", Scheme: "https",
Host: service.Spec.ClusterIP, Host: net.JoinHostPort(svc.Spec.ClusterIP, fmt.Sprintf("%d", svcPort.Port)),
}, nil }, nil
case svc.Spec.Type == v1.ServiceTypeExternalName:
if port.Type != intstr.Int {
return nil, fmt.Errorf("named ports not supported")
} }
return &url.URL{ return &url.URL{
Scheme: "https", Scheme: "https",
Host: destinationHost, Host: net.JoinHostPort(svc.Spec.ExternalName, port.String()),
}, nil }, nil
default:
return nil, fmt.Errorf("unsupported service type %q", svc.Spec.Type)
}
} }
...@@ -17,103 +17,227 @@ limitations under the License. ...@@ -17,103 +17,227 @@ limitations under the License.
package proxy package proxy
import ( import (
"net/url"
"testing" "testing"
"k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr"
listersv1 "k8s.io/client-go/listers/core/v1" v1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/pkg/api/v1"
"net/http" "k8s.io/client-go/tools/cache"
) )
type serviceListerMock struct { func TestResolve(t *testing.T) {
services []*v1.Service matchingEndpoints := func(svc *v1.Service) []*v1.Endpoints {
err error ports := []v1.EndpointPort{}
} for _, p := range svc.Spec.Ports {
if p.TargetPort.Type != intstr.Int {
func (s *serviceListerMock) List(selector labels.Selector) (ret []*v1.Service, err error) { continue
return s.services, err }
} ports = append(ports, v1.EndpointPort{Name: p.Name, Port: p.TargetPort.IntVal})
}
func (s *serviceListerMock) Services(namespace string) listersv1.ServiceNamespaceLister {
return nil
}
func (s *serviceListerMock) GetPodServices(pod *v1.Pod) ([]*v1.Service, error) {
return nil, nil
}
type endpointsListerMock struct {
endpoints []*v1.Endpoints
err error
}
func (e *endpointsListerMock) List(selector labels.Selector) (ret []*v1.Endpoints, err error) {
return e.endpoints, e.err
}
func (e *endpointsListerMock) Endpoints(namespace string) listersv1.EndpointsNamespaceLister { return []*v1.Endpoints{{
return endpointsNamespaceListMock{ ObjectMeta: metav1.ObjectMeta{Namespace: svc.Namespace, Name: svc.Name},
endpoints: e.endpoints, Subsets: []v1.EndpointSubset{{
err: e.err, Addresses: []v1.EndpointAddress{{Hostname: "dummy-host", IP: "127.0.0.1"}},
Ports: ports,
}},
}}
} }
}
type endpointsNamespaceListMock struct { type expectation struct {
endpoints []*v1.Endpoints url string
err error error bool
} }
func (e endpointsNamespaceListMock) List(selector labels.Selector) (ret []*v1.Endpoints, err error) { tests := []struct {
return e.endpoints, e.err name string
} services []*v1.Service
endpoints func(svc *v1.Service) []*v1.Endpoints
clusterMode expectation
endpointMode expectation
}{
{
name: "cluster ip without 443 port",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ClusterIP: "hit",
Ports: []v1.ServicePort{
{Port: 1234, TargetPort: intstr.FromInt(1234)},
},
},
},
},
endpoints: matchingEndpoints,
clusterMode: expectation{error: true},
endpointMode: expectation{error: true},
},
{
name: "cluster ip",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ClusterIP: "hit",
Ports: []v1.ServicePort{
{Name: "https", Port: 443, TargetPort: intstr.FromInt(1443)},
{Port: 1234, TargetPort: intstr.FromInt(1234)},
},
},
},
},
endpoints: matchingEndpoints,
clusterMode: expectation{url: "https://hit:443"},
endpointMode: expectation{url: "https://127.0.0.1:1443"},
},
{
name: "cluster ip without endpoints",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ClusterIP: "hit",
Ports: []v1.ServicePort{
{Name: "https", Port: 443, TargetPort: intstr.FromInt(1443)},
{Port: 1234, TargetPort: intstr.FromInt(1234)},
},
},
},
},
endpoints: nil,
clusterMode: expectation{url: "https://hit:443"},
endpointMode: expectation{error: true},
},
{
name: "none cluster ip",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ClusterIP: v1.ClusterIPNone,
},
},
},
endpoints: nil,
clusterMode: expectation{error: true},
endpointMode: expectation{error: true},
},
{
name: "loadbalancer",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
ClusterIP: "lb",
Ports: []v1.ServicePort{
{Name: "https", Port: 443, TargetPort: intstr.FromInt(1443)},
{Port: 1234, TargetPort: intstr.FromInt(1234)},
},
},
},
},
endpoints: matchingEndpoints,
clusterMode: expectation{url: "https://lb:443"},
endpointMode: expectation{url: "https://127.0.0.1:1443"},
},
{
name: "node port",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
ClusterIP: "np",
Ports: []v1.ServicePort{
{Name: "https", Port: 443, TargetPort: intstr.FromInt(1443)},
{Port: 1234, TargetPort: intstr.FromInt(1234)},
},
},
},
},
endpoints: matchingEndpoints,
clusterMode: expectation{url: "https://np:443"},
endpointMode: expectation{url: "https://127.0.0.1:1443"},
},
{
name: "external name",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeExternalName,
ExternalName: "foo.bar.com",
},
},
},
endpoints: nil,
clusterMode: expectation{url: "https://foo.bar.com:443"},
endpointMode: expectation{error: true},
},
{
name: "missing service",
services: nil,
endpoints: nil,
clusterMode: expectation{error: true},
endpointMode: expectation{error: true},
},
}
func (e endpointsNamespaceListMock) Get(name string) (*v1.Endpoints, error) { for _, test := range tests {
if len(e.endpoints) == 0 { serviceCache := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
return nil, e.err serviceLister := v1listers.NewServiceLister(serviceCache)
for i := range test.services {
if err := serviceCache.Add(test.services[i]); err != nil {
t.Fatalf("%s unexpected service add error: %v", test.name, err)
}
} }
return e.endpoints[0], e.err
}
func TestNoEndpointNoPort(t *testing.T) { endpointCache := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
services := &serviceListerMock{} endpointLister := v1listers.NewEndpointsLister(endpointCache)
endpoints := &endpointsListerMock{err: errors.NewNotFound(v1.Resource("endpoints"), "dummy-svc")} if test.endpoints != nil {
url, err := ResolveEndpoint(services, endpoints, "dummy-ns", "dummy-svc") for _, svc := range test.services {
if url != nil { for _, ep := range test.endpoints(svc) {
t.Error("Should not have gotten back an URL") if err := endpointCache.Add(ep); err != nil {
t.Fatalf("%s unexpected endpoint add error: %v", test.name, err)
} }
if err == nil {
t.Error("Should have gotten an error")
} }
se, ok := err.(*errors.StatusError)
if !ok {
t.Error("Should have gotten a status error not %T", err)
} }
if se.ErrStatus.Code != http.StatusNotFound {
t.Error("Should have gotten a http 404 not %d", se.ErrStatus.Code)
} }
}
func TestOneEndpointNoPort(t *testing.T) { check := func(mode string, expected expectation, url *url.URL, err error) {
services := &serviceListerMock{} switch {
address := v1.EndpointAddress{Hostname: "dummy-host", IP: "127.0.0.1"} case err == nil && expected.error:
addresses := []v1.EndpointAddress{address} t.Errorf("%s in %s mode expected error, got none", test.name, mode)
port := v1.EndpointPort{Port: 443} case err != nil && expected.error:
ports := []v1.EndpointPort{port} // ignore
endpoint := v1.EndpointSubset{Addresses: addresses, Ports: ports} case err != nil:
subsets := []v1.EndpointSubset{endpoint} t.Errorf("%s in %s mode unexpected error: %v", test.name, mode, err)
one := &v1.Endpoints{Subsets: subsets} case url.String() != expected.url:
slice := []*v1.Endpoints{one} t.Errorf("%s in %s mode expected url %q, got %q", test.name, mode, expected.url, url.String())
endpoints := &endpointsListerMock{endpoints: slice}
url, err := ResolveEndpoint(services, endpoints, "dummy-ns", "dummy-svc")
if err != nil {
t.Errorf("Should not have gotten error %v", err)
} }
if url == nil {
t.Error("Should not have gotten back an URL")
}
if url.Host != "127.0.0.1:443" {
t.Error("Should have gotten back a host of dummy-host not %s", url.Host)
} }
clusterURL, err := ResolveCluster(serviceLister, "one", "alfa")
check("cluster", test.clusterMode, clusterURL, err)
endpointURL, err := ResolveEndpoint(serviceLister, endpointLister, "one", "alfa")
check("endpoint", test.endpointMode, endpointURL, err)
}
} }
...@@ -11,7 +11,6 @@ load( ...@@ -11,7 +11,6 @@ load(
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = [ srcs = [
"apiservice_controller_test.go",
"handler_apis_test.go", "handler_apis_test.go",
"handler_proxy_test.go", "handler_proxy_test.go",
], ],
...@@ -25,8 +24,6 @@ go_test( ...@@ -25,8 +24,6 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library", "//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
"//vendor/k8s.io/client-go/listers/core/v1:go_default_library",
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library", "//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/apis/apiregistration:go_default_library",
"//vendor/k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion:go_default_library", "//vendor/k8s.io/kube-aggregator/pkg/client/listers/apiregistration/internalversion:go_default_library",
......
...@@ -106,28 +106,6 @@ func (c *APIServiceRegistrationController) sync(key string) error { ...@@ -106,28 +106,6 @@ func (c *APIServiceRegistrationController) sync(key string) error {
return nil return nil
} }
func (c *APIServiceRegistrationController) getDestinationHost(apiService *apiregistration.APIService) string {
if apiService.Spec.Service == nil {
return ""
}
destinationHost := apiService.Spec.Service.Name + "." + apiService.Spec.Service.Namespace + ".svc"
service, err := c.serviceLister.Services(apiService.Spec.Service.Namespace).Get(apiService.Spec.Service.Name)
if err != nil {
return destinationHost
}
switch {
// use IP from a clusterIP for these service types
case service.Spec.Type == v1.ServiceTypeClusterIP,
service.Spec.Type == v1.ServiceTypeNodePort,
service.Spec.Type == v1.ServiceTypeLoadBalancer:
return service.Spec.ClusterIP
}
// return the normal DNS name by default
return destinationHost
}
func (c *APIServiceRegistrationController) Run(stopCh <-chan struct{}) { func (c *APIServiceRegistrationController) Run(stopCh <-chan struct{}) {
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
defer c.queue.ShutDown() defer c.queue.ShutDown()
......
/*
Copyright 2016 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 apiserver
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/kube-aggregator/pkg/apis/apiregistration"
)
func TestGetDestinationHost(t *testing.T) {
tests := []struct {
name string
services []*v1.Service
apiService *apiregistration.APIService
expected string
}{
{
name: "cluster ip",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
ClusterIP: "hit",
},
},
},
apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1."},
Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{
Namespace: "one",
Name: "alfa",
},
},
},
expected: "hit",
},
{
name: "loadbalancer",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
ClusterIP: "lb",
},
},
},
apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1."},
Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{
Namespace: "one",
Name: "alfa",
},
},
},
expected: "lb",
},
{
name: "node port",
services: []*v1.Service{
{
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
ClusterIP: "np",
},
},
},
apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1."},
Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{
Namespace: "one",
Name: "alfa",
},
},
},
expected: "np",
},
{
name: "missing service",
apiService: &apiregistration.APIService{
ObjectMeta: metav1.ObjectMeta{Name: "v1."},
Spec: apiregistration.APIServiceSpec{
Service: &apiregistration.ServiceReference{
Namespace: "one",
Name: "alfa",
},
},
},
expected: "alfa.one.svc",
},
}
for _, test := range tests {
serviceCache := cache.NewIndexer(cache.DeletionHandlingMetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
serviceLister := v1listers.NewServiceLister(serviceCache)
c := &APIServiceRegistrationController{
serviceLister: serviceLister,
}
for i := range test.services {
serviceCache.Add(test.services[i])
}
actual := c.getDestinationHost(test.apiService)
if actual != test.expected {
t.Errorf("%s expected %v, got %v", test.name, test.expected, actual)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment