mirror of https://github.com/k3s-io/k3s
kubelet: move docker-related code into sub-package
parent
7de0989a4e
commit
0bf4fabc19
|
@ -34,6 +34,7 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/controller"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config"
|
"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/labels"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/master"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
|
@ -46,7 +47,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fakeDocker1, fakeDocker2 kubelet.FakeDockerClient
|
fakeDocker1, fakeDocker2 dockertools.FakeDockerClient
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakePodInfoGetter struct{}
|
type fakePodInfoGetter struct{}
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubelet
|
package dockertools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -111,7 +111,7 @@ type DockerContainers map[DockerID]*docker.APIContainers
|
||||||
|
|
||||||
func (c DockerContainers) FindPodContainer(podFullName, uuid, containerName string) (*docker.APIContainers, bool, uint64) {
|
func (c DockerContainers) FindPodContainer(podFullName, uuid, containerName string) (*docker.APIContainers, bool, uint64) {
|
||||||
for _, dockerContainer := range c {
|
for _, dockerContainer := range c {
|
||||||
dockerManifestID, dockerUUID, dockerContainerName, hash := parseDockerName(dockerContainer.Names[0])
|
dockerManifestID, dockerUUID, dockerContainerName, hash := ParseDockerName(dockerContainer.Names[0])
|
||||||
if dockerManifestID == podFullName &&
|
if dockerManifestID == podFullName &&
|
||||||
(uuid == "" || dockerUUID == uuid) &&
|
(uuid == "" || dockerUUID == uuid) &&
|
||||||
dockerContainerName == containerName {
|
dockerContainerName == containerName {
|
||||||
|
@ -126,7 +126,7 @@ func (c DockerContainers) FindContainersByPodFullName(podFullName string) map[st
|
||||||
containers := make(map[string]*docker.APIContainers)
|
containers := make(map[string]*docker.APIContainers)
|
||||||
|
|
||||||
for _, dockerContainer := range c {
|
for _, dockerContainer := range c {
|
||||||
dockerManifestID, _, dockerContainerName, _ := parseDockerName(dockerContainer.Names[0])
|
dockerManifestID, _, dockerContainerName, _ := ParseDockerName(dockerContainer.Names[0])
|
||||||
if dockerManifestID == podFullName {
|
if dockerManifestID == podFullName {
|
||||||
containers[dockerContainerName] = dockerContainer
|
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
|
// 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)
|
result := make(DockerContainers)
|
||||||
containers, err := client.ListContainers(docker.ListContainersOptions{})
|
containers, err := client.ListContainers(docker.ListContainersOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,16 +153,16 @@ func getKubeletDockerContainers(client DockerInterface) (DockerContainers, error
|
||||||
return result, nil
|
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.
|
// 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
|
var result []*docker.Container
|
||||||
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, dockerContainer := range containers {
|
for _, dockerContainer := range containers {
|
||||||
dockerPodName, dockerUUID, dockerContainerName, _ := parseDockerName(dockerContainer.Names[0])
|
dockerPodName, dockerUUID, dockerContainerName, _ := ParseDockerName(dockerContainer.Names[0])
|
||||||
if dockerPodName != podFullName {
|
if dockerPodName != podFullName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ func getRecentDockerContainersWithNameAndUUID(client DockerInterface, podFullNam
|
||||||
var ErrNoContainersInPod = errors.New("no containers exist for this pod")
|
var ErrNoContainersInPod = errors.New("no containers exist for this pod")
|
||||||
|
|
||||||
// GetDockerPodInfo returns docker info for all containers in the pod/manifest.
|
// 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{}
|
info := api.PodInfo{}
|
||||||
|
|
||||||
containers, err := client.ListContainers(docker.ListContainersOptions{All: true})
|
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 {
|
for _, value := range containers {
|
||||||
dockerManifestID, dockerUUID, dockerContainerName, _ := parseDockerName(value.Names[0])
|
dockerManifestID, dockerUUID, dockerContainerName, _ := ParseDockerName(value.Names[0])
|
||||||
if dockerManifestID != podFullName {
|
if dockerManifestID != podFullName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -239,35 +239,35 @@ func unescapeDash(in string) (out string) {
|
||||||
|
|
||||||
const containerNamePrefix = "k8s"
|
const containerNamePrefix = "k8s"
|
||||||
|
|
||||||
func hashContainer(container *api.Container) uint64 {
|
func HashContainer(container *api.Container) uint64 {
|
||||||
hash := adler32.New()
|
hash := adler32.New()
|
||||||
fmt.Fprintf(hash, "%#v", *container)
|
fmt.Fprintf(hash, "%#v", *container)
|
||||||
return uint64(hash.Sum32())
|
return uint64(hash.Sum32())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a name which can be reversed to identify both full pod name and container name.
|
// Creates a name which can be reversed to identify both full pod name and container name.
|
||||||
func buildDockerName(pod *Pod, container *api.Container) string {
|
func BuildDockerName(manifestUUID, podFullName string, container *api.Container) string {
|
||||||
containerName := escapeDash(container.Name) + "." + strconv.FormatUint(hashContainer(container), 16)
|
containerName := escapeDash(container.Name) + "." + strconv.FormatUint(HashContainer(container), 16)
|
||||||
// Note, manifest.ID could be blank.
|
// Note, manifest.ID could be blank.
|
||||||
if len(pod.Manifest.UUID) == 0 {
|
if len(manifestUUID) == 0 {
|
||||||
return fmt.Sprintf("%s--%s--%s--%08x",
|
return fmt.Sprintf("%s--%s--%s--%08x",
|
||||||
containerNamePrefix,
|
containerNamePrefix,
|
||||||
containerName,
|
containerName,
|
||||||
escapeDash(GetPodFullName(pod)),
|
escapeDash(podFullName),
|
||||||
rand.Uint32())
|
rand.Uint32())
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%s--%s--%s--%s--%08x",
|
return fmt.Sprintf("%s--%s--%s--%s--%08x",
|
||||||
containerNamePrefix,
|
containerNamePrefix,
|
||||||
containerName,
|
containerName,
|
||||||
escapeDash(GetPodFullName(pod)),
|
escapeDash(podFullName),
|
||||||
escapeDash(pod.Manifest.UUID),
|
escapeDash(manifestUUID),
|
||||||
rand.Uint32())
|
rand.Uint32())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upacks a container name, returning the pod full name and container name we would have used to
|
// 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.
|
// 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.
|
// For some reason docker appears to be appending '/' to names.
|
||||||
// If it's there, strip it.
|
// If it's there, strip it.
|
||||||
if name[0] == '/' {
|
if name[0] == '/' {
|
||||||
|
@ -319,3 +319,7 @@ func parseImageName(image string) (string, string) {
|
||||||
}
|
}
|
||||||
return image, tag
|
return image, tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ContainerCommandRunner interface {
|
||||||
|
RunInContainer(containerID string, cmd []string) ([]byte, error)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,11 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kubelet
|
package dockertools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/fsouza/go-dockerclient"
|
"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.
|
// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup.
|
||||||
type FakeDockerClient struct {
|
type FakeDockerClient struct {
|
||||||
lock sync.Mutex
|
sync.Mutex
|
||||||
containerList []docker.APIContainers
|
ContainerList []docker.APIContainers
|
||||||
container *docker.Container
|
Container *docker.Container
|
||||||
err error
|
Err error
|
||||||
called []string
|
called []string
|
||||||
stopped []string
|
Stopped []string
|
||||||
pulled []string
|
pulled []string
|
||||||
Created []string
|
Created []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDockerClient) clearCalls() {
|
func (f *FakeDockerClient) clearCalls() {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = []string{}
|
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.
|
// ListContainers is a test-spy implementation of DockerInterface.ListContainers.
|
||||||
// It adds an entry "list" to the internal method call record.
|
// It adds an entry "list" to the internal method call record.
|
||||||
func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
|
func (f *FakeDockerClient) ListContainers(options docker.ListContainersOptions) ([]docker.APIContainers, error) {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "list")
|
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.
|
// InspectContainer is a test-spy implementation of DockerInterface.InspectContainer.
|
||||||
// It adds an entry "inspect" to the internal method call record.
|
// It adds an entry "inspect" to the internal method call record.
|
||||||
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
|
func (f *FakeDockerClient) InspectContainer(id string) (*docker.Container, error) {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "inspect")
|
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.
|
// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer.
|
||||||
// It adds an entry "create" to the internal method call record.
|
// It adds an entry "create" to the internal method call record.
|
||||||
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
|
func (f *FakeDockerClient) CreateContainer(c docker.CreateContainerOptions) (*docker.Container, error) {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "create")
|
f.called = append(f.called, "create")
|
||||||
f.Created = append(f.Created, c.Name)
|
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.
|
// 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.
|
// Docker likes to add a '/', so copy that behavior.
|
||||||
name := "/" + c.Name
|
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
|
return &docker.Container{ID: name}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartContainer is a test-spy implementation of DockerInterface.StartContainer.
|
// StartContainer is a test-spy implementation of DockerInterface.StartContainer.
|
||||||
// It adds an entry "start" to the internal method call record.
|
// It adds an entry "start" to the internal method call record.
|
||||||
func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error {
|
func (f *FakeDockerClient) StartContainer(id string, hostConfig *docker.HostConfig) error {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "start")
|
f.called = append(f.called, "start")
|
||||||
return f.err
|
return f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopContainer is a test-spy implementation of DockerInterface.StopContainer.
|
// StopContainer is a test-spy implementation of DockerInterface.StopContainer.
|
||||||
// It adds an entry "stop" to the internal method call record.
|
// It adds an entry "stop" to the internal method call record.
|
||||||
func (f *FakeDockerClient) StopContainer(id string, timeout uint) error {
|
func (f *FakeDockerClient) StopContainer(id string, timeout uint) error {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "stop")
|
f.called = append(f.called, "stop")
|
||||||
f.stopped = append(f.stopped, id)
|
f.Stopped = append(f.Stopped, id)
|
||||||
var newList []docker.APIContainers
|
var newList []docker.APIContainers
|
||||||
for _, container := range f.containerList {
|
for _, container := range f.ContainerList {
|
||||||
if container.ID != id {
|
if container.ID != id {
|
||||||
newList = append(newList, container)
|
newList = append(newList, container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.containerList = newList
|
f.ContainerList = newList
|
||||||
return f.err
|
return f.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PullImage is a test-spy implementation of DockerInterface.StopContainer.
|
// PullImage is a test-spy implementation of DockerInterface.StopContainer.
|
||||||
// It adds an entry "pull" to the internal method call record.
|
// It adds an entry "pull" to the internal method call record.
|
||||||
func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error {
|
func (f *FakeDockerClient) PullImage(opts docker.PullImageOptions, auth docker.AuthConfiguration) error {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.called = append(f.called, "pull")
|
f.called = append(f.called, "pull")
|
||||||
f.pulled = append(f.pulled, fmt.Sprintf("%s/%s:%s", opts.Repository, opts.Registry, opts.Tag))
|
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.
|
// FakeDockerPuller is a stub implementation of DockerPuller.
|
||||||
type FakeDockerPuller struct {
|
type FakeDockerPuller struct {
|
||||||
lock sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
ImagesPulled []string
|
ImagesPulled []string
|
||||||
|
|
||||||
// Every pull will return the first error here, and then reslice
|
// 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.
|
// Pull records the image pull attempt, and optionally injects an error.
|
||||||
func (f *FakeDockerPuller) Pull(image string) (err error) {
|
func (f *FakeDockerPuller) Pull(image string) (err error) {
|
||||||
f.lock.Lock()
|
f.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.Unlock()
|
||||||
f.ImagesPulled = append(f.ImagesPulled, image)
|
f.ImagesPulled = append(f.ImagesPulled, image)
|
||||||
|
|
||||||
if len(f.ErrorsToInject) > 0 {
|
if len(f.ErrorsToInject) > 0 {
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
"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
|
// New creates a new Kubelet for use in main
|
||||||
func NewMainKubelet(
|
func NewMainKubelet(
|
||||||
hn string,
|
hn string,
|
||||||
dc DockerInterface,
|
dc dockertools.DockerInterface,
|
||||||
cc CadvisorInterface,
|
cc CadvisorInterface,
|
||||||
ec tools.EtcdClient,
|
ec tools.EtcdClient,
|
||||||
rd string,
|
rd string,
|
||||||
|
@ -75,27 +76,23 @@ func NewMainKubelet(
|
||||||
rootDirectory: rd,
|
rootDirectory: rd,
|
||||||
resyncInterval: ri,
|
resyncInterval: ri,
|
||||||
podWorkers: newPodWorkers(),
|
podWorkers: newPodWorkers(),
|
||||||
runner: NewDockerContainerCommandRunner(),
|
runner: dockertools.NewDockerContainerCommandRunner(),
|
||||||
httpClient: &http.Client{},
|
httpClient: &http.Client{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntegrationTestKubelet creates a new Kubelet for use in integration tests.
|
// NewIntegrationTestKubelet creates a new Kubelet for use in integration tests.
|
||||||
// TODO: add more integration tests, and expand parameter list as needed.
|
// 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{
|
return &Kubelet{
|
||||||
hostname: hn,
|
hostname: hn,
|
||||||
dockerClient: dc,
|
dockerClient: dc,
|
||||||
dockerPuller: &FakeDockerPuller{},
|
dockerPuller: &dockertools.FakeDockerPuller{},
|
||||||
resyncInterval: 3 * time.Second,
|
resyncInterval: 3 * time.Second,
|
||||||
podWorkers: newPodWorkers(),
|
podWorkers: newPodWorkers(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerCommandRunner interface {
|
|
||||||
RunInContainer(containerID string, cmd []string) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpGetInterface interface {
|
type httpGetInterface interface {
|
||||||
Get(url string) (*http.Response, error)
|
Get(url string) (*http.Response, error)
|
||||||
}
|
}
|
||||||
|
@ -103,7 +100,7 @@ type httpGetInterface interface {
|
||||||
// Kubelet is the main kubelet implementation.
|
// Kubelet is the main kubelet implementation.
|
||||||
type Kubelet struct {
|
type Kubelet struct {
|
||||||
hostname string
|
hostname string
|
||||||
dockerClient DockerInterface
|
dockerClient dockertools.DockerInterface
|
||||||
rootDirectory string
|
rootDirectory string
|
||||||
podWorkers podWorkers
|
podWorkers podWorkers
|
||||||
resyncInterval time.Duration
|
resyncInterval time.Duration
|
||||||
|
@ -115,11 +112,11 @@ type Kubelet struct {
|
||||||
// Optional, defaults to simple implementaiton
|
// Optional, defaults to simple implementaiton
|
||||||
healthChecker health.HealthChecker
|
healthChecker health.HealthChecker
|
||||||
// Optional, defaults to simple Docker implementation
|
// Optional, defaults to simple Docker implementation
|
||||||
dockerPuller DockerPuller
|
dockerPuller dockertools.DockerPuller
|
||||||
// Optional, defaults to /logs/ from /var/log
|
// Optional, defaults to /logs/ from /var/log
|
||||||
logServer http.Handler
|
logServer http.Handler
|
||||||
// Optional, defaults to simple Docker implementation
|
// Optional, defaults to simple Docker implementation
|
||||||
runner ContainerCommandRunner
|
runner dockertools.ContainerCommandRunner
|
||||||
// Optional, client for http requests, defaults to empty client
|
// Optional, client for http requests, defaults to empty client
|
||||||
httpClient httpGetInterface
|
httpClient httpGetInterface
|
||||||
}
|
}
|
||||||
|
@ -130,7 +127,7 @@ func (kl *Kubelet) Run(updates <-chan PodUpdate) {
|
||||||
kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))
|
kl.logServer = http.StripPrefix("/logs/", http.FileServer(http.Dir("/var/log/")))
|
||||||
}
|
}
|
||||||
if kl.dockerPuller == nil {
|
if kl.dockerPuller == nil {
|
||||||
kl.dockerPuller = NewDockerPuller(kl.dockerClient)
|
kl.dockerPuller = dockertools.NewDockerPuller(kl.dockerClient)
|
||||||
}
|
}
|
||||||
if kl.healthChecker == nil {
|
if kl.healthChecker == nil {
|
||||||
kl.healthChecker = health.NewHealthChecker()
|
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
|
// 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)
|
envVariables := makeEnvironmentVariables(container)
|
||||||
binds := makeBinds(pod, container, podVolumes)
|
binds := makeBinds(pod, container, podVolumes)
|
||||||
exposedPorts, portBindings := makePortsAndBindings(container)
|
exposedPorts, portBindings := makePortsAndBindings(container)
|
||||||
|
|
||||||
opts := docker.CreateContainerOptions{
|
opts := docker.CreateContainerOptions{
|
||||||
Name: buildDockerName(pod, container),
|
Name: dockertools.BuildDockerName(pod.Manifest.UUID, GetPodFullName(pod), container),
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Cmd: container.Command,
|
Cmd: container.Command,
|
||||||
Env: envVariables,
|
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)
|
handlerErr := kl.runHandler(GetPodFullName(pod), pod.Manifest.UUID, container, container.Lifecycle.PostStart)
|
||||||
if handlerErr != nil {
|
if handlerErr != nil {
|
||||||
kl.killContainerByID(dockerContainer.ID, "")
|
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
|
// Kill a docker container
|
||||||
|
@ -364,7 +361,7 @@ func (kl *Kubelet) killContainerByID(ID, name string) error {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
podFullName, uuid, containerName, _ := parseDockerName(name)
|
podFullName, uuid, containerName, _ := dockertools.ParseDockerName(name)
|
||||||
kl.LogEvent(&api.Event{
|
kl.LogEvent(&api.Event{
|
||||||
Event: "STOP",
|
Event: "STOP",
|
||||||
Manifest: &api.ContainerManifest{
|
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.
|
// 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
|
var ports []api.Port
|
||||||
// Docker only exports ports from the network container. Let's
|
// Docker only exports ports from the network container. Let's
|
||||||
// collect all of the relevant ports and export them.
|
// 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
|
// Delete all containers in a pod (except the network container) returns the number of containers deleted
|
||||||
// and an error if one occurs.
|
// 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
|
count := 0
|
||||||
errs := make(chan error, len(pod.Manifest.Containers))
|
errs := make(chan error, len(pod.Manifest.Containers))
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
@ -436,16 +433,16 @@ func (kl *Kubelet) deleteAllContainers(pod *Pod, podFullName string, dockerConta
|
||||||
|
|
||||||
type empty struct{}
|
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)
|
podFullName := GetPodFullName(pod)
|
||||||
uuid := pod.Manifest.UUID
|
uuid := pod.Manifest.UUID
|
||||||
containersToKeep := make(map[DockerID]empty)
|
containersToKeep := make(map[dockertools.DockerID]empty)
|
||||||
killedContainers := make(map[DockerID]empty)
|
killedContainers := make(map[dockertools.DockerID]empty)
|
||||||
|
|
||||||
// Make sure we have a network container
|
// Make sure we have a network container
|
||||||
var netID DockerID
|
var netID dockertools.DockerID
|
||||||
if networkDockerContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uuid, networkContainerName); found {
|
if networkDockerContainer, found, _ := dockerContainers.FindPodContainer(podFullName, uuid, networkContainerName); found {
|
||||||
netID = DockerID(networkDockerContainer.ID)
|
netID = dockertools.DockerID(networkDockerContainer.ID)
|
||||||
} else {
|
} else {
|
||||||
glog.Infof("Network container doesn't exist, creating")
|
glog.Infof("Network container doesn't exist, creating")
|
||||||
count, err := kl.deleteAllContainers(pod, podFullName, dockerContainers)
|
count, err := kl.deleteAllContainers(pod, podFullName, dockerContainers)
|
||||||
|
@ -460,7 +457,7 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error {
|
||||||
netID = dockerNetworkID
|
netID = dockerNetworkID
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
// relist everything, otherwise we'll think we're ok
|
// relist everything, otherwise we'll think we're ok
|
||||||
dockerContainers, err = getKubeletDockerContainers(kl.dockerClient)
|
dockerContainers, err = dockertools.GetKubeletDockerContainers(kl.dockerClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Error listing containers %#v", dockerContainers)
|
glog.Errorf("Error listing containers %#v", dockerContainers)
|
||||||
return err
|
return err
|
||||||
|
@ -487,9 +484,9 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, container := range pod.Manifest.Containers {
|
for _, container := range pod.Manifest.Containers {
|
||||||
expectedHash := hashContainer(&container)
|
expectedHash := dockertools.HashContainer(&container)
|
||||||
if dockerContainer, found, hash := dockerContainers.FindPodContainer(podFullName, uuid, container.Name); found {
|
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)
|
glog.V(1).Infof("pod %s container %s exists as %v", podFullName, container.Name, containerID)
|
||||||
|
|
||||||
// look for changes in the container.
|
// look for changes in the container.
|
||||||
|
@ -517,7 +514,7 @@ func (kl *Kubelet) syncPod(pod *Pod, dockerContainers DockerContainers) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check RestartPolicy for container
|
// 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 {
|
if err != nil {
|
||||||
glog.Errorf("Error listing recent containers with name and uuid:%s--%s--%s", podFullName, uuid, container.Name)
|
glog.Errorf("Error listing recent containers with name and uuid:%s--%s--%s", podFullName, uuid, container.Name)
|
||||||
// TODO(dawnchen): error handling here?
|
// 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).
|
// Kill any containers in this pod which were not identified above (guards against duplicates).
|
||||||
for id, container := range dockerContainers {
|
for id, container := range dockerContainers {
|
||||||
curPodFullName, curUUID, _, _ := parseDockerName(container.Names[0])
|
curPodFullName, curUUID, _, _ := dockertools.ParseDockerName(container.Names[0])
|
||||||
if curPodFullName == podFullName && curUUID == uuid {
|
if curPodFullName == podFullName && curUUID == uuid {
|
||||||
// Don't kill containers we want to keep or those we already killed.
|
// Don't kill containers we want to keep or those we already killed.
|
||||||
_, keep := containersToKeep[id]
|
_, keep := containersToKeep[id]
|
||||||
|
@ -618,7 +615,7 @@ func (kl *Kubelet) SyncPods(pods []Pod) error {
|
||||||
var err error
|
var err error
|
||||||
desiredContainers := make(map[podContainer]empty)
|
desiredContainers := make(map[podContainer]empty)
|
||||||
|
|
||||||
dockerContainers, err := getKubeletDockerContainers(kl.dockerClient)
|
dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Error listing containers %#v", dockerContainers)
|
glog.Errorf("Error listing containers %#v", dockerContainers)
|
||||||
return err
|
return err
|
||||||
|
@ -646,14 +643,14 @@ func (kl *Kubelet) SyncPods(pods []Pod) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill any containers we don't need
|
// Kill any containers we don't need
|
||||||
existingContainers, err := getKubeletDockerContainers(kl.dockerClient)
|
existingContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Error listing containers: %v", err)
|
glog.Errorf("Error listing containers: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, container := range existingContainers {
|
for _, container := range existingContainers {
|
||||||
// Don't kill containers that are in the desired pods.
|
// 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 {
|
if _, ok := desiredContainers[podContainer{podFullName, uuid, containerName}]; !ok {
|
||||||
err = kl.killContainer(container)
|
err = kl.killContainer(container)
|
||||||
if err != nil {
|
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
|
// GetPodInfo returns information from Docker about the containers in a pod
|
||||||
func (kl *Kubelet) GetPodInfo(podFullName, uuid string) (api.PodInfo, error) {
|
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.
|
// 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 {
|
if kl.cadvisorClient == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
dockerContainers, err := getKubeletDockerContainers(kl.dockerClient)
|
dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -798,7 +795,7 @@ func (kl *Kubelet) RunInContainer(podFullName, uuid, container string, cmd []str
|
||||||
if kl.runner == nil {
|
if kl.runner == nil {
|
||||||
return nil, fmt.Errorf("no runner specified.")
|
return nil, fmt.Errorf("no runner specified.")
|
||||||
}
|
}
|
||||||
dockerContainers, err := getKubeletDockerContainers(kl.dockerClient)
|
dockerContainers, err := dockertools.GetKubeletDockerContainers(kl.dockerClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ package kubelet
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/adler32"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -30,6 +29,7 @@ import (
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
||||||
|
@ -38,25 +38,24 @@ import (
|
||||||
"github.com/stretchr/testify/mock"
|
"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)
|
fakeEtcdClient := tools.NewFakeEtcdClient(t)
|
||||||
fakeDocker := &FakeDockerClient{
|
fakeDocker := &dockertools.FakeDockerClient{}
|
||||||
err: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
kubelet := &Kubelet{}
|
kubelet := &Kubelet{}
|
||||||
kubelet.dockerClient = fakeDocker
|
kubelet.dockerClient = fakeDocker
|
||||||
kubelet.dockerPuller = &FakeDockerPuller{}
|
kubelet.dockerPuller = &dockertools.FakeDockerPuller{}
|
||||||
kubelet.etcdClient = fakeEtcdClient
|
kubelet.etcdClient = fakeEtcdClient
|
||||||
kubelet.rootDirectory = "/tmp/kubelet"
|
kubelet.rootDirectory = "/tmp/kubelet"
|
||||||
kubelet.podWorkers = newPodWorkers()
|
kubelet.podWorkers = newPodWorkers()
|
||||||
return kubelet, fakeEtcdClient, fakeDocker
|
return kubelet, fakeEtcdClient, fakeDocker
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) {
|
func verifyCalls(t *testing.T, fakeDocker *dockertools.FakeDockerClient, calls []string) {
|
||||||
fakeDocker.lock.Lock()
|
err := fakeDocker.AssertCalls(calls)
|
||||||
defer fakeDocker.lock.Unlock()
|
if err != nil {
|
||||||
verifyStringArrayEquals(t, fakeDocker.called, calls)
|
t.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyStringArrayEquals(t *testing.T, actual, expected []string) {
|
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) {
|
func verifyBoolean(t *testing.T, expected, value bool) {
|
||||||
if expected != value {
|
if expected != value {
|
||||||
t.Errorf("Unexpected boolean. Expected %t. Found %t", 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) {
|
func TestKillContainerWithError(t *testing.T) {
|
||||||
fakeDocker := &FakeDockerClient{
|
fakeDocker := &dockertools.FakeDockerClient{
|
||||||
err: fmt.Errorf("sample error"),
|
Err: fmt.Errorf("sample error"),
|
||||||
containerList: []docker.APIContainers{
|
ContainerList: []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: "1234",
|
ID: "1234",
|
||||||
Names: []string{"/k8s--foo--qux--1234"},
|
Names: []string{"/k8s--foo--qux--1234"},
|
||||||
|
@ -168,7 +94,7 @@ func TestKillContainerWithError(t *testing.T) {
|
||||||
}
|
}
|
||||||
kubelet, _, _ := newTestKubelet(t)
|
kubelet, _, _ := newTestKubelet(t)
|
||||||
kubelet.dockerClient = fakeDocker
|
kubelet.dockerClient = fakeDocker
|
||||||
err := kubelet.killContainer(&fakeDocker.containerList[0])
|
err := kubelet.killContainer(&fakeDocker.ContainerList[0])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected error, found nil")
|
t.Errorf("expected error, found nil")
|
||||||
}
|
}
|
||||||
|
@ -177,7 +103,7 @@ func TestKillContainerWithError(t *testing.T) {
|
||||||
|
|
||||||
func TestKillContainer(t *testing.T) {
|
func TestKillContainer(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: "1234",
|
ID: "1234",
|
||||||
Names: []string{"/k8s--foo--qux--1234"},
|
Names: []string{"/k8s--foo--qux--1234"},
|
||||||
|
@ -187,11 +113,11 @@ func TestKillContainer(t *testing.T) {
|
||||||
Names: []string{"/k8s--bar--qux--5678"},
|
Names: []string{"/k8s--bar--qux--5678"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fakeDocker.container = &docker.Container{
|
fakeDocker.Container = &docker.Container{
|
||||||
ID: "foobar",
|
ID: "foobar",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := kubelet.killContainer(&fakeDocker.containerList[0])
|
err := kubelet.killContainer(&fakeDocker.ContainerList[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -227,10 +153,10 @@ func (cr *channelReader) GetList() [][]Pod {
|
||||||
func TestSyncPodsDoesNothing(t *testing.T) {
|
func TestSyncPodsDoesNothing(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
container := api.Container{Name: "bar"}
|
container := api.Container{Name: "bar"}
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
// format is k8s--<container-id>--<pod-fullname>
|
// 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",
|
ID: "1234",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -281,7 +207,7 @@ func matchString(t *testing.T, pattern, str string) bool {
|
||||||
|
|
||||||
func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{}
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||||
err := kubelet.SyncPods([]Pod{
|
err := kubelet.SyncPods([]Pod{
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
@ -302,18 +228,18 @@ func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "create", "start", "list", "inspect", "list", "create", "start"})
|
"list", "list", "create", "start", "list", "inspect", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.lock.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.Created) != 2 ||
|
if len(fakeDocker.Created) != 2 ||
|
||||||
!matchString(t, "k8s--net\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) ||
|
!matchString(t, "k8s--net\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) ||
|
||||||
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[1]) {
|
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[1]) {
|
||||||
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
||||||
}
|
}
|
||||||
fakeDocker.lock.Unlock()
|
fakeDocker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
|
func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
// network container
|
// network container
|
||||||
Names: []string{"/k8s--net--foo.test--"},
|
Names: []string{"/k8s--net--foo.test--"},
|
||||||
|
@ -340,19 +266,19 @@ func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "list", "inspect", "list", "create", "start"})
|
"list", "list", "list", "inspect", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.lock.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.Created) != 1 ||
|
if len(fakeDocker.Created) != 1 ||
|
||||||
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) {
|
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) {
|
||||||
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
||||||
}
|
}
|
||||||
fakeDocker.lock.Unlock()
|
fakeDocker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeHttp := fakeHTTP{}
|
fakeHttp := fakeHTTP{}
|
||||||
kubelet.httpClient = &fakeHttp
|
kubelet.httpClient = &fakeHttp
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
// network container
|
// network container
|
||||||
Names: []string{"/k8s--net--foo.test--"},
|
Names: []string{"/k8s--net--foo.test--"},
|
||||||
|
@ -390,12 +316,12 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
||||||
verifyCalls(t, fakeDocker, []string{
|
verifyCalls(t, fakeDocker, []string{
|
||||||
"list", "list", "list", "inspect", "list", "create", "start"})
|
"list", "list", "list", "inspect", "list", "create", "start"})
|
||||||
|
|
||||||
fakeDocker.lock.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.Created) != 1 ||
|
if len(fakeDocker.Created) != 1 ||
|
||||||
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) {
|
!matchString(t, "k8s--bar\\.[a-f0-9]+--foo.test--", fakeDocker.Created[0]) {
|
||||||
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
||||||
}
|
}
|
||||||
fakeDocker.lock.Unlock()
|
fakeDocker.Unlock()
|
||||||
if fakeHttp.url != "http://foo:8080/bar" {
|
if fakeHttp.url != "http://foo:8080/bar" {
|
||||||
t.Errorf("Unexpected handler: %s", fakeHttp.url)
|
t.Errorf("Unexpected handler: %s", fakeHttp.url)
|
||||||
}
|
}
|
||||||
|
@ -403,7 +329,7 @@ func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
||||||
|
|
||||||
func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
|
func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
// format is k8s--<container-id>--<pod-fullname>
|
// format is k8s--<container-id>--<pod-fullname>
|
||||||
Names: []string{"/k8s--bar--foo.test"},
|
Names: []string{"/k8s--bar--foo.test"},
|
||||||
|
@ -435,16 +361,16 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
|
||||||
expectedToStop := map[string]bool{
|
expectedToStop := map[string]bool{
|
||||||
"1234": true,
|
"1234": true,
|
||||||
}
|
}
|
||||||
fakeDocker.lock.Lock()
|
fakeDocker.Lock()
|
||||||
if len(fakeDocker.stopped) != 1 || !expectedToStop[fakeDocker.stopped[0]] {
|
if len(fakeDocker.Stopped) != 1 || !expectedToStop[fakeDocker.Stopped[0]] {
|
||||||
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
||||||
}
|
}
|
||||||
fakeDocker.lock.Unlock()
|
fakeDocker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncPodsDeletes(t *testing.T) {
|
func TestSyncPodsDeletes(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(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
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
Names: []string{"/k8s--foo--bar.test"},
|
Names: []string{"/k8s--foo--bar.test"},
|
||||||
|
@ -473,16 +399,16 @@ func TestSyncPodsDeletes(t *testing.T) {
|
||||||
"1234": true,
|
"1234": true,
|
||||||
"9876": true,
|
"9876": true,
|
||||||
}
|
}
|
||||||
if len(fakeDocker.stopped) != 2 ||
|
if len(fakeDocker.Stopped) != 2 ||
|
||||||
!expectedToStop[fakeDocker.stopped[0]] ||
|
!expectedToStop[fakeDocker.Stopped[0]] ||
|
||||||
!expectedToStop[fakeDocker.stopped[1]] {
|
!expectedToStop[fakeDocker.Stopped[1]] {
|
||||||
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncPodDeletesDuplicate(t *testing.T) {
|
func TestSyncPodDeletesDuplicate(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
dockerContainers := DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"1234": &docker.APIContainers{
|
"1234": &docker.APIContainers{
|
||||||
// the k8s prefix is required for the kubelet to manage the container
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
Names: []string{"/k8s--foo--bar.test--1"},
|
Names: []string{"/k8s--foo--bar.test--1"},
|
||||||
|
@ -521,8 +447,8 @@ func TestSyncPodDeletesDuplicate(t *testing.T) {
|
||||||
verifyCalls(t, fakeDocker, []string{"list", "stop"})
|
verifyCalls(t, fakeDocker, []string{"list", "stop"})
|
||||||
|
|
||||||
// Expect one of the duplicates to be killed.
|
// 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") {
|
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)
|
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) {
|
func TestSyncPodBadHash(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.healthChecker = &FalseHealthChecker{}
|
kubelet.healthChecker = &FalseHealthChecker{}
|
||||||
dockerContainers := DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"1234": &docker.APIContainers{
|
"1234": &docker.APIContainers{
|
||||||
// the k8s prefix is required for the kubelet to manage the container
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
Names: []string{"/k8s--bar.1234--foo.test"},
|
Names: []string{"/k8s--bar.1234--foo.test"},
|
||||||
|
@ -568,16 +494,16 @@ func TestSyncPodBadHash(t *testing.T) {
|
||||||
expectedToStop := map[string]bool{
|
expectedToStop := map[string]bool{
|
||||||
"1234": true,
|
"1234": true,
|
||||||
}
|
}
|
||||||
if len(fakeDocker.stopped) != 1 ||
|
if len(fakeDocker.Stopped) != 1 ||
|
||||||
!expectedToStop[fakeDocker.stopped[0]] {
|
!expectedToStop[fakeDocker.Stopped[0]] {
|
||||||
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncPodUnhealthy(t *testing.T) {
|
func TestSyncPodUnhealthy(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.healthChecker = &FalseHealthChecker{}
|
kubelet.healthChecker = &FalseHealthChecker{}
|
||||||
dockerContainers := DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"1234": &docker.APIContainers{
|
"1234": &docker.APIContainers{
|
||||||
// the k8s prefix is required for the kubelet to manage the container
|
// the k8s prefix is required for the kubelet to manage the container
|
||||||
Names: []string{"/k8s--bar--foo.test"},
|
Names: []string{"/k8s--bar--foo.test"},
|
||||||
|
@ -615,9 +541,9 @@ func TestSyncPodUnhealthy(t *testing.T) {
|
||||||
expectedToStop := map[string]bool{
|
expectedToStop := map[string]bool{
|
||||||
"1234": true,
|
"1234": true,
|
||||||
}
|
}
|
||||||
if len(fakeDocker.stopped) != 1 ||
|
if len(fakeDocker.Stopped) != 1 ||
|
||||||
!expectedToStop[fakeDocker.stopped[0]] {
|
!expectedToStop[fakeDocker.Stopped[0]] {
|
||||||
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -934,7 +860,7 @@ func TestGetContainerInfo(t *testing.T) {
|
||||||
|
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.cadvisorClient = mockCadvisor
|
kubelet.cadvisorClient = mockCadvisor
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
// pod id: qux
|
// pod id: qux
|
||||||
|
@ -958,7 +884,7 @@ func TestGetContainerInfo(t *testing.T) {
|
||||||
mockCadvisor.AssertExpectations(t)
|
mockCadvisor.AssertExpectations(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRooInfo(t *testing.T) {
|
func TestGetRootInfo(t *testing.T) {
|
||||||
containerPath := "/"
|
containerPath := "/"
|
||||||
containerInfo := &info.ContainerInfo{
|
containerInfo := &info.ContainerInfo{
|
||||||
ContainerReference: info.ContainerReference{
|
ContainerReference: info.ContainerReference{
|
||||||
|
@ -973,9 +899,7 @@ func TestGetRooInfo(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fakeDocker := FakeDockerClient{
|
fakeDocker := dockertools.FakeDockerClient{}
|
||||||
err: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
mockCadvisor := &mockCadvisorClient{}
|
mockCadvisor := &mockCadvisorClient{}
|
||||||
req := &info.ContainerInfoRequest{}
|
req := &info.ContainerInfoRequest{}
|
||||||
|
@ -984,7 +908,7 @@ func TestGetRooInfo(t *testing.T) {
|
||||||
|
|
||||||
kubelet := Kubelet{
|
kubelet := Kubelet{
|
||||||
dockerClient: &fakeDocker,
|
dockerClient: &fakeDocker,
|
||||||
dockerPuller: &FakeDockerPuller{},
|
dockerPuller: &dockertools.FakeDockerPuller{},
|
||||||
cadvisorClient: mockCadvisor,
|
cadvisorClient: mockCadvisor,
|
||||||
podWorkers: newPodWorkers(),
|
podWorkers: newPodWorkers(),
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +928,7 @@ func TestGetRooInfo(t *testing.T) {
|
||||||
|
|
||||||
func TestGetContainerInfoWithoutCadvisor(t *testing.T) {
|
func TestGetContainerInfoWithoutCadvisor(t *testing.T) {
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: "foobar",
|
ID: "foobar",
|
||||||
// pod id: qux
|
// pod id: qux
|
||||||
|
@ -1042,7 +966,7 @@ func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) {
|
||||||
|
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.cadvisorClient = mockCadvisor
|
kubelet.cadvisorClient = mockCadvisor
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
// pod id: qux
|
// pod id: qux
|
||||||
|
@ -1070,7 +994,7 @@ func TestGetContainerInfoOnNonExistContainer(t *testing.T) {
|
||||||
|
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
kubelet.cadvisorClient = mockCadvisor
|
kubelet.cadvisorClient = mockCadvisor
|
||||||
fakeDocker.containerList = []docker.APIContainers{}
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||||
|
|
||||||
stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil)
|
stats, _ := kubelet.GetContainerInfo("qux", "", "foo", nil)
|
||||||
if stats != nil {
|
if stats != nil {
|
||||||
|
@ -1094,7 +1018,7 @@ func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([]
|
||||||
func TestRunInContainerNoSuchPod(t *testing.T) {
|
func TestRunInContainerNoSuchPod(t *testing.T) {
|
||||||
fakeCommandRunner := fakeContainerCommandRunner{}
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
fakeDocker.containerList = []docker.APIContainers{}
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
||||||
kubelet.runner = &fakeCommandRunner
|
kubelet.runner = &fakeCommandRunner
|
||||||
|
|
||||||
podName := "podFoo"
|
podName := "podFoo"
|
||||||
|
@ -1123,7 +1047,7 @@ func TestRunInContainer(t *testing.T) {
|
||||||
podNamespace := "etcd"
|
podNamespace := "etcd"
|
||||||
containerName := "containerFoo"
|
containerName := "containerFoo"
|
||||||
|
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"},
|
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) {
|
func TestRunHandlerExec(t *testing.T) {
|
||||||
fakeCommandRunner := fakeContainerCommandRunner{}
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
||||||
kubelet, _, fakeDocker := newTestKubelet(t)
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
||||||
|
@ -1194,7 +1081,7 @@ func TestRunHandlerExec(t *testing.T) {
|
||||||
podNamespace := "etcd"
|
podNamespace := "etcd"
|
||||||
containerName := "containerFoo"
|
containerName := "containerFoo"
|
||||||
|
|
||||||
fakeDocker.containerList = []docker.APIContainers{
|
fakeDocker.ContainerList = []docker.APIContainers{
|
||||||
{
|
{
|
||||||
ID: containerID,
|
ID: containerID,
|
||||||
Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"},
|
Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"},
|
||||||
|
@ -1298,7 +1185,7 @@ func TestSyncPodEventHandlerFails(t *testing.T) {
|
||||||
kubelet.httpClient = &fakeHTTP{
|
kubelet.httpClient = &fakeHTTP{
|
||||||
err: fmt.Errorf("test error"),
|
err: fmt.Errorf("test error"),
|
||||||
}
|
}
|
||||||
dockerContainers := DockerContainers{
|
dockerContainers := dockertools.DockerContainers{
|
||||||
"9876": &docker.APIContainers{
|
"9876": &docker.APIContainers{
|
||||||
// network container
|
// network container
|
||||||
Names: []string{"/k8s--net--foo.test--"},
|
Names: []string{"/k8s--net--foo.test--"},
|
||||||
|
@ -1331,7 +1218,7 @@ func TestSyncPodEventHandlerFails(t *testing.T) {
|
||||||
|
|
||||||
verifyCalls(t, fakeDocker, []string{"list", "list", "create", "start", "stop"})
|
verifyCalls(t, fakeDocker, []string{"list", "list", "create", "start", "stop"})
|
||||||
|
|
||||||
if len(fakeDocker.stopped) != 1 {
|
if len(fakeDocker.Stopped) != 1 {
|
||||||
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/healthz"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/google/cadvisor/info"
|
"github.com/google/cadvisor/info"
|
||||||
"gopkg.in/v1/yaml"
|
"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
|
// TODO: backwards compatibility with existing API, needs API change
|
||||||
podFullName := GetPodFullName(&Pod{Name: podID, Namespace: "etcd"})
|
podFullName := GetPodFullName(&Pod{Name: podID, Namespace: "etcd"})
|
||||||
info, err := s.host.GetPodInfo(podFullName, podUUID)
|
info, err := s.host.GetPodInfo(podFullName, podUUID)
|
||||||
if err == ErrNoContainersInPod {
|
if err == dockertools.ErrNoContainersInPod {
|
||||||
http.Error(w, "Pod does not exist", http.StatusNotFound)
|
http.Error(w, "Pod does not exist", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue