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 (
|
|
|
|
"fmt"
|
2014-09-03 20:39:56 +00:00
|
|
|
"net/http"
|
2014-11-29 19:02:28 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
2014-06-09 20:47:25 +00:00
|
|
|
"reflect"
|
2014-08-07 23:59:18 +00:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2014-10-02 18:58:58 +00:00
|
|
|
"strings"
|
2014-06-06 23:40:48 +00:00
|
|
|
"sync"
|
|
|
|
"testing"
|
2014-08-08 04:49:17 +00:00
|
|
|
"time"
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2014-07-15 18:39:19 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/health"
|
2014-09-09 04:33:17 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
2014-06-30 19:00:14 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
|
2014-09-03 20:39:56 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
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
|
|
|
)
|
|
|
|
|
2014-12-10 01:53:29 +00:00
|
|
|
func init() {
|
|
|
|
api.ForTesting_ReferencesAllowBlankSelfLinks = true
|
|
|
|
util.ReallyCrash = true
|
|
|
|
}
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *dockertools.FakeDockerClient) {
|
2014-08-21 04:27:19 +00:00
|
|
|
fakeEtcdClient := tools.NewFakeEtcdClient(t)
|
2014-12-22 19:54:07 +00:00
|
|
|
fakeDocker := &dockertools.FakeDockerClient{
|
|
|
|
RemovedImages: util.StringSet{},
|
|
|
|
}
|
2014-07-01 16:15:49 +00:00
|
|
|
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet := &Kubelet{}
|
|
|
|
kubelet.dockerClient = fakeDocker
|
2014-09-09 04:33:17 +00:00
|
|
|
kubelet.dockerPuller = &dockertools.FakeDockerPuller{}
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.etcdClient = fakeEtcdClient
|
2014-07-19 00:13:34 +00:00
|
|
|
kubelet.rootDirectory = "/tmp/kubelet"
|
2014-07-18 18:42:47 +00:00
|
|
|
kubelet.podWorkers = newPodWorkers()
|
2015-01-13 05:47:49 +00:00
|
|
|
kubelet.sourceReady = func(source string) bool { return true }
|
2014-07-01 16:15:49 +00:00
|
|
|
return kubelet, fakeEtcdClient, fakeDocker
|
2014-06-24 23:31:33 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
func verifyCalls(t *testing.T, fakeDocker *dockertools.FakeDockerClient, calls []string) {
|
|
|
|
err := fakeDocker.AssertCalls(calls)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-06-09 23:50:44 +00:00
|
|
|
func verifyBoolean(t *testing.T, expected, value bool) {
|
|
|
|
if expected != value {
|
2014-07-18 19:03:22 +00:00
|
|
|
t.Errorf("Unexpected boolean. Expected %t. Found %t", expected, value)
|
2014-06-09 23:50:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:02:28 +00:00
|
|
|
func TestKubeletDirs(t *testing.T) {
|
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
|
|
|
root := kubelet.rootDirectory
|
|
|
|
if err := os.MkdirAll(root, 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var exp, got string
|
|
|
|
|
|
|
|
got = kubelet.GetPodsDir()
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods")
|
2014-11-29 19:02:28 +00:00
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodDir("abc123")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/abc123")
|
2014-11-29 19:02:28 +00:00
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodVolumesDir("abc123")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/abc123/volumes")
|
2014-11-29 19:02:28 +00:00
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodContainerDir("abc123", "def456")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/abc123/containers/def456")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestKubeletDirsCompat(t *testing.T) {
|
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
|
|
|
root := kubelet.rootDirectory
|
|
|
|
if err := os.MkdirAll(root, 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var exp, got string
|
|
|
|
|
|
|
|
// Old-style pod dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/oldpod", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
// New-style pod dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/pods/newpod", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
// Both-style pod dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/bothpod", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/pods/bothpod", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodDir("oldpod")
|
|
|
|
exp = path.Join(root, "oldpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodDir("newpod")
|
|
|
|
exp = path.Join(root, "pods/newpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodDir("bothpod")
|
|
|
|
exp = path.Join(root, "pods/bothpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodDir("neitherpod")
|
|
|
|
exp = path.Join(root, "pods/neitherpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
root = kubelet.GetPodDir("newpod")
|
|
|
|
|
|
|
|
// Old-style container dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/oldctr", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
// New-style container dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/containers/newctr", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
// Both-style container dir.
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/bothctr", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
if err := os.MkdirAll(fmt.Sprintf("%s/containers/bothctr", root), 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %s", root, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodContainerDir("newpod", "oldctr")
|
|
|
|
exp = path.Join(root, "oldctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodContainerDir("newpod", "newctr")
|
|
|
|
exp = path.Join(root, "containers/newctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodContainerDir("newpod", "bothctr")
|
|
|
|
exp = path.Join(root, "containers/bothctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.GetPodContainerDir("newpod", "neitherctr")
|
|
|
|
exp = path.Join(root, "containers/neitherctr")
|
2014-11-29 19:02:28 +00:00
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
func TestKillContainerWithError(t *testing.T) {
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker := &dockertools.FakeDockerClient{
|
|
|
|
Err: fmt.Errorf("sample error"),
|
|
|
|
ContainerList: []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "1234",
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_1234_42"},
|
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",
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_bar_qux_5678_42"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.dockerClient = fakeDocker
|
2014-09-09 04:33:17 +00:00
|
|
|
err := kubelet.killContainer(&fakeDocker.ContainerList[0])
|
2014-08-03 23:59:47 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected error, found nil")
|
|
|
|
}
|
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-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-06-25 23:24:20 +00:00
|
|
|
ID: "1234",
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_1234_42"},
|
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",
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_bar_qux_5678_42"},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Container = &docker.Container{
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foobar",
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
err := kubelet.killContainer(&fakeDocker.ContainerList[0])
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", 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-10-08 19:56:02 +00:00
|
|
|
list [][]api.BoundPod
|
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-10-08 19:56:02 +00:00
|
|
|
func (cr *channelReader) GetList() [][]api.BoundPod {
|
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-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-08-07 23:59:18 +00:00
|
|
|
container := api.Container{Name: "bar"}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2015-01-05 01:30:30 +00:00
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>_<random>
|
|
|
|
Names: []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&container), 16) + "_foo.new.test_12345678_0"},
|
2014-06-06 23:40:48 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-06-20 03:30:42 +00:00
|
|
|
{
|
|
|
|
// network container
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_0"},
|
2014-06-20 03:30:42 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-05 01:30:30 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-07-15 20:24:41 +00:00
|
|
|
Containers: []api.Container{
|
2014-08-07 23:59:18 +00:00
|
|
|
container,
|
2014-07-15 20:24:41 +00:00
|
|
|
},
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-10-31 16:52:01 +00:00
|
|
|
kubelet.drainWorkers()
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "list", "inspect_container", "inspect_container"})
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-11-07 06:41:16 +00:00
|
|
|
func TestSyncPodsWithTerminationLog(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
container := api.Container{
|
|
|
|
Name: "bar",
|
|
|
|
TerminationMessagePath: "/dev/somepath",
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-11-07 06:41:16 +00:00
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
container,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
"list", "create", "start", "list", "inspect_container", "list", "create", "start"})
|
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
parts := strings.Split(fakeDocker.Container.HostConfig.Binds[0], ":")
|
2015-01-10 01:19:31 +00:00
|
|
|
if !matchString(t, kubelet.GetPodContainerDir("12345678", "bar")+"/k8s_bar\\.[a-f0-9]", parts[0]) {
|
2014-11-29 19:02:28 +00:00
|
|
|
t.Errorf("Unexpected host path: %s", parts[0])
|
|
|
|
}
|
|
|
|
if parts[1] != "/dev/somepath" {
|
|
|
|
t.Errorf("Unexpected container path: %s", parts[1])
|
2014-11-07 06:41:16 +00:00
|
|
|
}
|
|
|
|
fakeDocker.Unlock()
|
|
|
|
}
|
|
|
|
|
2014-08-08 04:49:17 +00:00
|
|
|
// drainWorkers waits until all workers are done. Should only used for testing.
|
|
|
|
func (kl *Kubelet) drainWorkers() {
|
|
|
|
for {
|
|
|
|
kl.podWorkers.lock.Lock()
|
|
|
|
length := len(kl.podWorkers.workers)
|
|
|
|
kl.podWorkers.lock.Unlock()
|
|
|
|
if length == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
time.Sleep(time.Millisecond * 100)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-07 23:59:18 +00:00
|
|
|
func matchString(t *testing.T, pattern, str string) bool {
|
|
|
|
match, err := regexp.MatchString(pattern, str)
|
|
|
|
if err != nil {
|
|
|
|
t.Logf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
return match
|
|
|
|
}
|
|
|
|
|
2014-08-08 04:49:17 +00:00
|
|
|
func TestSyncPodsCreatesNetAndContainer(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-10-02 18:58:58 +00:00
|
|
|
kubelet.networkContainerImage = "custom_image_name"
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2014-10-20 04:35:08 +00:00
|
|
|
"list", "create", "start", "list", "inspect_container", "list", "create", "start"})
|
2014-08-08 04:49:17 +00:00
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Lock()
|
2014-10-02 18:58:58 +00:00
|
|
|
|
|
|
|
found := false
|
|
|
|
for _, c := range fakeDocker.ContainerList {
|
|
|
|
if c.Image == "custom_image_name" && strings.HasPrefix(c.Names[0], "/k8s_net") {
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
t.Errorf("Custom net container not found: %v", fakeDocker.ContainerList)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fakeDocker.Created) != 2 ||
|
2014-10-08 19:56:02 +00:00
|
|
|
!matchString(t, "k8s_net\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) ||
|
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[1]) {
|
2014-10-02 18:58:58 +00:00
|
|
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
|
|
|
}
|
|
|
|
fakeDocker.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodsCreatesNetAndContainerPullsImage(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
puller := kubelet.dockerPuller.(*dockertools.FakeDockerPuller)
|
|
|
|
puller.HasImages = []string{}
|
|
|
|
kubelet.networkContainerImage = "custom_image_name"
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-10-02 18:58:58 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-10-02 18:58:58 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2014-10-20 04:35:08 +00:00
|
|
|
"list", "create", "start", "list", "inspect_container", "list", "create", "start"})
|
2014-10-02 18:58:58 +00:00
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(puller.ImagesPulled, []string{"custom_image_name", ""}) {
|
|
|
|
t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
|
|
|
|
}
|
|
|
|
|
2014-08-08 04:49:17 +00:00
|
|
|
if len(fakeDocker.Created) != 2 ||
|
2014-10-08 19:56:02 +00:00
|
|
|
!matchString(t, "k8s_net\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) ||
|
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[1]) {
|
2014-08-08 04:49:17 +00:00
|
|
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Unlock()
|
2014-08-08 04:49:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodsWithNetCreatesContainer(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
|
|
|
// network container
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_0"},
|
2014-08-08 04:49:17 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-05 01:30:30 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2014-10-20 04:35:08 +00:00
|
|
|
"list", "list", "inspect_container", "list", "create", "start"})
|
2014-08-08 04:49:17 +00:00
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Lock()
|
2014-08-08 04:49:17 +00:00
|
|
|
if len(fakeDocker.Created) != 1 ||
|
2014-10-08 19:56:02 +00:00
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) {
|
2014-08-08 04:49:17 +00:00
|
|
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Unlock()
|
2014-08-08 04:49:17 +00:00
|
|
|
}
|
|
|
|
|
2014-09-03 20:39:56 +00:00
|
|
|
func TestSyncPodsWithNetCreatesContainerCallsHandler(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
fakeHttp := fakeHTTP{}
|
|
|
|
kubelet.httpClient = &fakeHttp
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-09-03 20:39:56 +00:00
|
|
|
{
|
|
|
|
// network container
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_0"},
|
2014-09-03 20:39:56 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-09-03 20:39:56 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-05 01:30:30 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-09-03 20:39:56 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{
|
|
|
|
Name: "bar",
|
|
|
|
Lifecycle: &api.Lifecycle{
|
|
|
|
PostStart: &api.Handler{
|
|
|
|
HTTPGet: &api.HTTPGetAction{
|
|
|
|
Host: "foo",
|
|
|
|
Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
|
|
|
|
Path: "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2014-10-20 04:35:08 +00:00
|
|
|
"list", "list", "inspect_container", "list", "create", "start"})
|
2014-09-03 20:39:56 +00:00
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Lock()
|
2014-09-03 20:39:56 +00:00
|
|
|
if len(fakeDocker.Created) != 1 ||
|
2014-10-08 19:56:02 +00:00
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo.new.test_", fakeDocker.Created[0]) {
|
2014-09-03 20:39:56 +00:00
|
|
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Unlock()
|
2014-09-03 20:39:56 +00:00
|
|
|
if fakeHttp.url != "http://foo:8080/bar" {
|
|
|
|
t.Errorf("Unexpected handler: %s", fakeHttp.url)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-08 04:49:17 +00:00
|
|
|
func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2015-01-05 01:30:30 +00:00
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_bar_foo.new.test_12345678_0"},
|
2014-08-08 04:49:17 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-05 01:30:30 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2014-10-20 04:35:08 +00:00
|
|
|
"list", "stop", "create", "start", "list", "list", "inspect_container", "list", "create", "start"})
|
2014-08-08 04:49:17 +00:00
|
|
|
|
|
|
|
// A map iteration is used to delete containers, so must not depend on
|
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Lock()
|
|
|
|
if len(fakeDocker.Stopped) != 1 || !expectedToStop[fakeDocker.Stopped[0]] {
|
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-08-08 04:49:17 +00:00
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.Unlock()
|
2014-08-08 04:49:17 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 05:11:27 +00:00
|
|
|
func TestSyncPodsDeletesWhenSourcesAreReady(t *testing.T) {
|
|
|
|
ready := false
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2015-01-13 05:47:49 +00:00
|
|
|
kubelet.sourceReady = func(source string) bool { return ready }
|
2014-12-17 05:11:27 +00:00
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_foo_bar.new.test_12345678_42"},
|
2014-12-17 05:11:27 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_42"},
|
2014-12-17 05:11:27 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
// Validate nothing happened.
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list"})
|
|
|
|
fakeDocker.ClearCalls()
|
|
|
|
|
|
|
|
ready = true
|
|
|
|
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop"})
|
|
|
|
|
|
|
|
// A map iteration is used to delete containers, so must not depend on
|
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
|
|
|
"9876": true,
|
|
|
|
}
|
|
|
|
if len(fakeDocker.Stopped) != 2 ||
|
|
|
|
!expectedToStop[fakeDocker.Stopped[0]] ||
|
|
|
|
!expectedToStop[fakeDocker.Stopped[1]] {
|
2015-01-13 05:47:49 +00:00
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodsDeletesWhenContainerSourceReady(t *testing.T) {
|
|
|
|
ready := false
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
kubelet.sourceReady = func(source string) bool {
|
|
|
|
if source == "testSource" {
|
|
|
|
return ready
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
|
|
|
Names: []string{"/k8s_boo_bar.default.testSource_12345678_42"},
|
|
|
|
ID: "7492",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
|
|
|
Names: []string{"/k8s_net_boo.default.testSource_12345678_42"},
|
|
|
|
ID: "3542",
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
|
|
|
Names: []string{"/k8s_foo_bar.new.otherSource_12345678_42"},
|
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
|
|
|
Names: []string{"/k8s_net_foo.new.otherSource_12345678_42"},
|
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
// Validate nothing happened.
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list"})
|
|
|
|
fakeDocker.ClearCalls()
|
|
|
|
|
|
|
|
ready = true
|
|
|
|
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop"})
|
|
|
|
|
|
|
|
// Validate container for testSource are killed because testSource is reported as seen, but
|
|
|
|
// containers for otherSource are not killed because otherSource has not.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"7492": true,
|
|
|
|
"3542": true,
|
|
|
|
"1234": false,
|
|
|
|
"9876": false,
|
|
|
|
}
|
|
|
|
if len(fakeDocker.Stopped) != 2 ||
|
|
|
|
!expectedToStop[fakeDocker.Stopped[0]] ||
|
|
|
|
!expectedToStop[fakeDocker.Stopped[1]] {
|
2014-12-17 05:11:27 +00:00
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsDeletes(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +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
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_foo_bar.new.test_12345678_42"},
|
2014-06-06 23:40:48 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-06-20 03:30:42 +00:00
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_42"},
|
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-10-08 19:56:02 +00:00
|
|
|
err := kubelet.SyncPods([]api.BoundPod{})
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-10-20 04:35:08 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop"})
|
2014-06-27 22:29:13 +00:00
|
|
|
|
2014-07-18 18:42:47 +00:00
|
|
|
// A map iteration is used to delete containers, so must not depend on
|
2014-06-27 22:29:13 +00:00
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
|
|
|
"9876": true,
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
if len(fakeDocker.Stopped) != 2 ||
|
|
|
|
!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-18 18:42:47 +00:00
|
|
|
func TestSyncPodDeletesDuplicate(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
dockerContainers := dockertools.DockerContainers{
|
2014-07-18 18:42:47 +00:00
|
|
|
"1234": &docker.APIContainers{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_foo_bar.new.test_12345678_1111"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
"9876": &docker.APIContainers{
|
|
|
|
// network container
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_net_bar.new.test_12345678_2222"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
"4567": &docker.APIContainers{
|
|
|
|
// Duplicate for the same container.
|
2015-01-05 01:30:30 +00:00
|
|
|
Names: []string{"/k8s_foo_bar.new.test_12345678_3333"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "4567",
|
|
|
|
},
|
|
|
|
"2304": &docker.APIContainers{
|
|
|
|
// Container for another pod, untouched.
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_baz_fiz.new.test_6_42"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "2304",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.syncPod(&api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-05 01:30:30 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "bar",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-07-18 18:42:47 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, dockerContainers)
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-08-01 00:35:54 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop"})
|
2014-07-18 18:42:47 +00:00
|
|
|
|
|
|
|
// Expect one of the duplicates to be killed.
|
2015-01-05 01:30:30 +00:00
|
|
|
if len(fakeDocker.Stopped) != 1 || (fakeDocker.Stopped[0] != "1234" && fakeDocker.Stopped[0] != "4567") {
|
2014-09-09 04:33:17 +00:00
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-07-18 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 05:35:50 +00:00
|
|
|
type FalseHealthChecker struct{}
|
|
|
|
|
2014-12-12 22:15:54 +00:00
|
|
|
func (f *FalseHealthChecker) HealthCheck(podFullName, podUUID string, status api.PodStatus, container api.Container) (health.Status, error) {
|
2014-07-15 18:39:19 +00:00
|
|
|
return health.Unhealthy, nil
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
|
|
|
|
2014-09-28 04:16:30 +00:00
|
|
|
func (f *FalseHealthChecker) CanCheck(probe *api.LivenessProbe) bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2014-08-07 23:59:18 +00:00
|
|
|
func TestSyncPodBadHash(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-08-07 23:59:18 +00:00
|
|
|
kubelet.healthChecker = &FalseHealthChecker{}
|
2014-09-09 04:33:17 +00:00
|
|
|
dockerContainers := dockertools.DockerContainers{
|
2014-08-07 23:59:18 +00:00
|
|
|
"1234": &docker.APIContainers{
|
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_bar.1234_foo.new.test_12345678_42"},
|
2014-08-07 23:59:18 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
"9876": &docker.APIContainers{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_42"},
|
2014-08-07 23:59:18 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.syncPod(&api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-07 23:59:18 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, dockerContainers)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-11-04 22:26:21 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "list", "create", "start"})
|
2014-08-07 23:59:18 +00:00
|
|
|
|
|
|
|
// A map interation is used to delete containers, so must not depend on
|
|
|
|
// order here.
|
|
|
|
expectedToStop := map[string]bool{
|
|
|
|
"1234": true,
|
2014-11-04 22:26:21 +00:00
|
|
|
"9876": true,
|
2014-08-07 23:59:18 +00:00
|
|
|
}
|
2014-11-04 22:26:21 +00:00
|
|
|
if len(fakeDocker.Stopped) != 2 ||
|
|
|
|
(!expectedToStop[fakeDocker.Stopped[0]] &&
|
|
|
|
!expectedToStop[fakeDocker.Stopped[1]]) {
|
2014-09-09 04:33:17 +00:00
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-08-07 23:59:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-18 18:42:47 +00:00
|
|
|
func TestSyncPodUnhealthy(t *testing.T) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.healthChecker = &FalseHealthChecker{}
|
2014-09-09 04:33:17 +00:00
|
|
|
dockerContainers := dockertools.DockerContainers{
|
2014-07-18 18:42:47 +00:00
|
|
|
"1234": &docker.APIContainers{
|
2014-07-03 05:35:50 +00:00
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_bar_foo.new.test_12345678_42"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-07-18 18:42:47 +00:00
|
|
|
"9876": &docker.APIContainers{
|
2014-07-03 05:35:50 +00:00
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_42"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.syncPod(&api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-07-18 18:42:47 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar",
|
|
|
|
LivenessProbe: &api.LivenessProbe{
|
2014-09-28 04:16:30 +00:00
|
|
|
// Always returns healthy == false
|
2014-07-03 05:35:50 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2014-07-18 18:42:47 +00:00
|
|
|
},
|
|
|
|
}, dockerContainers)
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-11-04 22:26:21 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop", "list", "create", "start"})
|
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,
|
2014-11-04 22:26:21 +00:00
|
|
|
"9876": true,
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
2014-11-04 22:26:21 +00:00
|
|
|
if len(fakeDocker.Stopped) != 2 ||
|
|
|
|
(!expectedToStop[fakeDocker.Stopped[0]] &&
|
|
|
|
expectedToStop[fakeDocker.Stopped[0]]) {
|
2014-09-09 04:33:17 +00:00
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 20:47:25 +00:00
|
|
|
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) {
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
2014-10-08 19:56:02 +00:00
|
|
|
pod := api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "test",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Volumes: []api.Volume{
|
|
|
|
{
|
|
|
|
Name: "host-dir",
|
|
|
|
Source: &api.VolumeSource{
|
|
|
|
HostDir: &api.HostDir{"/dir/path"},
|
|
|
|
},
|
2014-07-16 19:32:59 +00:00
|
|
|
},
|
2014-07-15 01:39:30 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
podVolumes, _ := kubelet.mountExternalVolumes(&pod)
|
2014-07-16 19:32:59 +00:00
|
|
|
expectedPodVolumes := make(volumeMap)
|
2014-10-01 20:35:21 +00:00
|
|
|
expectedPodVolumes["host-dir"] = &volume.HostDir{"/dir/path"}
|
2014-07-15 01:39:30 +00:00
|
|
|
if len(expectedPodVolumes) != len(podVolumes) {
|
2014-10-08 19:56:02 +00:00
|
|
|
t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
|
2014-07-15 01:39:30 +00:00
|
|
|
}
|
|
|
|
for name, expectedVolume := range expectedPodVolumes {
|
|
|
|
if _, ok := podVolumes[name]; !ok {
|
2014-10-08 19:56:02 +00:00
|
|
|
t.Errorf("api.BoundPod volumes map is missing key: %s. %#v", expectedVolume, podVolumes)
|
2014-07-15 01:39:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-19 23:59:48 +00:00
|
|
|
{
|
|
|
|
MountPath: "/mnt/path3",
|
2014-08-27 05:08:06 +00:00
|
|
|
Name: "disk",
|
|
|
|
ReadOnly: true,
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
2014-07-15 01:39:30 +00:00
|
|
|
{
|
|
|
|
MountPath: "/mnt/path4",
|
|
|
|
Name: "disk4",
|
|
|
|
ReadOnly: false,
|
|
|
|
},
|
2014-07-19 00:13:34 +00:00
|
|
|
{
|
|
|
|
MountPath: "/mnt/path5",
|
|
|
|
Name: "disk5",
|
|
|
|
ReadOnly: false,
|
|
|
|
},
|
2014-06-09 20:47:25 +00:00
|
|
|
},
|
|
|
|
}
|
2014-07-15 01:39:30 +00:00
|
|
|
|
2014-10-08 19:56:02 +00:00
|
|
|
pod := api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "pod",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "test",
|
|
|
|
},
|
2014-07-15 20:24:41 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 05:08:06 +00:00
|
|
|
podVolumes := volumeMap{
|
2014-10-01 20:35:21 +00:00
|
|
|
"disk": &volume.HostDir{"/mnt/disk"},
|
|
|
|
"disk4": &volume.HostDir{"/mnt/host"},
|
|
|
|
"disk5": &volume.EmptyDir{"disk5", "podID", "/var/lib/kubelet"},
|
2014-08-27 05:08:06 +00:00
|
|
|
}
|
2014-06-19 23:59:48 +00:00
|
|
|
|
2014-08-27 05:08:06 +00:00
|
|
|
binds := makeBinds(&pod, &container, podVolumes)
|
2014-07-15 20:24:41 +00:00
|
|
|
|
2014-08-27 05:08:06 +00:00
|
|
|
expectedBinds := []string{
|
|
|
|
"/mnt/disk:/mnt/path",
|
|
|
|
"/mnt/disk:/mnt/path3:ro",
|
|
|
|
"/mnt/host:/mnt/path4",
|
|
|
|
"/var/lib/kubelet/podID/volumes/empty/disk5:/mnt/path5",
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
2014-08-27 05:08:06 +00:00
|
|
|
|
2014-06-19 23:59:48 +00:00
|
|
|
if len(binds) != len(expectedBinds) {
|
2014-07-18 19:03:22 +00:00
|
|
|
t.Errorf("Unexpected binds: Expected %#v 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-12-18 19:15:35 +00:00
|
|
|
if value[0].HostIP != "127.0.0.1" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIP)
|
2014-07-09 05:44:15 +00:00
|
|
|
}
|
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-12-18 19:15:35 +00:00
|
|
|
if value[0].HostIP != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIP)
|
2014-07-09 05:44:15 +00:00
|
|
|
}
|
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-12-18 19:15:35 +00:00
|
|
|
if value[0].HostIP != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIP)
|
2014-07-09 05:44:15 +00:00
|
|
|
}
|
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-12-18 19:15:35 +00:00
|
|
|
if value[0].HostIP != "" {
|
|
|
|
t.Errorf("Unexpected host IP: %s", value[0].HostIP)
|
2014-07-09 05:44:15 +00:00
|
|
|
}
|
2014-06-16 04:57:29 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestCheckHostPortConflicts(t *testing.T) {
|
2014-10-08 19:56:02 +00:00
|
|
|
successCaseAll := []api.BoundPod{
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
successCaseNew := api.BoundPod{
|
|
|
|
Spec: api.PodSpec{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-10-08 19:56:02 +00:00
|
|
|
failureCaseAll := []api.BoundPod{
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 80}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 81}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.Port{{HostPort: 82}}}}}},
|
2014-07-08 04:48:47 +00:00
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
failureCaseNew := api.BoundPod{
|
|
|
|
Spec: api.PodSpec{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
|
|
|
|
2014-12-10 01:06:39 +00:00
|
|
|
func TestFieldPath(t *testing.T) {
|
|
|
|
pod := &api.BoundPod{Spec: api.PodSpec{Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
{Name: "bar"},
|
2014-12-30 01:10:38 +00:00
|
|
|
{Name: ""},
|
2014-12-10 01:06:39 +00:00
|
|
|
{Name: "baz"},
|
|
|
|
}}}
|
|
|
|
table := map[string]struct {
|
|
|
|
pod *api.BoundPod
|
|
|
|
container *api.Container
|
|
|
|
path string
|
|
|
|
success bool
|
|
|
|
}{
|
2014-12-30 01:10:38 +00:00
|
|
|
"basic": {pod, &api.Container{Name: "foo"}, "spec.containers{foo}", true},
|
|
|
|
"basic2": {pod, &api.Container{Name: "baz"}, "spec.containers{baz}", true},
|
|
|
|
"emptyName": {pod, &api.Container{Name: ""}, "spec.containers[2]", true},
|
|
|
|
"basicSamePointer": {pod, &pod.Spec.Containers[0], "spec.containers{foo}", true},
|
2014-12-10 01:06:39 +00:00
|
|
|
"missing": {pod, &api.Container{Name: "qux"}, "", false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, item := range table {
|
|
|
|
res, err := fieldPath(item.pod, item.container)
|
|
|
|
if item.success == false {
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("%v: unexpected non-error", name)
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v: unexpected error: %v", name, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if e, a := item.path, res; e != a {
|
|
|
|
t.Errorf("%v: wanted %v, got %v", name, e, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-12-01 11:10:59 +00:00
|
|
|
// DockerContainer is a mock implementation of CadvisorInterface.DockerContainer.
|
|
|
|
func (c *mockCadvisorClient) DockerContainer(name string, req *info.ContainerInfoRequest) (info.ContainerInfo, error) {
|
|
|
|
args := c.Called(name, req)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
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-12-01 11:10:59 +00:00
|
|
|
containerInfo := info.ContainerInfo{
|
2014-06-19 20:22:20 +00:00
|
|
|
ContainerReference: info.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-10-20 03:54:52 +00:00
|
|
|
cadvisorReq := &info.ContainerInfoRequest{}
|
2014-12-01 11:10:59 +00:00
|
|
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)
|
2014-06-19 20:22:20 +00:00
|
|
|
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.cadvisorClient = mockCadvisor
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-06-19 20:22:20 +00:00
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: containerID,
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_1234_42"},
|
2014-07-01 21:05:10 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-10-20 03:54:52 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux", "", "foo", cadvisorReq)
|
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-01 21:05:10 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
func TestGetRootInfo(t *testing.T) {
|
2014-07-01 21:05:10 +00:00
|
|
|
containerPath := "/"
|
|
|
|
containerInfo := &info.ContainerInfo{
|
|
|
|
ContainerReference: info.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker := dockertools.FakeDockerClient{}
|
2014-06-19 20:22:20 +00:00
|
|
|
|
2014-07-01 21:05:10 +00:00
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-10-20 03:54:52 +00:00
|
|
|
cadvisorReq := &info.ContainerInfoRequest{}
|
2014-07-14 21:48:51 +00:00
|
|
|
mockCadvisor.On("ContainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil)
|
2014-07-01 21:05:10 +00:00
|
|
|
|
|
|
|
kubelet := Kubelet{
|
2014-07-22 21:40:59 +00:00
|
|
|
dockerClient: &fakeDocker,
|
2014-09-09 04:33:17 +00:00
|
|
|
dockerPuller: &dockertools.FakeDockerPuller{},
|
2014-07-22 21:40:59 +00:00
|
|
|
cadvisorClient: mockCadvisor,
|
2014-07-18 18:42:47 +00:00
|
|
|
podWorkers: newPodWorkers(),
|
2014-07-01 21:05:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the container name is an empty string, then it means the root container.
|
2014-10-20 03:54:52 +00:00
|
|
|
_, err := kubelet.GetRootInfo(cadvisorReq)
|
2014-06-19 20:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
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-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-06-19 20:25:54 +00:00
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: "foobar",
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
2014-09-25 00:05:53 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_uuid_1234"},
|
2014-06-19 20:25:54 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-09-05 09:49:11 +00:00
|
|
|
stats, _ := kubelet.GetContainerInfo("qux", "uuid", "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-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"
|
2014-06-19 20:34:26 +00:00
|
|
|
|
2014-12-01 11:10:59 +00:00
|
|
|
containerInfo := info.ContainerInfo{}
|
2014-06-19 20:34:26 +00:00
|
|
|
mockCadvisor := &mockCadvisorClient{}
|
2014-10-20 03:54:52 +00:00
|
|
|
cadvisorReq := &info.ContainerInfoRequest{}
|
2014-06-19 20:34:26 +00:00
|
|
|
expectedErr := fmt.Errorf("some error")
|
2014-12-01 11:10:59 +00:00
|
|
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, expectedErr)
|
2014-06-19 20:34:26 +00:00
|
|
|
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.cadvisorClient = mockCadvisor
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-06-19 20:34:26 +00:00
|
|
|
{
|
2014-07-01 21:05:10 +00:00
|
|
|
ID: containerID,
|
|
|
|
// pod id: qux
|
|
|
|
// container id: foo
|
2014-09-25 00:05:53 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_uuid_1234"},
|
2014-06-19 20:34:26 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-10-20 03:54:52 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux", "uuid", "foo", cadvisorReq)
|
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-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet.cadvisorClient = mockCadvisor
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2014-06-19 20:34:26 +00:00
|
|
|
|
2014-09-05 09:49:11 +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-08-07 18:15:11 +00:00
|
|
|
type fakeContainerCommandRunner struct {
|
|
|
|
Cmd []string
|
|
|
|
ID string
|
|
|
|
E error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([]byte, error) {
|
|
|
|
f.Cmd = cmd
|
|
|
|
f.ID = id
|
|
|
|
return []byte{}, f.E
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRunInContainerNoSuchPod(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2014-08-07 18:15:11 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
|
|
|
podNamespace := "etcd"
|
|
|
|
containerName := "containerFoo"
|
|
|
|
output, err := kubelet.RunInContainer(
|
2014-10-23 20:51:34 +00:00
|
|
|
GetPodFullName(&api.BoundPod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
|
2014-09-05 09:49:11 +00:00
|
|
|
"",
|
2014-08-07 18:15:11 +00:00
|
|
|
containerName,
|
|
|
|
[]string{"ls"})
|
|
|
|
if output != nil {
|
|
|
|
t.Errorf("unexpected non-nil command: %v", output)
|
|
|
|
}
|
|
|
|
if err == nil {
|
|
|
|
t.Error("unexpected non-error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRunInContainer(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2014-08-21 04:27:19 +00:00
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
2014-08-07 18:15:11 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
containerID := "abc1234"
|
|
|
|
podName := "podFoo"
|
|
|
|
podNamespace := "etcd"
|
|
|
|
containerName := "containerFoo"
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-08-07 18:15:11 +00:00
|
|
|
{
|
|
|
|
ID: containerID,
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_" + containerName + "_" + podName + "." + podNamespace + ".test_12345678_42"},
|
2014-08-07 18:15:11 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := []string{"ls"}
|
|
|
|
_, err := kubelet.RunInContainer(
|
2014-10-08 19:56:02 +00:00
|
|
|
GetPodFullName(&api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: podName,
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: podNamespace,
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
}),
|
2014-09-05 09:49:11 +00:00
|
|
|
"",
|
2014-08-07 18:15:11 +00:00
|
|
|
containerName,
|
|
|
|
cmd)
|
|
|
|
if fakeCommandRunner.ID != containerID {
|
2014-10-22 17:02:02 +00:00
|
|
|
t.Errorf("unexected Name: %s", fakeCommandRunner.ID)
|
2014-08-07 18:15:11 +00:00
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(fakeCommandRunner.Cmd, cmd) {
|
|
|
|
t.Errorf("unexpected commnd: %s", fakeCommandRunner.Cmd)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-03 20:39:56 +00:00
|
|
|
func TestRunHandlerExec(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
containerID := "abc1234"
|
|
|
|
podName := "podFoo"
|
|
|
|
podNamespace := "etcd"
|
|
|
|
containerName := "containerFoo"
|
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2014-09-03 20:39:56 +00:00
|
|
|
{
|
|
|
|
ID: containerID,
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_" + containerName + "_" + podName + "." + podNamespace + "_12345678_42"},
|
2014-09-03 20:39:56 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
container := api.Container{
|
|
|
|
Name: containerName,
|
|
|
|
Lifecycle: &api.Lifecycle{
|
|
|
|
PostStart: &api.Handler{
|
|
|
|
Exec: &api.ExecAction{
|
|
|
|
Command: []string{"ls", "-a"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-09-05 09:49:11 +00:00
|
|
|
err := kubelet.runHandler(podName+"."+podNamespace, "", &container, container.Lifecycle.PostStart)
|
2014-09-03 20:39:56 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if fakeCommandRunner.ID != containerID ||
|
|
|
|
!reflect.DeepEqual(container.Lifecycle.PostStart.Exec.Command, fakeCommandRunner.Cmd) {
|
|
|
|
t.Errorf("unexpected commands: %v", fakeCommandRunner)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakeHTTP struct {
|
|
|
|
url string
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeHTTP) Get(url string) (*http.Response, error) {
|
|
|
|
f.url = url
|
|
|
|
return nil, f.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRunHandlerHttp(t *testing.T) {
|
|
|
|
fakeHttp := fakeHTTP{}
|
|
|
|
|
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
|
|
|
kubelet.httpClient = &fakeHttp
|
|
|
|
|
|
|
|
podName := "podFoo"
|
|
|
|
podNamespace := "etcd"
|
|
|
|
containerName := "containerFoo"
|
|
|
|
|
|
|
|
container := api.Container{
|
|
|
|
Name: containerName,
|
|
|
|
Lifecycle: &api.Lifecycle{
|
|
|
|
PostStart: &api.Handler{
|
|
|
|
HTTPGet: &api.HTTPGetAction{
|
|
|
|
Host: "foo",
|
|
|
|
Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
|
|
|
|
Path: "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-09-05 09:49:11 +00:00
|
|
|
err := kubelet.runHandler(podName+"."+podNamespace, "", &container, container.Lifecycle.PostStart)
|
2014-09-03 20:39:56 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if fakeHttp.url != "http://foo:8080/bar" {
|
|
|
|
t.Errorf("unexpected url: %s", fakeHttp.url)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewHandler(t *testing.T) {
|
|
|
|
kubelet, _, _ := newTestKubelet(t)
|
|
|
|
handler := &api.Handler{
|
|
|
|
HTTPGet: &api.HTTPGetAction{
|
|
|
|
Host: "foo",
|
|
|
|
Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
|
|
|
|
Path: "bar",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
actionHandler := kubelet.newActionHandler(handler)
|
|
|
|
if actionHandler == nil {
|
|
|
|
t.Error("unexpected nil action handler.")
|
|
|
|
}
|
|
|
|
|
|
|
|
handler = &api.Handler{
|
|
|
|
Exec: &api.ExecAction{
|
|
|
|
Command: []string{"ls", "-l"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
actionHandler = kubelet.newActionHandler(handler)
|
|
|
|
if actionHandler == nil {
|
|
|
|
t.Error("unexpected nil action handler.")
|
|
|
|
}
|
|
|
|
|
|
|
|
handler = &api.Handler{}
|
|
|
|
actionHandler = kubelet.newActionHandler(handler)
|
|
|
|
if actionHandler != nil {
|
|
|
|
t.Errorf("unexpected non-nil action handler: %v", actionHandler)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodEventHandlerFails(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
kubelet.httpClient = &fakeHTTP{
|
|
|
|
err: fmt.Errorf("test error"),
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
dockerContainers := dockertools.DockerContainers{
|
2014-09-03 20:39:56 +00:00
|
|
|
"9876": &docker.APIContainers{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_12345678_42"},
|
2014-09-03 20:39:56 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2014-10-08 19:56:02 +00:00
|
|
|
err := kubelet.syncPod(&api.BoundPod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-10-22 17:02:02 +00:00
|
|
|
Name: "foo",
|
2014-10-08 19:56:02 +00:00
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-09-03 20:39:56 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar",
|
|
|
|
Lifecycle: &api.Lifecycle{
|
|
|
|
PostStart: &api.Handler{
|
|
|
|
HTTPGet: &api.HTTPGetAction{
|
|
|
|
Host: "does.no.exist",
|
|
|
|
Port: util.IntOrString{IntVal: 8080, Kind: util.IntstrInt},
|
|
|
|
Path: "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, dockerContainers)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-08-26 18:25:17 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "list", "create", "start", "stop"})
|
2014-09-03 20:39:56 +00:00
|
|
|
|
2014-09-09 04:33:17 +00:00
|
|
|
if len(fakeDocker.Stopped) != 1 {
|
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-09-03 20:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-28 00:29:55 +00:00
|
|
|
|
|
|
|
func TestKubeletGarbageCollection(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
containers []docker.APIContainers
|
|
|
|
containerDetails map[string]*docker.Container
|
|
|
|
expectedRemoved []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
containers: []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "1876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "2876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "3876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "4876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "5876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "6876",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
containerDetails: map[string]*docker.Container{
|
|
|
|
"1876": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "1876",
|
|
|
|
Created: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedRemoved: []string{"1876"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
containers: []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "1876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "2876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "3876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "4876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "5876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "6876",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "7876",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
containerDetails: map[string]*docker.Container{
|
|
|
|
"1876": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: true,
|
|
|
|
},
|
|
|
|
ID: "1876",
|
|
|
|
Created: time.Now(),
|
|
|
|
},
|
|
|
|
"2876": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "2876",
|
|
|
|
Created: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedRemoved: []string{"2876"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
containers: []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// network container
|
2015-01-10 01:19:31 +00:00
|
|
|
Names: []string{"/k8s_net_foo.new.test_.deadbeef_42"},
|
2014-10-28 00:29:55 +00:00
|
|
|
ID: "1876",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
kubelet.maxContainerCount = 5
|
|
|
|
fakeDocker.ContainerList = test.containers
|
|
|
|
fakeDocker.ContainerMap = test.containerDetails
|
|
|
|
fakeDocker.Container = &docker.Container{ID: "error", Created: time.Now()}
|
|
|
|
err := kubelet.GarbageCollectContainers()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(fakeDocker.Removed, test.expectedRemoved) {
|
|
|
|
t.Errorf("expected: %v, got: %v", test.expectedRemoved, fakeDocker.Removed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPurgeOldest(t *testing.T) {
|
|
|
|
created := time.Now()
|
|
|
|
tests := []struct {
|
|
|
|
ids []string
|
|
|
|
containerDetails map[string]*docker.Container
|
|
|
|
expectedRemoved []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
ids: []string{"1", "2", "3", "4", "5"},
|
|
|
|
containerDetails: map[string]*docker.Container{
|
|
|
|
"1": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: true,
|
|
|
|
},
|
|
|
|
ID: "1",
|
|
|
|
Created: created,
|
|
|
|
},
|
|
|
|
"2": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "2",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"3": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "3",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"4": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "4",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"5": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "5",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ids: []string{"1", "2", "3", "4", "5", "6"},
|
|
|
|
containerDetails: map[string]*docker.Container{
|
|
|
|
"1": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "1",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"2": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "2",
|
|
|
|
Created: created.Add(time.Millisecond),
|
|
|
|
},
|
|
|
|
"3": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "3",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"4": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "4",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"5": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "5",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"6": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "6",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedRemoved: []string{"2"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ids: []string{"1", "2", "3", "4", "5", "6", "7"},
|
|
|
|
containerDetails: map[string]*docker.Container{
|
|
|
|
"1": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "1",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"2": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "2",
|
|
|
|
Created: created.Add(time.Millisecond),
|
|
|
|
},
|
|
|
|
"3": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "3",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"4": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "4",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"5": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "5",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
"6": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "6",
|
|
|
|
Created: created.Add(time.Microsecond),
|
|
|
|
},
|
|
|
|
"7": {
|
|
|
|
State: docker.State{
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
ID: "7",
|
|
|
|
Created: created.Add(time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedRemoved: []string{"2", "6"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
kubelet.maxContainerCount = 5
|
|
|
|
fakeDocker.ContainerMap = test.containerDetails
|
|
|
|
kubelet.purgeOldest(test.ids)
|
|
|
|
if !reflect.DeepEqual(fakeDocker.Removed, test.expectedRemoved) {
|
|
|
|
t.Errorf("expected: %v, got: %v", test.expectedRemoved, fakeDocker.Removed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-15 00:05:29 +00:00
|
|
|
|
|
|
|
func TestSyncPodsWithPullPolicy(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
puller := kubelet.dockerPuller.(*dockertools.FakeDockerPuller)
|
|
|
|
puller.HasImages = []string{"existing_one", "want:latest"}
|
|
|
|
kubelet.networkContainerImage = "custom_image_name"
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
|
|
|
err := kubelet.SyncPods([]api.BoundPod{
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-01-10 01:19:31 +00:00
|
|
|
UID: "12345678",
|
2014-11-15 00:05:29 +00:00
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{ConfigSourceAnnotationKey: "test"},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar", Image: "pull_always_image", ImagePullPolicy: api.PullAlways},
|
|
|
|
{Name: "bar1", Image: "pull_never_image", ImagePullPolicy: api.PullNever},
|
|
|
|
{Name: "bar2", Image: "pull_if_not_present_image", ImagePullPolicy: api.PullIfNotPresent},
|
|
|
|
{Name: "bar3", Image: "existing_one", ImagePullPolicy: api.PullIfNotPresent},
|
|
|
|
{Name: "bar4", Image: "want:latest", ImagePullPolicy: api.PullIfNotPresent},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.drainWorkers()
|
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(puller.ImagesPulled, []string{"custom_image_name", "pull_always_image", "pull_if_not_present_image", "want:latest"}) {
|
|
|
|
t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fakeDocker.Created) != 6 {
|
|
|
|
t.Errorf("Unexpected containers created %v", fakeDocker.Created)
|
|
|
|
}
|
|
|
|
fakeDocker.Unlock()
|
|
|
|
}
|
2014-12-22 19:54:07 +00:00
|
|
|
|
|
|
|
func TestGarbageCollectImages(t *testing.T) {
|
|
|
|
kubelet, _, fakeDocker := newTestKubelet(t)
|
|
|
|
|
|
|
|
fakeDocker.Images = []docker.APIImages{
|
|
|
|
{
|
|
|
|
ID: "foo",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: "bar",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := kubelet.GarbageCollectImages(); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fakeDocker.RemovedImages) != 2 ||
|
|
|
|
!fakeDocker.RemovedImages.Has("foo") ||
|
|
|
|
!fakeDocker.RemovedImages.Has("bar") {
|
|
|
|
t.Errorf("unexpected images removed: %v", fakeDocker.RemovedImages)
|
|
|
|
}
|
|
|
|
}
|
2014-11-12 05:21:40 +00:00
|
|
|
|
|
|
|
func TestParseResolvConf(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
data string
|
|
|
|
nameservers []string
|
|
|
|
searches []string
|
|
|
|
}{
|
|
|
|
{"", []string{}, []string{}},
|
|
|
|
{" ", []string{}, []string{}},
|
|
|
|
{"\n", []string{}, []string{}},
|
|
|
|
{"\t\n\t", []string{}, []string{}},
|
|
|
|
{"#comment\n", []string{}, []string{}},
|
|
|
|
{" #comment\n", []string{}, []string{}},
|
|
|
|
{"#comment\n#comment", []string{}, []string{}},
|
|
|
|
{"#comment\nnameserver", []string{}, []string{}},
|
|
|
|
{"#comment\nnameserver\nsearch", []string{}, []string{}},
|
|
|
|
{"nameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}},
|
|
|
|
{" nameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}},
|
|
|
|
{"\tnameserver 1.2.3.4", []string{"1.2.3.4"}, []string{}},
|
|
|
|
{"nameserver\t1.2.3.4", []string{"1.2.3.4"}, []string{}},
|
|
|
|
{"nameserver \t 1.2.3.4", []string{"1.2.3.4"}, []string{}},
|
|
|
|
{"nameserver 1.2.3.4\nnameserver 5.6.7.8", []string{"1.2.3.4", "5.6.7.8"}, []string{}},
|
|
|
|
{"search foo", []string{}, []string{"foo"}},
|
|
|
|
{"search foo bar", []string{}, []string{"foo", "bar"}},
|
|
|
|
{"search foo bar bat\n", []string{}, []string{"foo", "bar", "bat"}},
|
|
|
|
{"search foo\nsearch bar", []string{}, []string{"bar"}},
|
|
|
|
{"nameserver 1.2.3.4\nsearch foo bar", []string{"1.2.3.4"}, []string{"foo", "bar"}},
|
|
|
|
{"nameserver 1.2.3.4\nsearch foo\nnameserver 5.6.7.8\nsearch bar", []string{"1.2.3.4", "5.6.7.8"}, []string{"bar"}},
|
|
|
|
{"#comment\nnameserver 1.2.3.4\n#comment\nsearch foo\ncomment", []string{"1.2.3.4"}, []string{"foo"}},
|
|
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
|
|
ns, srch, err := parseResolvConf(strings.NewReader(tc.data))
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("expected success, got %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(ns, tc.nameservers) {
|
|
|
|
t.Errorf("[%d] expected nameservers %#v, got %#v", i, tc.nameservers, ns)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(srch, tc.searches) {
|
|
|
|
t.Errorf("[%d] expected searches %#v, got %#v", i, tc.searches, srch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|