From 66e2575f2b047371999a2ed1329122b58abd8ae3 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Sun, 8 Jun 2014 21:39:57 -0700 Subject: [PATCH 1/2] More Task -> Pod --- api/doc/controller-schema.json | 4 +- api/examples/controller-list.json | 2 +- api/examples/controller.json | 2 +- cmd/apiserver/apiserver.go | 10 +- examples/guestbook/frontend-controller.json | 2 +- examples/guestbook/guestbook.md | 4 +- .../guestbook/redis-slave-controller.json | 2 +- pkg/api/types.go | 20 +- pkg/client/client.go | 6 +- pkg/client/client_test.go | 14 +- pkg/cloudcfg/cloudcfg.go | 4 +- pkg/cloudcfg/cloudcfg_test.go | 10 +- pkg/registry/controller_registry_test.go | 4 +- pkg/registry/endpoints.go | 4 +- pkg/registry/endpoints_test.go | 12 +- pkg/registry/etcd_registry_test.go | 6 +- pkg/registry/interfaces.go | 2 +- pkg/registry/manifest_factory_test.go | 6 +- pkg/registry/memory_registry_test.go | 2 +- pkg/registry/replication_controller.go | 6 +- pkg/registry/replication_controller_test.go | 16 +- pkg/registry/scheduler.go | 4 +- pkg/registry/scheduler_test.go | 18 +- pkg/registry/task_registry.go | 121 ----------- pkg/registry/task_registry_test.go | 204 ------------------ 25 files changed, 80 insertions(+), 405 deletions(-) delete mode 100644 pkg/registry/task_registry.go delete mode 100644 pkg/registry/task_registry_test.go diff --git a/api/doc/controller-schema.json b/api/doc/controller-schema.json index 4008c7e22a0..fddc9db6576 100644 --- a/api/doc/controller-schema.json +++ b/api/doc/controller-schema.json @@ -2,7 +2,7 @@ "$schema": "http://json-schema.org/draft-03/schema", "type": "object", "required": false, - "description": "A replicationController resource. A replicationController helps to create and manage a set of tasks. It acts as a factory to create new tasks based on a template. It ensures that there are a specific number of tasks running. If fewer tasks are running than `replicas` then the needed tasks are generated using `taskTemplate`. If more tasks are running than `replicas`, then excess tasks are deleted.", + "description": "A replicationController resource. A replicationController helps to create and manage a set of tasks. It acts as a factory to create new tasks based on a template. It ensures that there are a specific number of tasks running. If fewer tasks are running than `replicas` then the needed tasks are generated using `podTemplate`. If more tasks are running than `replicas`, then excess tasks are deleted.", "properties": { "kind": { "type": "string", @@ -35,7 +35,7 @@ "required": false, "description": "Required labels used to identify tasks in the set" }, - "taskTemplate": { + "podTemplate": { "type": "object", "required": false, "description": "Template from which to create new tasks, as necessary. Identical to task schema." diff --git a/api/examples/controller-list.json b/api/examples/controller-list.json index 0042a9a1bc0..b2a17950b47 100644 --- a/api/examples/controller-list.json +++ b/api/examples/controller-list.json @@ -7,7 +7,7 @@ "replicasInSet": { "name": "testRun" }, - "taskTemplate": { + "podTemplate": { "desiredState": { "image": "dockerfile/nginx", "networkPorts": [ diff --git a/api/examples/controller.json b/api/examples/controller.json index 04b98f65519..c08be4aaaea 100644 --- a/api/examples/controller.json +++ b/api/examples/controller.json @@ -3,7 +3,7 @@ "desiredState": { "replicas": 2, "replicasInSet": {"name": "nginx"}, - "taskTemplate": { + "podTemplate": { "desiredState": { "manifest": { "containers": [{ diff --git a/cmd/apiserver/apiserver.go b/cmd/apiserver/apiserver.go index d2d0c3a5146..313ce3eea8e 100644 --- a/cmd/apiserver/apiserver.go +++ b/cmd/apiserver/apiserver.go @@ -52,7 +52,7 @@ func main() { } var ( - taskRegistry registry.TaskRegistry + podRegistry registry.PodRegistry controllerRegistry registry.ControllerRegistry serviceRegistry registry.ServiceRegistry ) @@ -60,11 +60,11 @@ func main() { if len(etcdServerList) > 0 { log.Printf("Creating etcd client pointing to %v", etcdServerList) etcdClient := etcd.NewClient(etcdServerList) - taskRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) + podRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) controllerRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) serviceRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) } else { - taskRegistry = registry.MakeMemoryRegistry() + podRegistry = registry.MakeMemoryRegistry() controllerRegistry = registry.MakeMemoryRegistry() serviceRegistry = registry.MakeMemoryRegistry() } @@ -75,12 +75,12 @@ func main() { } storage := map[string]apiserver.RESTStorage{ - "tasks": registry.MakeTaskRegistryStorage(taskRegistry, containerInfo, registry.MakeFirstFitScheduler(machineList, taskRegistry)), + "tasks": registry.MakeTaskRegistryStorage(podRegistry, containerInfo, registry.MakeFirstFitScheduler(machineList, podRegistry)), "replicationControllers": registry.MakeControllerRegistryStorage(controllerRegistry), "services": registry.MakeServiceRegistryStorage(serviceRegistry), } - endpoints := registry.MakeEndpointController(serviceRegistry, taskRegistry) + endpoints := registry.MakeEndpointController(serviceRegistry, podRegistry) go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10) s := &http.Server{ diff --git a/examples/guestbook/frontend-controller.json b/examples/guestbook/frontend-controller.json index 7c8febe3fe7..7575b475958 100644 --- a/examples/guestbook/frontend-controller.json +++ b/examples/guestbook/frontend-controller.json @@ -3,7 +3,7 @@ "desiredState": { "replicas": 3, "replicasInSet": {"name": "frontend"}, - "taskTemplate": { + "podTemplate": { "desiredState": { "manifest": { "containers": [{ diff --git a/examples/guestbook/guestbook.md b/examples/guestbook/guestbook.md index bc2292298b2..b48e1e8dc9b 100644 --- a/examples/guestbook/guestbook.md +++ b/examples/guestbook/guestbook.md @@ -82,7 +82,7 @@ Although the redis master is a single task, the redis read slaves are a 'replica "desiredState": { "replicas": 2, "replicasInSet": {"name": "redis-slave"}, - "taskTemplate": { + "podTemplate": { "desiredState": { "manifest": { "containers": [{ @@ -149,7 +149,7 @@ This is a simple PHP server that is configured to talk to both the slave and mas "desiredState": { "replicas": 3, "replicasInSet": {"name": "frontend"}, - "taskTemplate": { + "podTemplate": { "desiredState": { "manifest": { "containers": [{ diff --git a/examples/guestbook/redis-slave-controller.json b/examples/guestbook/redis-slave-controller.json index dd51a2583df..ee6a31e0dac 100644 --- a/examples/guestbook/redis-slave-controller.json +++ b/examples/guestbook/redis-slave-controller.json @@ -3,7 +3,7 @@ "desiredState": { "replicas": 2, "replicasInSet": {"name": "redisslave"}, - "taskTemplate": { + "podTemplate": { "desiredState": { "manifest": { "containers": [{ diff --git a/pkg/api/types.go b/pkg/api/types.go index 6938956258a..9689bd3396a 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -81,8 +81,8 @@ type JSONBase struct { SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` } -// TaskState is the state of a task, used as either input (desired state) or output (current state) -type TaskState struct { +// PodState is the state of a pod, used as either input (desired state) or output (current state) +type PodState struct { Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"` Status string `json:"status,omitempty" yaml:"status,omitempty"` Host string `json:"host,omitempty" yaml:"host,omitempty"` @@ -90,24 +90,24 @@ type TaskState struct { Info interface{} `json:"info,omitempty" yaml:"info,omitempty"` } -type TaskList struct { +type PodList struct { JSONBase Items []Pod `json:"items" yaml:"items,omitempty"` } -// Task is a single task, used as either input (create, update) or as output (list, get) +// Pod is a collection of containers, used as either input (create, update) or as output (list, get) type Pod struct { JSONBase Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - DesiredState TaskState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` - CurrentState TaskState `json:"currentState,omitempty" yaml:"currentState,omitempty"` + DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` + CurrentState PodState `json:"currentState,omitempty" yaml:"currentState,omitempty"` } // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get) type ReplicationControllerState struct { Replicas int `json:"replicas" yaml:"replicas"` ReplicasInSet map[string]string `json:"replicasInSet,omitempty" yaml:"replicasInSet,omitempty"` - TaskTemplate TaskTemplate `json:"taskTemplate,omitempty" yaml:"taskTemplate,omitempty"` + PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"` } type ReplicationControllerList struct { @@ -122,9 +122,9 @@ type ReplicationController struct { Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` } -// TaskTemplate holds the information used for creating tasks -type TaskTemplate struct { - DesiredState TaskState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` +// PodTemplate holds the information used for creating pods +type PodTemplate struct { + DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` } diff --git a/pkg/client/client.go b/pkg/client/client.go index 88a596ac7e0..001b371d03f 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -38,7 +38,7 @@ import ( // ClientInterface holds the methods for clients of Kubenetes, an interface to allow mock testing type ClientInterface interface { - ListTasks(labelQuery map[string]string) (api.TaskList, error) + ListTasks(labelQuery map[string]string) (api.PodList, error) GetTask(name string) (api.Pod, error) DeleteTask(name string) error CreateTask(api.Pod) (api.Pod, error) @@ -143,12 +143,12 @@ func DecodeLabelQuery(labelQuery string) map[string]string { } // ListTasks takes a label query, and returns the list of tasks that match that query -func (client Client) ListTasks(labelQuery map[string]string) (api.TaskList, error) { +func (client Client) ListTasks(labelQuery map[string]string) (api.PodList, error) { path := "tasks" if labelQuery != nil && len(labelQuery) > 0 { path += "?labels=" + EncodeLabelQuery(labelQuery) } - var result api.TaskList + var result api.PodList _, err := client.rawRequest("GET", path, nil, &result) return result, err } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 0ff642c9dde..334c9f86811 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -61,10 +61,10 @@ func TestListEmptyTasks(t *testing.T) { } func TestListTasks(t *testing.T) { - expectedTaskList := api.TaskList{ + expectedTaskList := api.PodList{ Items: []api.Pod{ api.Pod{ - CurrentState: api.TaskState{ + CurrentState: api.PodState{ Status: "Foobar", }, Labels: map[string]string{ @@ -95,10 +95,10 @@ func TestListTasks(t *testing.T) { } func TestListTasksLabels(t *testing.T) { - expectedTaskList := api.TaskList{ + expectedTaskList := api.PodList{ Items: []api.Pod{ api.Pod{ - CurrentState: api.TaskState{ + CurrentState: api.PodState{ Status: "Foobar", }, Labels: map[string]string{ @@ -138,7 +138,7 @@ func TestListTasksLabels(t *testing.T) { func TestGetTask(t *testing.T) { expectedTask := api.Pod{ - CurrentState: api.TaskState{ + CurrentState: api.PodState{ Status: "Foobar", }, Labels: map[string]string{ @@ -185,7 +185,7 @@ func TestDeleteTask(t *testing.T) { func TestCreateTask(t *testing.T) { requestTask := api.Pod{ - CurrentState: api.TaskState{ + CurrentState: api.PodState{ Status: "Foobar", }, Labels: map[string]string{ @@ -216,7 +216,7 @@ func TestCreateTask(t *testing.T) { func TestUpdateTask(t *testing.T) { requestTask := api.Pod{ JSONBase: api.JSONBase{ID: "foo"}, - CurrentState: api.TaskState{ + CurrentState: api.PodState{ Status: "Foobar", }, Labels: map[string]string{ diff --git a/pkg/cloudcfg/cloudcfg.go b/pkg/cloudcfg/cloudcfg.go index 208a6f082cd..7fd5d3e719b 100644 --- a/pkg/cloudcfg/cloudcfg.go +++ b/pkg/cloudcfg/cloudcfg.go @@ -183,8 +183,8 @@ func RunController(image, name string, replicas int, client client.ClientInterfa ReplicasInSet: map[string]string{ "name": name, }, - TaskTemplate: api.TaskTemplate{ - DesiredState: api.TaskState{ + PodTemplate: api.PodTemplate{ + DesiredState: api.PodState{ Manifest: api.ContainerManifest{ Containers: []api.Container{ api.Container{ diff --git a/pkg/cloudcfg/cloudcfg_test.go b/pkg/cloudcfg/cloudcfg_test.go index 9bd1925aebd..497cce9d084 100644 --- a/pkg/cloudcfg/cloudcfg_test.go +++ b/pkg/cloudcfg/cloudcfg_test.go @@ -40,11 +40,11 @@ type Action struct { type FakeKubeClient struct { actions []Action - tasks TaskList + tasks PodList ctrl ReplicationController } -func (client *FakeKubeClient) ListTasks(labelQuery map[string]string) (TaskList, error) { +func (client *FakeKubeClient) ListTasks(labelQuery map[string]string) (PodList, error) { client.actions = append(client.actions, Action{action: "list-tasks"}) return client.tasks, nil } @@ -117,7 +117,7 @@ func validateAction(expectedAction, actualAction Action, t *testing.T) { func TestUpdateWithTasks(t *testing.T) { client := FakeKubeClient{ - tasks: TaskList{ + tasks: PodList{ Items: []Pod{ Pod{JSONBase: JSONBase{ID: "task-1"}}, Pod{JSONBase: JSONBase{ID: "task-2"}}, @@ -177,7 +177,7 @@ func TestRunController(t *testing.T) { controller := fakeClient.actions[0].value.(ReplicationController) if controller.ID != name || controller.DesiredState.Replicas != replicas || - controller.DesiredState.TaskTemplate.DesiredState.Manifest.Containers[0].Image != image { + controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image != image { t.Errorf("Unexpected controller: %#v", controller) } } @@ -196,7 +196,7 @@ func TestRunControllerWithService(t *testing.T) { controller := fakeClient.actions[0].value.(ReplicationController) if controller.ID != name || controller.DesiredState.Replicas != replicas || - controller.DesiredState.TaskTemplate.DesiredState.Manifest.Containers[0].Image != image { + controller.DesiredState.PodTemplate.DesiredState.Manifest.Containers[0].Image != image { t.Errorf("Unexpected controller: %#v", controller) } } diff --git a/pkg/registry/controller_registry_test.go b/pkg/registry/controller_registry_test.go index b7c8813f323..60a68887702 100644 --- a/pkg/registry/controller_registry_test.go +++ b/pkg/registry/controller_registry_test.go @@ -141,8 +141,8 @@ func TestControllerParsing(t *testing.T) { ReplicasInSet: map[string]string{ "name": "nginx", }, - TaskTemplate: TaskTemplate{ - DesiredState: TaskState{ + PodTemplate: PodTemplate{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ diff --git a/pkg/registry/endpoints.go b/pkg/registry/endpoints.go index 01e7c20aabc..23b45f6c3a7 100644 --- a/pkg/registry/endpoints.go +++ b/pkg/registry/endpoints.go @@ -22,7 +22,7 @@ import ( . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) -func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry TaskRegistry) *EndpointController { +func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry PodRegistry) *EndpointController { return &EndpointController{ serviceRegistry: serviceRegistry, taskRegistry: taskRegistry, @@ -31,7 +31,7 @@ func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry TaskRe type EndpointController struct { serviceRegistry ServiceRegistry - taskRegistry TaskRegistry + taskRegistry PodRegistry } func (e *EndpointController) SyncServiceEndpoints() error { diff --git a/pkg/registry/endpoints_test.go b/pkg/registry/endpoints_test.go index 787c6191842..84e541d495e 100644 --- a/pkg/registry/endpoints_test.go +++ b/pkg/registry/endpoints_test.go @@ -24,7 +24,7 @@ import ( func TestSyncEndpointsEmpty(t *testing.T) { serviceRegistry := MockServiceRegistry{} - taskRegistry := MockTaskRegistry{} + taskRegistry := MockPodRegistry{} endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry) err := endpoints.SyncServiceEndpoints() @@ -35,7 +35,7 @@ func TestSyncEndpointsError(t *testing.T) { serviceRegistry := MockServiceRegistry{ err: fmt.Errorf("Test Error"), } - taskRegistry := MockTaskRegistry{} + taskRegistry := MockPodRegistry{} endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry) err := endpoints.SyncServiceEndpoints() @@ -56,10 +56,10 @@ func TestSyncEndpointsItems(t *testing.T) { }, }, } - taskRegistry := MockTaskRegistry{ - tasks: []Pod{ + taskRegistry := MockPodRegistry{ + pods: []Pod{ Pod{ - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -96,7 +96,7 @@ func TestSyncEndpointsTaskError(t *testing.T) { }, }, } - taskRegistry := MockTaskRegistry{ + taskRegistry := MockPodRegistry{ err: fmt.Errorf("test error."), } diff --git a/pkg/registry/etcd_registry_test.go b/pkg/registry/etcd_registry_test.go index 332a8b6a668..364ca73d5c9 100644 --- a/pkg/registry/etcd_registry_test.go +++ b/pkg/registry/etcd_registry_test.go @@ -67,7 +67,7 @@ func TestEtcdCreateTask(t *testing.T) { JSONBase: JSONBase{ ID: "foo", }, - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -167,7 +167,7 @@ func TestEtcdCreateTaskWithContainersNotFound(t *testing.T) { JSONBase: JSONBase{ ID: "foo", }, - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Id: "foo", Containers: []Container{ @@ -214,7 +214,7 @@ func TestEtcdCreateTaskWithExistingContainers(t *testing.T) { JSONBase: JSONBase{ ID: "foo", }, - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Id: "foo", Containers: []Container{ diff --git a/pkg/registry/interfaces.go b/pkg/registry/interfaces.go index 66fb6c59d4b..26aeec4e15c 100644 --- a/pkg/registry/interfaces.go +++ b/pkg/registry/interfaces.go @@ -20,7 +20,7 @@ import ( ) // TaskRegistry is an interface implemented by things that know how to store Task objects -type TaskRegistry interface { +type PodRegistry interface { // ListTasks obtains a list of tasks that match query. // Query may be nil in which case all tasks are returned. ListTasks(query *map[string]string) ([]api.Pod, error) diff --git a/pkg/registry/manifest_factory_test.go b/pkg/registry/manifest_factory_test.go index 56154bd833a..026fc691f73 100644 --- a/pkg/registry/manifest_factory_test.go +++ b/pkg/registry/manifest_factory_test.go @@ -29,7 +29,7 @@ func TestMakeManifestNoServices(t *testing.T) { manifest, err := factory.MakeManifest("machine", Pod{ JSONBase: JSONBase{ID: "foobar"}, - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -67,7 +67,7 @@ func TestMakeManifestServices(t *testing.T) { } manifest, err := factory.MakeManifest("machine", Pod{ - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -104,7 +104,7 @@ func TestMakeManifestServicesExistingEnvVar(t *testing.T) { } manifest, err := factory.MakeManifest("machine", Pod{ - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ diff --git a/pkg/registry/memory_registry_test.go b/pkg/registry/memory_registry_test.go index d48189ec3be..1fb815bc0fe 100644 --- a/pkg/registry/memory_registry_test.go +++ b/pkg/registry/memory_registry_test.go @@ -58,7 +58,7 @@ func TestMemorySetUpdateGetTasks(t *testing.T) { JSONBase: JSONBase{ ID: "foo", }, - DesiredState: TaskState{ + DesiredState: PodState{ Host: "foo.com", }, } diff --git a/pkg/registry/replication_controller.go b/pkg/registry/replication_controller.go index 1b6b6ebb2b3..7a3dcc508b5 100644 --- a/pkg/registry/replication_controller.go +++ b/pkg/registry/replication_controller.go @@ -52,7 +52,7 @@ type RealTaskControl struct { } func (r RealTaskControl) createReplica(controllerSpec ReplicationController) { - labels := controllerSpec.DesiredState.TaskTemplate.Labels + labels := controllerSpec.DesiredState.PodTemplate.Labels if labels != nil { labels["replicationController"] = controllerSpec.ID } @@ -60,8 +60,8 @@ func (r RealTaskControl) createReplica(controllerSpec ReplicationController) { JSONBase: JSONBase{ ID: fmt.Sprintf("%x", rand.Int()), }, - DesiredState: controllerSpec.DesiredState.TaskTemplate.DesiredState, - Labels: controllerSpec.DesiredState.TaskTemplate.Labels, + DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState, + Labels: controllerSpec.DesiredState.PodTemplate.Labels, } _, err := r.kubeClient.CreateTask(task) if err != nil { diff --git a/pkg/registry/replication_controller_test.go b/pkg/registry/replication_controller_test.go index 54b95d7f289..423ade8d8e4 100644 --- a/pkg/registry/replication_controller_test.go +++ b/pkg/registry/replication_controller_test.go @@ -53,8 +53,8 @@ func makeReplicationController(replicas int) ReplicationController { return ReplicationController{ DesiredState: ReplicationControllerState{ Replicas: replicas, - TaskTemplate: TaskTemplate{ - DesiredState: TaskState{ + PodTemplate: PodTemplate{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -72,7 +72,7 @@ func makeReplicationController(replicas int) ReplicationController { } } -func makeTaskList(count int) TaskList { +func makeTaskList(count int) PodList { tasks := []Pod{} for i := 0; i < count; i++ { tasks = append(tasks, Pod{ @@ -81,7 +81,7 @@ func makeTaskList(count int) TaskList { }, }) } - return TaskList{ + return PodList{ Items: tasks, } } @@ -178,8 +178,8 @@ func TestCreateReplica(t *testing.T) { controllerSpec := ReplicationController{ DesiredState: ReplicationControllerState{ - TaskTemplate: TaskTemplate{ - DesiredState: TaskState{ + PodTemplate: PodTemplate{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -199,8 +199,8 @@ func TestCreateReplica(t *testing.T) { taskControl.createReplica(controllerSpec) //expectedTask := Task{ - // Labels: controllerSpec.DesiredState.TaskTemplate.Labels, - // DesiredState: controllerSpec.DesiredState.TaskTemplate.DesiredState, + // Labels: controllerSpec.DesiredState.PodTemplate.Labels, + // DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState, //} // TODO: fix this so that it validates the body. fakeHandler.ValidateRequest(t, makeUrl("/tasks"), "POST", nil) diff --git a/pkg/registry/scheduler.go b/pkg/registry/scheduler.go index cb3752875a8..48f9e15a389 100644 --- a/pkg/registry/scheduler.go +++ b/pkg/registry/scheduler.go @@ -65,10 +65,10 @@ func (s *RoundRobinScheduler) Schedule(task Pod) (string, error) { type FirstFitScheduler struct { machines []string - registry TaskRegistry + registry PodRegistry } -func MakeFirstFitScheduler(machines []string, registry TaskRegistry) Scheduler { +func MakeFirstFitScheduler(machines []string, registry PodRegistry) Scheduler { return &FirstFitScheduler{ machines: machines, registry: registry, diff --git a/pkg/registry/scheduler_test.go b/pkg/registry/scheduler_test.go index efe73f446a6..c1d8428ba3d 100644 --- a/pkg/registry/scheduler_test.go +++ b/pkg/registry/scheduler_test.go @@ -46,7 +46,7 @@ func TestRandomScheduler(t *testing.T) { } func TestFirstFitSchedulerNothingScheduled(t *testing.T) { - mockRegistry := MockTaskRegistry{} + mockRegistry := MockPodRegistry{} scheduler := MakeFirstFitScheduler([]string{"m1", "m2", "m3"}, &mockRegistry) expectSchedule(scheduler, Pod{}, "m1", t) } @@ -57,10 +57,10 @@ func makeTask(host string, hostPorts ...int) Pod { networkPorts = append(networkPorts, Port{HostPort: port}) } return Pod{ - CurrentState: TaskState{ + CurrentState: PodState{ Host: host, }, - DesiredState: TaskState{ + DesiredState: PodState{ Manifest: ContainerManifest{ Containers: []Container{ Container{ @@ -73,8 +73,8 @@ func makeTask(host string, hostPorts ...int) Pod { } func TestFirstFitSchedulerFirstScheduled(t *testing.T) { - mockRegistry := MockTaskRegistry{ - tasks: []Pod{ + mockRegistry := MockPodRegistry{ + pods: []Pod{ makeTask("m1", 8080), }, } @@ -83,8 +83,8 @@ func TestFirstFitSchedulerFirstScheduled(t *testing.T) { } func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) { - mockRegistry := MockTaskRegistry{ - tasks: []Pod{ + mockRegistry := MockPodRegistry{ + pods: []Pod{ makeTask("m1", 80, 8080), makeTask("m2", 8081, 8082, 8083), makeTask("m3", 80, 443, 8085), @@ -95,8 +95,8 @@ func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) { } func TestFirstFitSchedulerFirstScheduledImpossible(t *testing.T) { - mockRegistry := MockTaskRegistry{ - tasks: []Pod{ + mockRegistry := MockPodRegistry{ + pods: []Pod{ makeTask("m1", 8080), makeTask("m2", 8081), makeTask("m3", 8080), diff --git a/pkg/registry/task_registry.go b/pkg/registry/task_registry.go deleted file mode 100644 index 0aa3433434f..00000000000 --- a/pkg/registry/task_registry.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 registry - -import ( - "encoding/json" - "fmt" - "net/url" - - . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" - "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" - "github.com/GoogleCloudPlatform/kubernetes/pkg/client" -) - -// TaskRegistryStorage implements the RESTStorage interface in terms of a TaskRegistry -type TaskRegistryStorage struct { - registry TaskRegistry - containerInfo client.ContainerInfo - scheduler Scheduler -} - -func MakeTaskRegistryStorage(registry TaskRegistry, containerInfo client.ContainerInfo, scheduler Scheduler) apiserver.RESTStorage { - return &TaskRegistryStorage{ - registry: registry, - containerInfo: containerInfo, - scheduler: scheduler, - } -} - -// LabelMatch tests to see if a Task's labels map contains 'key' mapping to 'value' -func LabelMatch(task Pod, queryKey, queryValue string) bool { - for key, value := range task.Labels { - if queryKey == key && queryValue == value { - return true - } - } - return false -} - -// LabelMatch tests to see if a Task's labels map contains all key/value pairs in 'labelQuery' -func LabelsMatch(task Pod, labelQuery *map[string]string) bool { - if labelQuery == nil { - return true - } - for key, value := range *labelQuery { - if !LabelMatch(task, key, value) { - return false - } - } - return true -} - -func (storage *TaskRegistryStorage) List(url *url.URL) (interface{}, error) { - var result TaskList - var query *map[string]string - if url != nil { - queryMap := client.DecodeLabelQuery(url.Query().Get("labels")) - query = &queryMap - } - tasks, err := storage.registry.ListTasks(query) - if err == nil { - result = TaskList{ - Items: tasks, - } - } - result.Kind = "cluster#taskList" - return result, err -} - -func (storage *TaskRegistryStorage) Get(id string) (interface{}, error) { - task, err := storage.registry.GetTask(id) - if err != nil { - return task, err - } - info, err := storage.containerInfo.GetContainerInfo(task.CurrentState.Host, id) - if err != nil { - return task, err - } - task.CurrentState.Info = info - task.Kind = "cluster#task" - return task, err -} - -func (storage *TaskRegistryStorage) Delete(id string) error { - return storage.registry.DeleteTask(id) -} - -func (storage *TaskRegistryStorage) Extract(body string) (interface{}, error) { - task := Pod{} - err := json.Unmarshal([]byte(body), &task) - return task, err -} - -func (storage *TaskRegistryStorage) Create(task interface{}) error { - taskObj := task.(Pod) - if len(taskObj.ID) == 0 { - return fmt.Errorf("ID is unspecified: %#v", task) - } - machine, err := storage.scheduler.Schedule(taskObj) - if err != nil { - return err - } - return storage.registry.CreateTask(machine, taskObj) -} - -func (storage *TaskRegistryStorage) Update(task interface{}) error { - return storage.registry.UpdateTask(task.(Pod)) -} diff --git a/pkg/registry/task_registry_test.go b/pkg/registry/task_registry_test.go deleted file mode 100644 index e6e515c70a0..00000000000 --- a/pkg/registry/task_registry_test.go +++ /dev/null @@ -1,204 +0,0 @@ -/* -Copyright 2014 Google Inc. All rights reserved. - -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 registry - -import ( - "encoding/json" - "fmt" - "testing" - - . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" -) - -type MockTaskRegistry struct { - err error - tasks []Pod -} - -func expectNoError(t *testing.T, err error) { - if err != nil { - t.Errorf("Unexpected error: %#v", err) - } -} - -func (registry *MockTaskRegistry) ListTasks(*map[string]string) ([]Pod, error) { - return registry.tasks, registry.err -} - -func (registry *MockTaskRegistry) GetTask(taskId string) (*Pod, error) { - return &Pod{}, registry.err -} - -func (registry *MockTaskRegistry) CreateTask(machine string, task Pod) error { - return registry.err -} - -func (registry *MockTaskRegistry) UpdateTask(task Pod) error { - return registry.err -} -func (registry *MockTaskRegistry) DeleteTask(taskId string) error { - return registry.err -} - -func TestListTasksError(t *testing.T) { - mockRegistry := MockTaskRegistry{ - err: fmt.Errorf("Test Error"), - } - storage := TaskRegistryStorage{ - registry: &mockRegistry, - } - tasks, err := storage.List(nil) - if err != mockRegistry.err { - t.Errorf("Expected %#v, Got %#v", mockRegistry.err, err) - } - if len(tasks.(TaskList).Items) != 0 { - t.Errorf("Unexpected non-zero task list: %#v", tasks) - } -} - -func TestListEmptyTaskList(t *testing.T) { - mockRegistry := MockTaskRegistry{} - storage := TaskRegistryStorage{ - registry: &mockRegistry, - } - tasks, err := storage.List(nil) - expectNoError(t, err) - if len(tasks.(TaskList).Items) != 0 { - t.Errorf("Unexpected non-zero task list: %#v", tasks) - } -} - -func TestListTaskList(t *testing.T) { - mockRegistry := MockTaskRegistry{ - tasks: []Pod{ - Pod{ - JSONBase: JSONBase{ - ID: "foo", - }, - }, - Pod{ - JSONBase: JSONBase{ - ID: "bar", - }, - }, - }, - } - storage := TaskRegistryStorage{ - registry: &mockRegistry, - } - tasksObj, err := storage.List(nil) - tasks := tasksObj.(TaskList) - expectNoError(t, err) - if len(tasks.Items) != 2 { - t.Errorf("Unexpected task list: %#v", tasks) - } - if tasks.Items[0].ID != "foo" { - t.Errorf("Unexpected task: %#v", tasks.Items[0]) - } - if tasks.Items[1].ID != "bar" { - t.Errorf("Unexpected task: %#v", tasks.Items[1]) - } -} - -func TestExtractJson(t *testing.T) { - mockRegistry := MockTaskRegistry{} - storage := TaskRegistryStorage{ - registry: &mockRegistry, - } - task := Pod{ - JSONBase: JSONBase{ - ID: "foo", - }, - } - body, err := json.Marshal(task) - expectNoError(t, err) - taskOut, err := storage.Extract(string(body)) - expectNoError(t, err) - jsonOut, err := json.Marshal(taskOut) - expectNoError(t, err) - if string(body) != string(jsonOut) { - t.Errorf("Expected %#v, found %#v", task, taskOut) - } -} - -func expectLabelMatch(t *testing.T, task Pod, key, value string) { - if !LabelMatch(task, key, value) { - t.Errorf("Unexpected match failure: %#v %s %s", task, key, value) - } -} - -func expectNoLabelMatch(t *testing.T, task Pod, key, value string) { - if LabelMatch(task, key, value) { - t.Errorf("Unexpected match success: %#v %s %s", task, key, value) - } -} - -func expectLabelsMatch(t *testing.T, task Pod, query *map[string]string) { - if !LabelsMatch(task, query) { - t.Errorf("Unexpected match failure: %#v %#v", task, *query) - } -} - -func expectNoLabelsMatch(t *testing.T, task Pod, query *map[string]string) { - if LabelsMatch(task, query) { - t.Errorf("Unexpected match success: %#v %#v", task, *query) - } -} - -func TestLabelMatch(t *testing.T) { - task := Pod{ - Labels: map[string]string{ - "foo": "bar", - "baz": "blah", - }, - } - expectLabelMatch(t, task, "foo", "bar") - expectLabelMatch(t, task, "baz", "blah") - expectNoLabelMatch(t, task, "foo", "blah") - expectNoLabelMatch(t, task, "baz", "bar") -} - -func TestLabelsMatch(t *testing.T) { - task := Pod{ - Labels: map[string]string{ - "foo": "bar", - "baz": "blah", - }, - } - expectLabelsMatch(t, task, &map[string]string{}) - expectLabelsMatch(t, task, &map[string]string{ - "foo": "bar", - }) - expectLabelsMatch(t, task, &map[string]string{ - "baz": "blah", - }) - expectLabelsMatch(t, task, &map[string]string{ - "foo": "bar", - "baz": "blah", - }) - expectNoLabelsMatch(t, task, &map[string]string{ - "foo": "blah", - }) - expectNoLabelsMatch(t, task, &map[string]string{ - "baz": "bar", - }) - expectNoLabelsMatch(t, task, &map[string]string{ - "foo": "bar", - "foobar": "bar", - "baz": "blah", - }) - -} From 79b7976cbf5fd1e41875a320d9e3dd688942e96b Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Sun, 8 Jun 2014 21:42:09 -0700 Subject: [PATCH 2/2] Add pod registry. --- pkg/registry/pod_registry.go | 121 ++++++++++++++++++ pkg/registry/pod_registry_test.go | 204 ++++++++++++++++++++++++++++++ 2 files changed, 325 insertions(+) create mode 100644 pkg/registry/pod_registry.go create mode 100644 pkg/registry/pod_registry_test.go diff --git a/pkg/registry/pod_registry.go b/pkg/registry/pod_registry.go new file mode 100644 index 00000000000..60efe2551c3 --- /dev/null +++ b/pkg/registry/pod_registry.go @@ -0,0 +1,121 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +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 registry + +import ( + "encoding/json" + "fmt" + "net/url" + + . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver" + "github.com/GoogleCloudPlatform/kubernetes/pkg/client" +) + +// TaskRegistryStorage implements the RESTStorage interface in terms of a TaskRegistry +type TaskRegistryStorage struct { + registry PodRegistry + containerInfo client.ContainerInfo + scheduler Scheduler +} + +func MakeTaskRegistryStorage(registry PodRegistry, containerInfo client.ContainerInfo, scheduler Scheduler) apiserver.RESTStorage { + return &TaskRegistryStorage{ + registry: registry, + containerInfo: containerInfo, + scheduler: scheduler, + } +} + +// LabelMatch tests to see if a Task's labels map contains 'key' mapping to 'value' +func LabelMatch(task Pod, queryKey, queryValue string) bool { + for key, value := range task.Labels { + if queryKey == key && queryValue == value { + return true + } + } + return false +} + +// LabelMatch tests to see if a Task's labels map contains all key/value pairs in 'labelQuery' +func LabelsMatch(task Pod, labelQuery *map[string]string) bool { + if labelQuery == nil { + return true + } + for key, value := range *labelQuery { + if !LabelMatch(task, key, value) { + return false + } + } + return true +} + +func (storage *TaskRegistryStorage) List(url *url.URL) (interface{}, error) { + var result PodList + var query *map[string]string + if url != nil { + queryMap := client.DecodeLabelQuery(url.Query().Get("labels")) + query = &queryMap + } + tasks, err := storage.registry.ListTasks(query) + if err == nil { + result = PodList{ + Items: tasks, + } + } + result.Kind = "cluster#taskList" + return result, err +} + +func (storage *TaskRegistryStorage) Get(id string) (interface{}, error) { + task, err := storage.registry.GetTask(id) + if err != nil { + return task, err + } + info, err := storage.containerInfo.GetContainerInfo(task.CurrentState.Host, id) + if err != nil { + return task, err + } + task.CurrentState.Info = info + task.Kind = "cluster#task" + return task, err +} + +func (storage *TaskRegistryStorage) Delete(id string) error { + return storage.registry.DeleteTask(id) +} + +func (storage *TaskRegistryStorage) Extract(body string) (interface{}, error) { + task := Pod{} + err := json.Unmarshal([]byte(body), &task) + return task, err +} + +func (storage *TaskRegistryStorage) Create(task interface{}) error { + taskObj := task.(Pod) + if len(taskObj.ID) == 0 { + return fmt.Errorf("ID is unspecified: %#v", task) + } + machine, err := storage.scheduler.Schedule(taskObj) + if err != nil { + return err + } + return storage.registry.CreateTask(machine, taskObj) +} + +func (storage *TaskRegistryStorage) Update(task interface{}) error { + return storage.registry.UpdateTask(task.(Pod)) +} diff --git a/pkg/registry/pod_registry_test.go b/pkg/registry/pod_registry_test.go new file mode 100644 index 00000000000..819ae6df3b9 --- /dev/null +++ b/pkg/registry/pod_registry_test.go @@ -0,0 +1,204 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +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 registry + +import ( + "encoding/json" + "fmt" + "testing" + + . "github.com/GoogleCloudPlatform/kubernetes/pkg/api" +) + +type MockPodRegistry struct { + err error + pods []Pod +} + +func expectNoError(t *testing.T, err error) { + if err != nil { + t.Errorf("Unexpected error: %#v", err) + } +} + +func (registry *MockPodRegistry) ListTasks(*map[string]string) ([]Pod, error) { + return registry.pods, registry.err +} + +func (registry *MockPodRegistry) GetTask(podId string) (*Pod, error) { + return &Pod{}, registry.err +} + +func (registry *MockPodRegistry) CreateTask(machine string, pod Pod) error { + return registry.err +} + +func (registry *MockPodRegistry) UpdateTask(pod Pod) error { + return registry.err +} +func (registry *MockPodRegistry) DeleteTask(podId string) error { + return registry.err +} + +func TestListTasksError(t *testing.T) { + mockRegistry := MockPodRegistry{ + err: fmt.Errorf("Test Error"), + } + storage := TaskRegistryStorage{ + registry: &mockRegistry, + } + pods, err := storage.List(nil) + if err != mockRegistry.err { + t.Errorf("Expected %#v, Got %#v", mockRegistry.err, err) + } + if len(pods.(PodList).Items) != 0 { + t.Errorf("Unexpected non-zero pod list: %#v", pods) + } +} + +func TestListEmptyTaskList(t *testing.T) { + mockRegistry := MockPodRegistry{} + storage := TaskRegistryStorage{ + registry: &mockRegistry, + } + pods, err := storage.List(nil) + expectNoError(t, err) + if len(pods.(PodList).Items) != 0 { + t.Errorf("Unexpected non-zero pod list: %#v", pods) + } +} + +func TestListTaskList(t *testing.T) { + mockRegistry := MockPodRegistry{ + pods: []Pod{ + Pod{ + JSONBase: JSONBase{ + ID: "foo", + }, + }, + Pod{ + JSONBase: JSONBase{ + ID: "bar", + }, + }, + }, + } + storage := TaskRegistryStorage{ + registry: &mockRegistry, + } + podsObj, err := storage.List(nil) + pods := podsObj.(PodList) + expectNoError(t, err) + if len(pods.Items) != 2 { + t.Errorf("Unexpected pod list: %#v", pods) + } + if pods.Items[0].ID != "foo" { + t.Errorf("Unexpected pod: %#v", pods.Items[0]) + } + if pods.Items[1].ID != "bar" { + t.Errorf("Unexpected pod: %#v", pods.Items[1]) + } +} + +func TestExtractJson(t *testing.T) { + mockRegistry := MockPodRegistry{} + storage := TaskRegistryStorage{ + registry: &mockRegistry, + } + pod := Pod{ + JSONBase: JSONBase{ + ID: "foo", + }, + } + body, err := json.Marshal(pod) + expectNoError(t, err) + podOut, err := storage.Extract(string(body)) + expectNoError(t, err) + jsonOut, err := json.Marshal(podOut) + expectNoError(t, err) + if string(body) != string(jsonOut) { + t.Errorf("Expected %#v, found %#v", pod, podOut) + } +} + +func expectLabelMatch(t *testing.T, pod Pod, key, value string) { + if !LabelMatch(pod, key, value) { + t.Errorf("Unexpected match failure: %#v %s %s", pod, key, value) + } +} + +func expectNoLabelMatch(t *testing.T, pod Pod, key, value string) { + if LabelMatch(pod, key, value) { + t.Errorf("Unexpected match success: %#v %s %s", pod, key, value) + } +} + +func expectLabelsMatch(t *testing.T, pod Pod, query *map[string]string) { + if !LabelsMatch(pod, query) { + t.Errorf("Unexpected match failure: %#v %#v", pod, *query) + } +} + +func expectNoLabelsMatch(t *testing.T, pod Pod, query *map[string]string) { + if LabelsMatch(pod, query) { + t.Errorf("Unexpected match success: %#v %#v", pod, *query) + } +} + +func TestLabelMatch(t *testing.T) { + pod := Pod{ + Labels: map[string]string{ + "foo": "bar", + "baz": "blah", + }, + } + expectLabelMatch(t, pod, "foo", "bar") + expectLabelMatch(t, pod, "baz", "blah") + expectNoLabelMatch(t, pod, "foo", "blah") + expectNoLabelMatch(t, pod, "baz", "bar") +} + +func TestLabelsMatch(t *testing.T) { + pod := Pod{ + Labels: map[string]string{ + "foo": "bar", + "baz": "blah", + }, + } + expectLabelsMatch(t, pod, &map[string]string{}) + expectLabelsMatch(t, pod, &map[string]string{ + "foo": "bar", + }) + expectLabelsMatch(t, pod, &map[string]string{ + "baz": "blah", + }) + expectLabelsMatch(t, pod, &map[string]string{ + "foo": "bar", + "baz": "blah", + }) + expectNoLabelsMatch(t, pod, &map[string]string{ + "foo": "blah", + }) + expectNoLabelsMatch(t, pod, &map[string]string{ + "baz": "bar", + }) + expectNoLabelsMatch(t, pod, &map[string]string{ + "foo": "bar", + "foobar": "bar", + "baz": "blah", + }) + +}