diff --git a/pkg/controller/replication_controller.go b/pkg/controller/replication_controller.go index ce17106b31..552c836c43 100644 --- a/pkg/controller/replication_controller.go +++ b/pkg/controller/replication_controller.go @@ -35,7 +35,7 @@ import ( // with actual running pods. // TODO: Remove the etcd dependency and re-factor in terms of a generic watch interface type ReplicationManager struct { - etcdClient *etcd.Client + etcdClient util.EtcdClient kubeClient client.ClientInterface podControl PodControlInterface updateLock sync.Mutex @@ -74,7 +74,7 @@ func (r RealPodControl) deletePod(podID string) error { return r.kubeClient.DeletePod(podID) } -func MakeReplicationManager(etcdClient *etcd.Client, kubeClient client.ClientInterface) *ReplicationManager { +func MakeReplicationManager(etcdClient util.EtcdClient, kubeClient client.ClientInterface) *ReplicationManager { return &ReplicationManager{ kubeClient: kubeClient, etcdClient: etcdClient, diff --git a/pkg/controller/replication_controller_test.go b/pkg/controller/replication_controller_test.go index efe90f80fb..696af15960 100644 --- a/pkg/controller/replication_controller_test.go +++ b/pkg/controller/replication_controller_test.go @@ -317,3 +317,79 @@ func TestHandleWatchResponse(t *testing.T) { t.Errorf("Unexpected mismatch. Expected %#v, Saw: %#v", controller, controllerOut) } } + +func TestSyncronize(t *testing.T) { + controllerSpec1 := api.ReplicationController{ + DesiredState: api.ReplicationControllerState{ + Replicas: 4, + PodTemplate: api.PodTemplate{ + DesiredState: api.PodState{ + Manifest: api.ContainerManifest{ + Containers: []api.Container{ + { + Image: "foo/bar", + }, + }, + }, + }, + Labels: map[string]string{ + "name": "foo", + "type": "production", + }, + }, + }, + } + controllerSpec2 := api.ReplicationController{ + DesiredState: api.ReplicationControllerState{ + Replicas: 3, + PodTemplate: api.PodTemplate{ + DesiredState: api.PodState{ + Manifest: api.ContainerManifest{ + Containers: []api.Container{ + { + Image: "bar/baz", + }, + }, + }, + }, + Labels: map[string]string{ + "name": "bar", + "type": "production", + }, + }, + }, + } + + fakeEtcd := util.MakeFakeEtcdClient(t) + fakeEtcd.Data["/registry/controllers"] = util.EtcdResponseWithError{ + R: &etcd.Response{ + Node: &etcd.Node{ + Nodes: []*etcd.Node{ + { + Value: util.MakeJSONString(controllerSpec1), + }, + { + Value: util.MakeJSONString(controllerSpec2), + }, + }, + }, + }, + } + + fakeHandler := util.FakeHandler{ + StatusCode: 200, + ResponseBody: "{}", + T: t, + } + testServer := httptest.NewTLSServer(&fakeHandler) + client := client.Client{ + Host: testServer.URL, + } + manager := MakeReplicationManager(fakeEtcd, client) + fakePodControl := FakePodControl{} + manager.podControl = &fakePodControl + + manager.synchronize() + + validateSyncReplication(t, &fakePodControl, 7, 0) +} diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 0167af4031..620c99df7e 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -33,7 +33,6 @@ import ( "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - "github.com/GoogleCloudPlatform/kubernetes/pkg/registry" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/coreos/go-etcd/etcd" "github.com/fsouza/go-dockerclient" @@ -62,7 +61,7 @@ type DockerInterface interface { // The main kubelet implementation type Kubelet struct { Hostname string - Client registry.EtcdClient + Client util.EtcdClient DockerClient DockerInterface FileCheckFrequency time.Duration SyncFrequency time.Duration diff --git a/pkg/registry/etcd_registry.go b/pkg/registry/etcd_registry.go index b45233d907..389e4b98ec 100644 --- a/pkg/registry/etcd_registry.go +++ b/pkg/registry/etcd_registry.go @@ -21,8 +21,6 @@ import ( "fmt" "log" - "github.com/coreos/go-etcd/etcd" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -31,21 +29,9 @@ import ( // TODO: Need to add a reconciler loop that makes sure that things in pods are reflected into // kubelet (and vice versa) -// EtcdClient is an injectable interface for testing. -type EtcdClient interface { - AddChild(key, data string, ttl uint64) (*etcd.Response, error) - Get(key string, sort, recursive bool) (*etcd.Response, error) - Set(key, value string, ttl uint64) (*etcd.Response, error) - Create(key, value string, ttl uint64) (*etcd.Response, error) - Delete(key string, recursive bool) (*etcd.Response, error) - // I'd like to use directional channels here (e.g. <-chan) but this interface mimics - // the etcd client interface which doesn't, and it doesn't seem worth it to wrap the api. - Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) -} - // EtcdRegistry is an implementation of both ControllerRegistry and PodRegistry which is backed with etcd. type EtcdRegistry struct { - etcdClient EtcdClient + etcdClient util.EtcdClient machines []string manifestFactory ManifestFactory } @@ -54,7 +40,7 @@ type EtcdRegistry struct { // 'client' is the connection to etcd // 'machines' is the list of machines // 'scheduler' is the scheduling algorithm to use. -func MakeEtcdRegistry(client EtcdClient, machines []string) *EtcdRegistry { +func MakeEtcdRegistry(client util.EtcdClient, machines []string) *EtcdRegistry { registry := &EtcdRegistry{ etcdClient: client, machines: machines, diff --git a/pkg/registry/etcd_registry_test.go b/pkg/registry/etcd_registry_test.go index 27b30884e4..85676d80f8 100644 --- a/pkg/registry/etcd_registry_test.go +++ b/pkg/registry/etcd_registry_test.go @@ -26,7 +26,7 @@ import ( "github.com/coreos/go-etcd/etcd" ) -func MakeTestEtcdRegistry(client EtcdClient, machines []string) *EtcdRegistry { +func MakeTestEtcdRegistry(client util.EtcdClient, machines []string) *EtcdRegistry { registry := MakeEtcdRegistry(client, machines) registry.manifestFactory = &BasicManifestFactory{ serviceRegistry: &MockServiceRegistry{}, diff --git a/pkg/util/fake_etcd_client.go b/pkg/util/fake_etcd_client.go index 9fff51a41b..d98bb500c2 100644 --- a/pkg/util/fake_etcd_client.go +++ b/pkg/util/fake_etcd_client.go @@ -22,6 +22,18 @@ import ( "github.com/coreos/go-etcd/etcd" ) +// EtcdClient is an injectable interface for testing. +type EtcdClient interface { + AddChild(key, data string, ttl uint64) (*etcd.Response, error) + Get(key string, sort, recursive bool) (*etcd.Response, error) + Set(key, value string, ttl uint64) (*etcd.Response, error) + Create(key, value string, ttl uint64) (*etcd.Response, error) + Delete(key string, recursive bool) (*etcd.Response, error) + // I'd like to use directional channels here (e.g. <-chan) but this interface mimics + // the etcd client interface which doesn't, and it doesn't seem worth it to wrap the api. + Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) +} + type EtcdResponseWithError struct { R *etcd.Response E error