Merge pull request #5131 from brendandburns/service

Place external load balancers in a namespace.
This commit is contained in:
Tim Hockin 2015-03-06 08:49:37 -08:00
commit c2ebad2ac0
3 changed files with 28 additions and 6 deletions

View File

@ -24,6 +24,15 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider" "github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
) )
// FakeBalancer is a fake storage of balancer information
type FakeBalancer struct {
Name string
Region string
ExternalIP net.IP
Port int
Hosts []string
}
// FakeCloud is a test-double implementation of Interface, TCPLoadBalancer and Instances. It is useful for testing. // FakeCloud is a test-double implementation of Interface, TCPLoadBalancer and Instances. It is useful for testing.
type FakeCloud struct { type FakeCloud struct {
Exists bool Exists bool
@ -36,6 +45,7 @@ type FakeCloud struct {
ClusterList []string ClusterList []string
MasterName string MasterName string
ExternalIP net.IP ExternalIP net.IP
Balancers []FakeBalancer
cloudprovider.Zone cloudprovider.Zone
} }
@ -87,6 +97,7 @@ func (f *FakeCloud) TCPLoadBalancerExists(name, region string) (bool, error) {
// It adds an entry "create" into the internal method call record. // It adds an entry "create" into the internal method call record.
func (f *FakeCloud) CreateTCPLoadBalancer(name, region string, externalIP net.IP, port int, hosts []string, affinityType api.AffinityType) (net.IP, error) { func (f *FakeCloud) CreateTCPLoadBalancer(name, region string, externalIP net.IP, port int, hosts []string, affinityType api.AffinityType) (net.IP, error) {
f.addCall("create") f.addCall("create")
f.Balancers = append(f.Balancers, FakeBalancer{name, region, externalIP, port, hosts})
return f.ExternalIP, f.Err return f.ExternalIP, f.Err
} }

View File

@ -138,7 +138,7 @@ func (rs *REST) Delete(ctx api.Context, id string) (runtime.Object, error) {
} }
rs.portalMgr.Release(net.ParseIP(service.Spec.PortalIP)) rs.portalMgr.Release(net.ParseIP(service.Spec.PortalIP))
if service.Spec.CreateExternalLoadBalancer { if service.Spec.CreateExternalLoadBalancer {
rs.deleteExternalLoadBalancer(service) rs.deleteExternalLoadBalancer(ctx, service)
} }
return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(ctx, id) return &api.Status{Status: api.StatusSuccess}, rs.registry.DeleteService(ctx, id)
} }
@ -201,7 +201,7 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
if externalLoadBalancerNeedsUpdate(oldService, service) { if externalLoadBalancerNeedsUpdate(oldService, service) {
// TODO: support updating existing balancers // TODO: support updating existing balancers
if oldService.Spec.CreateExternalLoadBalancer { if oldService.Spec.CreateExternalLoadBalancer {
err = rs.deleteExternalLoadBalancer(oldService) err = rs.deleteExternalLoadBalancer(ctx, oldService)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -232,6 +232,10 @@ func (rs *REST) ResourceLocation(ctx api.Context, id string) (string, error) {
return net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port)), nil return net.JoinHostPort(ep.IP, strconv.Itoa(ep.Port)), nil
} }
func (rs *REST) getLoadbalancerName(ctx api.Context, service *api.Service) string {
return rs.clusterName + "-" + api.NamespaceValue(ctx) + "-" + service.Name
}
func (rs *REST) createExternalLoadBalancer(ctx api.Context, service *api.Service) error { func (rs *REST) createExternalLoadBalancer(ctx api.Context, service *api.Service) error {
if rs.cloud == nil { if rs.cloud == nil {
return fmt.Errorf("requested an external service, but no cloud provider supplied.") return fmt.Errorf("requested an external service, but no cloud provider supplied.")
@ -256,18 +260,19 @@ func (rs *REST) createExternalLoadBalancer(ctx api.Context, service *api.Service
if err != nil { if err != nil {
return err return err
} }
name := rs.getLoadbalancerName(ctx, service)
// TODO: We should be able to rely on valid input, and not do defaulting here. // TODO: We should be able to rely on valid input, and not do defaulting here.
var affinityType api.AffinityType = service.Spec.SessionAffinity var affinityType api.AffinityType = service.Spec.SessionAffinity
if len(service.Spec.PublicIPs) > 0 { if len(service.Spec.PublicIPs) > 0 {
for _, publicIP := range service.Spec.PublicIPs { for _, publicIP := range service.Spec.PublicIPs {
_, err = balancer.CreateTCPLoadBalancer(rs.clusterName+"-"+service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts), affinityType) _, err = balancer.CreateTCPLoadBalancer(name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts), affinityType)
if err != nil { if err != nil {
// TODO: have to roll-back any successful calls. // TODO: have to roll-back any successful calls.
return err return err
} }
} }
} else { } else {
ip, err := balancer.CreateTCPLoadBalancer(rs.clusterName+"-"+service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts), affinityType) ip, err := balancer.CreateTCPLoadBalancer(name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts), affinityType)
if err != nil { if err != nil {
return err return err
} }
@ -276,7 +281,7 @@ func (rs *REST) createExternalLoadBalancer(ctx api.Context, service *api.Service
return nil return nil
} }
func (rs *REST) deleteExternalLoadBalancer(service *api.Service) error { func (rs *REST) deleteExternalLoadBalancer(ctx api.Context, service *api.Service) error {
if rs.cloud == nil { if rs.cloud == nil {
return fmt.Errorf("requested an external service, but no cloud provider supplied.") return fmt.Errorf("requested an external service, but no cloud provider supplied.")
} }
@ -296,7 +301,7 @@ func (rs *REST) deleteExternalLoadBalancer(service *api.Service) error {
if err != nil { if err != nil {
return err return err
} }
if err := balancer.DeleteTCPLoadBalancer(rs.clusterName+"-"+service.Name, zone.Region); err != nil { if err := balancer.DeleteTCPLoadBalancer(rs.getLoadbalancerName(ctx, service), zone.Region); err != nil {
return err return err
} }
return nil return nil

View File

@ -224,6 +224,9 @@ func TestServiceRegistryExternalService(t *testing.T) {
if srv == nil { if srv == nil {
t.Errorf("Failed to find service: %s", svc.Name) t.Errorf("Failed to find service: %s", svc.Name)
} }
if len(fakeCloud.Balancers) != 1 || fakeCloud.Balancers[0].Name != "kubernetes-default-foo" || fakeCloud.Balancers[0].Port != 6502 {
t.Errorf("Unexpected balancer created: %v", fakeCloud.Balancers)
}
} }
func TestServiceRegistryExternalServiceError(t *testing.T) { func TestServiceRegistryExternalServiceError(t *testing.T) {
@ -627,6 +630,9 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unexpected error %v", err) t.Errorf("Unexpected error %v", err)
} }
if len(fakeCloud.Balancers) != 1 || fakeCloud.Balancers[0].Name != "kubernetes-default-foo" || fakeCloud.Balancers[0].Port != 6502 {
t.Errorf("Unexpected balancer created: %v", fakeCloud.Balancers)
}
} }
func TestServiceRegistryIPReloadFromStorage(t *testing.T) { func TestServiceRegistryIPReloadFromStorage(t *testing.T) {