diff --git a/pkg/cloudprovider/cloud.go b/pkg/cloudprovider/cloud.go index 4307b0a5c9c..b2935357913 100644 --- a/pkg/cloudprovider/cloud.go +++ b/pkg/cloudprovider/cloud.go @@ -26,6 +26,8 @@ type Interface interface { TCPLoadBalancer() (TCPLoadBalancer, bool) // Instances returns an instances interface. Also returns true if the interface is supported, false otherwise. Instances() (Instances, bool) + // Zones returns a zones interface. Also returns true if the interface is supported, false otherwise. + Zones() (Zones, bool) } // TCPLoadBalancer is an abstract, pluggable interface for TCP load balancers. @@ -48,3 +50,9 @@ type Instances interface { // List lists instances that match 'filter' which is a regular expression which must match the entire instance name (fqdn) List(filter string) ([]string, error) } + +// Zones is an abstract, pluggable interface for zone enumeration. +type Zones interface { + // GetZone returns the name of the current failure zone that the program is running in + GetZone() (string, error) +} diff --git a/pkg/cloudprovider/fake_cloud.go b/pkg/cloudprovider/fake_cloud.go index 7c6bb9bd441..b0cf1dd9bd1 100644 --- a/pkg/cloudprovider/fake_cloud.go +++ b/pkg/cloudprovider/fake_cloud.go @@ -28,6 +28,7 @@ type FakeCloud struct { Calls []string IP net.IP Machines []string + Zone string } func (f *FakeCloud) addCall(desc string) { @@ -53,6 +54,10 @@ func (f *FakeCloud) Instances() (Instances, bool) { return f, true } +func (f *FakeCloud) Zones() (Zones, bool) { + return f, true +} + // TCPLoadBalancerExists is a stub implementation of TCPLoadBalancer.TCPLoadBalancerExists. func (f *FakeCloud) TCPLoadBalancerExists(name, region string) (bool, error) { return f.Exists, f.Err @@ -98,3 +103,8 @@ func (f *FakeCloud) List(filter string) ([]string, error) { } return result, f.Err } + +func (f *FakeCloud) GetZone() (string, error) { + f.addCall("get-zone") + return f.Zone, f.Err +} diff --git a/pkg/cloudprovider/gce.go b/pkg/cloudprovider/gce.go index 5697ff2289e..c753f00697a 100644 --- a/pkg/cloudprovider/gce.go +++ b/pkg/cloudprovider/gce.go @@ -93,6 +93,11 @@ func (gce *GCECloud) Instances() (Instances, bool) { return gce, true } +// Zones returns an implementation of Zones for Google Compute Engine. +func (gce *GCECloud) Zones() (Zones, bool) { + return gce, true +} + func makeHostLink(projectID, zone, host string) string { ix := strings.Index(host, ".") if ix != -1 { @@ -231,3 +236,7 @@ func (gce *GCECloud) List(filter string) ([]string, error) { } return instances, nil } + +func (gce *GCECloud) GetZone() (string, error) { + return gce.zone, nil +} diff --git a/pkg/registry/service_registry.go b/pkg/registry/service_registry.go index efc48a36a74..316a60fc9d7 100644 --- a/pkg/registry/service_registry.go +++ b/pkg/registry/service_registry.go @@ -155,16 +155,24 @@ func (sr *ServiceRegistryStorage) Create(obj interface{}) (<-chan interface{}, e // correctly no matter what http operations happen. if srv.CreateExternalLoadBalancer { var balancer cloudprovider.TCPLoadBalancer + var zones cloudprovider.Zones var ok bool if sr.cloud != nil { balancer, ok = sr.cloud.TCPLoadBalancer() + if ok { + zones, ok = sr.cloud.Zones() + } } - if ok && balancer != nil { + if ok && balancer != nil && zones != nil { hosts, err := sr.machines.List() if err != nil { return nil, err } - err = balancer.CreateTCPLoadBalancer(srv.ID, "us-central1", srv.Port, hosts) + zone, err := zones.GetZone() + if err != nil { + return nil, err + } + err = balancer.CreateTCPLoadBalancer(srv.ID, zone, srv.Port, hosts) if err != nil { return nil, err } diff --git a/pkg/registry/service_registry_test.go b/pkg/registry/service_registry_test.go index 1754d982827..ae117bdf777 100644 --- a/pkg/registry/service_registry_test.go +++ b/pkg/registry/service_registry_test.go @@ -54,11 +54,11 @@ func TestServiceStorageValidatesCreate(t *testing.T) { storage := MakeServiceRegistryStorage(memory, nil, nil) failureCases := map[string]api.Service{ - "empty ID": api.Service{ + "empty ID": { JSONBase: api.JSONBase{ID: ""}, Selector: map[string]string{"bar": "baz"}, }, - "empty selector": api.Service{ + "empty selector": { JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{}, }, @@ -83,11 +83,11 @@ func TestServiceStorageValidatesUpdate(t *testing.T) { storage := MakeServiceRegistryStorage(memory, nil, nil) failureCases := map[string]api.Service{ - "empty ID": api.Service{ + "empty ID": { JSONBase: api.JSONBase{ID: ""}, Selector: map[string]string{"bar": "baz"}, }, - "empty selector": api.Service{ + "empty selector": { JSONBase: api.JSONBase{ID: "foo"}, Selector: map[string]string{}, }, @@ -118,7 +118,7 @@ func TestServiceRegistryExternalService(t *testing.T) { c, _ := storage.Create(svc) <-c - if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "create" { + if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[0] != "get-zone" || fakeCloud.Calls[1] != "create" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := memory.GetService(svc.ID) @@ -145,7 +145,7 @@ func TestServiceRegistryExternalServiceError(t *testing.T) { c, _ := storage.Create(svc) <-c - if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "create" { + if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "get-zone" { t.Errorf("Unexpected call(s): %#v", fakeCloud.Calls) } srv, err := memory.GetService("foo")