From 0bf4fabc1985394ac5bfc49ad28c53126cf55cc6 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Mon, 8 Sep 2014 21:33:17 -0700 Subject: [PATCH] kubelet: move docker-related code into sub-package --- cmd/integration/integration.go | 3 +- pkg/kubelet/{ => dockertools}/docker.go | 38 +-- pkg/kubelet/dockertools/docker_test.go | 153 ++++++++++++ .../{ => dockertools}/fake_docker_client.go | 77 +++--- pkg/kubelet/kubelet.go | 67 +++-- pkg/kubelet/kubelet_test.go | 235 +++++------------- pkg/kubelet/server.go | 3 +- 7 files changed, 316 insertions(+), 260 deletions(-) rename pkg/kubelet/{ => dockertools}/docker.go (89%) create mode 100644 pkg/kubelet/dockertools/docker_test.go rename pkg/kubelet/{ => dockertools}/fake_docker_client.go (80%) diff --git a/cmd/integration/integration.go b/cmd/integration/integration.go index 14fe09fdd3..9ec635336a 100644 --- a/cmd/integration/integration.go +++ b/cmd/integration/integration.go @@ -34,6 +34,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/controller" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet" "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/master" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" @@ -46,7 +47,7 @@ import ( ) var ( - fakeDocker1, fakeDocker2 kubelet.FakeDockerClient + fakeDocker1, fakeDocker2 dockertools.FakeDockerClient ) type fakePodInfoGetter struct{} diff --git a/pkg/kubelet/docker.go b/pkg/kubelet/dockertools/docker.go similarity index 89% rename from pkg/kubelet/docker.go rename to pkg/kubelet/dockertools/docker.go index 7942954445..f1690af964 100644 --- a/pkg/kubelet/docker.go +++ b/pkg/kubelet/dockertools/docker.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubelet +package dockertools import ( "errors" @@ -111,7 +111,7 @@ type DockerContainers map[DockerID]*docker.APIContainers func (c DockerContainers) FindPodContainer(podFullName, uuid, containerName string) (*docker.APIContainers, bool, uint64) { for _, dockerContainer := range c { - dockerManifestID, dockerUUID, dockerContainerName, hash := parseDockerName(dockerContainer.Names[0]) + dockerManifestID, dockerUUID, dockerContainerName, hash := ParseDockerName(dockerContainer.Names[0]) if dockerManifestID == podFullName && (uuid == "" || dockerUUID == uuid) && dockerContainerName == containerName { @@ -126,7 +126,7 @@ func (c DockerContainers) FindContainersByPodFullName(podFullName string) map[st containers := make(map[string]*docker.APIContainers) for _, dockerContainer := range c { - dockerManifestID, _, dockerContainerName, _ := parseDockerName(dockerContainer.Names[0]) + dockerManifestID, _, dockerContainerName, _ := ParseDockerName(dockerContainer.Names[0]) if dockerManifestID == podFullName { containers[dockerContainerName] = dockerContainer } @@ -135,7 +135,7 @@ func (c DockerContainers) FindContainersByPodFullName(podFullName string) map[st } // GetKubeletDockerContainers returns a map of docker containers that we manage. The map key is the docker container ID -func getKubeletDockerContainers(client DockerInterface) (DockerContainers, error) { +func GetKubeletDockerContainers(client DockerInterface) (DockerContainers, error) { result := make(DockerContainers) containers, err := client.ListContainers(docker.ListContainersOptions{}) if err != nil { @@ -153,16 +153,16 @@ func getKubeletDockerContainers(client DockerInterface) (DockerContainers, error return result, nil } -// getRecentDockerContainersWithName returns a list of dead docker containers which matches the name +// GetRecentDockerContainersWithNameAndUUID returns a list of dead docker containers which matches the name // and uuid given. -func getRecentDockerContainersWithNameAndUUID(client DockerInterface, podFullName, uuid, containerName string) ([]*docker.Container, error) { +func GetRecentDockerContainersWithNameAndUUID(client DockerInterface, podFullName, uuid, containerName string) ([]*docker.Container, error) { var result []*docker.Container containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) if err != nil { return nil, err } for _, dockerContainer := range containers { - dockerPodName, dockerUUID, dockerContainerName, _ := parseDockerName(dockerContainer.Names[0]) + dockerPodName, dockerUUID, dockerContainerName, _ := ParseDockerName(dockerContainer.Names[0]) if dockerPodName != podFullName { continue } @@ -184,7 +184,7 @@ func getRecentDockerContainersWithNameAndUUID(client DockerInterface, podFullNam var ErrNoContainersInPod = errors.New("no containers exist for this pod") // GetDockerPodInfo returns docker info for all containers in the pod/manifest. -func getDockerPodInfo(client DockerInterface, podFullName, uuid string) (api.PodInfo, error) { +func GetDockerPodInfo(client DockerInterface, podFullName, uuid string) (api.PodInfo, error) { info := api.PodInfo{} containers, err := client.ListContainers(docker.ListContainersOptions{All: true}) @@ -193,7 +193,7 @@ func getDockerPodInfo(client DockerInterface, podFullName, uuid string) (api.Pod } for _, value := range containers { - dockerManifestID, dockerUUID, dockerContainerName, _ := parseDockerName(value.Names[0]) + dockerManifestID, dockerUUID, dockerContainerName, _ := ParseDockerName(value.Names[0]) if dockerManifestID != podFullName { continue } @@ -239,35 +239,35 @@ func unescapeDash(in string) (out string) { const containerNamePrefix = "k8s" -func hashContainer(container *api.Container) uint64 { +func HashContainer(container *api.Container) uint64 { hash := adler32.New() fmt.Fprintf(hash, "%#v", *container) return uint64(hash.Sum32()) } // Creates a name which can be reversed to identify both full pod name and container name. -func buildDockerName(pod *Pod, container *api.Container) string { - containerName := escapeDash(container.Name) + "." + strconv.FormatUint(hashContainer(container), 16) +func BuildDockerName(manifestUUID, podFullName string, container *api.Container) string { + containerName := escapeDash(container.Name) + "." + strconv.FormatUint(HashContainer(container), 16) // Note, manifest.ID could be blank. - if len(pod.Manifest.UUID) == 0 { + if len(manifestUUID) == 0 { return fmt.Sprintf("%s--%s--%s--%08x", containerNamePrefix, containerName, - escapeDash(GetPodFullName(pod)), + escapeDash(podFullName), rand.Uint32()) } else { return fmt.Sprintf("%s--%s--%s--%s--%08x", containerNamePrefix, containerName, - escapeDash(GetPodFullName(pod)), - escapeDash(pod.Manifest.UUID), + escapeDash(podFullName), + escapeDash(manifestUUID), rand.Uint32()) } } // Upacks a container name, returning the pod full name and container name we would have used to // construct the docker name. If the docker name isn't one we created, we may return empty strings. -func parseDockerName(name string) (podFullName, uuid, containerName string, hash uint64) { +func ParseDockerName(name string) (podFullName, uuid, containerName string, hash uint64) { // For some reason docker appears to be appending '/' to names. // If it's there, strip it. if name[0] == '/' { @@ -319,3 +319,7 @@ func parseImageName(image string) (string, string) { } return image, tag } + +type ContainerCommandRunner interface { + RunInContainer(containerID string, cmd []string) ([]byte, error) +} diff --git a/pkg/kubelet/dockertools/docker_test.go b/pkg/kubelet/dockertools/docker_test.go new file mode 100644 index 0000000000..6822b3a0c5 --- /dev/null +++ b/pkg/kubelet/dockertools/docker_test.go @@ -0,0 +1,153 @@ +/* +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 dockertools + +import ( + "fmt" + "hash/adler32" + "reflect" + "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/fsouza/go-dockerclient" +) + +func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) { + fakeDocker.Lock() + defer fakeDocker.Unlock() + verifyStringArrayEquals(t, fakeDocker.called, calls) +} + +func verifyStringArrayEquals(t *testing.T, actual, expected []string) { + invalid := len(actual) != len(expected) + if !invalid { + for ix, value := range actual { + if expected[ix] != value { + invalid = true + } + } + } + if invalid { + t.Errorf("Expected: %#v, Actual: %#v", expected, actual) + } +} + +func TestGetContainerID(t *testing.T) { + fakeDocker := &FakeDockerClient{} + fakeDocker.ContainerList = []docker.APIContainers{ + { + ID: "foobar", + Names: []string{"/k8s--foo--qux--1234"}, + }, + { + ID: "barbar", + Names: []string{"/k8s--bar--qux--2565"}, + }, + } + fakeDocker.Container = &docker.Container{ + ID: "foobar", + } + + dockerContainers, err := GetKubeletDockerContainers(fakeDocker) + if err != nil { + t.Errorf("Expected no error, Got %#v", err) + } + if len(dockerContainers) != 2 { + t.Errorf("Expected %#v, Got %#v", fakeDocker.ContainerList, dockerContainers) + } + verifyCalls(t, fakeDocker, []string{"list"}) + dockerContainer, found, _ := dockerContainers.FindPodContainer("qux", "", "foo") + if dockerContainer == nil || !found { + t.Errorf("Failed to find container %#v", dockerContainer) + } + + fakeDocker.clearCalls() + dockerContainer, found, _ = dockerContainers.FindPodContainer("foobar", "", "foo") + verifyCalls(t, fakeDocker, []string{}) + if dockerContainer != nil || found { + t.Errorf("Should not have found container %#v", dockerContainer) + } +} + +func verifyPackUnpack(t *testing.T, podNamespace, podName, containerName string) { + container := &api.Container{Name: containerName} + hasher := adler32.New() + data := fmt.Sprintf("%#v", *container) + hasher.Write([]byte(data)) + computedHash := uint64(hasher.Sum32()) + podFullName := fmt.Sprintf("%s.%s", podName, podNamespace) + name := BuildDockerName("", podFullName, container) + returnedPodFullName, _, returnedContainerName, hash := ParseDockerName(name) + if podFullName != returnedPodFullName || containerName != returnedContainerName || computedHash != hash { + t.Errorf("For (%s, %s, %d), unpacked (%s, %s, %d)", podFullName, containerName, computedHash, returnedPodFullName, returnedContainerName, hash) + } +} + +func TestContainerManifestNaming(t *testing.T) { + verifyPackUnpack(t, "file", "manifest1234", "container5678") + verifyPackUnpack(t, "file", "manifest--", "container__") + verifyPackUnpack(t, "file", "--manifest", "__container") + verifyPackUnpack(t, "", "m___anifest_", "container-_-") + verifyPackUnpack(t, "other", "_m___anifest", "-_-container") + + container := &api.Container{Name: "container"} + podName := "foo" + podNamespace := "test" + name := fmt.Sprintf("k8s--%s--%s.%s--12345", container.Name, podName, podNamespace) + + podFullName := fmt.Sprintf("%s.%s", podName, podNamespace) + returnedPodFullName, _, returnedContainerName, hash := ParseDockerName(name) + if returnedPodFullName != podFullName || returnedContainerName != container.Name || hash != 0 { + t.Errorf("unexpected parse: %s %s %d", returnedPodFullName, returnedContainerName, hash) + } +} + +func TestDockerContainerCommand(t *testing.T) { + runner := dockerContainerCommandRunner{} + containerID := "1234" + command := []string{"ls"} + cmd, _ := runner.getRunInContainerCommand(containerID, command) + if cmd.Dir != "/var/lib/docker/execdriver/native/"+containerID { + t.Errorf("unexpected command CWD: %s", cmd.Dir) + } + if !reflect.DeepEqual(cmd.Args, []string{"/usr/sbin/nsinit", "exec", "ls"}) { + t.Errorf("unexpectd command args: %s", cmd.Args) + } +} + +var parseImageNameTests = []struct { + imageName string + name string + tag string +}{ + {"ubuntu", "ubuntu", ""}, + {"ubuntu:2342", "ubuntu", "2342"}, + {"ubuntu:latest", "ubuntu", "latest"}, + {"foo/bar:445566", "foo/bar", "445566"}, + {"registry.example.com:5000/foobar", "registry.example.com:5000/foobar", ""}, + {"registry.example.com:5000/foobar:5342", "registry.example.com:5000/foobar", "5342"}, + {"registry.example.com:5000/foobar:latest", "registry.example.com:5000/foobar", "latest"}, +} + +func TestParseImageName(t *testing.T) { + for _, tt := range parseImageNameTests { + name, tag := parseImageName(tt.imageName) + if name != tt.name || tag != tt.tag { + t.Errorf("Expected name/tag: %s/%s, got %s/%s", tt.name, tt.tag, name, tag) + } + } +} diff --git a/pkg/kubelet/fake_docker_client.go b/pkg/kubelet/dockertools/fake_docker_client.go similarity index 80% rename from pkg/kubelet/fake_docker_client.go rename to pkg/kubelet/dockertools/fake_docker_client.go index baaf58d090..c5d36a5057 100644 --- a/pkg/kubelet/fake_docker_client.go +++ b/pkg/kubelet/dockertools/fake_docker_client.go @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubelet +package dockertools import ( "fmt" + "reflect" "sync" "github.com/fsouza/go-dockerclient" @@ -25,93 +26,105 @@ import ( // FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup. type FakeDockerClient struct { - lock sync.Mutex - containerList []docker.APIContainers - container *docker.Container - err error + sync.Mutex + ContainerList []docker.APIContainers + Container *docker.Container + Err error called []string - stopped []string + Stopped []string pulled []string Created []string } func (f *FakeDockerClient) clearCalls() { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = []string{} } +func (f *FakeDockerClient) AssertCalls(calls []string) (err error) { + f.Lock() + defer f.Unlock() + + if !reflect.DeepEqual(calls, f.called) { + err = fmt.Errorf("expected %#v, got %#v", calls, f.called) + } + + return +} + // ListContainers is a test-spy implementation of DockerInterface.ListContainers. // It adds an entry "list" to the internal method call record. func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "list") - return f.containerList, f.err + return f.ContainerList, f.Err } // InspectContainer is a test-spy implementation of DockerInterface.InspectContainer. // It adds an entry "inspect" to the internal method call record. func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "inspect") - return f.container, f.err + return f.Container, f.Err } // CreateContainer is a test-spy implementation of DockerInterface.CreateContainer. // It adds an entry "create" to the internal method call record. func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "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. name := "/" + c.Name - f.containerList = append(f.containerList, docker.APIContainers{ID: name, Names: []string{name}}) + f.ContainerList = append(f.ContainerList, docker.APIContainers{ID: name, Names: []string{name}}) return &docker.Container{ID: name}, nil } // StartContainer is a test-spy implementation of DockerInterface.StartContainer. // It adds an entry "start" to the internal method call record. func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "start") - return f.err + return f.Err } // StopContainer is a test-spy implementation of DockerInterface.StopContainer. // It adds an entry "stop" to the internal method call record. func (f *FakeDockerClient) StopContainer(id string, timeout uint) error { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "stop") - f.stopped = append(f.stopped, id) + f.Stopped = append(f.Stopped, id) var newList []docker.APIContainers - for _, container := range f.containerList { + for _, container := range f.ContainerList { if container.ID != id { newList = append(newList, container) } } - f.containerList = newList - return f.err + f.ContainerList = newList + return f.Err } // PullImage is a test-spy implementation of DockerInterface.StopContainer. // It adds an entry "pull" to the internal method call record. func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.called = append(f.called, "pull") f.pulled = append(f.pulled, fmt.Sprintf("%s/%s:%s", opts.Repository, opts.Registry, opts.Tag)) - return f.err + return f.Err } // FakeDockerPuller is a stub implementation of DockerPuller. type FakeDockerPuller struct { - lock sync.Mutex + sync.Mutex + ImagesPulled []string // Every pull will return the first error here, and then reslice @@ -121,8 +134,8 @@ type FakeDockerPuller struct { // Pull records the image pull attempt, and optionally injects an error. func (f *FakeDockerPuller) Pull(image string) (err error) { - f.lock.Lock() - defer f.lock.Unlock() + f.Lock() + defer f.Unlock() f.ImagesPulled = append(f.ImagesPulled, image) if len(f.ErrorsToInject) > 0 { diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 8bfd8f75c4..79ab7843a6 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -30,6 +30,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" "github.com/GoogleCloudPlatform/kubernetes/pkg/health" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume" @@ -62,7 +63,7 @@ type volumeMap map[string]volume.Interface // New creates a new Kubelet for use in main func NewMainKubelet( hn string, - dc DockerInterface, + dc dockertools.DockerInterface, cc CadvisorInterface, ec tools.EtcdClient, rd string, @@ -75,27 +76,23 @@ func NewMainKubelet( rootDirectory: rd, resyncInterval: ri, podWorkers: newPodWorkers(), - runner: NewDockerContainerCommandRunner(), + runner: dockertools.NewDockerContainerCommandRunner(), httpClient: &http.Client{}, } } // NewIntegrationTestKubelet creates a new Kubelet for use in integration tests. // TODO: add more integration tests, and expand parameter list as needed. -func NewIntegrationTestKubelet(hn string, dc DockerInterface) *Kubelet { +func NewIntegrationTestKubelet(hn string, dc dockertools.DockerInterface) *Kubelet { return &Kubelet{ hostname: hn, dockerClient: dc, - dockerPuller: &FakeDockerPuller{}, + dockerPuller: &dockertools.FakeDockerPuller{}, resyncInterval: 3 * time.Second, podWorkers: newPodWorkers(), } } -type ContainerCommandRunner interface { - RunInContainer(containerID string, cmd []string) ([]byte, error) -} - type httpGetInterface interface { Get(url string) (*http.Response, error) } @@ -103,7 +100,7 @@ type httpGetInterface interface { // Kubelet is the main kubelet implementation. type Kubelet struct { hostname string - dockerClient DockerInterface + dockerClient dockertools.DockerInterface rootDirectory string podWorkers podWorkers resyncInterval time.Duration @@ -115,11 +112,11 @@ type Kubelet struct { // Optional, defaults to simple implementaiton healthChecker health.HealthChecker // Optional, defaults to simple Docker implementation - dockerPuller DockerPuller + dockerPuller dockertools.DockerPuller // Optional, defaults to /logs/ from /var/log logServer http.Handler // Optional, defaults to simple Docker implementation - runner ContainerCommandRunner + runner dockertools.ContainerCommandRunner // Optional, client for http requests, defaults to empty client httpClient httpGetInterface } @@ -130,7 +127,7 @@ func (kl *Kubelet) Run(updates <-chan PodUpdate) { kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/"))) } if kl.dockerPuller == nil { - kl.dockerPuller = NewDockerPuller(kl.dockerClient) + kl.dockerPuller = dockertools.NewDockerPuller(kl.dockerClient) } if kl.healthChecker == nil { kl.healthChecker = health.NewHealthChecker() @@ -316,13 +313,13 @@ func (kl *Kubelet) runHandler(podFullName, uuid string, container *api.Container } // Run a single container from a pod. Returns the docker container ID -func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes volumeMap, netMode string) (id DockerID, err error) { +func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes volumeMap, netMode string) (id dockertools.DockerID, err error) { envVariables := makeEnvironmentVariables(container) binds := makeBinds(pod, container, podVolumes) exposedPorts, portBindings := makePortsAndBindings(container) opts := docker.CreateContainerOptions{ - Name: buildDockerName(pod, container), + Name: dockertools.BuildDockerName(pod.Manifest.UUID, GetPodFullName(pod), container), Config: &docker.Config{ Cmd: container.Command, Env: envVariables, @@ -347,10 +344,10 @@ func (kl *Kubelet) runContainer(pod *Pod, container *api.Container, podVolumes v handlerErr := kl.runHandler(GetPodFullName(pod), pod.Manifest.UUID, container, container.Lifecycle.PostStart) if handlerErr != nil { kl.killContainerByID(dockerContainer.ID, "") - return DockerID(""), fmt.Errorf("failed to call event handler: %v", handlerErr) + return dockertools.DockerID(""), fmt.Errorf("failed to call event handler: %v", handlerErr) } } - return DockerID(dockerContainer.ID), err + return dockertools.DockerID(dockerContainer.ID), err } // Kill a docker container @@ -364,7 +361,7 @@ func (kl *Kubelet) killContainerByID(ID, name string) error { if len(name) == 0 { return err } - podFullName, uuid, containerName, _ := parseDockerName(name) + podFullName, uuid, containerName, _ := dockertools.ParseDockerName(name) kl.LogEvent(&api.Event{ Event: "STOP", Manifest: &api.ContainerManifest{ @@ -386,7 +383,7 @@ const ( ) // createNetworkContainer starts the network container for a pod. Returns the docker container ID of the newly created container. -func (kl *Kubelet) createNetworkContainer(pod *Pod) (DockerID, error) { +func (kl *Kubelet) createNetworkContainer(pod *Pod) (dockertools.DockerID, error) { var ports []api.Port // Docker only exports ports from the network container. Let's // collect all of the relevant ports and export them. @@ -404,7 +401,7 @@ func (kl *Kubelet) createNetworkContainer(pod *Pod) (DockerID, error) { // Delete all containers in a pod (except the network container) returns the number of containers deleted // and an error if one occurs. -func (kl *Kubelet) deleteAllContainers(pod *Pod, podFullName string, dockerContainers DockerContainers) (int, error) { +func (kl *Kubelet) deleteAllContainers(pod *Pod, podFullName string, dockerContainers dockertools.DockerContainers) (int, error) { count := 0 errs := make(chan error, len(pod.Manifest.Containers)) wg := sync.WaitGroup{} @@ -436,16 +433,16 @@ func (kl *Kubelet) deleteAllContainers(pod *Pod, podFullName string, dockerConta type empty struct{} -func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error { +func (kl *Kubelet) syncPod(pod *Pod, dockerContainers dockertools.DockerContainers) error { podFullName := GetPodFullName(pod) uuid := pod.Manifest.UUID - containersToKeep := make(map[DockerID]empty) - killedContainers := make(map[DockerID]empty) + containersToKeep := make(map[dockertools.DockerID]empty) + killedContainers := make(map[dockertools.DockerID]empty) // Make sure we have a network container - var netID DockerID + var netID dockertools.DockerID if networkDockerContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uuid, networkContainerName); found { - netID = DockerID(networkDockerContainer.ID) + netID = dockertools.DockerID(networkDockerContainer.ID) } else { glog.Infof("Network container doesn't exist, creating") count, err := kl.deleteAllContainers(pod, podFullName, dockerContainers) @@ -460,7 +457,7 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error { netID = dockerNetworkID if count > 0 { // relist everything, otherwise we'll think we're ok - dockerContainers, err = getKubeletDockerContainers(kl.dockerClient) + dockerContainers, err = dockertools.GetKubeletDockerContainers(kl.dockerClient) if err != nil { glog.Errorf("Error listing containers %#v", dockerContainers) return err @@ -487,9 +484,9 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error { } for _, container := range pod.Manifest.Containers { - expectedHash := hashContainer(&container) + expectedHash := dockertools.HashContainer(&container) if dockerContainer, found, hash := dockerContainers.FindPodContainer(podFullName, uuid, container.Name); found { - containerID := DockerID(dockerContainer.ID) + containerID := dockertools.DockerID(dockerContainer.ID) glog.V(1).Infof("pod %s container %s exists as %v", podFullName, container.Name, containerID) // look for changes in the container. @@ -517,7 +514,7 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error { } // Check RestartPolicy for container - recentContainers, err := getRecentDockerContainersWithNameAndUUID(kl.dockerClient, podFullName, uuid, container.Name) + recentContainers, err := dockertools.GetRecentDockerContainersWithNameAndUUID(kl.dockerClient, podFullName, uuid, container.Name) if err != nil { glog.Errorf("Error listing recent containers with name and uuid:%s--%s--%s", podFullName, uuid, container.Name) // TODO(dawnchen): error handling here? @@ -556,7 +553,7 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error { // Kill any containers in this pod which were not identified above (guards against duplicates). for id, container := range dockerContainers { - curPodFullName, curUUID, _, _ := parseDockerName(container.Names[0]) + curPodFullName, curUUID, _, _ := dockertools.ParseDockerName(container.Names[0]) if curPodFullName == podFullName && curUUID == uuid { // Don't kill containers we want to keep or those we already killed. _, keep := containersToKeep[id] @@ -618,7 +615,7 @@ func (kl *Kubelet) SyncPods(pods []Pod) error { var err error desiredContainers := make(map[podContainer]empty) - dockerContainers, err := getKubeletDockerContainers(kl.dockerClient) + dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient) if err != nil { glog.Errorf("Error listing containers %#v", dockerContainers) return err @@ -646,14 +643,14 @@ func (kl *Kubelet) SyncPods(pods []Pod) error { } // Kill any containers we don't need - existingContainers, err := getKubeletDockerContainers(kl.dockerClient) + existingContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient) if err != nil { glog.Errorf("Error listing containers: %v", err) return err } for _, container := range existingContainers { // Don't kill containers that are in the desired pods. - podFullName, uuid, containerName, _ := parseDockerName(container.Names[0]) + podFullName, uuid, containerName, _ := dockertools.ParseDockerName(container.Names[0]) if _, ok := desiredContainers[podContainer{podFullName, uuid, containerName}]; !ok { err = kl.killContainer(container) if err != nil { @@ -745,7 +742,7 @@ func (kl *Kubelet) statsFromContainerPath(containerPath string, req *info.Contai // GetPodInfo returns information from Docker about the containers in a pod func (kl *Kubelet) GetPodInfo(podFullName, uuid string) (api.PodInfo, error) { - return getDockerPodInfo(kl.dockerClient, podFullName, uuid) + return dockertools.GetDockerPodInfo(kl.dockerClient, podFullName, uuid) } // GetContainerInfo returns stats (from Cadvisor) for a container. @@ -753,7 +750,7 @@ func (kl *Kubelet) GetContainerInfo(podFullName, uuid, containerName string, req if kl.cadvisorClient == nil { return nil, nil } - dockerContainers, err := getKubeletDockerContainers(kl.dockerClient) + dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient) if err != nil { return nil, err } @@ -798,7 +795,7 @@ func (kl *Kubelet) RunInContainer(podFullName, uuid, container string, cmd []str if kl.runner == nil { return nil, fmt.Errorf("no runner specified.") } - dockerContainers, err := getKubeletDockerContainers(kl.dockerClient) + dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient) if err != nil { return nil, err } diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index dd88466f75..567924241c 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -19,7 +19,6 @@ package kubelet import ( "encoding/json" "fmt" - "hash/adler32" "net/http" "reflect" "regexp" @@ -30,6 +29,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/health" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/GoogleCloudPlatform/kubernetes/pkg/tools" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/volume" @@ -38,25 +38,24 @@ import ( "github.com/stretchr/testify/mock" ) -func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *FakeDockerClient) { +func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *dockertools.FakeDockerClient) { fakeEtcdClient := tools.NewFakeEtcdClient(t) - fakeDocker := &FakeDockerClient{ - err: nil, - } + fakeDocker := &dockertools.FakeDockerClient{} kubelet := &Kubelet{} kubelet.dockerClient = fakeDocker - kubelet.dockerPuller = &FakeDockerPuller{} + kubelet.dockerPuller = &dockertools.FakeDockerPuller{} kubelet.etcdClient = fakeEtcdClient kubelet.rootDirectory = "/tmp/kubelet" kubelet.podWorkers = newPodWorkers() return kubelet, fakeEtcdClient, fakeDocker } -func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) { - fakeDocker.lock.Lock() - defer fakeDocker.lock.Unlock() - verifyStringArrayEquals(t, fakeDocker.called, calls) +func verifyCalls(t *testing.T, fakeDocker *dockertools.FakeDockerClient, calls []string) { + err := fakeDocker.AssertCalls(calls) + if err != nil { + t.Error(err) + } } func verifyStringArrayEquals(t *testing.T, actual, expected []string) { @@ -73,89 +72,16 @@ func verifyStringArrayEquals(t *testing.T, actual, expected []string) { } } -func verifyPackUnpack(t *testing.T, podNamespace, podName, containerName string) { - container := &api.Container{Name: containerName} - hasher := adler32.New() - data := fmt.Sprintf("%#v", *container) - hasher.Write([]byte(data)) - computedHash := uint64(hasher.Sum32()) - name := buildDockerName( - &Pod{Name: podName, Namespace: podNamespace}, - container, - ) - podFullName := fmt.Sprintf("%s.%s", podName, podNamespace) - returnedPodFullName, _, returnedContainerName, hash := parseDockerName(name) - if podFullName != returnedPodFullName || containerName != returnedContainerName || computedHash != hash { - t.Errorf("For (%s, %s, %d), unpacked (%s, %s, %d)", podFullName, containerName, computedHash, returnedPodFullName, returnedContainerName, hash) - } -} - func verifyBoolean(t *testing.T, expected, value bool) { if expected != value { t.Errorf("Unexpected boolean. Expected %t. Found %t", expected, value) } } -func TestContainerManifestNaming(t *testing.T) { - verifyPackUnpack(t, "file", "manifest1234", "container5678") - verifyPackUnpack(t, "file", "manifest--", "container__") - verifyPackUnpack(t, "file", "--manifest", "__container") - verifyPackUnpack(t, "", "m___anifest_", "container-_-") - verifyPackUnpack(t, "other", "_m___anifest", "-_-container") - - container := &api.Container{Name: "container"} - pod := &Pod{Name: "foo", Namespace: "test"} - name := fmt.Sprintf("k8s--%s--%s.%s--12345", container.Name, pod.Name, pod.Namespace) - - podFullName := fmt.Sprintf("%s.%s", pod.Name, pod.Namespace) - returnedPodFullName, _, returnedContainerName, hash := parseDockerName(name) - if returnedPodFullName != podFullName || returnedContainerName != container.Name || hash != 0 { - t.Errorf("unexpected parse: %s %s %d", returnedPodFullName, returnedContainerName, hash) - } - -} - -func TestGetContainerID(t *testing.T) { - _, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ - { - ID: "foobar", - Names: []string{"/k8s--foo--qux--1234"}, - }, - { - ID: "barbar", - Names: []string{"/k8s--bar--qux--2565"}, - }, - } - fakeDocker.container = &docker.Container{ - ID: "foobar", - } - - dockerContainers, err := getKubeletDockerContainers(fakeDocker) - if err != nil { - t.Errorf("Expected no error, Got %#v", err) - } - if len(dockerContainers) != 2 { - t.Errorf("Expected %#v, Got %#v", fakeDocker.containerList, dockerContainers) - } - verifyCalls(t, fakeDocker, []string{"list"}) - dockerContainer, found, _ := dockerContainers.FindPodContainer("qux", "", "foo") - if dockerContainer == nil || !found { - t.Errorf("Failed to find container %#v", dockerContainer) - } - - fakeDocker.clearCalls() - dockerContainer, found, _ = dockerContainers.FindPodContainer("foobar", "", "foo") - verifyCalls(t, fakeDocker, []string{}) - if dockerContainer != nil || found { - t.Errorf("Should not have found container %#v", dockerContainer) - } -} - func TestKillContainerWithError(t *testing.T) { - fakeDocker := &FakeDockerClient{ - err: fmt.Errorf("sample error"), - containerList: []docker.APIContainers{ + fakeDocker := &dockertools.FakeDockerClient{ + Err: fmt.Errorf("sample error"), + ContainerList: []docker.APIContainers{ { ID: "1234", Names: []string{"/k8s--foo--qux--1234"}, @@ -168,7 +94,7 @@ func TestKillContainerWithError(t *testing.T) { } kubelet, _, _ := newTestKubelet(t) kubelet.dockerClient = fakeDocker - err := kubelet.killContainer(&fakeDocker.containerList[0]) + err := kubelet.killContainer(&fakeDocker.ContainerList[0]) if err == nil { t.Errorf("expected error, found nil") } @@ -177,7 +103,7 @@ func TestKillContainerWithError(t *testing.T) { func TestKillContainer(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: "1234", Names: []string{"/k8s--foo--qux--1234"}, @@ -187,11 +113,11 @@ func TestKillContainer(t *testing.T) { Names: []string{"/k8s--bar--qux--5678"}, }, } - fakeDocker.container = &docker.Container{ + fakeDocker.Container = &docker.Container{ ID: "foobar", } - err := kubelet.killContainer(&fakeDocker.containerList[0]) + err := kubelet.killContainer(&fakeDocker.ContainerList[0]) if err != nil { t.Errorf("unexpected error: %v", err) } @@ -227,10 +153,10 @@ func (cr *channelReader) GetList() [][]Pod { func TestSyncPodsDoesNothing(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) container := api.Container{Name: "bar"} - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { // format is k8s---- - Names: []string{"/k8s--bar." + strconv.FormatUint(hashContainer(&container), 16) + "--foo.test"}, + Names: []string{"/k8s--bar." + strconv.FormatUint(dockertools.HashContainer(&container), 16) + "--foo.test"}, ID: "1234", }, { @@ -281,7 +207,7 @@ func matchString(t *testing.T, pattern, str string) bool { func TestSyncPodsCreatesNetAndContainer(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{} + fakeDocker.ContainerList = []docker.APIContainers{} err := kubelet.SyncPods([]Pod{ { Name: "foo", @@ -302,18 +228,18 @@ func TestSyncPodsCreatesNetAndContainer(t *testing.T) { verifyCalls(t, fakeDocker, []string{ "list", "list", "create", "start", "list", "inspect", "list", "create", "start"}) - fakeDocker.lock.Lock() + fakeDocker.Lock() if len(fakeDocker.Created) != 2 || !matchString(t, "k8s--net\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) || !matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[1]) { t.Errorf("Unexpected containers created %v", fakeDocker.Created) } - fakeDocker.lock.Unlock() + fakeDocker.Unlock() } func TestSyncPodsWithNetCreatesContainer(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { // network container Names: []string{"/k8s--net--foo.test--"}, @@ -340,19 +266,19 @@ func TestSyncPodsWithNetCreatesContainer(t *testing.T) { verifyCalls(t, fakeDocker, []string{ "list", "list", "list", "inspect", "list", "create", "start"}) - fakeDocker.lock.Lock() + fakeDocker.Lock() if len(fakeDocker.Created) != 1 || !matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) { t.Errorf("Unexpected containers created %v", fakeDocker.Created) } - fakeDocker.lock.Unlock() + fakeDocker.Unlock() } func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) fakeHttp := fakeHTTP{} kubelet.httpClient = &fakeHttp - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { // network container Names: []string{"/k8s--net--foo.test--"}, @@ -390,12 +316,12 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) { verifyCalls(t, fakeDocker, []string{ "list", "list", "list", "inspect", "list", "create", "start"}) - fakeDocker.lock.Lock() + fakeDocker.Lock() if len(fakeDocker.Created) != 1 || !matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) { t.Errorf("Unexpected containers created %v", fakeDocker.Created) } - fakeDocker.lock.Unlock() + fakeDocker.Unlock() if fakeHttp.url != "http://foo:8080/bar" { t.Errorf("Unexpected handler: %s", fakeHttp.url) } @@ -403,7 +329,7 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) { func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { // format is k8s---- Names: []string{"/k8s--bar--foo.test"}, @@ -435,16 +361,16 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) { expectedToStop := map[string]bool{ "1234": true, } - fakeDocker.lock.Lock() - if len(fakeDocker.stopped) != 1 || !expectedToStop[fakeDocker.stopped[0]] { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + fakeDocker.Lock() + if len(fakeDocker.Stopped) != 1 || !expectedToStop[fakeDocker.Stopped[0]] { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } - fakeDocker.lock.Unlock() + fakeDocker.Unlock() } func TestSyncPodsDeletes(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { // the k8s prefix is required for the kubelet to manage the container Names: []string{"/k8s--foo--bar.test"}, @@ -473,16 +399,16 @@ func TestSyncPodsDeletes(t *testing.T) { "1234": true, "9876": true, } - if len(fakeDocker.stopped) != 2 || - !expectedToStop[fakeDocker.stopped[0]] || - !expectedToStop[fakeDocker.stopped[1]] { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + if len(fakeDocker.Stopped) != 2 || + !expectedToStop[fakeDocker.Stopped[0]] || + !expectedToStop[fakeDocker.Stopped[1]] { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } } func TestSyncPodDeletesDuplicate(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - dockerContainers := DockerContainers{ + dockerContainers := dockertools.DockerContainers{ "1234": &docker.APIContainers{ // the k8s prefix is required for the kubelet to manage the container Names: []string{"/k8s--foo--bar.test--1"}, @@ -521,8 +447,8 @@ func TestSyncPodDeletesDuplicate(t *testing.T) { verifyCalls(t, fakeDocker, []string{"list", "stop"}) // Expect one of the duplicates to be killed. - if len(fakeDocker.stopped) != 1 || (len(fakeDocker.stopped) != 0 && fakeDocker.stopped[0] != "1234" && fakeDocker.stopped[0] != "4567") { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + if len(fakeDocker.Stopped) != 1 || (len(fakeDocker.Stopped) != 0 && fakeDocker.Stopped[0] != "1234" && fakeDocker.Stopped[0] != "4567") { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } } @@ -535,7 +461,7 @@ func (f *FalseHealthChecker) HealthCheck(podFullName string, state api.PodState, func TestSyncPodBadHash(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) kubelet.healthChecker = &FalseHealthChecker{} - dockerContainers := DockerContainers{ + dockerContainers := dockertools.DockerContainers{ "1234": &docker.APIContainers{ // the k8s prefix is required for the kubelet to manage the container Names: []string{"/k8s--bar.1234--foo.test"}, @@ -568,16 +494,16 @@ func TestSyncPodBadHash(t *testing.T) { expectedToStop := map[string]bool{ "1234": true, } - if len(fakeDocker.stopped) != 1 || - !expectedToStop[fakeDocker.stopped[0]] { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + if len(fakeDocker.Stopped) != 1 || + !expectedToStop[fakeDocker.Stopped[0]] { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } } func TestSyncPodUnhealthy(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) kubelet.healthChecker = &FalseHealthChecker{} - dockerContainers := DockerContainers{ + dockerContainers := dockertools.DockerContainers{ "1234": &docker.APIContainers{ // the k8s prefix is required for the kubelet to manage the container Names: []string{"/k8s--bar--foo.test"}, @@ -615,9 +541,9 @@ func TestSyncPodUnhealthy(t *testing.T) { expectedToStop := map[string]bool{ "1234": true, } - if len(fakeDocker.stopped) != 1 || - !expectedToStop[fakeDocker.stopped[0]] { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + if len(fakeDocker.Stopped) != 1 || + !expectedToStop[fakeDocker.Stopped[0]] { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } } @@ -934,7 +860,7 @@ func TestGetContainerInfo(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) kubelet.cadvisorClient = mockCadvisor - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: containerID, // pod id: qux @@ -958,7 +884,7 @@ func TestGetContainerInfo(t *testing.T) { mockCadvisor.AssertExpectations(t) } -func TestGetRooInfo(t *testing.T) { +func TestGetRootInfo(t *testing.T) { containerPath := "/" containerInfo := &info.ContainerInfo{ ContainerReference: info.ContainerReference{ @@ -973,9 +899,7 @@ func TestGetRooInfo(t *testing.T) { }, }, } - fakeDocker := FakeDockerClient{ - err: nil, - } + fakeDocker := dockertools.FakeDockerClient{} mockCadvisor := &mockCadvisorClient{} req := &info.ContainerInfoRequest{} @@ -984,7 +908,7 @@ func TestGetRooInfo(t *testing.T) { kubelet := Kubelet{ dockerClient: &fakeDocker, - dockerPuller: &FakeDockerPuller{}, + dockerPuller: &dockertools.FakeDockerPuller{}, cadvisorClient: mockCadvisor, podWorkers: newPodWorkers(), } @@ -1004,7 +928,7 @@ func TestGetRooInfo(t *testing.T) { func TestGetContainerInfoWithoutCadvisor(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: "foobar", // pod id: qux @@ -1042,7 +966,7 @@ func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) kubelet.cadvisorClient = mockCadvisor - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: containerID, // pod id: qux @@ -1070,7 +994,7 @@ func TestGetContainerInfoOnNonExistContainer(t *testing.T) { kubelet, _, fakeDocker := newTestKubelet(t) kubelet.cadvisorClient = mockCadvisor - fakeDocker.containerList = []docker.APIContainers{} + fakeDocker.ContainerList = []docker.APIContainers{} stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil) if stats != nil { @@ -1094,7 +1018,7 @@ func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([] func TestRunInContainerNoSuchPod(t *testing.T) { fakeCommandRunner := fakeContainerCommandRunner{} kubelet, _, fakeDocker := newTestKubelet(t) - fakeDocker.containerList = []docker.APIContainers{} + fakeDocker.ContainerList = []docker.APIContainers{} kubelet.runner = &fakeCommandRunner podName := "podFoo" @@ -1123,7 +1047,7 @@ func TestRunInContainer(t *testing.T) { podNamespace := "etcd" containerName := "containerFoo" - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: containerID, Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"}, @@ -1147,43 +1071,6 @@ func TestRunInContainer(t *testing.T) { } } -func TestDockerContainerCommand(t *testing.T) { - runner := dockerContainerCommandRunner{} - containerID := "1234" - command := []string{"ls"} - cmd, _ := runner.getRunInContainerCommand(containerID, command) - if cmd.Dir != "/var/lib/docker/execdriver/native/"+containerID { - t.Errorf("unexpected command CWD: %s", cmd.Dir) - } - if !reflect.DeepEqual(cmd.Args, []string{"/usr/sbin/nsinit", "exec", "ls"}) { - t.Errorf("unexpectd command args: %s", cmd.Args) - } - -} - -var parseImageNameTests = []struct { - imageName string - name string - tag string -}{ - {"ubuntu", "ubuntu", ""}, - {"ubuntu:2342", "ubuntu", "2342"}, - {"ubuntu:latest", "ubuntu", "latest"}, - {"foo/bar:445566", "foo/bar", "445566"}, - {"registry.example.com:5000/foobar", "registry.example.com:5000/foobar", ""}, - {"registry.example.com:5000/foobar:5342", "registry.example.com:5000/foobar", "5342"}, - {"registry.example.com:5000/foobar:latest", "registry.example.com:5000/foobar", "latest"}, -} - -func TestParseImageName(t *testing.T) { - for _, tt := range parseImageNameTests { - name, tag := parseImageName(tt.imageName) - if name != tt.name || tag != tt.tag { - t.Errorf("Expected name/tag: %s/%s, got %s/%s", tt.name, tt.tag, name, tag) - } - } -} - func TestRunHandlerExec(t *testing.T) { fakeCommandRunner := fakeContainerCommandRunner{} kubelet, _, fakeDocker := newTestKubelet(t) @@ -1194,7 +1081,7 @@ func TestRunHandlerExec(t *testing.T) { podNamespace := "etcd" containerName := "containerFoo" - fakeDocker.containerList = []docker.APIContainers{ + fakeDocker.ContainerList = []docker.APIContainers{ { ID: containerID, Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"}, @@ -1298,7 +1185,7 @@ func TestSyncPodEventHandlerFails(t *testing.T) { kubelet.httpClient = &fakeHTTP{ err: fmt.Errorf("test error"), } - dockerContainers := DockerContainers{ + dockerContainers := dockertools.DockerContainers{ "9876": &docker.APIContainers{ // network container Names: []string{"/k8s--net--foo.test--"}, @@ -1331,7 +1218,7 @@ func TestSyncPodEventHandlerFails(t *testing.T) { verifyCalls(t, fakeDocker, []string{"list", "list", "create", "start", "stop"}) - if len(fakeDocker.stopped) != 1 { - t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped) + if len(fakeDocker.Stopped) != 1 { + t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped) } } diff --git a/pkg/kubelet/server.go b/pkg/kubelet/server.go index 5c0c9a80af..14ea087515 100644 --- a/pkg/kubelet/server.go +++ b/pkg/kubelet/server.go @@ -33,6 +33,7 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/healthz" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" + "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools" "github.com/golang/glog" "github.com/google/cadvisor/info" "gopkg.in/v1/yaml" @@ -159,7 +160,7 @@ func (s *Server) handlePodInfo(w http.ResponseWriter, req *http.Request) { // TODO: backwards compatibility with existing API, needs API change podFullName := GetPodFullName(&Pod{Name: podID, Namespace: "etcd"}) info, err := s.host.GetPodInfo(podFullName, podUUID) - if err == ErrNoContainersInPod { + if err == dockertools.ErrNoContainersInPod { http.Error(w, "Pod does not exist", http.StatusNotFound) return }