2014-06-06 23:40:48 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
2014-06-23 18:32:11 +00:00
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
package kubelet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2014-06-09 20:47:25 +00:00
|
|
|
"reflect"
|
2014-06-06 23:40:48 +00:00
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2014-07-15 18:39:19 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
2014-06-30 19:00:14 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
2014-07-15 01:39:30 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
2014-06-06 23:40:48 +00:00
|
|
|
"github.com/fsouza/go-dockerclient"
|
2014-06-19 20:22:20 +00:00
|
|
|
"github.com/google/cadvisor/info"
|
|
|
|
"github.com/stretchr/testify/mock"
|
2014-06-06 23:40:48 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// TODO: This doesn't reduce typing enough to make it worth the less readable errors. Remove.
|
|
|
|
func expectNoError(t *testing.T, err error) {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error: %#v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyNoError(t *testing.T, e error) {
|
|
|
|
if e != nil {
|
|
|
|
t.Errorf("Expected no error, found %#v", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyError(t *testing.T, e error) {
|
|
|
|
if e == nil {
|
|
|
|
t.Errorf("Expected error, found nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-30 19:00:14 +00:00
|
|
|
func makeTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *FakeDockerClient) {
|
|
|
|
fakeEtcdClient := tools.MakeFakeEtcdClient(t)
|
2014-07-01 16:15:49 +00:00
|
|
|
fakeDocker := &FakeDockerClient{
|
|
|
|
err: nil,
|
2014-06-24 23:31:33 +00:00
|
|
|
}
|
2014-07-01 16:15:49 +00:00
|
|
|
|
|
|
|
kubelet := New()
|
|
|
|
kubelet.DockerClient = fakeDocker
|
|
|
|
kubelet.DockerPuller = &FakeDockerPuller{}
|
|
|
|
kubelet.EtcdClient = fakeEtcdClient
|
|
|
|
return kubelet, fakeEtcdClient, fakeDocker
|
2014-06-24 23:31:33 +00:00
|
|
|
}
|
|
|
|
|
2014-07-01 16:15:49 +00:00
|
|
|
func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) {
|
2014-06-06 23:40:48 +00:00
|
|
|
verifyStringArrayEquals(t, fakeDocker.called, calls)
|
|
|
|
}
|
|
|
|
|
|
|
|
func verifyStringArrayEquals(t *testing.T, actual, expected []string) {
|
|
|
|
invalid := len(actual) != len(expected)
|
2014-07-03 05:35:50 +00:00
|
|
|
if !invalid {
|
|
|
|
for ix, value := range actual {
|
|
|
|
if expected[ix] != value {
|
|
|
|
invalid = true
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if invalid {
|
|
|
|
t.Errorf("Expected: %#v, Actual: %#v", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func verifyPackUnpack(t *testing.T, podNamespace, podName, containerName string) {
|
2014-06-27 19:09:53 +00:00
|
|
|
name := buildDockerName(
|
2014-07-15 20:24:41 +00:00
|
|
|
&Pod{Name: podName, Namespace: podNamespace},
|
2014-06-06 23:40:48 +00:00
|
|
|
&api.Container{Name: containerName},
|
|
|
|
)
|
2014-07-15 20:24:41 +00:00
|
|
|
podFullName := fmt.Sprintf("%s.%s", podName, podNamespace)
|
|
|
|
returnedPodFullName, returnedContainerName := parseDockerName(name)
|
|
|
|
if podFullName != returnedPodFullName || containerName != returnedContainerName {
|
|
|
|
t.Errorf("For (%s, %s), unpacked (%s, %s)", podFullName, containerName, returnedPodFullName, returnedContainerName)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 23:50:44 +00:00
|
|
|
func verifyBoolean(t *testing.T, expected, value bool) {
|
|
|
|
if expected != value {
|
2014-07-19 00:16:30 +00:00
|
|
|
t.Errorf("Unexpected boolean. Expected %s. Found %s", expected, value)
|
2014-06-09 23:50:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
func TestContainerManifestNaming(t *testing.T) {
|
2014-07-15 20:24:41 +00:00
|
|
|
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")
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 18:21:29 +00:00
|
|
|
func TestGetContainerID(t *testing.T) {
|
2014-07-15 17:26:56 +00:00
|
|
|
_, _, fakeDocker := makeTestKubelet(t)
|
2014-06-06 23:40:48 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "foobar",
|
2014-06-21 20:16:20 +00:00
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "barbar",
|
|
|
|
Names: []string{"/k8s--bar--qux--2565"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.container = &docker.Container{
|
|
|
|
ID: "foobar",
|
|
|
|
}
|
|
|
|
|
2014-07-15 17:26:56 +00:00
|
|
|
dockerContainers, err := getKubeletDockerContainers(fakeDocker)
|
2014-06-06 23:40:48 +00:00
|
|
|
if err != nil {
|
2014-07-15 17:26:56 +00:00
|
|
|
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)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-06-09 20:47:25 +00:00
|
|
|
|
|
|
|
fakeDocker.clearCalls()
|
2014-07-15 17:26:56 +00:00
|
|
|
dockerContainer, found = dockerContainers.FindPodContainer("foobar", "foo")
|
|
|
|
verifyCalls(t, fakeDocker, []string{})
|
|
|
|
if dockerContainer != nil || found {
|
|
|
|
t.Errorf("Should not have found container %#v", dockerContainer)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestKillContainerWithError(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
fakeDocker := &FakeDockerClient{
|
2014-06-13 22:45:19 +00:00
|
|
|
err: fmt.Errorf("sample error"),
|
2014-06-06 23:40:48 +00:00
|
|
|
containerList: []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "1234",
|
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "5678",
|
|
|
|
Names: []string{"/k8s--bar--qux--5678"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, _ := makeTestKubelet(t)
|
|
|
|
kubelet.DockerClient = fakeDocker
|
2014-06-25 23:24:20 +00:00
|
|
|
err := kubelet.killContainer(fakeDocker.containerList[0])
|
2014-06-06 23:40:48 +00:00
|
|
|
verifyError(t, err)
|
2014-06-25 23:24:20 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"stop"})
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestKillContainer(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
2014-06-06 23:40:48 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "1234",
|
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "5678",
|
|
|
|
Names: []string{"/k8s--bar--qux--5678"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.container = &docker.Container{
|
|
|
|
ID: "foobar",
|
|
|
|
}
|
|
|
|
|
2014-06-25 23:24:20 +00:00
|
|
|
err := kubelet.killContainer(fakeDocker.containerList[0])
|
2014-06-06 23:40:48 +00:00
|
|
|
verifyNoError(t, err)
|
2014-06-25 23:24:20 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"stop"})
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type channelReader struct {
|
2014-07-15 20:24:41 +00:00
|
|
|
list [][]Pod
|
2014-06-06 23:40:48 +00:00
|
|
|
wg sync.WaitGroup
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func startReading(channel <-chan interface{}) *channelReader {
|
2014-06-06 23:40:48 +00:00
|
|
|
cr := &channelReader{}
|
|
|
|
cr.wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
for {
|
2014-06-21 21:20:35 +00:00
|
|
|
update, ok := <-channel
|
2014-06-06 23:40:48 +00:00
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
cr.list = append(cr.list, update.(PodUpdate).Pods)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
cr.wg.Done()
|
|
|
|
}()
|
|
|
|
return cr
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func (cr *channelReader) GetList() [][]Pod {
|
2014-06-06 23:40:48 +00:00
|
|
|
cr.wg.Wait()
|
|
|
|
return cr.list
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsDoesNothing(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
2014-06-06 23:40:48 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-07-15 20:24:41 +00:00
|
|
|
// format is k8s--<container-id>--<pod-fullname>
|
|
|
|
Names: []string{"/k8s--bar--foo.test"},
|
2014-06-06 23:40:48 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-06-20 03:30:42 +00:00
|
|
|
{
|
|
|
|
// network container
|
2014-07-15 20:24:41 +00:00
|
|
|
Names: []string{"/k8s--net--foo.test--"},
|
2014-06-20 03:30:42 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
fakeDocker.container = &docker.Container{
|
|
|
|
ID: "1234",
|
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
err := kubelet.SyncPods([]Pod{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-07-15 20:24:41 +00:00
|
|
|
Name: "foo",
|
|
|
|
Namespace: "test",
|
|
|
|
Manifest: api.ContainerManifest{
|
|
|
|
ID: "foo",
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
expectNoError(t, err)
|
2014-07-15 17:26:56 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "list"})
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsDeletes(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
2014-06-06 23:40:48 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-21 20:16:20 +00:00
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2014-07-15 20:24:41 +00:00
|
|
|
Names: []string{"/k8s--foo--bar.test"},
|
2014-06-06 23:40:48 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-06-20 03:30:42 +00:00
|
|
|
{
|
|
|
|
// network container
|
2014-07-15 20:24:41 +00:00
|
|
|
Names: []string{"/k8s--net--foo.test--"},
|
2014-06-20 03:30:42 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
2014-06-13 19:09:48 +00:00
|
|
|
{
|
|
|
|
Names: []string{"foo"},
|
|
|
|
ID: "4567",
|
|
|
|
},
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
err := kubelet.SyncPods([]Pod{})
|
2014-06-06 23:40:48 +00:00
|
|
|
expectNoError(t, err)
|
2014-07-15 17:26:56 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "list", "stop", "stop"})
|
2014-06-27 22:29:13 +00:00
|
|
|
|
|
|
|
// A map interation is used to delete containers, so must not depend on
|
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
|
|
|
"9876": true,
|
|
|
|
}
|
2014-06-25 23:24:20 +00:00
|
|
|
if len(fakeDocker.stopped) != 2 ||
|
2014-06-27 22:29:13 +00:00
|
|
|
!expectedToStop[fakeDocker.stopped[0]] ||
|
|
|
|
!expectedToStop[fakeDocker.stopped[1]] {
|
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-09 20:47:25 +00:00
|
|
|
|
2014-07-03 05:35:50 +00:00
|
|
|
type FalseHealthChecker struct{}
|
|
|
|
|
2014-07-15 18:39:19 +00:00
|
|
|
func (f *FalseHealthChecker) HealthCheck(container api.Container) (health.Status, error) {
|
|
|
|
return health.Unhealthy, nil
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsUnhealthy(t *testing.T) {
|
2014-07-03 05:35:50 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
|
|
|
kubelet.HealthChecker = &FalseHealthChecker{}
|
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2014-07-15 20:24:41 +00:00
|
|
|
Names: []string{"/k8s--bar--foo.test"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2014-07-15 20:24:41 +00:00
|
|
|
Names: []string{"/k8s--net--foo.test--"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
err := kubelet.SyncPods([]Pod{
|
2014-07-03 05:35:50 +00:00
|
|
|
{
|
2014-07-15 20:24:41 +00:00
|
|
|
Name: "foo",
|
|
|
|
Namespace: "test",
|
|
|
|
Manifest: api.ContainerManifest{
|
|
|
|
ID: "foo",
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar",
|
|
|
|
LivenessProbe: &api.LivenessProbe{
|
|
|
|
// Always returns healthy == false
|
|
|
|
Type: "false",
|
|
|
|
},
|
2014-07-03 05:35:50 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}})
|
|
|
|
expectNoError(t, err)
|
2014-07-15 17:26:56 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "create", "start", "list"})
|
2014-07-03 05:35:50 +00:00
|
|
|
|
|
|
|
// A map interation is used to delete containers, so must not depend on
|
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
|
|
|
}
|
|
|
|
if len(fakeDocker.stopped) != 1 ||
|
|
|
|
!expectedToStop[fakeDocker.stopped[0]] {
|
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.stopped)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 20:47:25 +00:00
|
|
|
func TestEventWriting(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, fakeEtcd, _ := makeTestKubelet(t)
|
2014-06-09 20:47:25 +00:00
|
|
|
expectedEvent := api.Event{
|
|
|
|
Event: "test",
|
|
|
|
Container: &api.Container{
|
|
|
|
Name: "foo",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err := kubelet.LogEvent(&expectedEvent)
|
|
|
|
expectNoError(t, err)
|
|
|
|
if fakeEtcd.Ix != 1 {
|
|
|
|
t.Errorf("Unexpected number of children added: %d, expected 1", fakeEtcd.Ix)
|
|
|
|
}
|
|
|
|
response, err := fakeEtcd.Get("/events/foo/1", false, false)
|
|
|
|
expectNoError(t, err)
|
|
|
|
var event api.Event
|
|
|
|
err = json.Unmarshal([]byte(response.Node.Value), &event)
|
|
|
|
expectNoError(t, err)
|
|
|
|
if event.Event != expectedEvent.Event ||
|
|
|
|
event.Container.Name != expectedEvent.Container.Name {
|
|
|
|
t.Errorf("Event's don't match. Expected: %#v Saw: %#v", expectedEvent, event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEventWritingError(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, fakeEtcd, _ := makeTestKubelet(t)
|
2014-06-13 22:45:19 +00:00
|
|
|
fakeEtcd.Err = fmt.Errorf("test error")
|
2014-06-09 20:47:25 +00:00
|
|
|
err := kubelet.LogEvent(&api.Event{
|
|
|
|
Event: "test",
|
|
|
|
Container: &api.Container{
|
|
|
|
Name: "foo",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("Unexpected non-error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMakeEnvVariables(t *testing.T) {
|
|
|
|
container := api.Container{
|
|
|
|
Env: []api.EnvVar{
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
Name: "foo",
|
|
|
|
Value: "bar",
|
|
|
|
},
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
Name: "baz",
|
|
|
|
Value: "blah",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
vars := makeEnvironmentVariables(&container)
|
|
|
|
if len(vars) != len(container.Env) {
|
|
|
|
t.Errorf("Vars don't match. Expected: %#v Found: %#v", container.Env, vars)
|
|
|
|
}
|
|
|
|
for ix, env := range container.Env {
|
|
|
|
value := fmt.Sprintf("%s=%s", env.Name, env.Value)
|
|
|
|
if value != vars[ix] {
|
|
|
|
t.Errorf("Unexpected value: %s. Expected: %s", vars[ix], value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 01:39:30 +00:00
|
|
|
func TestMountExternalVolumes(t *testing.T) {
|
|
|
|
kubelet, _, _ := makeTestKubelet(t)
|
|
|
|
manifest := api.ContainerManifest{
|
|
|
|
Volumes: []api.Volume{
|
|
|
|
{
|
|
|
|
Name: "host-dir",
|
2014-07-16 19:32:59 +00:00
|
|
|
Source: &api.VolumeSource{
|
|
|
|
HostDirectory: &api.HostDirectory{"/dir/path"},
|
|
|
|
},
|
2014-07-15 01:39:30 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
podVolumes, _ := kubelet.mountExternalVolumes(&manifest)
|
2014-07-16 19:32:59 +00:00
|
|
|
expectedPodVolumes := make(volumeMap)
|
|
|
|
expectedPodVolumes["host-dir"] = &volume.HostDirectory{"/dir/path"}
|
2014-07-15 01:39:30 +00:00
|
|
|
if len(expectedPodVolumes) != len(podVolumes) {
|
|
|
|
t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, manifest)
|
|
|
|
}
|
|
|
|
for name, expectedVolume := range expectedPodVolumes {
|
|
|
|
if _, ok := podVolumes[name]; !ok {
|
|
|
|
t.Errorf("Pod volumes map is missing key: %s. %#v", expectedVolume, podVolumes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 20:47:25 +00:00
|
|
|
func TestMakeVolumesAndBinds(t *testing.T) {
|
|
|
|
container := api.Container{
|
|
|
|
VolumeMounts: []api.VolumeMount{
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
MountPath: "/mnt/path",
|
|
|
|
Name: "disk",
|
|
|
|
ReadOnly: false,
|
|
|
|
},
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
MountPath: "/mnt/path2",
|
|
|
|
Name: "disk2",
|
|
|
|
ReadOnly: true,
|
2014-06-19 23:59:48 +00:00
|
|
|
MountType: "LOCAL",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
MountPath: "/mnt/path3",
|
|
|
|
Name: "disk3",
|
|
|
|
ReadOnly: false,
|
|
|
|
MountType: "HOST",
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
2014-07-15 01:39:30 +00:00
|
|
|
{
|
|
|
|
MountPath: "/mnt/path4",
|
|
|
|
Name: "disk4",
|
|
|
|
ReadOnly: false,
|
|
|
|
},
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
|
|
|
}
|
2014-07-15 01:39:30 +00:00
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
pod := Pod{
|
|
|
|
Name: "pod",
|
|
|
|
Namespace: "test",
|
|
|
|
}
|
|
|
|
|
2014-07-15 01:39:30 +00:00
|
|
|
podVolumes := make(volumeMap)
|
|
|
|
podVolumes["disk4"] = &volume.HostDirectory{"/mnt/host"}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
volumes, binds := makeVolumesAndBinds(&pod, &container, podVolumes)
|
2014-06-19 23:59:48 +00:00
|
|
|
|
|
|
|
expectedVolumes := []string{"/mnt/path", "/mnt/path2"}
|
2014-07-15 20:24:41 +00:00
|
|
|
expectedBinds := []string{"/exports/pod.test/disk:/mnt/path", "/exports/pod.test/disk2:/mnt/path2:ro", "/mnt/path3:/mnt/path3",
|
2014-07-21 01:56:43 +00:00
|
|
|
"/mnt/host:/mnt/path4"}
|
2014-07-15 20:24:41 +00:00
|
|
|
|
2014-06-19 23:59:48 +00:00
|
|
|
if len(volumes) != len(expectedVolumes) {
|
|
|
|
t.Errorf("Unexpected volumes. Expected %#v got %#v. Container was: %#v", expectedVolumes, volumes, container)
|
|
|
|
}
|
|
|
|
for _, expectedVolume := range expectedVolumes {
|
|
|
|
if _, ok := volumes[expectedVolume]; !ok {
|
|
|
|
t.Errorf("Volumes map is missing key: %s. %#v", expectedVolume, volumes)
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-19 23:59:48 +00:00
|
|
|
if len(binds) != len(expectedBinds) {
|
2014-07-19 00:16:30 +00:00
|
|
|
t.Errorf("Unexpected binds: Expected %# got %#v. Container was: %#v", expectedBinds, binds, container)
|
2014-06-19 23:59:48 +00:00
|
|
|
}
|
|
|
|
verifyStringArrayEquals(t, binds, expectedBinds)
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestMakePortsAndBindings(t *testing.T) {
|
|
|
|
container := api.Container{
|
|
|
|
Ports: []api.Port{
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
ContainerPort: 80,
|
|
|
|
HostPort: 8080,
|
2014-07-09 05:44:15 +00:00
|
|
|
HostIP: "127.0.0.1",
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
2014-06-13 01:34:47 +00:00
|
|
|
{
|
2014-06-09 20:47:25 +00:00
|
|
|
ContainerPort: 443,
|
|
|
|
HostPort: 443,
|
2014-06-16 04:57:29 +00:00
|
|
|
Protocol: "tcp",
|
2014-06-16 04:19:35 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
ContainerPort: 444,
|
|
|
|
HostPort: 444,
|
2014-06-16 04:57:29 +00:00
|
|
|
Protocol: "udp",
|
2014-06-16 04:19:35 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
ContainerPort: 445,
|
|
|
|
HostPort: 445,
|
2014-06-16 04:57:29 +00:00
|
|
|
Protocol: "foobar",
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
exposedPorts, bindings := makePortsAndBindings(&container)
|
|
|
|
if len(container.Ports) != len(exposedPorts) ||
|
|
|
|
len(container.Ports) != len(bindings) {
|
|
|
|
t.Errorf("Unexpected ports and bindings, %#v %#v %#v", container, exposedPorts, bindings)
|
|
|
|
}
|
2014-06-16 04:57:29 +00:00
|
|
|
for key, value := range bindings {
|
|
|
|
switch value[0].HostPort {
|
2014-06-16 04:19:35 +00:00
|
|
|
case "8080":
|
2014-06-16 04:57:29 +00:00
|
|
|
if !reflect.DeepEqual(docker.Port("80/tcp"), key) {
|
|
|
|
t.Errorf("Unexpected docker port: %#v", key)
|
2014-06-16 04:19:35 +00:00
|
|
|
}
|
2014-07-09 05:44:15 +00:00
|
|
|
if value[0].HostIp != "127.0.0.1" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIp)
|
|
|
|
}
|
2014-06-16 04:19:35 +00:00
|
|
|
case "443":
|
2014-06-16 04:57:29 +00:00
|
|
|
if !reflect.DeepEqual(docker.Port("443/tcp"), key) {
|
|
|
|
t.Errorf("Unexpected docker port: %#v", key)
|
2014-06-16 04:19:35 +00:00
|
|
|
}
|
2014-07-09 05:44:15 +00:00
|
|
|
if value[0].HostIp != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIp)
|
|
|
|
}
|
2014-06-16 04:19:35 +00:00
|
|
|
case "444":
|
2014-06-16 04:57:29 +00:00
|
|
|
if !reflect.DeepEqual(docker.Port("444/udp"), key) {
|
|
|
|
t.Errorf("Unexpected docker port: %#v", key)
|
2014-06-16 04:19:35 +00:00
|
|
|
}
|
2014-07-09 05:44:15 +00:00
|
|
|
if value[0].HostIp != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIp)
|
|
|
|
}
|
2014-06-16 04:19:35 +00:00
|
|
|
case "445":
|
2014-06-16 04:57:29 +00:00
|
|
|
if !reflect.DeepEqual(docker.Port("445/tcp"), key) {
|
|
|
|
t.Errorf("Unexpected docker port: %#v", key)
|
2014-06-16 04:19:35 +00:00
|
|
|
}
|
2014-07-09 05:44:15 +00:00
|
|
|
if value[0].HostIp != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIp)
|
|
|
|
}
|
2014-06-16 04:57:29 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCheckHostPortConflicts(t *testing.T) {
|
2014-07-15 20:24:41 +00:00
|
|
|
successCaseAll := []Pod{
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
successCaseNew := Pod{
|
|
|
|
Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 83}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
expected := append(successCaseAll, successCaseNew)
|
|
|
|
if actual := filterHostPortConflicts(expected); !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Errorf("Expected %#v, Got %#v", expected, actual)
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-06-16 04:19:35 +00:00
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
failureCaseAll := []Pod{
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
|
|
|
|
{Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
failureCaseNew := Pod{
|
|
|
|
Manifest: api.ContainerManifest{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-07-15 20:24:41 +00:00
|
|
|
if actual := filterHostPortConflicts(append(failureCaseAll, failureCaseNew)); !reflect.DeepEqual(failureCaseAll, actual) {
|
|
|
|
t.Errorf("Expected %#v, Got %#v", expected, actual)
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-19 20:22:20 +00:00
|
|
|
|
|
|
|
type mockCadvisorClient struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// ContainerInfo is a mock implementation of CadvisorInterface.ContainerInfo.
|
2014-07-14 21:48:51 +00:00
|
|
|
func (c *mockCadvisorClient) ContainerInfo(name string, req *info.ContainerInfoRequest) (*info.ContainerInfo, error) {
|
|
|
|
args := c.Called(name, req)
|
2014-06-19 20:22:20 +00:00
|
|
|
return args.Get(0).(*info.ContainerInfo), args.Error(1)
|
|
|
|
}
|
|
|
|
|
2014-07-10 12:26:24 +00:00
|
|
|
// MachineInfo is a mock implementation of CadvisorInterface.MachineInfo.
|
|
|
|
func (c *mockCadvisorClient) MachineInfo() (*info.MachineInfo, error) {
|
|
|
|
args := c.Called()
|
2014-06-19 20:22:20 +00:00
|
|
|
return args.Get(0).(*info.MachineInfo), args.Error(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func areSamePercentiles(
|
|
|
|
cadvisorPercentiles []info.Percentile,
|
2014-07-14 21:48:51 +00:00
|
|
|
kubePercentiles []info.Percentile,
|
2014-06-19 20:22:20 +00:00
|
|
|
t *testing.T,
|
|
|
|
) {
|
|
|
|
if len(cadvisorPercentiles) != len(kubePercentiles) {
|
|
|
|
t.Errorf("cadvisor gives %v percentiles; kubelet got %v", len(cadvisorPercentiles), len(kubePercentiles))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, ap := range cadvisorPercentiles {
|
|
|
|
found := false
|
|
|
|
for _, kp := range kubePercentiles {
|
|
|
|
if ap.Percentage == kp.Percentage {
|
|
|
|
found = true
|
|
|
|
if ap.Value != kp.Value {
|
|
|
|
t.Errorf("%v percentile from cadvisor is %v; kubelet got %v",
|
|
|
|
ap.Percentage,
|
|
|
|
ap.Value,
|
|
|
|
kp.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
t.Errorf("Unable to find %v percentile in kubelet's data", ap.Percentage)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetContainerInfo(t *testing.T) {
|
2014-07-02 18:21:29 +00:00
|
|
|
containerID := "ab2cdf"
|
|
|
|
containerPath := fmt.Sprintf("/docker/%v", containerID)
|
2014-06-19 20:22:20 +00:00
|
|
|
containerInfo := &info.ContainerInfo{
|
|
|
|
ContainerReference: info.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
StatsPercentiles: &info.ContainerStatsPercentiles{
|
|
|
|
MaxMemoryUsage: 1024000,
|
|
|
|
MemoryUsagePercentiles: []info.Percentile{
|
2014-06-19 20:59:20 +00:00
|
|
|
{50, 100},
|
|
|
|
{80, 180},
|
|
|
|
{90, 190},
|
2014-06-19 20:22:20 +00:00
|
|
|
},
|
|
|
|
CpuUsagePercentiles: []info.Percentile{
|
2014-06-19 20:59:20 +00:00
|
|
|
{51, 101},
|
|
|
|
{81, 181},
|
|
|
|
{91, 191},
|
2014-06-19 20:22:20 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-07-14 21:48:51 +00:00
|
|
|
req := &info.ContainerInfoRequest{}
|
|
|
|
cadvisorReq := getCadvisorContainerInfoRequest(req)
|
|
|
|
mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil)
|
2014-06-19 20:22:20 +00:00
|
|
|
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
|
|
|
kubelet.CadvisorClient = mockCadvisor
|
2014-06-19 20:22:20 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: containerID,
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-07-15 00:01:57 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux", "foo", req)
|
2014-07-01 21:05:10 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-07-15 17:26:56 +00:00
|
|
|
if stats == nil {
|
|
|
|
t.Fatalf("stats should not be nil")
|
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
if stats.StatsPercentiles.MaxMemoryUsage != containerInfo.StatsPercentiles.MaxMemoryUsage {
|
2014-07-01 21:05:10 +00:00
|
|
|
t.Errorf("wrong max memory usage")
|
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
areSamePercentiles(containerInfo.StatsPercentiles.CpuUsagePercentiles, stats.StatsPercentiles.CpuUsagePercentiles, t)
|
|
|
|
areSamePercentiles(containerInfo.StatsPercentiles.MemoryUsagePercentiles, stats.StatsPercentiles.MemoryUsagePercentiles, t)
|
2014-07-01 21:05:10 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetRooInfo(t *testing.T) {
|
2014-07-01 21:05:10 +00:00
|
|
|
containerPath := "/"
|
|
|
|
containerInfo := &info.ContainerInfo{
|
|
|
|
ContainerReference: info.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
}, StatsPercentiles: &info.ContainerStatsPercentiles{MaxMemoryUsage: 1024000, MemoryUsagePercentiles: []info.Percentile{{50, 100}, {80, 180},
|
|
|
|
{90, 190},
|
2014-06-19 20:22:20 +00:00
|
|
|
},
|
2014-07-01 21:05:10 +00:00
|
|
|
CpuUsagePercentiles: []info.Percentile{
|
|
|
|
{51, 101},
|
|
|
|
{81, 181},
|
|
|
|
{91, 191},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker := FakeDockerClient{
|
|
|
|
err: nil,
|
2014-06-19 20:22:20 +00:00
|
|
|
}
|
|
|
|
|
2014-07-01 21:05:10 +00:00
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-07-14 21:48:51 +00:00
|
|
|
req := &info.ContainerInfoRequest{}
|
|
|
|
cadvisorReq := getCadvisorContainerInfoRequest(req)
|
|
|
|
mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil)
|
2014-07-01 21:05:10 +00:00
|
|
|
|
|
|
|
kubelet := Kubelet{
|
|
|
|
DockerClient: &fakeDocker,
|
|
|
|
DockerPuller: &FakeDockerPuller{},
|
|
|
|
CadvisorClient: mockCadvisor,
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the container name is an empty string, then it means the root container.
|
2014-07-15 22:40:02 +00:00
|
|
|
stats, err := kubelet.GetRootInfo(req)
|
2014-06-19 20:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
if stats.StatsPercentiles.MaxMemoryUsage != containerInfo.StatsPercentiles.MaxMemoryUsage {
|
2014-06-19 20:22:20 +00:00
|
|
|
t.Errorf("wrong max memory usage")
|
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
areSamePercentiles(containerInfo.StatsPercentiles.CpuUsagePercentiles, stats.StatsPercentiles.CpuUsagePercentiles, t)
|
|
|
|
areSamePercentiles(containerInfo.StatsPercentiles.MemoryUsagePercentiles, stats.StatsPercentiles.MemoryUsagePercentiles, t)
|
2014-06-19 20:22:20 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
2014-06-19 20:25:54 +00:00
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetContainerInfoWithoutCadvisor(t *testing.T) {
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
2014-06-19 20:25:54 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: "foobar",
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
2014-06-19 20:25:54 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-07-15 00:01:57 +00:00
|
|
|
stats, _ := kubelet.GetContainerInfo("qux", "foo", nil)
|
2014-06-19 20:25:54 +00:00
|
|
|
// When there's no cAdvisor, the stats should be either nil or empty
|
|
|
|
if stats == nil {
|
|
|
|
return
|
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
if stats.StatsPercentiles.MaxMemoryUsage != 0 {
|
|
|
|
t.Errorf("MaxMemoryUsage is %v even if there's no cadvisor", stats.StatsPercentiles.MaxMemoryUsage)
|
2014-06-19 20:25:54 +00:00
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
if len(stats.StatsPercentiles.CpuUsagePercentiles) > 0 {
|
2014-07-16 12:25:51 +00:00
|
|
|
t.Errorf("CPU usage percentiles is not empty (%+v) even if there's no cadvisor", stats.StatsPercentiles.CpuUsagePercentiles)
|
2014-06-19 20:25:54 +00:00
|
|
|
}
|
2014-07-14 21:48:51 +00:00
|
|
|
if len(stats.StatsPercentiles.MemoryUsagePercentiles) > 0 {
|
|
|
|
t.Errorf("Memory usage percentiles is not empty (%+v) even if there's no cadvisor", stats.StatsPercentiles.MemoryUsagePercentiles)
|
2014-06-19 20:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-19 20:34:26 +00:00
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetContainerInfoWhenCadvisorFailed(t *testing.T) {
|
2014-07-02 18:21:29 +00:00
|
|
|
containerID := "ab2cdf"
|
|
|
|
containerPath := fmt.Sprintf("/docker/%v", containerID)
|
2014-06-19 20:34:26 +00:00
|
|
|
|
|
|
|
containerInfo := &info.ContainerInfo{}
|
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-07-14 21:48:51 +00:00
|
|
|
req := &info.ContainerInfoRequest{}
|
|
|
|
cadvisorReq := getCadvisorContainerInfoRequest(req)
|
2014-06-19 20:34:26 +00:00
|
|
|
expectedErr := fmt.Errorf("some error")
|
2014-07-14 21:48:51 +00:00
|
|
|
mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, expectedErr)
|
2014-06-19 20:34:26 +00:00
|
|
|
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
|
|
|
kubelet.CadvisorClient = mockCadvisor
|
2014-06-19 20:34:26 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{
|
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: containerID,
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
|
|
|
Names: []string{"/k8s--foo--qux--1234"},
|
2014-06-19 20:34:26 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-07-15 00:01:57 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux", "foo", req)
|
2014-06-19 20:34:26 +00:00
|
|
|
if stats != nil {
|
|
|
|
t.Errorf("non-nil stats on error")
|
|
|
|
}
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expect error but received nil error")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if err.Error() != expectedErr.Error() {
|
|
|
|
t.Errorf("wrong error message. expect %v, got %v", err, expectedErr)
|
|
|
|
}
|
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetContainerInfoOnNonExistContainer(t *testing.T) {
|
2014-06-19 20:34:26 +00:00
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
|
|
|
|
2014-07-01 16:15:49 +00:00
|
|
|
kubelet, _, fakeDocker := makeTestKubelet(t)
|
|
|
|
kubelet.CadvisorClient = mockCadvisor
|
2014-06-19 20:34:26 +00:00
|
|
|
fakeDocker.containerList = []docker.APIContainers{}
|
|
|
|
|
2014-07-15 00:01:57 +00:00
|
|
|
stats, _ := kubelet.GetContainerInfo("qux", "foo", nil)
|
2014-06-19 20:34:26 +00:00
|
|
|
if stats != nil {
|
|
|
|
t.Errorf("non-nil stats on non exist container")
|
|
|
|
}
|
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
2014-06-19 12:29:42 +00:00
|
|
|
|
2014-07-21 01:56:43 +00:00
|
|
|
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"},
|
|
|
|
}
|
2014-06-19 12:29:42 +00:00
|
|
|
|
2014-07-21 01:56:43 +00:00
|
|
|
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)
|
|
|
|
}
|
2014-06-19 12:29:42 +00:00
|
|
|
}
|
|
|
|
}
|