kubelet: move docker-related code into sub-package

pull/6/head
Brian Waldon 2014-09-08 21:33:17 -07:00
parent 7de0989a4e
commit 0bf4fabc19
7 changed files with 316 additions and 260 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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--<container-id>--<pod-fullname>
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--<container-id>--<pod-fullname>
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)
}
}

View File

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