More Task -> Pod

pull/6/head
Brendan Burns 2014-06-08 21:39:57 -07:00
parent 4bd809e11e
commit 66e2575f2b
25 changed files with 80 additions and 405 deletions

View File

@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-03/schema", "$schema": "http://json-schema.org/draft-03/schema",
"type": "object", "type": "object",
"required": false, "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": { "properties": {
"kind": { "kind": {
"type": "string", "type": "string",
@ -35,7 +35,7 @@
"required": false, "required": false,
"description": "Required labels used to identify tasks in the set" "description": "Required labels used to identify tasks in the set"
}, },
"taskTemplate": { "podTemplate": {
"type": "object", "type": "object",
"required": false, "required": false,
"description": "Template from which to create new tasks, as necessary. Identical to task schema." "description": "Template from which to create new tasks, as necessary. Identical to task schema."

View File

@ -7,7 +7,7 @@
"replicasInSet": { "replicasInSet": {
"name": "testRun" "name": "testRun"
}, },
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"image": "dockerfile/nginx", "image": "dockerfile/nginx",
"networkPorts": [ "networkPorts": [

View File

@ -3,7 +3,7 @@
"desiredState": { "desiredState": {
"replicas": 2, "replicas": 2,
"replicasInSet": {"name": "nginx"}, "replicasInSet": {"name": "nginx"},
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"manifest": { "manifest": {
"containers": [{ "containers": [{

View File

@ -52,7 +52,7 @@ func main() {
} }
var ( var (
taskRegistry registry.TaskRegistry podRegistry registry.PodRegistry
controllerRegistry registry.ControllerRegistry controllerRegistry registry.ControllerRegistry
serviceRegistry registry.ServiceRegistry serviceRegistry registry.ServiceRegistry
) )
@ -60,11 +60,11 @@ func main() {
if len(etcdServerList) > 0 { if len(etcdServerList) > 0 {
log.Printf("Creating etcd client pointing to %v", etcdServerList) log.Printf("Creating etcd client pointing to %v", etcdServerList)
etcdClient := etcd.NewClient(etcdServerList) etcdClient := etcd.NewClient(etcdServerList)
taskRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) podRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
controllerRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) controllerRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
serviceRegistry = registry.MakeEtcdRegistry(etcdClient, machineList) serviceRegistry = registry.MakeEtcdRegistry(etcdClient, machineList)
} else { } else {
taskRegistry = registry.MakeMemoryRegistry() podRegistry = registry.MakeMemoryRegistry()
controllerRegistry = registry.MakeMemoryRegistry() controllerRegistry = registry.MakeMemoryRegistry()
serviceRegistry = registry.MakeMemoryRegistry() serviceRegistry = registry.MakeMemoryRegistry()
} }
@ -75,12 +75,12 @@ func main() {
} }
storage := map[string]apiserver.RESTStorage{ 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), "replicationControllers": registry.MakeControllerRegistryStorage(controllerRegistry),
"services": registry.MakeServiceRegistryStorage(serviceRegistry), "services": registry.MakeServiceRegistryStorage(serviceRegistry),
} }
endpoints := registry.MakeEndpointController(serviceRegistry, taskRegistry) endpoints := registry.MakeEndpointController(serviceRegistry, podRegistry)
go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10) go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10)
s := &http.Server{ s := &http.Server{

View File

@ -3,7 +3,7 @@
"desiredState": { "desiredState": {
"replicas": 3, "replicas": 3,
"replicasInSet": {"name": "frontend"}, "replicasInSet": {"name": "frontend"},
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"manifest": { "manifest": {
"containers": [{ "containers": [{

View File

@ -82,7 +82,7 @@ Although the redis master is a single task, the redis read slaves are a 'replica
"desiredState": { "desiredState": {
"replicas": 2, "replicas": 2,
"replicasInSet": {"name": "redis-slave"}, "replicasInSet": {"name": "redis-slave"},
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"manifest": { "manifest": {
"containers": [{ "containers": [{
@ -149,7 +149,7 @@ This is a simple PHP server that is configured to talk to both the slave and mas
"desiredState": { "desiredState": {
"replicas": 3, "replicas": 3,
"replicasInSet": {"name": "frontend"}, "replicasInSet": {"name": "frontend"},
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"manifest": { "manifest": {
"containers": [{ "containers": [{

View File

@ -3,7 +3,7 @@
"desiredState": { "desiredState": {
"replicas": 2, "replicas": 2,
"replicasInSet": {"name": "redisslave"}, "replicasInSet": {"name": "redisslave"},
"taskTemplate": { "podTemplate": {
"desiredState": { "desiredState": {
"manifest": { "manifest": {
"containers": [{ "containers": [{

View File

@ -81,8 +81,8 @@ type JSONBase struct {
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"` 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) // PodState is the state of a pod, used as either input (desired state) or output (current state)
type TaskState struct { type PodState struct {
Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"` Manifest ContainerManifest `json:"manifest,omitempty" yaml:"manifest,omitempty"`
Status string `json:"status,omitempty" yaml:"status,omitempty"` Status string `json:"status,omitempty" yaml:"status,omitempty"`
Host string `json:"host,omitempty" yaml:"host,omitempty"` Host string `json:"host,omitempty" yaml:"host,omitempty"`
@ -90,24 +90,24 @@ type TaskState struct {
Info interface{} `json:"info,omitempty" yaml:"info,omitempty"` Info interface{} `json:"info,omitempty" yaml:"info,omitempty"`
} }
type TaskList struct { type PodList struct {
JSONBase JSONBase
Items []Pod `json:"items" yaml:"items,omitempty"` 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 { type Pod struct {
JSONBase JSONBase
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
DesiredState TaskState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
CurrentState TaskState `json:"currentState,omitempty" yaml:"currentState,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) // ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get)
type ReplicationControllerState struct { type ReplicationControllerState struct {
Replicas int `json:"replicas" yaml:"replicas"` Replicas int `json:"replicas" yaml:"replicas"`
ReplicasInSet map[string]string `json:"replicasInSet,omitempty" yaml:"replicasInSet,omitempty"` 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 { type ReplicationControllerList struct {
@ -122,9 +122,9 @@ type ReplicationController struct {
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
} }
// TaskTemplate holds the information used for creating tasks // PodTemplate holds the information used for creating pods
type TaskTemplate struct { type PodTemplate struct {
DesiredState TaskState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"` DesiredState PodState `json:"desiredState,omitempty" yaml:"desiredState,omitempty"`
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
} }

View File

@ -38,7 +38,7 @@ import (
// ClientInterface holds the methods for clients of Kubenetes, an interface to allow mock testing // ClientInterface holds the methods for clients of Kubenetes, an interface to allow mock testing
type ClientInterface interface { 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) GetTask(name string) (api.Pod, error)
DeleteTask(name string) error DeleteTask(name string) error
CreateTask(api.Pod) (api.Pod, 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 // 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" path := "tasks"
if labelQuery != nil && len(labelQuery) > 0 { if labelQuery != nil && len(labelQuery) > 0 {
path += "?labels=" + EncodeLabelQuery(labelQuery) path += "?labels=" + EncodeLabelQuery(labelQuery)
} }
var result api.TaskList var result api.PodList
_, err := client.rawRequest("GET", path, nil, &result) _, err := client.rawRequest("GET", path, nil, &result)
return result, err return result, err
} }

View File

@ -61,10 +61,10 @@ func TestListEmptyTasks(t *testing.T) {
} }
func TestListTasks(t *testing.T) { func TestListTasks(t *testing.T) {
expectedTaskList := api.TaskList{ expectedTaskList := api.PodList{
Items: []api.Pod{ Items: []api.Pod{
api.Pod{ api.Pod{
CurrentState: api.TaskState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
Labels: map[string]string{ Labels: map[string]string{
@ -95,10 +95,10 @@ func TestListTasks(t *testing.T) {
} }
func TestListTasksLabels(t *testing.T) { func TestListTasksLabels(t *testing.T) {
expectedTaskList := api.TaskList{ expectedTaskList := api.PodList{
Items: []api.Pod{ Items: []api.Pod{
api.Pod{ api.Pod{
CurrentState: api.TaskState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
Labels: map[string]string{ Labels: map[string]string{
@ -138,7 +138,7 @@ func TestListTasksLabels(t *testing.T) {
func TestGetTask(t *testing.T) { func TestGetTask(t *testing.T) {
expectedTask := api.Pod{ expectedTask := api.Pod{
CurrentState: api.TaskState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
Labels: map[string]string{ Labels: map[string]string{
@ -185,7 +185,7 @@ func TestDeleteTask(t *testing.T) {
func TestCreateTask(t *testing.T) { func TestCreateTask(t *testing.T) {
requestTask := api.Pod{ requestTask := api.Pod{
CurrentState: api.TaskState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
Labels: map[string]string{ Labels: map[string]string{
@ -216,7 +216,7 @@ func TestCreateTask(t *testing.T) {
func TestUpdateTask(t *testing.T) { func TestUpdateTask(t *testing.T) {
requestTask := api.Pod{ requestTask := api.Pod{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
CurrentState: api.TaskState{ CurrentState: api.PodState{
Status: "Foobar", Status: "Foobar",
}, },
Labels: map[string]string{ Labels: map[string]string{

View File

@ -183,8 +183,8 @@ func RunController(image, name string, replicas int, client client.ClientInterfa
ReplicasInSet: map[string]string{ ReplicasInSet: map[string]string{
"name": name, "name": name,
}, },
TaskTemplate: api.TaskTemplate{ PodTemplate: api.PodTemplate{
DesiredState: api.TaskState{ DesiredState: api.PodState{
Manifest: api.ContainerManifest{ Manifest: api.ContainerManifest{
Containers: []api.Container{ Containers: []api.Container{
api.Container{ api.Container{

View File

@ -40,11 +40,11 @@ type Action struct {
type FakeKubeClient struct { type FakeKubeClient struct {
actions []Action actions []Action
tasks TaskList tasks PodList
ctrl ReplicationController 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"}) client.actions = append(client.actions, Action{action: "list-tasks"})
return client.tasks, nil return client.tasks, nil
} }
@ -117,7 +117,7 @@ func validateAction(expectedAction, actualAction Action, t *testing.T) {
func TestUpdateWithTasks(t *testing.T) { func TestUpdateWithTasks(t *testing.T) {
client := FakeKubeClient{ client := FakeKubeClient{
tasks: TaskList{ tasks: PodList{
Items: []Pod{ Items: []Pod{
Pod{JSONBase: JSONBase{ID: "task-1"}}, Pod{JSONBase: JSONBase{ID: "task-1"}},
Pod{JSONBase: JSONBase{ID: "task-2"}}, Pod{JSONBase: JSONBase{ID: "task-2"}},
@ -177,7 +177,7 @@ func TestRunController(t *testing.T) {
controller := fakeClient.actions[0].value.(ReplicationController) controller := fakeClient.actions[0].value.(ReplicationController)
if controller.ID != name || if controller.ID != name ||
controller.DesiredState.Replicas != replicas || 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) t.Errorf("Unexpected controller: %#v", controller)
} }
} }
@ -196,7 +196,7 @@ func TestRunControllerWithService(t *testing.T) {
controller := fakeClient.actions[0].value.(ReplicationController) controller := fakeClient.actions[0].value.(ReplicationController)
if controller.ID != name || if controller.ID != name ||
controller.DesiredState.Replicas != replicas || 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) t.Errorf("Unexpected controller: %#v", controller)
} }
} }

View File

@ -141,8 +141,8 @@ func TestControllerParsing(t *testing.T) {
ReplicasInSet: map[string]string{ ReplicasInSet: map[string]string{
"name": "nginx", "name": "nginx",
}, },
TaskTemplate: TaskTemplate{ PodTemplate: PodTemplate{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{

View File

@ -22,7 +22,7 @@ import (
. "github.com/GoogleCloudPlatform/kubernetes/pkg/api" . "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
) )
func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry TaskRegistry) *EndpointController { func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry PodRegistry) *EndpointController {
return &EndpointController{ return &EndpointController{
serviceRegistry: serviceRegistry, serviceRegistry: serviceRegistry,
taskRegistry: taskRegistry, taskRegistry: taskRegistry,
@ -31,7 +31,7 @@ func MakeEndpointController(serviceRegistry ServiceRegistry, taskRegistry TaskRe
type EndpointController struct { type EndpointController struct {
serviceRegistry ServiceRegistry serviceRegistry ServiceRegistry
taskRegistry TaskRegistry taskRegistry PodRegistry
} }
func (e *EndpointController) SyncServiceEndpoints() error { func (e *EndpointController) SyncServiceEndpoints() error {

View File

@ -24,7 +24,7 @@ import (
func TestSyncEndpointsEmpty(t *testing.T) { func TestSyncEndpointsEmpty(t *testing.T) {
serviceRegistry := MockServiceRegistry{} serviceRegistry := MockServiceRegistry{}
taskRegistry := MockTaskRegistry{} taskRegistry := MockPodRegistry{}
endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry) endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry)
err := endpoints.SyncServiceEndpoints() err := endpoints.SyncServiceEndpoints()
@ -35,7 +35,7 @@ func TestSyncEndpointsError(t *testing.T) {
serviceRegistry := MockServiceRegistry{ serviceRegistry := MockServiceRegistry{
err: fmt.Errorf("Test Error"), err: fmt.Errorf("Test Error"),
} }
taskRegistry := MockTaskRegistry{} taskRegistry := MockPodRegistry{}
endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry) endpoints := MakeEndpointController(&serviceRegistry, &taskRegistry)
err := endpoints.SyncServiceEndpoints() err := endpoints.SyncServiceEndpoints()
@ -56,10 +56,10 @@ func TestSyncEndpointsItems(t *testing.T) {
}, },
}, },
} }
taskRegistry := MockTaskRegistry{ taskRegistry := MockPodRegistry{
tasks: []Pod{ pods: []Pod{
Pod{ Pod{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -96,7 +96,7 @@ func TestSyncEndpointsTaskError(t *testing.T) {
}, },
}, },
} }
taskRegistry := MockTaskRegistry{ taskRegistry := MockPodRegistry{
err: fmt.Errorf("test error."), err: fmt.Errorf("test error."),
} }

View File

@ -67,7 +67,7 @@ func TestEtcdCreateTask(t *testing.T) {
JSONBase: JSONBase{ JSONBase: JSONBase{
ID: "foo", ID: "foo",
}, },
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -167,7 +167,7 @@ func TestEtcdCreateTaskWithContainersNotFound(t *testing.T) {
JSONBase: JSONBase{ JSONBase: JSONBase{
ID: "foo", ID: "foo",
}, },
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Id: "foo", Id: "foo",
Containers: []Container{ Containers: []Container{
@ -214,7 +214,7 @@ func TestEtcdCreateTaskWithExistingContainers(t *testing.T) {
JSONBase: JSONBase{ JSONBase: JSONBase{
ID: "foo", ID: "foo",
}, },
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Id: "foo", Id: "foo",
Containers: []Container{ Containers: []Container{

View File

@ -20,7 +20,7 @@ import (
) )
// TaskRegistry is an interface implemented by things that know how to store Task objects // 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. // ListTasks obtains a list of tasks that match query.
// Query may be nil in which case all tasks are returned. // Query may be nil in which case all tasks are returned.
ListTasks(query *map[string]string) ([]api.Pod, error) ListTasks(query *map[string]string) ([]api.Pod, error)

View File

@ -29,7 +29,7 @@ func TestMakeManifestNoServices(t *testing.T) {
manifest, err := factory.MakeManifest("machine", Pod{ manifest, err := factory.MakeManifest("machine", Pod{
JSONBase: JSONBase{ID: "foobar"}, JSONBase: JSONBase{ID: "foobar"},
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -67,7 +67,7 @@ func TestMakeManifestServices(t *testing.T) {
} }
manifest, err := factory.MakeManifest("machine", Pod{ manifest, err := factory.MakeManifest("machine", Pod{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -104,7 +104,7 @@ func TestMakeManifestServicesExistingEnvVar(t *testing.T) {
} }
manifest, err := factory.MakeManifest("machine", Pod{ manifest, err := factory.MakeManifest("machine", Pod{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{

View File

@ -58,7 +58,7 @@ func TestMemorySetUpdateGetTasks(t *testing.T) {
JSONBase: JSONBase{ JSONBase: JSONBase{
ID: "foo", ID: "foo",
}, },
DesiredState: TaskState{ DesiredState: PodState{
Host: "foo.com", Host: "foo.com",
}, },
} }

View File

@ -52,7 +52,7 @@ type RealTaskControl struct {
} }
func (r RealTaskControl) createReplica(controllerSpec ReplicationController) { func (r RealTaskControl) createReplica(controllerSpec ReplicationController) {
labels := controllerSpec.DesiredState.TaskTemplate.Labels labels := controllerSpec.DesiredState.PodTemplate.Labels
if labels != nil { if labels != nil {
labels["replicationController"] = controllerSpec.ID labels["replicationController"] = controllerSpec.ID
} }
@ -60,8 +60,8 @@ func (r RealTaskControl) createReplica(controllerSpec ReplicationController) {
JSONBase: JSONBase{ JSONBase: JSONBase{
ID: fmt.Sprintf("%x", rand.Int()), ID: fmt.Sprintf("%x", rand.Int()),
}, },
DesiredState: controllerSpec.DesiredState.TaskTemplate.DesiredState, DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
Labels: controllerSpec.DesiredState.TaskTemplate.Labels, Labels: controllerSpec.DesiredState.PodTemplate.Labels,
} }
_, err := r.kubeClient.CreateTask(task) _, err := r.kubeClient.CreateTask(task)
if err != nil { if err != nil {

View File

@ -53,8 +53,8 @@ func makeReplicationController(replicas int) ReplicationController {
return ReplicationController{ return ReplicationController{
DesiredState: ReplicationControllerState{ DesiredState: ReplicationControllerState{
Replicas: replicas, Replicas: replicas,
TaskTemplate: TaskTemplate{ PodTemplate: PodTemplate{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -72,7 +72,7 @@ func makeReplicationController(replicas int) ReplicationController {
} }
} }
func makeTaskList(count int) TaskList { func makeTaskList(count int) PodList {
tasks := []Pod{} tasks := []Pod{}
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
tasks = append(tasks, Pod{ tasks = append(tasks, Pod{
@ -81,7 +81,7 @@ func makeTaskList(count int) TaskList {
}, },
}) })
} }
return TaskList{ return PodList{
Items: tasks, Items: tasks,
} }
} }
@ -178,8 +178,8 @@ func TestCreateReplica(t *testing.T) {
controllerSpec := ReplicationController{ controllerSpec := ReplicationController{
DesiredState: ReplicationControllerState{ DesiredState: ReplicationControllerState{
TaskTemplate: TaskTemplate{ PodTemplate: PodTemplate{
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -199,8 +199,8 @@ func TestCreateReplica(t *testing.T) {
taskControl.createReplica(controllerSpec) taskControl.createReplica(controllerSpec)
//expectedTask := Task{ //expectedTask := Task{
// Labels: controllerSpec.DesiredState.TaskTemplate.Labels, // Labels: controllerSpec.DesiredState.PodTemplate.Labels,
// DesiredState: controllerSpec.DesiredState.TaskTemplate.DesiredState, // DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState,
//} //}
// TODO: fix this so that it validates the body. // TODO: fix this so that it validates the body.
fakeHandler.ValidateRequest(t, makeUrl("/tasks"), "POST", nil) fakeHandler.ValidateRequest(t, makeUrl("/tasks"), "POST", nil)

View File

@ -65,10 +65,10 @@ func (s *RoundRobinScheduler) Schedule(task Pod) (string, error) {
type FirstFitScheduler struct { type FirstFitScheduler struct {
machines []string machines []string
registry TaskRegistry registry PodRegistry
} }
func MakeFirstFitScheduler(machines []string, registry TaskRegistry) Scheduler { func MakeFirstFitScheduler(machines []string, registry PodRegistry) Scheduler {
return &FirstFitScheduler{ return &FirstFitScheduler{
machines: machines, machines: machines,
registry: registry, registry: registry,

View File

@ -46,7 +46,7 @@ func TestRandomScheduler(t *testing.T) {
} }
func TestFirstFitSchedulerNothingScheduled(t *testing.T) { func TestFirstFitSchedulerNothingScheduled(t *testing.T) {
mockRegistry := MockTaskRegistry{} mockRegistry := MockPodRegistry{}
scheduler := MakeFirstFitScheduler([]string{"m1", "m2", "m3"}, &mockRegistry) scheduler := MakeFirstFitScheduler([]string{"m1", "m2", "m3"}, &mockRegistry)
expectSchedule(scheduler, Pod{}, "m1", t) expectSchedule(scheduler, Pod{}, "m1", t)
} }
@ -57,10 +57,10 @@ func makeTask(host string, hostPorts ...int) Pod {
networkPorts = append(networkPorts, Port{HostPort: port}) networkPorts = append(networkPorts, Port{HostPort: port})
} }
return Pod{ return Pod{
CurrentState: TaskState{ CurrentState: PodState{
Host: host, Host: host,
}, },
DesiredState: TaskState{ DesiredState: PodState{
Manifest: ContainerManifest{ Manifest: ContainerManifest{
Containers: []Container{ Containers: []Container{
Container{ Container{
@ -73,8 +73,8 @@ func makeTask(host string, hostPorts ...int) Pod {
} }
func TestFirstFitSchedulerFirstScheduled(t *testing.T) { func TestFirstFitSchedulerFirstScheduled(t *testing.T) {
mockRegistry := MockTaskRegistry{ mockRegistry := MockPodRegistry{
tasks: []Pod{ pods: []Pod{
makeTask("m1", 8080), makeTask("m1", 8080),
}, },
} }
@ -83,8 +83,8 @@ func TestFirstFitSchedulerFirstScheduled(t *testing.T) {
} }
func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) { func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) {
mockRegistry := MockTaskRegistry{ mockRegistry := MockPodRegistry{
tasks: []Pod{ pods: []Pod{
makeTask("m1", 80, 8080), makeTask("m1", 80, 8080),
makeTask("m2", 8081, 8082, 8083), makeTask("m2", 8081, 8082, 8083),
makeTask("m3", 80, 443, 8085), makeTask("m3", 80, 443, 8085),
@ -95,8 +95,8 @@ func TestFirstFitSchedulerFirstScheduledComplicated(t *testing.T) {
} }
func TestFirstFitSchedulerFirstScheduledImpossible(t *testing.T) { func TestFirstFitSchedulerFirstScheduledImpossible(t *testing.T) {
mockRegistry := MockTaskRegistry{ mockRegistry := MockPodRegistry{
tasks: []Pod{ pods: []Pod{
makeTask("m1", 8080), makeTask("m1", 8080),
makeTask("m2", 8081), makeTask("m2", 8081),
makeTask("m3", 8080), makeTask("m3", 8080),

View File

@ -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))
}

View File

@ -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",
})
}