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",
"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."

View File

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

View File

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

View File

@ -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{

View File

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

View File

@ -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": [{

View File

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

View File

@ -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"`
}

View File

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

View File

@ -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{

View File

@ -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{

View File

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

View File

@ -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{

View File

@ -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 {

View File

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

View File

@ -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{

View File

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

View File

@ -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{

View File

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

View File

@ -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 {

View File

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

View File

@ -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,

View File

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

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