Add kubelet testing to integration test. Test that kubelet makes the requested containers. Check that the url manifest feature works.

pull/6/head
Daniel Smith 2014-06-23 18:28:06 -07:00
parent 9d8a16f180
commit 6900431b13
4 changed files with 125 additions and 57 deletions

View File

@ -26,39 +26,55 @@ import (
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
"github.com/coreos/go-etcd/etcd"
)
func main() {
// Setup
servers := []string{"http://localhost:4001"}
log.Printf("Creating etcd client pointing to %v", servers)
etcdClient := etcd.NewClient(servers)
machineList := registry.MakeMinionRegistry([]string{"machine"})
machineList := []string{"localhost", "machine"}
reg := registry.MakeEtcdRegistry(etcdClient, machineList)
// Master
m := master.New(servers, machineList, nil)
apiserver := httptest.NewServer(m.ConstructHandler("/api/v1beta1"))
apiserver := apiserver.New(map[string]apiserver.RESTStorage{
"pods": registry.MakePodRegistryStorage(reg, &client.FakeContainerInfo{}, registry.MakeRoundRobinScheduler(machineList), nil, nil),
"replicationControllers": registry.MakeControllerRegistryStorage(reg),
}, "/api/v1beta1")
server := httptest.NewServer(apiserver)
controllerManager := controller.MakeReplicationManager(etcd.NewClient(servers), client.New(server.URL, nil))
controllerManager := controller.MakeReplicationManager(etcd.NewClient(servers), client.New(apiserver.URL, nil))
controllerManager.Run(10 * time.Second)
// Kublet
fakeDocker := &kubelet.FakeDockerClient{}
my_kubelet := kubelet.Kubelet{
Hostname: machineList[0],
DockerClient: fakeDocker,
FileCheckFrequency: 5 * time.Second,
SyncFrequency: 5 * time.Second,
HTTPCheckFrequency: 5 * time.Second,
}
go my_kubelet.RunKubelet("", "https://raw.githubusercontent.com/GoogleCloudPlatform/container-vm-guestbook-redis-python/master/manifest.yaml", servers[0], "localhost", 0)
// Create a second kublet so that the guestbook example's two redis slaves both
// have a place they can schedule.
other_kubelet := kubelet.Kubelet{
Hostname: machineList[1],
DockerClient: &kubelet.FakeDockerClient{},
FileCheckFrequency: 5 * time.Second,
SyncFrequency: 5 * time.Second,
HTTPCheckFrequency: 5 * time.Second,
}
go other_kubelet.RunKubelet("", "", servers[0], "localhost", 0)
// Ok. we're good to go.
log.Printf("API Server started on %s", server.URL)
log.Printf("API Server started on %s", apiserver.URL)
// Wait for the synchronization threads to come up.
time.Sleep(time.Second * 10)
kubeClient := client.New(server.URL, nil)
kubeClient := client.New(apiserver.URL, nil)
data, err := ioutil.ReadFile("api/examples/controller.json")
if err != nil {
log.Fatalf("Unexpected error: %#v", err)
@ -79,5 +95,21 @@ func main() {
if err != nil || len(pods.Items) != 2 {
log.Fatal("FAILED")
}
// Check that kubelet tried to make the pods.
// Using a set to list unique creation attempts. Our fake is
// really stupid, so kubelet tries to create these multiple times.
createdPods := map[string]struct{}{}
for _, p := range fakeDocker.Created {
// The last 8 characters are random, so slice them off.
n := len(p)
if n > 8 {
createdPods[p[:n-8]] = struct{}{}
}
}
// We expect 3: 1 net container + 1 pod from the replication controller + 1 pod from the URL.
if len(createdPods) != 3 {
log.Fatalf("Unexpected list of created pods: %#v\n", createdPods)
}
log.Printf("OK")
}

View File

@ -0,0 +1,69 @@
/*
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 kubelet
import (
"github.com/fsouza/go-dockerclient"
)
// A simple fake docker client, so that kublet can be run for testing without requiring a real docker setup.
type FakeDockerClient struct {
containerList []docker.APIContainers
container *docker.Container
err error
called []string
stopped []string
Created []string
}
func (f *FakeDockerClient) clearCalls() {
f.called = []string{}
}
func (f *FakeDockerClient) appendCall(call string) {
f.called = append(f.called, call)
}
func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
f.appendCall("list")
return f.containerList, f.err
}
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
f.appendCall("inspect")
return f.container, f.err
}
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
f.appendCall("create")
f.Created = append(f.Created, c.Name)
// This is not a very good fake. We'll just add this container's name to the list.
// Docker likes to add a '/', so copy that behavior.
f.containerList = append(f.containerList, docker.APIContainers{ID: c.Name, Names: []string{"/" + c.Name}})
return &docker.Container{ID: "/" + c.Name}, nil
}
func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error {
f.appendCall("start")
return nil
}
func (f *FakeDockerClient) StopContainer(id string, timeout uint) error {
f.appendCall("stop")
f.stopped = append(f.stopped, id)
return nil
}

View File

@ -86,48 +86,6 @@ func TestExtractJSON(t *testing.T) {
verifyIntEquals(t, obj.Data.Number, 10)
}
type FakeDockerClient struct {
containerList []docker.APIContainers
container *docker.Container
err error
called []string
stopped []string
}
func (f *FakeDockerClient) clearCalls() {
f.called = []string{}
}
func (f *FakeDockerClient) appendCall(call string) {
f.called = append(f.called, call)
}
func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
f.appendCall("list")
return f.containerList, f.err
}
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
f.appendCall("inspect")
return f.container, f.err
}
func (f *FakeDockerClient) CreateContainer(docker.CreateContainerOptions) (*docker.Container, error) {
f.appendCall("create")
return nil, nil
}
func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error {
f.appendCall("start")
return nil
}
func (f *FakeDockerClient) StopContainer(id string, timeout uint) error {
f.appendCall("stop")
f.stopped = append(f.stopped, id)
return nil
}
func verifyCalls(t *testing.T, fakeDocker FakeDockerClient, calls []string) {
verifyStringArrayEquals(t, fakeDocker.called, calls)
}

View File

@ -98,3 +98,12 @@ func (m *Master) Run(myAddress, apiPrefix string) error {
}
return s.ListenAndServe()
}
// Instead of calling Run, call ConstructHandler to get a handler for your own
// server. Intended for testing. Only call once.
func (m *Master) ConstructHandler(apiPrefix string) http.Handler {
endpoints := registry.MakeEndpointController(m.serviceRegistry, m.podRegistry)
go util.Forever(func() { endpoints.SyncServiceEndpoints() }, time.Second*10)
return apiserver.New(m.storage, apiPrefix)
}