Implement multi-port Endpoints
This is a part of multi-port services.
This commit is contained in:
@@ -27,10 +27,20 @@ import (
|
||||
)
|
||||
|
||||
func TestGetEndpoints(t *testing.T) {
|
||||
expected := []api.Endpoint{
|
||||
{IP: "127.0.0.1", Ports: []api.EndpointPort{
|
||||
{Name: "p", Port: 9000, Protocol: api.ProtocolTCP},
|
||||
{Name: "q", Port: 9000, Protocol: api.ProtocolUDP},
|
||||
}},
|
||||
{IP: "127.0.0.2", Ports: []api.EndpointPort{
|
||||
{Name: "p", Port: 8000, Protocol: api.ProtocolTCP},
|
||||
{Name: "q", Port: 8000, Protocol: api.ProtocolUDP},
|
||||
}},
|
||||
}
|
||||
registry := ®istrytest.ServiceRegistry{
|
||||
Endpoints: api.Endpoints{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Endpoints: []api.Endpoint{{IP: "127.0.0.1", Port: 9000}},
|
||||
Endpoints: expected,
|
||||
},
|
||||
}
|
||||
storage := NewREST(registry)
|
||||
@@ -39,7 +49,7 @@ func TestGetEndpoints(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %#v", err)
|
||||
}
|
||||
if !reflect.DeepEqual([]api.Endpoint{{IP: "127.0.0.1", Port: 9000}}, obj.(*api.Endpoints).Endpoints) {
|
||||
if !reflect.DeepEqual(expected, obj.(*api.Endpoints).Endpoints) {
|
||||
t.Errorf("unexpected endpoints: %#v", obj)
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,8 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
etcdgeneric "github.com/GoogleCloudPlatform/kubernetes/pkg/registry/generic/etcd"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||
@@ -598,10 +600,10 @@ func TestEtcdListEndpoints(t *testing.T) {
|
||||
Node: &etcd.Node{
|
||||
Nodes: []*etcd.Node{
|
||||
{
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Protocol: "TCP", Endpoints: []api.Endpoint{{IP: "127.0.0.1", Port: 8345}}}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Endpoints: []api.Endpoint{{IP: "127.0.0.1", Ports: []api.EndpointPort{{Name: "p", Port: 8345, Protocol: api.ProtocolTCP}}}}}),
|
||||
},
|
||||
{
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "bar"}, Protocol: "TCP"}),
|
||||
Value: runtime.EncodeOrDie(latest.Codec, &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "bar"}}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -625,8 +627,7 @@ func TestEtcdGetEndpoints(t *testing.T) {
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
endpoints := &api.Endpoints{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Protocol: "TCP",
|
||||
Endpoints: []api.Endpoint{{IP: "127.0.0.1", Port: 34855}},
|
||||
Endpoints: []api.Endpoint{{IP: "127.0.0.1", Ports: []api.EndpointPort{{Port: 34855, Protocol: api.ProtocolTCP}}}},
|
||||
}
|
||||
|
||||
key, _ := makeServiceEndpointsKey(ctx, "foo")
|
||||
@@ -647,10 +648,19 @@ func TestEtcdUpdateEndpoints(t *testing.T) {
|
||||
fakeClient := tools.NewFakeEtcdClient(t)
|
||||
fakeClient.TestIndex = true
|
||||
registry := NewTestEtcdRegistry(fakeClient)
|
||||
|
||||
// TODO: Once we drop single-port APIs, make this test use the
|
||||
// multi-port features. This will force a compile error when those APIs
|
||||
// are deleted.
|
||||
_ = v1beta1.Dependency
|
||||
_ = v1beta2.Dependency
|
||||
|
||||
endpoints := api.Endpoints{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Protocol: "TCP",
|
||||
Endpoints: []api.Endpoint{{IP: "baz"}, {IP: "bar"}},
|
||||
Endpoints: []api.Endpoint{
|
||||
{IP: "baz", Ports: []api.EndpointPort{{Port: 1, Protocol: api.ProtocolTCP}}},
|
||||
{IP: "bar", Ports: []api.EndpointPort{{Port: 2, Protocol: api.ProtocolTCP}}},
|
||||
},
|
||||
}
|
||||
|
||||
key, _ := makeServiceEndpointsKey(ctx, "foo")
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
||||
@@ -218,17 +219,57 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
|
||||
|
||||
// ResourceLocation returns a URL to which one can send traffic for the specified service.
|
||||
func (rs *REST) ResourceLocation(ctx api.Context, id string) (string, error) {
|
||||
eps, err := rs.registry.GetEndpoints(ctx, id)
|
||||
// Allow ID as "svcname" or "svcname:port". Choose an endpoint at
|
||||
// random. If the port is specified as a number, use that value
|
||||
// directly. If the port is specified as a name, try to look up that
|
||||
// name on the chosen endpoint. If port is not specified, try to use
|
||||
// the first unnamed port on the chosen endpoint. If there are no
|
||||
// unnamed ports, try to use the first defined port.
|
||||
parts := strings.Split(id, ":")
|
||||
if len(parts) > 2 {
|
||||
return "", errors.NewBadRequest(fmt.Sprintf("invalid service request %q", id))
|
||||
}
|
||||
name := parts[0]
|
||||
port := ""
|
||||
if len(parts) == 2 {
|
||||
port = parts[1]
|
||||
}
|
||||
|
||||
eps, err := rs.registry.GetEndpoints(ctx, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(eps.Endpoints) == 0 {
|
||||
return "", fmt.Errorf("no endpoints available for %v", id)
|
||||
return "", fmt.Errorf("no endpoints available for %v", name)
|
||||
}
|
||||
ep := &eps.Endpoints[rand.Intn(len(eps.Endpoints))]
|
||||
|
||||
// Try to figure out a port.
|
||||
if _, err := strconv.Atoi(port); err != nil {
|
||||
// Do nothing - port is correct as is.
|
||||
} else {
|
||||
// Try a name lookup, even if name is "".
|
||||
for i := range ep.Ports {
|
||||
if ep.Ports[i].Name == port {
|
||||
port = strconv.Itoa(ep.Ports[i].Port)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if port == "" {
|
||||
// Still nothing - try the first defined port.
|
||||
if len(ep.Ports) > 0 {
|
||||
port = strconv.Itoa(ep.Ports[0].Port)
|
||||
}
|
||||
}
|
||||
|
||||
// We leave off the scheme ('http://') because we have no idea what sort of server
|
||||
// is listening at this endpoint.
|
||||
ep := &eps.Endpoints[rand.Intn(len(eps.Endpoints))]
|
||||
return net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port)), nil
|
||||
loc := ep.IP
|
||||
if port != "" {
|
||||
loc += fmt.Sprintf(":%s", port)
|
||||
}
|
||||
return loc, nil
|
||||
}
|
||||
|
||||
func (rs *REST) createExternalLoadBalancer(ctx api.Context, service *api.Service) error {
|
||||
|
@@ -370,7 +370,7 @@ func TestServiceRegistryGet(t *testing.T) {
|
||||
func TestServiceRegistryResourceLocation(t *testing.T) {
|
||||
ctx := api.NewDefaultContext()
|
||||
registry := registrytest.NewServiceRegistry()
|
||||
registry.Endpoints = api.Endpoints{Endpoints: []api.Endpoint{{IP: "foo", Port: 80}}}
|
||||
registry.Endpoints = api.Endpoints{Endpoints: []api.Endpoint{{IP: "foo", Ports: []api.EndpointPort{{Port: 80}}}}}
|
||||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
|
Reference in New Issue
Block a user