2014-06-06 23:40:48 +00:00
|
|
|
/*
|
2015-05-01 16:19:44 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
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 (
|
2015-01-08 20:41:38 +00:00
|
|
|
"bytes"
|
2015-03-20 16:52:32 +00:00
|
|
|
"errors"
|
2014-06-06 23:40:48 +00:00
|
|
|
"fmt"
|
2015-01-08 20:41:38 +00:00
|
|
|
"io"
|
2014-11-23 15:47:25 +00:00
|
|
|
"io/ioutil"
|
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"
|
2015-03-26 22:14:02 +00:00
|
|
|
"sort"
|
2014-08-07 23:59:18 +00:00
|
|
|
"strconv"
|
2014-10-02 18:58:58 +00:00
|
|
|
"strings"
|
2014-06-06 23:40:48 +00:00
|
|
|
"testing"
|
2014-08-08 04:49:17 +00:00
|
|
|
"time"
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2015-02-23 21:04:45 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
|
2015-03-24 23:09:16 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/capabilities"
|
2015-03-03 06:06:20 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
|
2015-04-06 23:27:53 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/testclient"
|
2015-03-06 07:56:30 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
|
2015-03-20 21:20:01 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
|
2014-09-09 04:33:17 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
|
2015-02-24 23:29:18 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
|
2015-03-19 23:14:13 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
|
2015-01-14 23:22:21 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
2014-09-03 20:39:56 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
2015-03-31 07:22:37 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
2015-03-19 05:18:31 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
|
|
|
|
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/volume/host_path"
|
2014-06-06 23:40:48 +00:00
|
|
|
"github.com/fsouza/go-dockerclient"
|
2015-03-07 00:06:38 +00:00
|
|
|
cadvisorApi "github.com/google/cadvisor/info/v1"
|
2015-05-12 08:24:08 +00:00
|
|
|
cadvisorApiv2 "github.com/google/cadvisor/info/v2"
|
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
|
|
|
|
}
|
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
type TestKubelet struct {
|
2015-03-23 19:17:12 +00:00
|
|
|
kubelet *Kubelet
|
|
|
|
fakeDocker *dockertools.FakeDockerClient
|
|
|
|
fakeCadvisor *cadvisor.Mock
|
2015-04-06 23:27:53 +00:00
|
|
|
fakeKubeClient *testclient.Fake
|
2015-03-23 19:17:12 +00:00
|
|
|
fakeMirrorClient *fakeMirrorClient
|
2015-02-23 21:04:45 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 20:57:30 +00:00
|
|
|
const testKubeletHostname = "testnode"
|
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
func newTestKubelet(t *testing.T) *TestKubelet {
|
2015-04-09 18:57:53 +00:00
|
|
|
fakeDocker := &dockertools.FakeDockerClient{Errors: make(map[string]error), RemovedImages: util.StringSet{}}
|
2015-05-05 10:19:54 +00:00
|
|
|
fakeDocker.VersionInfo = []string{"ApiVersion=1.15"}
|
2015-02-23 21:04:45 +00:00
|
|
|
fakeRecorder := &record.FakeRecorder{}
|
2015-04-06 23:27:53 +00:00
|
|
|
fakeKubeClient := &testclient.Fake{}
|
2014-07-22 21:40:59 +00:00
|
|
|
kubelet := &Kubelet{}
|
|
|
|
kubelet.dockerClient = fakeDocker
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet.kubeClient = fakeKubeClient
|
2015-04-27 20:03:55 +00:00
|
|
|
kubelet.os = kubecontainer.FakeOS{}
|
2015-04-13 19:24:01 +00:00
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet.hostname = "testnode"
|
2015-05-05 10:19:54 +00:00
|
|
|
kubelet.runtimeUpThreshold = maxWaitForContainerRuntime
|
2015-03-19 23:14:13 +00:00
|
|
|
kubelet.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
|
2014-11-23 15:47:25 +00:00
|
|
|
if tempDir, err := ioutil.TempDir("/tmp", "kubelet_test."); err != nil {
|
|
|
|
t.Fatalf("can't make a temp rootdir: %v", err)
|
|
|
|
} else {
|
|
|
|
kubelet.rootDirectory = tempDir
|
|
|
|
}
|
|
|
|
if err := os.MkdirAll(kubelet.rootDirectory, 0750); err != nil {
|
|
|
|
t.Fatalf("can't mkdir(%q): %v", kubelet.rootDirectory, err)
|
|
|
|
}
|
2015-03-05 18:49:36 +00:00
|
|
|
kubelet.sourcesReady = func() bool { return true }
|
2014-11-21 21:14:30 +00:00
|
|
|
kubelet.masterServiceNamespace = api.NamespaceDefault
|
|
|
|
kubelet.serviceLister = testServiceLister{}
|
2015-03-20 16:52:32 +00:00
|
|
|
kubelet.nodeLister = testNodeLister{}
|
2015-03-27 01:45:23 +00:00
|
|
|
kubelet.readinessManager = kubecontainer.NewReadinessManager()
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet.recorder = fakeRecorder
|
2015-03-20 16:37:08 +00:00
|
|
|
kubelet.statusManager = newStatusManager(fakeKubeClient)
|
2014-11-23 15:47:25 +00:00
|
|
|
if err := kubelet.setupDataDirs(); err != nil {
|
|
|
|
t.Fatalf("can't initialize kubelet data dirs: %v", err)
|
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor := &cadvisor.Mock{}
|
|
|
|
kubelet.cadvisor = mockCadvisor
|
2015-03-23 19:17:12 +00:00
|
|
|
podManager, fakeMirrorClient := newFakePodManager()
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager = podManager
|
2015-03-26 18:44:52 +00:00
|
|
|
kubelet.containerRefManager = kubecontainer.NewRefManager()
|
2015-05-01 01:37:15 +00:00
|
|
|
runtimeHooks := newKubeletRuntimeHooks(kubelet.recorder)
|
2015-05-12 08:24:08 +00:00
|
|
|
diskSpaceManager, err := newDiskSpaceManager(mockCadvisor, DiskSpacePolicy{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't initialize disk space manager: %v", err)
|
|
|
|
}
|
|
|
|
kubelet.diskSpaceManager = diskSpaceManager
|
2015-05-01 22:25:11 +00:00
|
|
|
|
|
|
|
kubelet.containerRuntime = dockertools.NewFakeDockerManager(fakeDocker, fakeRecorder, kubelet.readinessManager, kubelet.containerRefManager, dockertools.PodInfraContainerImage, 0, 0, "", kubelet.os, kubelet.networkPlugin, kubelet, &fakeHTTP{}, runtimeHooks)
|
|
|
|
kubelet.runtimeCache = kubecontainer.NewFakeRuntimeCache(kubelet.containerRuntime)
|
2015-05-08 18:48:26 +00:00
|
|
|
kubelet.podWorkers = &fakePodWorkers{
|
|
|
|
syncPodFn: kubelet.syncPod,
|
|
|
|
runtimeCache: kubelet.runtimeCache,
|
|
|
|
t: t,
|
|
|
|
}
|
2015-04-16 00:40:07 +00:00
|
|
|
kubelet.volumeManager = newVolumeManager()
|
2015-05-08 18:48:26 +00:00
|
|
|
return &TestKubelet{kubelet, fakeDocker, mockCadvisor, fakeKubeClient, fakeMirrorClient}
|
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
|
|
|
}
|
|
|
|
|
2015-03-26 22:06:27 +00:00
|
|
|
func verifyUnorderedCalls(t *testing.T, fakeDocker *dockertools.FakeDockerClient, calls []string) {
|
|
|
|
err := fakeDocker.AssertUnorderedCalls(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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-13 21:08:15 +00:00
|
|
|
func verifyStringArrayEqualsAnyOrder(t *testing.T, actual, expected []string) {
|
2015-03-31 00:02:41 +00:00
|
|
|
act := make([]string, len(actual))
|
|
|
|
exp := make([]string, len(expected))
|
2015-03-26 22:14:02 +00:00
|
|
|
copy(act, actual)
|
|
|
|
copy(exp, expected)
|
|
|
|
|
|
|
|
sort.StringSlice(act).Sort()
|
|
|
|
sort.StringSlice(exp).Sort()
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(exp, act) {
|
|
|
|
t.Errorf("Expected(sorted): %#v, Actual(sorted): %#v", exp, act)
|
2015-02-13 21:08:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-24 18:20:23 +00:00
|
|
|
func newTestPods(count int) []*api.Pod {
|
|
|
|
pods := make([]*api.Pod, count)
|
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
pods[i] = &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: fmt.Sprintf("pod%d", i),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pods
|
|
|
|
}
|
|
|
|
|
2014-11-29 19:02:28 +00:00
|
|
|
func TestKubeletDirs(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2014-11-29 19:02:28 +00:00
|
|
|
root := kubelet.rootDirectory
|
|
|
|
|
|
|
|
var exp, got string
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPluginsDir()
|
|
|
|
exp = path.Join(root, "plugins")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.getPluginDir("foobar")
|
|
|
|
exp = path.Join(root, "plugins/foobar")
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodVolumeDir("abc123", "plugin", "foobar")
|
|
|
|
exp = path.Join(root, "pods/abc123/volumes/plugin/foobar")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.getPodPluginsDir("abc123")
|
|
|
|
exp = path.Join(root, "pods/abc123/plugins")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
|
|
|
got = kubelet.getPodPluginDir("abc123", "foobar")
|
|
|
|
exp = path.Join(root, "pods/abc123/plugins/foobar")
|
|
|
|
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) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2014-11-29 19:02:28 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodDir("oldpod")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "oldpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodDir("newpod")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/newpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodDir("bothpod")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/bothpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodDir("neitherpod")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "pods/neitherpod")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
root = kubelet.getPodDir("newpod")
|
2014-11-29 19:02:28 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodContainerDir("newpod", "oldctr")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "oldctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodContainerDir("newpod", "newctr")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "containers/newctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodContainerDir("newpod", "bothctr")
|
2014-11-29 19:02:28 +00:00
|
|
|
exp = path.Join(root, "containers/bothctr")
|
|
|
|
if got != exp {
|
|
|
|
t.Errorf("expected %q', got %q", exp, got)
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
got = kubelet.getPodContainerDir("newpod", "neitherctr")
|
2014-11-29 19:02:28 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-20 21:20:01 +00:00
|
|
|
func apiContainerToContainer(c docker.APIContainers) container.Container {
|
|
|
|
dockerName, hash, err := dockertools.ParseDockerName(c.Names[0])
|
|
|
|
if err != nil {
|
|
|
|
return container.Container{}
|
|
|
|
}
|
|
|
|
return container.Container{
|
|
|
|
ID: types.UID(c.ID),
|
|
|
|
Name: dockerName.ContainerName,
|
|
|
|
Hash: hash,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:29:18 +00:00
|
|
|
var emptyPodUIDs map[types.UID]metrics.SyncPodType
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
func generatePodInfraContainerHash(pod *api.Pod) uint64 {
|
|
|
|
var ports []api.ContainerPort
|
|
|
|
if !pod.Spec.HostNetwork {
|
|
|
|
for _, container := range pod.Spec.Containers {
|
|
|
|
ports = append(ports, container.Ports...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
container := &api.Container{
|
|
|
|
Name: dockertools.PodInfraContainerName,
|
|
|
|
Image: dockertools.PodInfraContainerImage,
|
|
|
|
Ports: ports,
|
|
|
|
}
|
|
|
|
return dockertools.HashContainer(container)
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsDoesNothing(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
|
2014-08-07 23:59:18 +00:00
|
|
|
container := api.Container{Name: "bar"}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
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
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>_<random>
|
|
|
|
Names: []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&container), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_0"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
Config: &docker.Config{},
|
|
|
|
},
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
Config: &docker.Config{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra contianer.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-11-07 06:41:16 +00:00
|
|
|
func TestSyncPodsWithTerminationLog(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2014-11-07 06:41:16 +00:00
|
|
|
container := api.Container{
|
|
|
|
Name: "bar",
|
|
|
|
TerminationMessagePath: "/dev/somepath",
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-11-07 06:41:16 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-11-07 06:41:16 +00:00
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
container,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-11-07 06:41:16 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_image",
|
|
|
|
// Create pod infra container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2014-11-07 06:41:16 +00:00
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
parts := strings.Split(fakeDocker.Container.HostConfig.Binds[0], ":")
|
2014-11-23 15:47:25 +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-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) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-05-01 22:25:11 +00:00
|
|
|
// TODO: Move this test to dockertools so that we don't have to do the hacky
|
|
|
|
// type assertion here.
|
|
|
|
dm := kubelet.containerRuntime.(*dockertools.DockerManager)
|
|
|
|
dm.PodInfraContainerImage = "custom_image_name"
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-08 04:49:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_image",
|
|
|
|
// Create pod infra container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
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 {
|
2015-01-21 00:59:26 +00:00
|
|
|
if c.Image == "custom_image_name" && strings.HasPrefix(c.Names[0], "/k8s_POD") {
|
2014-10-02 18:58:58 +00:00
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
2015-01-28 23:03:06 +00:00
|
|
|
t.Errorf("Custom pod infra container not found: %v", fakeDocker.ContainerList)
|
2014-10-02 18:58:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(fakeDocker.Created) != 2 ||
|
2015-02-26 20:27:14 +00:00
|
|
|
!matchString(t, "k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
|
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo_new_", 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) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-05-01 22:25:11 +00:00
|
|
|
// TODO: Move this test to dockertools so that we don't have to do the hacky
|
|
|
|
// type assertion here.
|
|
|
|
dm := kubelet.containerRuntime.(*dockertools.DockerManager)
|
|
|
|
puller := dm.Puller.(*dockertools.FakeDockerPuller)
|
2014-10-02 18:58:58 +00:00
|
|
|
puller.HasImages = []string{}
|
2015-05-01 22:25:11 +00:00
|
|
|
dm.PodInfraContainerImage = "custom_image_name"
|
2014-10-02 18:58:58 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-10-02 18:58:58 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-10-02 18:58:58 +00:00
|
|
|
Containers: []api.Container{
|
2015-01-21 04:30:42 +00:00
|
|
|
{Name: "bar", Image: "something", ImagePullPolicy: "IfNotPresent"},
|
2014-10-02 18:58:58 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-10-02 18:58:58 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_image",
|
|
|
|
// Create pod infra container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2014-10-02 18:58:58 +00:00
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
|
2015-01-17 00:55:19 +00:00
|
|
|
if !reflect.DeepEqual(puller.ImagesPulled, []string{"custom_image_name", "something"}) {
|
2014-10-02 18:58:58 +00:00
|
|
|
t.Errorf("Unexpected pulled containers: %v", puller.ImagesPulled)
|
|
|
|
}
|
|
|
|
|
2014-08-08 04:49:17 +00:00
|
|
|
if len(fakeDocker.Created) != 2 ||
|
2015-02-26 20:27:14 +00:00
|
|
|
!matchString(t, "k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
|
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo_new_", 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
|
|
|
}
|
|
|
|
|
2015-02-20 03:17:44 +00:00
|
|
|
func TestSyncPodsWithPodInfraCreatesContainer(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_0"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-08 04:49:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_image",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
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 ||
|
2015-02-26 20:27:14 +00:00
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo_new_", 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
|
|
|
}
|
|
|
|
|
2015-05-01 01:37:15 +00:00
|
|
|
type fakeHTTP struct {
|
|
|
|
url string
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeHTTP) Get(url string) (*http.Response, error) {
|
|
|
|
f.url = url
|
|
|
|
return nil, f.err
|
|
|
|
}
|
|
|
|
|
2015-02-20 03:17:44 +00:00
|
|
|
func TestSyncPodsWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2014-09-03 20:39:56 +00:00
|
|
|
fakeHttp := fakeHTTP{}
|
2015-05-01 01:37:15 +00:00
|
|
|
|
2015-05-01 22:25:11 +00:00
|
|
|
// Simulate HTTP failure. Re-create the containerRuntime to inject the failure.
|
2014-09-03 20:39:56 +00:00
|
|
|
kubelet.httpClient = &fakeHttp
|
2015-05-01 01:37:15 +00:00
|
|
|
runtimeHooks := newKubeletRuntimeHooks(kubelet.recorder)
|
2015-05-01 22:25:11 +00:00
|
|
|
kubelet.containerRuntime = dockertools.NewFakeDockerManager(kubelet.dockerClient, kubelet.recorder, kubelet.readinessManager, kubelet.containerRefManager, dockertools.PodInfraContainerImage, 0, 0, "", kubelet.os, kubelet.networkPlugin, kubelet, kubelet.httpClient, runtimeHooks)
|
2015-05-01 01:37:15 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-09-03 20:39:56 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
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",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_0"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-09-03 20:39:56 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_image",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
2015-05-01 22:25:11 +00:00
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
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 ||
|
2015-02-26 20:27:14 +00:00
|
|
|
!matchString(t, "k8s_bar\\.[a-f0-9]+_foo_new_", 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" {
|
2015-05-01 01:37:15 +00:00
|
|
|
t.Errorf("Unexpected handler: %q", fakeHttp.url)
|
2014-09-03 20:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-20 03:17:44 +00:00
|
|
|
func TestSyncPodsDeletesWithNoPodInfraContainer(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-08-08 04:49:17 +00:00
|
|
|
{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
2015-03-13 21:46:35 +00:00
|
|
|
Name: "foo1",
|
2015-02-26 20:27:14 +00:00
|
|
|
Namespace: "new",
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2014-08-08 04:49:17 +00:00
|
|
|
Containers: []api.Container{
|
2015-03-13 21:46:35 +00:00
|
|
|
{Name: "bar1"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "87654321",
|
|
|
|
Name: "foo2",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar2"},
|
2014-08-08 04:49:17 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_bar1_foo1_new_12345678_0"},
|
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_bar2_foo2_new_87654321_0"},
|
|
|
|
ID: "5678",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo2_new_87654321_0"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "8765",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
"5678": {
|
|
|
|
ID: "5678",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
"8765": {
|
|
|
|
ID: "8765",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-08 04:49:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-05-08 18:48:26 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-04-07 22:38:01 +00:00
|
|
|
"list",
|
2015-05-08 18:48:26 +00:00
|
|
|
|
2015-04-07 22:38:01 +00:00
|
|
|
// foo1
|
2015-04-13 17:02:58 +00:00
|
|
|
"list",
|
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container",
|
|
|
|
// Kill the container since pod infra container is not running.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Create pod infra container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
// Create container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
2015-04-07 22:38:01 +00:00
|
|
|
|
|
|
|
// foo2
|
2015-04-13 17:02:58 +00:00
|
|
|
"list",
|
2015-05-08 18:48:26 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container",
|
2015-05-08 18:48:26 +00:00
|
|
|
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
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
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-03-05 18:49:36 +00:00
|
|
|
kubelet.sourcesReady = func() 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-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_bar_new_12345678_42"},
|
2014-12-17 05:11:27 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
2015-01-21 00:59:26 +00:00
|
|
|
// pod infra container
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_POD_foo_new_12345678_42"},
|
2014-12-17 05:11:27 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2015-04-20 18:20:53 +00:00
|
|
|
if err := kubelet.SyncPods([]*api.Pod{}, emptyPodUIDs, map[string]*api.Pod{}, time.Now()); err != nil {
|
2014-12-17 05:11:27 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
// Validate nothing happened.
|
|
|
|
verifyCalls(t, fakeDocker, []string{"list"})
|
|
|
|
fakeDocker.ClearCalls()
|
|
|
|
|
|
|
|
ready = true
|
2015-04-20 18:20:53 +00:00
|
|
|
if err := kubelet.SyncPods([]*api.Pod{}, emptyPodUIDs, map[string]*api.Pod{}, time.Now()); err != nil {
|
2014-12-17 05:11:27 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-05-06 03:50:45 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "inspect_container", "stop", "inspect_container", "stop", "list"})
|
2014-12-17 05:11:27 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 20:24:41 +00:00
|
|
|
func TestSyncPodsDeletes(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
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-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_bar_new_12345678_42"},
|
2014-06-06 23:40:48 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2014-06-20 03:30:42 +00:00
|
|
|
{
|
2015-01-21 00:59:26 +00:00
|
|
|
// pod infra container
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_POD_foo_new_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
|
|
|
}
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods([]*api.Pod{}, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-05-06 03:50:45 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "inspect_container", "stop", "inspect_container", "stop", "list"})
|
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
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
func TestSyncPodsDeletesDuplicate(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-04-13 17:02:58 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "bar",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
2014-07-18 18:42:47 +00:00
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_bar_new_12345678_1111"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
2015-01-21 00:59:26 +00:00
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_bar_new_12345678_2222"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
2014-07-18 18:42:47 +00:00
|
|
|
// Duplicate for the same container.
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_bar_new_12345678_3333"},
|
2014-07-18 18:42:47 +00:00
|
|
|
ID: "4567",
|
|
|
|
},
|
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
"4567": {
|
|
|
|
ID: "4567",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-07-18 18:42:47 +00:00
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Kill the duplicated container.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
func TestSyncPodsBadHash(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-04-13 17:02:58 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
2014-08-07 23:59:18 +00:00
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_bar.1234_foo_new_12345678_42"},
|
2014-08-07 23:59:18 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
2015-01-21 00:59:26 +00:00
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_42"},
|
2014-08-07 23:59:18 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-08-07 23:59:18 +00:00
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-07 23:59:18 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Kill and restart the bad hash container.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop", "create", "start",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2015-04-13 17:02:58 +00:00
|
|
|
|
|
|
|
if err := fakeDocker.AssertStopped([]string{"1234"}); err != nil {
|
|
|
|
t.Errorf("%v", err)
|
2014-08-07 23:59:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
func TestSyncPodsUnhealthy(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-04-13 17:02:58 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar",
|
|
|
|
LivenessProbe: &api.Probe{
|
|
|
|
// Always returns healthy == false
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
2014-07-03 05:35:50 +00:00
|
|
|
// the k8s prefix is required for the kubelet to manage the container
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_bar_foo_new_12345678_42"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "1234",
|
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
2015-01-21 00:59:26 +00:00
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_42"},
|
2014-07-03 05:35:50 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
2015-04-13 17:02:58 +00:00
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2014-07-18 18:42:47 +00:00
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-08-03 23:59:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Kill the unhealthy container.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Restart the unhealthy container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2015-04-13 17:02:58 +00:00
|
|
|
|
|
|
|
if err := fakeDocker.AssertStopped([]string{"1234"}); err != nil {
|
|
|
|
t.Errorf("%v", err)
|
2014-07-03 05:35:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-15 01:39:30 +00:00
|
|
|
func TestMountExternalVolumes(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2015-03-19 05:18:31 +00:00
|
|
|
kubelet.volumePluginMgr.InitPlugins([]volume.VolumePlugin{&volume.FakeVolumePlugin{"fake", nil}}, &volumeHost{kubelet})
|
2014-11-23 15:47:25 +00:00
|
|
|
|
2015-03-13 13:19:07 +00:00
|
|
|
pod := api.Pod{
|
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{
|
|
|
|
{
|
2015-03-03 22:48:55 +00:00
|
|
|
Name: "vol1",
|
|
|
|
VolumeSource: api.VolumeSource{},
|
2014-07-16 19:32:59 +00:00
|
|
|
},
|
2014-07-15 01:39:30 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2014-11-23 15:47:25 +00:00
|
|
|
podVolumes, err := kubelet.mountExternalVolumes(&pod)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Expected sucess: %v", err)
|
|
|
|
}
|
|
|
|
expectedPodVolumes := []string{"vol1"}
|
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
|
|
|
}
|
2014-11-23 15:47:25 +00:00
|
|
|
for _, name := range expectedPodVolumes {
|
2014-07-15 01:39:30 +00:00
|
|
|
if _, ok := podVolumes[name]; !ok {
|
2015-03-13 13:19:07 +00:00
|
|
|
t.Errorf("api.Pod volumes map is missing key: %s. %#v", name, podVolumes)
|
2014-07-15 01:39:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-23 15:47:25 +00:00
|
|
|
func TestGetPodVolumesFromDisk(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2015-03-19 05:18:31 +00:00
|
|
|
plug := &volume.FakeVolumePlugin{"fake", nil}
|
|
|
|
kubelet.volumePluginMgr.InitPlugins([]volume.VolumePlugin{plug}, &volumeHost{kubelet})
|
2014-11-23 15:47:25 +00:00
|
|
|
|
|
|
|
volsOnDisk := []struct {
|
|
|
|
podUID types.UID
|
|
|
|
volName string
|
|
|
|
}{
|
|
|
|
{"pod1", "vol1"},
|
|
|
|
{"pod1", "vol2"},
|
|
|
|
{"pod2", "vol1"},
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedPaths := []string{}
|
|
|
|
for i := range volsOnDisk {
|
|
|
|
fv := volume.FakeVolume{volsOnDisk[i].podUID, volsOnDisk[i].volName, plug}
|
|
|
|
fv.SetUp()
|
|
|
|
expectedPaths = append(expectedPaths, fv.GetPath())
|
|
|
|
}
|
|
|
|
|
|
|
|
volumesFound := kubelet.getPodVolumesFromDisk()
|
|
|
|
if len(volumesFound) != len(expectedPaths) {
|
|
|
|
t.Errorf("Expected to find %d cleaners, got %d", len(expectedPaths), len(volumesFound))
|
|
|
|
}
|
|
|
|
for _, ep := range expectedPaths {
|
|
|
|
found := false
|
|
|
|
for _, cl := range volumesFound {
|
|
|
|
if ep == cl.GetPath() {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
t.Errorf("Could not find a volume with path %s", ep)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type stubVolume struct {
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *stubVolume) GetPath() string {
|
|
|
|
return f.path
|
|
|
|
}
|
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
func TestMakeVolumeMounts(t *testing.T) {
|
2014-06-09 20:47:25 +00:00
|
|
|
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
|
|
|
|
2015-05-06 23:50:57 +00:00
|
|
|
podVolumes := kubecontainer.VolumeMap{
|
2014-11-23 15:47:25 +00:00
|
|
|
"disk": &stubVolume{"/mnt/disk"},
|
|
|
|
"disk4": &stubVolume{"/mnt/host"},
|
|
|
|
"disk5": &stubVolume{"/var/lib/kubelet/podID/volumes/empty/disk5"},
|
2014-08-27 05:08:06 +00:00
|
|
|
}
|
2014-06-19 23:59:48 +00:00
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
mounts := makeMounts(&container, podVolumes)
|
2014-07-15 20:24:41 +00:00
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedMounts := []kubecontainer.Mount{
|
|
|
|
{
|
|
|
|
"disk",
|
|
|
|
"/mnt/path",
|
|
|
|
"/mnt/disk",
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"disk",
|
|
|
|
"/mnt/path3",
|
|
|
|
"/mnt/disk",
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"disk4",
|
|
|
|
"/mnt/path4",
|
|
|
|
"/mnt/host",
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"disk5",
|
|
|
|
"/mnt/path5",
|
|
|
|
"/var/lib/kubelet/podID/volumes/empty/disk5",
|
|
|
|
false,
|
|
|
|
},
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
2015-05-12 21:49:35 +00:00
|
|
|
if !reflect.DeepEqual(mounts, expectedMounts) {
|
|
|
|
t.Errorf("Unexpected mounts: Expected %#v got %#v. Container was: %#v", expectedMounts, mounts, container)
|
2014-06-19 23:59:48 +00:00
|
|
|
}
|
2014-06-09 20:47:25 +00:00
|
|
|
}
|
|
|
|
|
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)
|
2015-03-07 00:06:38 +00:00
|
|
|
containerInfo := cadvisorApi.ContainerInfo{
|
|
|
|
ContainerReference: cadvisorApi.ContainerReference{
|
2014-06-19 20:22:20 +00:00
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-03-07 00:06:38 +00:00
|
|
|
cadvisorReq := &cadvisorApi.ContainerInfoRequest{}
|
2014-12-01 11:10:59 +00:00
|
|
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
|
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-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_ns_1234_42"},
|
2014-07-01 21:05:10 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-02-26 20:27:14 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux_ns", "", "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)
|
|
|
|
}
|
|
|
|
|
2015-04-23 17:14:08 +00:00
|
|
|
func TestGetRawContainerInfoRoot(t *testing.T) {
|
2014-07-01 21:05:10 +00:00
|
|
|
containerPath := "/"
|
2015-03-07 00:06:38 +00:00
|
|
|
containerInfo := &cadvisorApi.ContainerInfo{
|
|
|
|
ContainerReference: cadvisorApi.ContainerReference{
|
2014-07-01 21:05:10 +00:00
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
}
|
2014-09-09 04:33:17 +00:00
|
|
|
fakeDocker := dockertools.FakeDockerClient{}
|
2014-06-19 20:22:20 +00:00
|
|
|
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor := &cadvisor.Mock{}
|
2015-03-07 00:06:38 +00:00
|
|
|
cadvisorReq := &cadvisorApi.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{
|
2015-03-06 07:56:30 +00:00
|
|
|
dockerClient: &fakeDocker,
|
|
|
|
cadvisor: mockCadvisor,
|
2014-07-01 21:05:10 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 17:14:08 +00:00
|
|
|
_, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, false)
|
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
|
|
|
|
2015-04-23 17:14:08 +00:00
|
|
|
func TestGetRawContainerInfoSubcontainers(t *testing.T) {
|
|
|
|
containerPath := "/kubelet"
|
|
|
|
containerInfo := map[string]*cadvisorApi.ContainerInfo{
|
|
|
|
containerPath: {
|
|
|
|
ContainerReference: cadvisorApi.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"/kubelet/sub": {
|
|
|
|
ContainerReference: cadvisorApi.ContainerReference{
|
|
|
|
Name: "/kubelet/sub",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker := dockertools.FakeDockerClient{}
|
|
|
|
|
|
|
|
mockCadvisor := &cadvisor.Mock{}
|
|
|
|
cadvisorReq := &cadvisorApi.ContainerInfoRequest{}
|
|
|
|
mockCadvisor.On("SubcontainerInfo", containerPath, cadvisorReq).Return(containerInfo, nil)
|
|
|
|
|
|
|
|
kubelet := Kubelet{
|
|
|
|
dockerClient: &fakeDocker,
|
|
|
|
cadvisor: mockCadvisor,
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := kubelet.GetRawContainerInfo(containerPath, cadvisorReq, true)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if len(result) != 2 {
|
|
|
|
t.Errorf("Expected 2 elements, received: %+v", result)
|
|
|
|
}
|
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-03-06 07:56:30 +00:00
|
|
|
cadvisorApiFailure := fmt.Errorf("cAdvisor failure")
|
2015-03-07 00:06:38 +00:00
|
|
|
containerInfo := cadvisorApi.ContainerInfo{}
|
|
|
|
cadvisorReq := &cadvisorApi.ContainerInfoRequest{}
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, cadvisorApiFailure)
|
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
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_foo_qux_ns_uuid_1234"},
|
2014-06-19 20:34:26 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-02-26 20:27:14 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux_ns", "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
|
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
if err.Error() != cadvisorApiFailure.Error() {
|
|
|
|
t.Errorf("wrong error message. expect %v, got %v", cadvisorApiFailure, err)
|
2014-06-19 20:34:26 +00:00
|
|
|
}
|
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
|
|
|
|
2014-07-15 22:40:02 +00:00
|
|
|
func TestGetContainerInfoOnNonExistContainer(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
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
|
|
|
|
2015-02-13 16:54:06 +00:00
|
|
|
func TestGetContainerInfoWhenDockerToolsFailed(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-04-30 19:15:23 +00:00
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-02-13 16:54:06 +00:00
|
|
|
expectedErr := fmt.Errorf("List containers error")
|
2015-04-30 19:15:23 +00:00
|
|
|
fakeDocker.Errors["list"] = expectedErr
|
2015-02-13 16:54:06 +00:00
|
|
|
|
|
|
|
stats, err := kubelet.GetContainerInfo("qux", "", "foo", nil)
|
|
|
|
if err == nil {
|
2015-04-30 19:15:23 +00:00
|
|
|
t.Errorf("expected error from dockertools, got none")
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
if err.Error() != expectedErr.Error() {
|
2015-04-30 19:15:23 +00:00
|
|
|
t.Errorf("expected error %v got %v", expectedErr.Error(), err.Error())
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
if stats != nil {
|
|
|
|
t.Errorf("non-nil stats when dockertools failed")
|
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetContainerInfoWithNoContainers(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-02-13 16:54:06 +00:00
|
|
|
|
2015-02-26 20:27:14 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil)
|
2015-02-13 16:54:06 +00:00
|
|
|
if err == nil {
|
2015-04-30 19:15:23 +00:00
|
|
|
t.Errorf("expected error from cadvisor client, got none")
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
2015-04-30 19:15:23 +00:00
|
|
|
if err != ErrContainerNotFound {
|
|
|
|
t.Errorf("expected error %v, got %v", ErrContainerNotFound.Error(), err.Error())
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
if stats != nil {
|
|
|
|
t.Errorf("non-nil stats when dockertools returned no containers")
|
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetContainerInfoWithNoMatchingContainers(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-04-30 19:15:23 +00:00
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
2015-02-13 16:54:06 +00:00
|
|
|
{
|
|
|
|
ID: "fakeId",
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_bar_qux_ns_1234_42"},
|
2015-02-13 16:54:06 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-02-26 20:27:14 +00:00
|
|
|
stats, err := kubelet.GetContainerInfo("qux_ns", "", "foo", nil)
|
2015-02-13 16:54:06 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("Expected error from cadvisor client, got none")
|
|
|
|
}
|
|
|
|
if err != ErrContainerNotFound {
|
|
|
|
t.Errorf("Expected error %v, got %v", ErrContainerNotFound.Error(), err.Error())
|
|
|
|
}
|
|
|
|
if stats != nil {
|
|
|
|
t.Errorf("non-nil stats when dockertools returned no containers")
|
|
|
|
}
|
2015-03-06 07:56:30 +00:00
|
|
|
mockCadvisor.AssertExpectations(t)
|
2015-02-13 16:54:06 +00:00
|
|
|
}
|
|
|
|
|
2014-08-07 18:15:11 +00:00
|
|
|
type fakeContainerCommandRunner struct {
|
2015-01-08 20:41:38 +00:00
|
|
|
Cmd []string
|
|
|
|
ID string
|
|
|
|
E error
|
|
|
|
Stdin io.Reader
|
|
|
|
Stdout io.WriteCloser
|
|
|
|
Stderr io.WriteCloser
|
|
|
|
TTY bool
|
|
|
|
Port uint16
|
|
|
|
Stream io.ReadWriteCloser
|
2014-08-07 18:15:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([]byte, error) {
|
|
|
|
f.Cmd = cmd
|
|
|
|
f.ID = id
|
|
|
|
return []byte{}, f.E
|
|
|
|
}
|
|
|
|
|
2015-01-08 20:41:38 +00:00
|
|
|
func (f *fakeContainerCommandRunner) ExecInContainer(id string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool) error {
|
|
|
|
f.Cmd = cmd
|
|
|
|
f.ID = id
|
|
|
|
f.Stdin = in
|
|
|
|
f.Stdout = out
|
|
|
|
f.Stderr = err
|
|
|
|
f.TTY = tty
|
|
|
|
return f.E
|
|
|
|
}
|
|
|
|
|
2015-04-06 23:58:34 +00:00
|
|
|
func (f *fakeContainerCommandRunner) PortForward(pod *kubecontainer.Pod, port uint16, stream io.ReadWriteCloser) error {
|
|
|
|
podInfraContainer := pod.FindContainerByName(dockertools.PodInfraContainerName)
|
|
|
|
if podInfraContainer == nil {
|
|
|
|
return fmt.Errorf("cannot find pod infra container in pod %q", kubecontainer.BuildPodFullName(pod.Name, pod.Namespace))
|
|
|
|
}
|
|
|
|
f.ID = string(podInfraContainer.ID)
|
2015-01-08 20:41:38 +00:00
|
|
|
f.Port = port
|
|
|
|
f.Stream = stream
|
|
|
|
return nil
|
|
|
|
}
|
2015-05-11 22:32:51 +00:00
|
|
|
|
2014-08-07 18:15:11 +00:00
|
|
|
func TestRunInContainerNoSuchPod(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
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"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2014-08-07 18:15:11 +00:00
|
|
|
containerName := "containerFoo"
|
|
|
|
output, err := kubelet.RunInContainer(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{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{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2014-08-07 18:15:11 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
containerID := "abc1234"
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2014-08-07 18:15:11 +00:00
|
|
|
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-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_" + containerName + "_" + podName + "_" + podNamespace + "_12345678_42"},
|
2014-08-07 18:15:11 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := []string{"ls"}
|
|
|
|
_, err := kubelet.RunInContainer(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{
|
2014-10-23 20:51:34 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
2014-10-08 19:56:02 +00:00
|
|
|
},
|
|
|
|
}),
|
2014-09-05 09:49:11 +00:00
|
|
|
"",
|
2014-08-07 18:15:11 +00:00
|
|
|
containerName,
|
|
|
|
cmd)
|
|
|
|
if fakeCommandRunner.ID != containerID {
|
2015-01-18 07:32:34 +00:00
|
|
|
t.Errorf("unexpected Name: %s", fakeCommandRunner.ID)
|
2014-08-07 18:15:11 +00:00
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(fakeCommandRunner.Cmd, cmd) {
|
2015-01-18 07:32:34 +00:00
|
|
|
t.Errorf("unexpected command: %s", fakeCommandRunner.Cmd)
|
2014-08-07 18:15:11 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-03 20:39:56 +00:00
|
|
|
func TestSyncPodEventHandlerFails(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-04-13 17:02:58 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-05-01 22:25:11 +00:00
|
|
|
// Simulate HTTP failure. Re-create the containerRuntime to inject the failure.
|
2014-09-03 20:39:56 +00:00
|
|
|
kubelet.httpClient = &fakeHTTP{
|
|
|
|
err: fmt.Errorf("test error"),
|
|
|
|
}
|
2015-05-01 01:37:15 +00:00
|
|
|
runtimeHooks := newKubeletRuntimeHooks(kubelet.recorder)
|
2015-05-01 22:25:11 +00:00
|
|
|
kubelet.containerRuntime = dockertools.NewFakeDockerManager(kubelet.dockerClient, kubelet.recorder, kubelet.readinessManager, kubelet.containerRefManager, dockertools.PodInfraContainerImage, 0, 0, "", kubelet.os, kubelet.networkPlugin, kubelet, kubelet.httpClient, runtimeHooks)
|
2015-04-13 17:02:58 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
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",
|
|
|
|
},
|
2014-09-03 20:39:56 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-09 21:55:36 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_42"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
},
|
|
|
|
}
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-09-03 20:39:56 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:02:58 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_image",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
2015-05-01 22:25:11 +00:00
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Create the container.
|
|
|
|
"create", "start",
|
|
|
|
// Kill the container since event handler fails.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
})
|
2015-04-13 17:02:58 +00:00
|
|
|
|
|
|
|
// TODO(yifan): Check the stopped container's name.
|
2014-09-09 04:33:17 +00:00
|
|
|
if len(fakeDocker.Stopped) != 1 {
|
2015-05-01 01:37:15 +00:00
|
|
|
t.Fatalf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
2014-09-03 20:39:56 +00:00
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
dockerName, _, err := dockertools.ParseDockerName(fakeDocker.Stopped[0])
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if dockerName.ContainerName != "bar" {
|
|
|
|
t.Errorf("Wrong stopped container, expected: bar, get: %q", dockerName.ContainerName)
|
|
|
|
}
|
2014-09-03 20:39:56 +00:00
|
|
|
}
|
2014-10-28 00:29:55 +00:00
|
|
|
|
2014-11-15 00:05:29 +00:00
|
|
|
func TestSyncPodsWithPullPolicy(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-05-01 22:25:11 +00:00
|
|
|
// TODO: Move this test to dockertools so that we don't have to do the hacky
|
|
|
|
// type assertion here.
|
|
|
|
dm := kubelet.containerRuntime.(*dockertools.DockerManager)
|
|
|
|
puller := dm.Puller.(*dockertools.FakeDockerPuller)
|
2014-11-15 00:05:29 +00:00
|
|
|
puller.HasImages = []string{"existing_one", "want:latest"}
|
2015-05-01 22:25:11 +00:00
|
|
|
dm.PodInfraContainerImage = "custom_image_name"
|
2014-11-15 00:05:29 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
2015-04-07 22:38:01 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2014-11-15 00:05:29 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
2014-11-15 00:05:29 +00:00
|
|
|
},
|
|
|
|
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},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-04-07 22:38:01 +00:00
|
|
|
}
|
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2014-11-15 00:05:29 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fakeDocker.Lock()
|
|
|
|
|
2015-03-10 14:09:55 +00:00
|
|
|
pulledImageSet := make(map[string]empty)
|
|
|
|
for v := range puller.ImagesPulled {
|
|
|
|
pulledImageSet[puller.ImagesPulled[v]] = empty{}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(pulledImageSet, map[string]empty{
|
|
|
|
"custom_image_name": {},
|
|
|
|
"pull_always_image": {},
|
|
|
|
"pull_if_not_present_image": {},
|
|
|
|
}) {
|
2014-11-15 00:05:29 +00:00
|
|
|
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
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-08 15:25:14 +00:00
|
|
|
|
|
|
|
type testServiceLister struct {
|
|
|
|
services []api.Service
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls testServiceLister) List() (api.ServiceList, error) {
|
|
|
|
return api.ServiceList{
|
|
|
|
Items: ls.services,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2015-03-20 16:52:32 +00:00
|
|
|
type testNodeLister struct {
|
|
|
|
nodes []api.Node
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls testNodeLister) GetNodeInfo(id string) (*api.Node, error) {
|
|
|
|
return nil, errors.New("not implemented")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ls testNodeLister) List() (api.NodeList, error) {
|
|
|
|
return api.NodeList{
|
|
|
|
Items: ls.nodes,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
type envs []kubecontainer.EnvVar
|
|
|
|
|
|
|
|
func (e envs) Len() int {
|
|
|
|
return len(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e envs) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
|
|
|
|
|
|
|
|
func (e envs) Less(i, j int) bool { return e[i].Name < e[j].Name }
|
|
|
|
|
2015-01-08 15:25:14 +00:00
|
|
|
func TestMakeEnvironmentVariables(t *testing.T) {
|
|
|
|
services := []api.Service{
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes", Namespace: api.NamespaceDefault},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8081,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes-ro", Namespace: api.NamespaceDefault},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8082,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.2",
|
|
|
|
},
|
|
|
|
},
|
2015-03-16 21:36:30 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes-ro", Namespace: api.NamespaceDefault},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8082,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
PortalIP: "None",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes-ro", Namespace: api.NamespaceDefault},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8082,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
PortalIP: "",
|
|
|
|
},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "test1"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8083,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.3",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes", Namespace: "test2"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8084,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.4",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "test2"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8085,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.5",
|
|
|
|
},
|
|
|
|
},
|
2015-03-16 21:36:30 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "test2"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8085,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
PortalIP: "None",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "test", Namespace: "test2"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8085,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes", Namespace: "kubernetes"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8086,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.6",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "kubernetes-ro", Namespace: "kubernetes"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8087,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.7",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "not-special", Namespace: "kubernetes"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8088,
|
|
|
|
}},
|
2015-01-08 15:25:14 +00:00
|
|
|
PortalIP: "1.2.3.8",
|
|
|
|
},
|
|
|
|
},
|
2015-03-16 21:36:30 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "not-special", Namespace: "kubernetes"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8088,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
PortalIP: "None",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "not-special", Namespace: "kubernetes"},
|
|
|
|
Spec: api.ServiceSpec{
|
2015-03-13 15:16:41 +00:00
|
|
|
Ports: []api.ServicePort{{
|
|
|
|
Protocol: "TCP",
|
|
|
|
Port: 8088,
|
|
|
|
}},
|
2015-03-16 21:36:30 +00:00
|
|
|
PortalIP: "",
|
|
|
|
},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
testCases := []struct {
|
2015-05-12 21:49:35 +00:00
|
|
|
name string // the name of the test case
|
|
|
|
ns string // the namespace to generate environment for
|
|
|
|
container *api.Container // the container to use
|
|
|
|
masterServiceNs string // the namespace to read master service info from
|
|
|
|
nilLister bool // whether the lister should be nil
|
|
|
|
expectedEnvs []kubecontainer.EnvVar // a set of expected environment vars
|
2015-01-08 15:25:14 +00:00
|
|
|
}{
|
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "api server = Y, kubelet = Y",
|
|
|
|
ns: "test1",
|
|
|
|
container: &api.Container{
|
2015-01-08 15:25:14 +00:00
|
|
|
Env: []api.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAR"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
|
|
|
|
},
|
|
|
|
},
|
2015-05-12 21:14:32 +00:00
|
|
|
masterServiceNs: api.NamespaceDefault,
|
|
|
|
nilLister: false,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAR"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_PORT", Value: "8081"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.1"},
|
|
|
|
{Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.1:8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP", Value: "tcp://1.2.3.1:8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_PORT", Value: "8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_ADDR", Value: "1.2.3.1"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_HOST", Value: "1.2.3.2"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_PORT", Value: "8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT", Value: "tcp://1.2.3.2:8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP", Value: "tcp://1.2.3.2:8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_PORT", Value: "8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_ADDR", Value: "1.2.3.2"},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
},
|
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "api server = Y, kubelet = N",
|
|
|
|
ns: "test1",
|
|
|
|
container: &api.Container{
|
2015-01-08 15:25:14 +00:00
|
|
|
Env: []api.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAR"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
|
|
|
|
},
|
|
|
|
},
|
2015-05-12 21:14:32 +00:00
|
|
|
masterServiceNs: api.NamespaceDefault,
|
|
|
|
nilLister: true,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAR"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
},
|
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "api server = N; kubelet = Y",
|
|
|
|
ns: "test1",
|
|
|
|
container: &api.Container{
|
2015-01-08 15:25:14 +00:00
|
|
|
Env: []api.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAZ"},
|
|
|
|
},
|
|
|
|
},
|
2015-05-12 21:14:32 +00:00
|
|
|
masterServiceNs: api.NamespaceDefault,
|
|
|
|
nilLister: false,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "FOO", Value: "BAZ"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
|
|
|
|
{Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.1"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_PORT", Value: "8081"},
|
|
|
|
{Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.1:8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP", Value: "tcp://1.2.3.1:8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_PORT", Value: "8081"},
|
|
|
|
{Name: "KUBERNETES_PORT_8081_TCP_ADDR", Value: "1.2.3.1"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_HOST", Value: "1.2.3.2"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_PORT", Value: "8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT", Value: "tcp://1.2.3.2:8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP", Value: "tcp://1.2.3.2:8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_PORT", Value: "8082"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8082_TCP_ADDR", Value: "1.2.3.2"},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
},
|
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "master service in pod ns",
|
|
|
|
ns: "test2",
|
|
|
|
container: &api.Container{
|
2015-01-08 15:25:14 +00:00
|
|
|
Env: []api.EnvVar{
|
|
|
|
{Name: "FOO", Value: "ZAP"},
|
|
|
|
},
|
|
|
|
},
|
2015-05-12 21:14:32 +00:00
|
|
|
masterServiceNs: "kubernetes",
|
|
|
|
nilLister: false,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "FOO", Value: "ZAP"},
|
|
|
|
{Name: "TEST_SERVICE_HOST", Value: "1.2.3.5"},
|
|
|
|
{Name: "TEST_SERVICE_PORT", Value: "8085"},
|
|
|
|
{Name: "TEST_PORT", Value: "tcp://1.2.3.5:8085"},
|
|
|
|
{Name: "TEST_PORT_8085_TCP", Value: "tcp://1.2.3.5:8085"},
|
|
|
|
{Name: "TEST_PORT_8085_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "TEST_PORT_8085_TCP_PORT", Value: "8085"},
|
|
|
|
{Name: "TEST_PORT_8085_TCP_ADDR", Value: "1.2.3.5"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.4"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_PORT", Value: "8084"},
|
|
|
|
{Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.4:8084"},
|
|
|
|
{Name: "KUBERNETES_PORT_8084_TCP", Value: "tcp://1.2.3.4:8084"},
|
|
|
|
{Name: "KUBERNETES_PORT_8084_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_PORT_8084_TCP_PORT", Value: "8084"},
|
|
|
|
{Name: "KUBERNETES_PORT_8084_TCP_ADDR", Value: "1.2.3.4"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_HOST", Value: "1.2.3.7"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_PORT", Value: "8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT", Value: "tcp://1.2.3.7:8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP", Value: "tcp://1.2.3.7:8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_PORT", Value: "8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_ADDR", Value: "1.2.3.7"},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
},
|
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "pod in master service ns",
|
|
|
|
ns: "kubernetes",
|
|
|
|
container: &api.Container{},
|
|
|
|
masterServiceNs: "kubernetes",
|
|
|
|
nilLister: false,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "NOT_SPECIAL_SERVICE_HOST", Value: "1.2.3.8"},
|
|
|
|
{Name: "NOT_SPECIAL_SERVICE_PORT", Value: "8088"},
|
|
|
|
{Name: "NOT_SPECIAL_PORT", Value: "tcp://1.2.3.8:8088"},
|
|
|
|
{Name: "NOT_SPECIAL_PORT_8088_TCP", Value: "tcp://1.2.3.8:8088"},
|
|
|
|
{Name: "NOT_SPECIAL_PORT_8088_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "NOT_SPECIAL_PORT_8088_TCP_PORT", Value: "8088"},
|
|
|
|
{Name: "NOT_SPECIAL_PORT_8088_TCP_ADDR", Value: "1.2.3.8"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.6"},
|
|
|
|
{Name: "KUBERNETES_SERVICE_PORT", Value: "8086"},
|
|
|
|
{Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.6:8086"},
|
|
|
|
{Name: "KUBERNETES_PORT_8086_TCP", Value: "tcp://1.2.3.6:8086"},
|
|
|
|
{Name: "KUBERNETES_PORT_8086_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_PORT_8086_TCP_PORT", Value: "8086"},
|
|
|
|
{Name: "KUBERNETES_PORT_8086_TCP_ADDR", Value: "1.2.3.6"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_HOST", Value: "1.2.3.7"},
|
|
|
|
{Name: "KUBERNETES_RO_SERVICE_PORT", Value: "8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT", Value: "tcp://1.2.3.7:8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP", Value: "tcp://1.2.3.7:8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_PROTO", Value: "tcp"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_PORT", Value: "8087"},
|
|
|
|
{Name: "KUBERNETES_RO_PORT_8087_TCP_ADDR", Value: "1.2.3.7"},
|
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
},
|
2015-04-23 20:57:30 +00:00
|
|
|
{
|
2015-05-12 21:14:32 +00:00
|
|
|
name: "downward api pod",
|
|
|
|
ns: "downward-api",
|
|
|
|
container: &api.Container{
|
2015-04-23 20:57:30 +00:00
|
|
|
Env: []api.EnvVar{
|
|
|
|
{
|
|
|
|
Name: "POD_NAME",
|
|
|
|
ValueFrom: &api.EnvVarSource{
|
2015-05-04 17:31:36 +00:00
|
|
|
FieldRef: &api.ObjectFieldSelector{
|
2015-04-23 20:57:30 +00:00
|
|
|
APIVersion: "v1beta3",
|
|
|
|
FieldPath: "metadata.name",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "POD_NAMESPACE",
|
|
|
|
ValueFrom: &api.EnvVarSource{
|
2015-05-04 17:31:36 +00:00
|
|
|
FieldRef: &api.ObjectFieldSelector{
|
2015-04-23 20:57:30 +00:00
|
|
|
APIVersion: "v1beta3",
|
|
|
|
FieldPath: "metadata.namespace",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-05-12 21:14:32 +00:00
|
|
|
masterServiceNs: "nothing",
|
|
|
|
nilLister: true,
|
2015-05-12 21:49:35 +00:00
|
|
|
expectedEnvs: []kubecontainer.EnvVar{
|
|
|
|
{Name: "POD_NAME", Value: "dapi-test-pod-name"},
|
|
|
|
{Name: "POD_NAMESPACE", Value: "downward-api"},
|
|
|
|
},
|
2015-04-23 20:57:30 +00:00
|
|
|
},
|
2015-01-08 15:25:14 +00:00
|
|
|
}
|
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
for i, tc := range testCases {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kl := testKubelet.kubelet
|
2015-05-12 21:14:32 +00:00
|
|
|
kl.masterServiceNamespace = tc.masterServiceNs
|
2015-01-08 15:25:14 +00:00
|
|
|
if tc.nilLister {
|
|
|
|
kl.serviceLister = nil
|
|
|
|
} else {
|
|
|
|
kl.serviceLister = testServiceLister{services}
|
|
|
|
}
|
|
|
|
|
2015-04-23 20:57:30 +00:00
|
|
|
testPod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Namespace: tc.ns,
|
|
|
|
Name: "dapi-test-pod-name",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := kl.makeEnvironmentVariables(testPod, tc.container)
|
2015-01-08 15:25:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("[%v] Unexpected error: %v", tc.name, err)
|
|
|
|
}
|
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
sort.Sort(envs(result))
|
|
|
|
sort.Sort(envs(tc.expectedEnvs))
|
2015-05-12 21:14:32 +00:00
|
|
|
|
2015-05-12 21:49:35 +00:00
|
|
|
if !reflect.DeepEqual(result, tc.expectedEnvs) {
|
|
|
|
t.Errorf("%d: [%v] Unexpected env entries; expected {%v}, got {%v}", i, tc.name, tc.expectedEnvs, result)
|
2015-01-08 15:25:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-28 17:56:35 +00:00
|
|
|
|
2015-03-25 11:09:35 +00:00
|
|
|
func runningState(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Running: &api.ContainerStateRunning{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func stoppedState(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Termination: &api.ContainerStateTerminated{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func succeededState(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Termination: &api.ContainerStateTerminated{
|
|
|
|
ExitCode: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func failedState(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Termination: &api.ContainerStateTerminated{
|
|
|
|
ExitCode: -1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-28 17:56:35 +00:00
|
|
|
func TestPodPhaseWithRestartAlways(t *testing.T) {
|
|
|
|
desiredState := api.PodSpec{
|
2015-04-02 12:52:03 +00:00
|
|
|
Host: "machine",
|
2015-01-28 17:56:35 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "containerA"},
|
|
|
|
{Name: "containerB"},
|
|
|
|
},
|
2015-03-14 01:38:07 +00:00
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
2015-01-28 17:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
pod *api.Pod
|
|
|
|
status api.PodPhase
|
|
|
|
test string
|
|
|
|
}{
|
2015-04-02 12:52:03 +00:00
|
|
|
{&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
|
2015-01-28 17:56:35 +00:00
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
runningState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"all running",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
stoppedState("containerA"),
|
|
|
|
stoppedState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"all stopped with restart always",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
stoppedState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"mixed state #1 with restart always",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodPending,
|
|
|
|
"mixed state #2 with restart always",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
2015-03-25 11:09:35 +00:00
|
|
|
if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
|
2015-01-28 17:56:35 +00:00
|
|
|
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPodPhaseWithRestartNever(t *testing.T) {
|
|
|
|
desiredState := api.PodSpec{
|
2015-04-02 12:52:03 +00:00
|
|
|
Host: "machine",
|
2015-01-28 17:56:35 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "containerA"},
|
|
|
|
{Name: "containerB"},
|
|
|
|
},
|
2015-03-14 01:38:07 +00:00
|
|
|
RestartPolicy: api.RestartPolicyNever,
|
2015-01-28 17:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
pod *api.Pod
|
|
|
|
status api.PodPhase
|
|
|
|
test string
|
|
|
|
}{
|
2015-04-02 12:52:03 +00:00
|
|
|
{&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
|
2015-01-28 17:56:35 +00:00
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
runningState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"all running with restart never",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
succeededState("containerA"),
|
|
|
|
succeededState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodSucceeded,
|
|
|
|
"all succeeded with restart never",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
failedState("containerA"),
|
|
|
|
failedState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodFailed,
|
|
|
|
"all failed with restart never",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
succeededState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"mixed state #1 with restart never",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodPending,
|
|
|
|
"mixed state #2 with restart never",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
2015-03-25 11:09:35 +00:00
|
|
|
if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
|
2015-01-28 17:56:35 +00:00
|
|
|
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPodPhaseWithRestartOnFailure(t *testing.T) {
|
|
|
|
desiredState := api.PodSpec{
|
2015-04-02 12:52:03 +00:00
|
|
|
Host: "machine",
|
2015-01-28 17:56:35 +00:00
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "containerA"},
|
|
|
|
{Name: "containerB"},
|
|
|
|
},
|
2015-03-14 01:38:07 +00:00
|
|
|
RestartPolicy: api.RestartPolicyOnFailure,
|
2015-01-28 17:56:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
pod *api.Pod
|
|
|
|
status api.PodPhase
|
|
|
|
test string
|
|
|
|
}{
|
2015-04-02 12:52:03 +00:00
|
|
|
{&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
|
2015-01-28 17:56:35 +00:00
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
runningState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"all running with restart onfailure",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
succeededState("containerA"),
|
|
|
|
succeededState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodSucceeded,
|
|
|
|
"all succeeded with restart onfailure",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
failedState("containerA"),
|
|
|
|
failedState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"all failed with restart never",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
|
|
|
succeededState("containerB"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodRunning,
|
|
|
|
"mixed state #1 with restart onfailure",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&api.Pod{
|
|
|
|
Spec: desiredState,
|
|
|
|
Status: api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: []api.ContainerStatus{
|
|
|
|
runningState("containerA"),
|
2015-01-28 17:56:35 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
api.PodPending,
|
|
|
|
"mixed state #2 with restart onfailure",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, test := range tests {
|
2015-03-25 11:09:35 +00:00
|
|
|
if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
|
2015-01-28 17:56:35 +00:00
|
|
|
t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-02-08 21:22:19 +00:00
|
|
|
|
2015-03-25 11:09:35 +00:00
|
|
|
func getReadyStatus(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
Ready: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func getNotReadyStatus(cName string) api.ContainerStatus {
|
|
|
|
return api.ContainerStatus{
|
|
|
|
Name: cName,
|
|
|
|
Ready: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-08 21:22:19 +00:00
|
|
|
func TestGetPodReadyCondition(t *testing.T) {
|
|
|
|
ready := []api.PodCondition{{
|
2015-02-24 05:21:14 +00:00
|
|
|
Type: api.PodReady,
|
2015-03-23 18:33:55 +00:00
|
|
|
Status: api.ConditionTrue,
|
2015-02-08 21:22:19 +00:00
|
|
|
}}
|
|
|
|
unready := []api.PodCondition{{
|
2015-02-24 05:21:14 +00:00
|
|
|
Type: api.PodReady,
|
2015-03-23 18:33:55 +00:00
|
|
|
Status: api.ConditionFalse,
|
2015-02-08 21:22:19 +00:00
|
|
|
}}
|
|
|
|
tests := []struct {
|
|
|
|
spec *api.PodSpec
|
2015-03-25 11:09:35 +00:00
|
|
|
info []api.ContainerStatus
|
2015-02-08 21:22:19 +00:00
|
|
|
expected []api.PodCondition
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
spec: nil,
|
|
|
|
info: nil,
|
|
|
|
expected: unready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{},
|
2015-02-08 21:22:19 +00:00
|
|
|
expected: ready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{},
|
2015-02-08 21:22:19 +00:00
|
|
|
expected: unready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{
|
|
|
|
getReadyStatus("1234"),
|
2015-02-08 21:22:19 +00:00
|
|
|
},
|
|
|
|
expected: ready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234"},
|
|
|
|
{Name: "5678"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{
|
|
|
|
getReadyStatus("1234"),
|
|
|
|
getReadyStatus("5678"),
|
2015-02-08 21:22:19 +00:00
|
|
|
},
|
|
|
|
expected: ready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234"},
|
|
|
|
{Name: "5678"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{
|
|
|
|
getReadyStatus("1234"),
|
2015-02-08 21:22:19 +00:00
|
|
|
},
|
|
|
|
expected: unready,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
spec: &api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234"},
|
|
|
|
{Name: "5678"},
|
|
|
|
},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
info: []api.ContainerStatus{
|
|
|
|
getReadyStatus("1234"),
|
|
|
|
getNotReadyStatus("5678"),
|
2015-02-08 21:22:19 +00:00
|
|
|
},
|
|
|
|
expected: unready,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
condition := getPodReadyCondition(test.spec, test.info)
|
|
|
|
if !reflect.DeepEqual(condition, test.expected) {
|
|
|
|
t.Errorf("On test case %v, expected:\n%+v\ngot\n%+v\n", i, test.expected, condition)
|
|
|
|
}
|
|
|
|
}
|
2015-01-08 20:41:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestExecInContainerNoSuchPod(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
containerName := "containerFoo"
|
|
|
|
err := kubelet.ExecInContainer(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
|
2015-01-08 20:41:38 +00:00
|
|
|
"",
|
|
|
|
containerName,
|
|
|
|
[]string{"ls"},
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("unexpected non-error")
|
|
|
|
}
|
|
|
|
if fakeCommandRunner.ID != "" {
|
|
|
|
t.Fatal("unexpected invocation of runner.ExecInContainer")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExecInContainerNoSuchContainer(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
containerID := "containerFoo"
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
ID: "notfound",
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_notfound_" + podName + "_" + podNamespace + "_12345678_42"},
|
2015-01-08 20:41:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := kubelet.ExecInContainer(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
2015-01-08 20:41:38 +00:00
|
|
|
}}),
|
|
|
|
"",
|
|
|
|
containerID,
|
|
|
|
[]string{"ls"},
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("unexpected non-error")
|
|
|
|
}
|
|
|
|
if fakeCommandRunner.ID != "" {
|
|
|
|
t.Fatal("unexpected invocation of runner.ExecInContainer")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakeReadWriteCloser struct{}
|
|
|
|
|
|
|
|
func (f *fakeReadWriteCloser) Write(data []byte) (int, error) {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeReadWriteCloser) Read(data []byte) (int, error) {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeReadWriteCloser) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExecInContainer(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
containerID := "containerFoo"
|
|
|
|
command := []string{"ls"}
|
|
|
|
stdin := &bytes.Buffer{}
|
|
|
|
stdout := &fakeReadWriteCloser{}
|
|
|
|
stderr := &fakeReadWriteCloser{}
|
|
|
|
tty := true
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
ID: containerID,
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_" + containerID + "_" + podName + "_" + podNamespace + "_12345678_42"},
|
2015-01-08 20:41:38 +00:00
|
|
|
},
|
|
|
|
}
|
2015-02-08 21:22:19 +00:00
|
|
|
|
2015-01-08 20:41:38 +00:00
|
|
|
err := kubelet.ExecInContainer(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
2015-01-08 20:41:38 +00:00
|
|
|
}}),
|
|
|
|
"",
|
|
|
|
containerID,
|
|
|
|
[]string{"ls"},
|
|
|
|
stdin,
|
|
|
|
stdout,
|
|
|
|
stderr,
|
|
|
|
tty,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
if e, a := containerID, fakeCommandRunner.ID; e != a {
|
|
|
|
t.Fatalf("container id: expected %s, got %s", e, a)
|
|
|
|
}
|
|
|
|
if e, a := command, fakeCommandRunner.Cmd; !reflect.DeepEqual(e, a) {
|
|
|
|
t.Fatalf("command: expected '%v', got '%v'", e, a)
|
|
|
|
}
|
|
|
|
if e, a := stdin, fakeCommandRunner.Stdin; e != a {
|
|
|
|
t.Fatalf("stdin: expected %#v, got %#v", e, a)
|
|
|
|
}
|
|
|
|
if e, a := stdout, fakeCommandRunner.Stdout; e != a {
|
|
|
|
t.Fatalf("stdout: expected %#v, got %#v", e, a)
|
|
|
|
}
|
|
|
|
if e, a := stderr, fakeCommandRunner.Stderr; e != a {
|
|
|
|
t.Fatalf("stderr: expected %#v, got %#v", e, a)
|
|
|
|
}
|
|
|
|
if e, a := tty, fakeCommandRunner.TTY; e != a {
|
|
|
|
t.Fatalf("tty: expected %t, got %t", e, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPortForwardNoSuchPod(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{}
|
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
var port uint16 = 5000
|
|
|
|
|
|
|
|
err := kubelet.PortForward(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
|
2015-01-08 20:41:38 +00:00
|
|
|
"",
|
|
|
|
port,
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("unexpected non-error")
|
|
|
|
}
|
|
|
|
if fakeCommandRunner.ID != "" {
|
|
|
|
t.Fatal("unexpected invocation of runner.PortForward")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPortForwardNoSuchContainer(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
var port uint16 = 5000
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
ID: "notfound",
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_notfound_" + podName + "_" + podNamespace + "_12345678_42"},
|
2015-01-08 20:41:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := kubelet.PortForward(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
2015-01-08 20:41:38 +00:00
|
|
|
}}),
|
|
|
|
"",
|
|
|
|
port,
|
|
|
|
nil,
|
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("unexpected non-error")
|
|
|
|
}
|
|
|
|
if fakeCommandRunner.ID != "" {
|
|
|
|
t.Fatal("unexpected invocation of runner.PortForward")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPortForward(t *testing.T) {
|
|
|
|
fakeCommandRunner := fakeContainerCommandRunner{}
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-01-08 20:41:38 +00:00
|
|
|
kubelet.runner = &fakeCommandRunner
|
|
|
|
|
|
|
|
podName := "podFoo"
|
2015-03-11 23:40:20 +00:00
|
|
|
podNamespace := "nsFoo"
|
2015-01-08 20:41:38 +00:00
|
|
|
containerID := "containerFoo"
|
|
|
|
var port uint16 = 5000
|
|
|
|
stream := &fakeReadWriteCloser{}
|
|
|
|
|
2015-04-09 01:56:58 +00:00
|
|
|
podInfraContainerImage := "POD"
|
2015-01-08 20:41:38 +00:00
|
|
|
infraContainerID := "infra"
|
2015-05-01 22:25:11 +00:00
|
|
|
// TODO: Move this test to dockertools so that we don't have to do the hacky
|
|
|
|
// type assertion here.
|
|
|
|
dm := kubelet.containerRuntime.(*dockertools.DockerManager)
|
|
|
|
dm.PodInfraContainerImage = podInfraContainerImage
|
2015-01-08 20:41:38 +00:00
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
ID: infraContainerID,
|
2015-04-09 01:56:58 +00:00
|
|
|
Names: []string{"/k8s_" + podInfraContainerImage + "_" + podName + "_" + podNamespace + "_12345678_42"},
|
2015-01-08 20:41:38 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: containerID,
|
2015-02-26 20:27:14 +00:00
|
|
|
Names: []string{"/k8s_" + containerID + "_" + podName + "_" + podNamespace + "_12345678_42"},
|
2015-01-08 20:41:38 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := kubelet.PortForward(
|
2015-03-23 17:14:30 +00:00
|
|
|
kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
|
2015-02-26 20:27:14 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
2015-01-08 20:41:38 +00:00
|
|
|
}}),
|
|
|
|
"",
|
|
|
|
port,
|
|
|
|
stream,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %s", err)
|
|
|
|
}
|
|
|
|
if e, a := infraContainerID, fakeCommandRunner.ID; e != a {
|
|
|
|
t.Fatalf("container id: expected %s, got %s", e, a)
|
|
|
|
}
|
|
|
|
if e, a := port, fakeCommandRunner.Port; e != a {
|
|
|
|
t.Fatalf("port: expected %v, got %v", e, a)
|
|
|
|
}
|
|
|
|
if e, a := stream, fakeCommandRunner.Stream; e != a {
|
|
|
|
t.Fatalf("stream: expected %v, got %v", e, a)
|
|
|
|
}
|
2015-02-08 21:22:19 +00:00
|
|
|
}
|
2015-02-27 21:43:21 +00:00
|
|
|
|
2015-03-03 18:33:25 +00:00
|
|
|
// Tests that identify the host port conflicts are detected correctly.
|
|
|
|
func TestGetHostPortConflicts(t *testing.T) {
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-03 18:33:25 +00:00
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 81}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 82}}}}}},
|
|
|
|
{Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 83}}}}}},
|
|
|
|
}
|
|
|
|
// Pods should not cause any conflict.
|
2015-03-20 16:52:32 +00:00
|
|
|
_, conflicts := checkHostPortConflicts(pods)
|
2015-03-03 18:33:25 +00:00
|
|
|
if len(conflicts) != 0 {
|
|
|
|
t.Errorf("expected no conflicts, Got %#v", conflicts)
|
|
|
|
}
|
2015-03-03 06:06:20 +00:00
|
|
|
|
2015-03-03 18:33:25 +00:00
|
|
|
// The new pod should cause conflict and be reported.
|
2015-04-03 22:51:50 +00:00
|
|
|
expected := &api.Pod{
|
2015-03-03 18:33:25 +00:00
|
|
|
Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 81}}}}},
|
|
|
|
}
|
|
|
|
pods = append(pods, expected)
|
2015-04-03 22:51:50 +00:00
|
|
|
if _, actual := checkHostPortConflicts(pods); !reflect.DeepEqual(actual, []*api.Pod{expected}) {
|
2015-03-03 18:33:25 +00:00
|
|
|
t.Errorf("expected %#v, Got %#v", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that we handle port conflicts correctly by setting the failed status in status map.
|
|
|
|
func TestHandlePortConflicts(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kl := testKubelet.kubelet
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-03-16 12:50:00 +00:00
|
|
|
|
2015-02-23 22:25:56 +00:00
|
|
|
spec := api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-02-27 21:43:21 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "123456789",
|
|
|
|
Name: "newpod",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: spec,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "987654321",
|
|
|
|
Name: "oldpod",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: spec,
|
|
|
|
},
|
|
|
|
}
|
2015-03-13 13:19:07 +00:00
|
|
|
// Make sure the Pods are in the reverse order of creation time.
|
2015-02-27 21:43:21 +00:00
|
|
|
pods[1].CreationTimestamp = util.NewTime(time.Now())
|
|
|
|
pods[0].CreationTimestamp = util.NewTime(time.Now().Add(1 * time.Second))
|
2015-03-03 18:33:25 +00:00
|
|
|
// The newer pod should be rejected.
|
2015-04-03 22:51:50 +00:00
|
|
|
conflictedPodName := kubecontainer.GetPodFullName(pods[0])
|
2015-03-03 18:33:25 +00:00
|
|
|
|
2015-03-20 16:52:32 +00:00
|
|
|
kl.handleNotFittingPods(pods)
|
2015-03-03 18:33:25 +00:00
|
|
|
// Check pod status stored in the status map.
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err := kl.GetPodStatus(conflictedPodName)
|
|
|
|
if err != nil {
|
2015-03-31 22:32:02 +00:00
|
|
|
t.Fatalf("status of pod %q is not found in the status map: %#v", conflictedPodName, err)
|
2015-03-03 18:33:25 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we can retrieve the pod status from GetPodStatus().
|
2015-03-21 00:22:02 +00:00
|
|
|
kl.podManager.SetPods(pods)
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err = kl.GetPodStatus(conflictedPodName)
|
2015-03-03 18:33:25 +00:00
|
|
|
if err != nil {
|
2015-03-20 16:37:08 +00:00
|
|
|
t.Fatalf("unable to retrieve pod status for pod %q: %#v.", conflictedPodName, err)
|
2015-03-03 18:33:25 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-20 16:52:32 +00:00
|
|
|
// Tests that we handle not matching labels selector correctly by setting the failed status in status map.
|
|
|
|
func TestHandleNodeSelector(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kl := testKubelet.kubelet
|
|
|
|
kl.nodeLister = testNodeLister{nodes: []api.Node{
|
|
|
|
{ObjectMeta: api.ObjectMeta{Name: "testnode", Labels: map[string]string{"key": "B"}}},
|
|
|
|
}}
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-20 16:52:32 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "123456789",
|
|
|
|
Name: "podA",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{NodeSelector: map[string]string{"key": "A"}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "987654321",
|
|
|
|
Name: "podB",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{NodeSelector: map[string]string{"key": "B"}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// The first pod should be rejected.
|
2015-04-03 22:51:50 +00:00
|
|
|
notfittingPodName := kubecontainer.GetPodFullName(pods[0])
|
2015-03-20 16:52:32 +00:00
|
|
|
|
|
|
|
kl.handleNotFittingPods(pods)
|
|
|
|
// Check pod status stored in the status map.
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err := kl.GetPodStatus(notfittingPodName)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("status of pod %q is not found in the status map: %#v", notfittingPodName, err)
|
2015-03-20 16:52:32 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we can retrieve the pod status from GetPodStatus().
|
2015-03-21 00:22:02 +00:00
|
|
|
kl.podManager.SetPods(pods)
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err = kl.GetPodStatus(notfittingPodName)
|
2015-03-20 16:52:32 +00:00
|
|
|
if err != nil {
|
2015-03-20 16:37:08 +00:00
|
|
|
t.Fatalf("unable to retrieve pod status for pod %q: %#v.", notfittingPodName, err)
|
2015-03-20 16:52:32 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 12:50:00 +00:00
|
|
|
// Tests that we handle exceeded resources correctly by setting the failed status in status map.
|
|
|
|
func TestHandleMemExceeded(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kl := testKubelet.kubelet
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{MemoryCapacity: 100}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-03-16 12:50:00 +00:00
|
|
|
|
|
|
|
spec := api.PodSpec{Containers: []api.Container{{Resources: api.ResourceRequirements{
|
|
|
|
Limits: api.ResourceList{
|
|
|
|
"memory": resource.MustParse("90"),
|
|
|
|
},
|
|
|
|
}}}}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-16 12:50:00 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "123456789",
|
|
|
|
Name: "newpod",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: spec,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "987654321",
|
|
|
|
Name: "oldpod",
|
|
|
|
Namespace: "foo",
|
|
|
|
},
|
|
|
|
Spec: spec,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// Make sure the Pods are in the reverse order of creation time.
|
|
|
|
pods[1].CreationTimestamp = util.NewTime(time.Now())
|
|
|
|
pods[0].CreationTimestamp = util.NewTime(time.Now().Add(1 * time.Second))
|
|
|
|
// The newer pod should be rejected.
|
2015-04-03 22:51:50 +00:00
|
|
|
notfittingPodName := kubecontainer.GetPodFullName(pods[0])
|
2015-03-16 12:50:00 +00:00
|
|
|
|
2015-03-20 16:52:32 +00:00
|
|
|
kl.handleNotFittingPods(pods)
|
2015-03-16 12:50:00 +00:00
|
|
|
// Check pod status stored in the status map.
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err := kl.GetPodStatus(notfittingPodName)
|
|
|
|
if err != nil {
|
2015-03-31 22:32:02 +00:00
|
|
|
t.Fatalf("status of pod %q is not found in the status map: %#v", notfittingPodName, err)
|
2015-03-16 12:50:00 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we can retrieve the pod status from GetPodStatus().
|
2015-03-21 00:22:02 +00:00
|
|
|
kl.podManager.SetPods(pods)
|
2015-03-20 16:37:08 +00:00
|
|
|
status, err = kl.GetPodStatus(notfittingPodName)
|
2015-03-16 12:50:00 +00:00
|
|
|
if err != nil {
|
2015-03-31 22:32:02 +00:00
|
|
|
t.Fatalf("unable to retrieve pod status for pod %q: %#v.", notfittingPodName, err)
|
2015-03-16 12:50:00 +00:00
|
|
|
}
|
|
|
|
if status.Phase != api.PodFailed {
|
|
|
|
t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-20 16:37:08 +00:00
|
|
|
// TODO(filipg): This test should be removed once StatusSyncer can do garbage collection without external signal.
|
2015-03-03 18:33:25 +00:00
|
|
|
func TestPurgingObsoleteStatusMapEntries(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-03-16 12:50:00 +00:00
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
kl := testKubelet.kubelet
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-20 16:37:08 +00:00
|
|
|
{ObjectMeta: api.ObjectMeta{Name: "pod1"}, Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
|
|
|
|
{ObjectMeta: api.ObjectMeta{Name: "pod2"}, Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
|
2015-03-03 18:33:25 +00:00
|
|
|
}
|
|
|
|
// Run once to populate the status map.
|
2015-03-20 16:52:32 +00:00
|
|
|
kl.handleNotFittingPods(pods)
|
2015-03-23 17:14:30 +00:00
|
|
|
if _, err := kl.GetPodStatus(kubecontainer.BuildPodFullName("pod2", "")); err != nil {
|
2015-03-20 16:37:08 +00:00
|
|
|
t.Fatalf("expected to have status cached for %q: %v", "pod2", err)
|
2015-02-27 21:43:21 +00:00
|
|
|
}
|
2015-03-03 18:33:25 +00:00
|
|
|
// Sync with empty pods so that the entry in status map will be removed.
|
2015-04-20 18:20:53 +00:00
|
|
|
kl.SyncPods([]*api.Pod{}, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2015-03-23 17:14:30 +00:00
|
|
|
if _, err := kl.GetPodStatus(kubecontainer.BuildPodFullName("pod2", "")); err == nil {
|
2015-03-20 16:37:08 +00:00
|
|
|
t.Fatalf("expected to not have status cached for %q: %v", "pod2", err)
|
2015-02-27 21:43:21 +00:00
|
|
|
}
|
2015-02-24 00:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestValidatePodStatus(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2015-02-24 00:33:43 +00:00
|
|
|
testCases := []struct {
|
|
|
|
podPhase api.PodPhase
|
|
|
|
success bool
|
|
|
|
}{
|
|
|
|
{api.PodRunning, true},
|
|
|
|
{api.PodSucceeded, true},
|
|
|
|
{api.PodFailed, true},
|
|
|
|
{api.PodPending, false},
|
|
|
|
{api.PodUnknown, false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tc := range testCases {
|
|
|
|
err := kubelet.validatePodPhase(&api.PodStatus{Phase: tc.podPhase})
|
|
|
|
if tc.success {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("[case %d]: unexpected failure - %v", i, err)
|
|
|
|
}
|
|
|
|
} else if err == nil {
|
|
|
|
t.Errorf("[case %d]: unexpected success", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestValidateContainerStatus(t *testing.T) {
|
2015-02-23 21:04:45 +00:00
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
2015-02-24 00:33:43 +00:00
|
|
|
containerName := "x"
|
|
|
|
testCases := []struct {
|
2015-03-25 11:09:35 +00:00
|
|
|
statuses []api.ContainerStatus
|
|
|
|
success bool
|
2015-02-24 00:33:43 +00:00
|
|
|
}{
|
|
|
|
{
|
2015-03-25 11:09:35 +00:00
|
|
|
statuses: []api.ContainerStatus{
|
|
|
|
{
|
|
|
|
Name: containerName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Running: &api.ContainerStateRunning{},
|
|
|
|
},
|
2015-05-07 18:34:16 +00:00
|
|
|
LastTerminationState: api.ContainerState{
|
|
|
|
Termination: &api.ContainerStateTerminated{},
|
|
|
|
},
|
2015-03-25 11:09:35 +00:00
|
|
|
},
|
|
|
|
},
|
2015-02-24 00:33:43 +00:00
|
|
|
success: true,
|
|
|
|
},
|
|
|
|
{
|
2015-03-25 11:09:35 +00:00
|
|
|
statuses: []api.ContainerStatus{
|
|
|
|
{
|
|
|
|
Name: containerName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Termination: &api.ContainerStateTerminated{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-24 00:33:43 +00:00
|
|
|
success: true,
|
|
|
|
},
|
|
|
|
{
|
2015-03-25 11:09:35 +00:00
|
|
|
statuses: []api.ContainerStatus{
|
|
|
|
{
|
|
|
|
Name: containerName,
|
|
|
|
State: api.ContainerState{
|
|
|
|
Waiting: &api.ContainerStateWaiting{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-02-24 00:33:43 +00:00
|
|
|
success: false,
|
|
|
|
},
|
|
|
|
}
|
2015-02-27 21:43:21 +00:00
|
|
|
|
2015-02-24 00:33:43 +00:00
|
|
|
for i, tc := range testCases {
|
|
|
|
_, err := kubelet.validateContainerStatus(&api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: tc.statuses,
|
2015-05-07 18:34:16 +00:00
|
|
|
}, containerName, false)
|
2015-02-24 00:33:43 +00:00
|
|
|
if tc.success {
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("[case %d]: unexpected failure - %v", i, err)
|
|
|
|
}
|
|
|
|
} else if err == nil {
|
|
|
|
t.Errorf("[case %d]: unexpected success", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if _, err := kubelet.validateContainerStatus(&api.PodStatus{
|
2015-03-25 11:09:35 +00:00
|
|
|
ContainerStatuses: testCases[0].statuses,
|
2015-05-07 18:34:16 +00:00
|
|
|
}, "blah", false); err == nil {
|
2015-02-24 00:33:43 +00:00
|
|
|
t.Errorf("expected error with invalid container name")
|
|
|
|
}
|
2015-05-07 18:34:16 +00:00
|
|
|
if _, err := kubelet.validateContainerStatus(&api.PodStatus{
|
|
|
|
ContainerStatuses: testCases[0].statuses,
|
|
|
|
}, containerName, true); err != nil {
|
|
|
|
t.Errorf("unexpected error with for previous terminated container - %v", err)
|
|
|
|
}
|
|
|
|
if _, err := kubelet.validateContainerStatus(&api.PodStatus{
|
|
|
|
ContainerStatuses: testCases[1].statuses,
|
|
|
|
}, containerName, true); err == nil {
|
|
|
|
t.Errorf("expected error with for previous terminated container")
|
|
|
|
}
|
2015-02-27 21:43:21 +00:00
|
|
|
}
|
2015-02-23 21:04:45 +00:00
|
|
|
|
|
|
|
func TestUpdateNewNodeStatus(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
kubeClient := testKubelet.fakeKubeClient
|
2015-04-06 23:27:53 +00:00
|
|
|
kubeClient.ReactFn = testclient.NewSimpleFake(&api.NodeList{Items: []api.Node{
|
2015-02-23 21:04:45 +00:00
|
|
|
{ObjectMeta: api.ObjectMeta{Name: "testnode"}},
|
2015-04-06 23:27:53 +00:00
|
|
|
}}).ReactFn
|
2015-03-23 16:30:45 +00:00
|
|
|
machineInfo := &cadvisorApi.MachineInfo{
|
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
NumCores: 2,
|
|
|
|
MemoryCapacity: 1024,
|
|
|
|
}
|
2015-04-06 23:27:53 +00:00
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-02-23 21:04:45 +00:00
|
|
|
mockCadvisor.On("MachineInfo").Return(machineInfo, nil)
|
2015-03-31 07:22:37 +00:00
|
|
|
versionInfo := &cadvisorApi.VersionInfo{
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
ContainerOsVersion: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
DockerVersion: "1.5.0",
|
|
|
|
}
|
|
|
|
mockCadvisor.On("VersionInfo").Return(versionInfo, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
expectedNode := &api.Node{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "testnode"},
|
2015-03-25 13:44:40 +00:00
|
|
|
Spec: api.NodeSpec{},
|
2015-02-23 21:04:45 +00:00
|
|
|
Status: api.NodeStatus{
|
|
|
|
Conditions: []api.NodeCondition{
|
|
|
|
{
|
2015-03-20 17:35:41 +00:00
|
|
|
Type: api.NodeReady,
|
2015-03-23 18:33:55 +00:00
|
|
|
Status: api.ConditionTrue,
|
2015-03-20 17:35:41 +00:00
|
|
|
Reason: fmt.Sprintf("kubelet is posting ready status"),
|
2015-03-27 14:09:51 +00:00
|
|
|
LastHeartbeatTime: util.Time{},
|
2015-03-20 17:35:41 +00:00
|
|
|
LastTransitionTime: util.Time{},
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
NodeInfo: api.NodeSystemInfo{
|
2015-03-31 07:22:37 +00:00
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
OsImage: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
ContainerRuntimeVersion: "docker://1.5.0",
|
|
|
|
KubeletVersion: version.Get().String(),
|
|
|
|
KubeProxyVersion: version.Get().String(),
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
2015-03-25 13:44:40 +00:00
|
|
|
Capacity: api.ResourceList{
|
|
|
|
api.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
|
|
|
|
api.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
|
|
|
|
},
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-05-05 10:19:54 +00:00
|
|
|
kubelet.updateRuntimeUp()
|
2015-02-23 21:04:45 +00:00
|
|
|
if err := kubelet.updateNodeStatus(); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-04-08 09:32:47 +00:00
|
|
|
if len(kubeClient.Actions) != 2 || kubeClient.Actions[1].Action != "update-status-node" {
|
2015-04-06 23:27:53 +00:00
|
|
|
t.Fatalf("unexpected actions: %v", kubeClient.Actions)
|
2015-02-23 21:04:45 +00:00
|
|
|
}
|
|
|
|
updatedNode, ok := kubeClient.Actions[1].Value.(*api.Node)
|
|
|
|
if !ok {
|
|
|
|
t.Errorf("unexpected object type")
|
|
|
|
}
|
2015-03-27 14:09:51 +00:00
|
|
|
if updatedNode.Status.Conditions[0].LastHeartbeatTime.IsZero() {
|
2015-02-23 21:04:45 +00:00
|
|
|
t.Errorf("unexpected zero last probe timestamp")
|
|
|
|
}
|
2015-03-20 17:35:41 +00:00
|
|
|
if updatedNode.Status.Conditions[0].LastTransitionTime.IsZero() {
|
|
|
|
t.Errorf("unexpected zero last transition timestamp")
|
|
|
|
}
|
2015-03-27 14:09:51 +00:00
|
|
|
updatedNode.Status.Conditions[0].LastHeartbeatTime = util.Time{}
|
2015-03-20 17:35:41 +00:00
|
|
|
updatedNode.Status.Conditions[0].LastTransitionTime = util.Time{}
|
2015-02-23 21:04:45 +00:00
|
|
|
if !reflect.DeepEqual(expectedNode, updatedNode) {
|
2015-04-06 23:27:53 +00:00
|
|
|
t.Errorf("unexpected objects: %s", util.ObjectDiff(expectedNode, updatedNode))
|
2015-02-23 21:04:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateExistingNodeStatus(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
kubeClient := testKubelet.fakeKubeClient
|
2015-04-06 23:27:53 +00:00
|
|
|
kubeClient.ReactFn = testclient.NewSimpleFake(&api.NodeList{Items: []api.Node{
|
2015-02-23 21:04:45 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "testnode"},
|
2015-03-25 13:44:40 +00:00
|
|
|
Spec: api.NodeSpec{},
|
2015-02-23 21:04:45 +00:00
|
|
|
Status: api.NodeStatus{
|
|
|
|
Conditions: []api.NodeCondition{
|
|
|
|
{
|
2015-03-20 17:35:41 +00:00
|
|
|
Type: api.NodeReady,
|
2015-03-23 18:33:55 +00:00
|
|
|
Status: api.ConditionTrue,
|
2015-03-20 17:35:41 +00:00
|
|
|
Reason: fmt.Sprintf("kubelet is posting ready status"),
|
2015-03-27 14:09:51 +00:00
|
|
|
LastHeartbeatTime: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC),
|
2015-03-20 17:35:41 +00:00
|
|
|
LastTransitionTime: util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC),
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
},
|
2015-03-25 13:44:40 +00:00
|
|
|
Capacity: api.ResourceList{
|
|
|
|
api.ResourceCPU: *resource.NewMilliQuantity(3000, resource.DecimalSI),
|
|
|
|
api.ResourceMemory: *resource.NewQuantity(2048, resource.BinarySI),
|
|
|
|
},
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
},
|
2015-04-06 23:27:53 +00:00
|
|
|
}}).ReactFn
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
2015-03-23 16:30:45 +00:00
|
|
|
machineInfo := &cadvisorApi.MachineInfo{
|
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
NumCores: 2,
|
|
|
|
MemoryCapacity: 1024,
|
|
|
|
}
|
2015-02-23 21:04:45 +00:00
|
|
|
mockCadvisor.On("MachineInfo").Return(machineInfo, nil)
|
2015-03-31 07:22:37 +00:00
|
|
|
versionInfo := &cadvisorApi.VersionInfo{
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
ContainerOsVersion: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
DockerVersion: "1.5.0",
|
|
|
|
}
|
|
|
|
mockCadvisor.On("VersionInfo").Return(versionInfo, nil)
|
2015-02-23 21:04:45 +00:00
|
|
|
expectedNode := &api.Node{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "testnode"},
|
2015-03-25 13:44:40 +00:00
|
|
|
Spec: api.NodeSpec{},
|
2015-02-23 21:04:45 +00:00
|
|
|
Status: api.NodeStatus{
|
|
|
|
Conditions: []api.NodeCondition{
|
|
|
|
{
|
2015-03-20 17:35:41 +00:00
|
|
|
Type: api.NodeReady,
|
2015-03-23 18:33:55 +00:00
|
|
|
Status: api.ConditionTrue,
|
2015-03-20 17:35:41 +00:00
|
|
|
Reason: fmt.Sprintf("kubelet is posting ready status"),
|
2015-03-27 14:09:51 +00:00
|
|
|
LastHeartbeatTime: util.Time{}, // placeholder
|
2015-03-20 17:35:41 +00:00
|
|
|
LastTransitionTime: util.Time{}, // placeholder
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
NodeInfo: api.NodeSystemInfo{
|
2015-03-31 07:22:37 +00:00
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
OsImage: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
ContainerRuntimeVersion: "docker://1.5.0",
|
|
|
|
KubeletVersion: version.Get().String(),
|
|
|
|
KubeProxyVersion: version.Get().String(),
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
2015-03-25 13:44:40 +00:00
|
|
|
Capacity: api.ResourceList{
|
|
|
|
api.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
|
|
|
|
api.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
|
|
|
|
},
|
2015-02-23 21:04:45 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-05-05 10:19:54 +00:00
|
|
|
kubelet.updateRuntimeUp()
|
2015-02-23 21:04:45 +00:00
|
|
|
if err := kubelet.updateNodeStatus(); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if len(kubeClient.Actions) != 2 {
|
|
|
|
t.Errorf("unexpected actions: %v", kubeClient.Actions)
|
|
|
|
}
|
|
|
|
updatedNode, ok := kubeClient.Actions[1].Value.(*api.Node)
|
|
|
|
if !ok {
|
|
|
|
t.Errorf("unexpected object type")
|
|
|
|
}
|
2015-03-20 17:35:41 +00:00
|
|
|
// Expect LastProbeTime to be updated to Now, while LastTransitionTime to be the same.
|
2015-03-27 14:09:51 +00:00
|
|
|
if reflect.DeepEqual(updatedNode.Status.Conditions[0].LastHeartbeatTime.Rfc3339Copy().UTC(), util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC).Time) {
|
2015-03-20 17:35:41 +00:00
|
|
|
t.Errorf("expected \n%v\n, got \n%v", util.Now(), util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC))
|
|
|
|
}
|
2015-04-06 23:27:53 +00:00
|
|
|
if !reflect.DeepEqual(updatedNode.Status.Conditions[0].LastTransitionTime.Rfc3339Copy().UTC(), util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC).Time) {
|
|
|
|
t.Errorf("expected \n%#v\n, got \n%#v", updatedNode.Status.Conditions[0].LastTransitionTime.Rfc3339Copy(),
|
2015-02-23 21:04:45 +00:00
|
|
|
util.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC))
|
|
|
|
}
|
2015-03-27 14:09:51 +00:00
|
|
|
updatedNode.Status.Conditions[0].LastHeartbeatTime = util.Time{}
|
2015-03-20 17:35:41 +00:00
|
|
|
updatedNode.Status.Conditions[0].LastTransitionTime = util.Time{}
|
2015-02-23 21:04:45 +00:00
|
|
|
if !reflect.DeepEqual(expectedNode, updatedNode) {
|
|
|
|
t.Errorf("expected \n%v\n, got \n%v", expectedNode, updatedNode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-05 10:19:54 +00:00
|
|
|
func TestUpdateNodeStatusWithoutContainerRuntime(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
kubeClient := testKubelet.fakeKubeClient
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
// This causes returning an error from GetContainerRuntimeVersion() which
|
|
|
|
// simulates that container runtime is down.
|
|
|
|
fakeDocker.VersionInfo = []string{}
|
|
|
|
|
|
|
|
kubeClient.ReactFn = testclient.NewSimpleFake(&api.NodeList{Items: []api.Node{
|
|
|
|
{ObjectMeta: api.ObjectMeta{Name: "testnode"}},
|
|
|
|
}}).ReactFn
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
|
|
|
machineInfo := &cadvisorApi.MachineInfo{
|
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
NumCores: 2,
|
|
|
|
MemoryCapacity: 1024,
|
|
|
|
}
|
|
|
|
mockCadvisor.On("MachineInfo").Return(machineInfo, nil)
|
|
|
|
versionInfo := &cadvisorApi.VersionInfo{
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
ContainerOsVersion: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
DockerVersion: "1.5.0",
|
|
|
|
}
|
|
|
|
mockCadvisor.On("VersionInfo").Return(versionInfo, nil)
|
|
|
|
|
|
|
|
expectedNode := &api.Node{
|
|
|
|
ObjectMeta: api.ObjectMeta{Name: "testnode"},
|
|
|
|
Spec: api.NodeSpec{},
|
|
|
|
Status: api.NodeStatus{
|
|
|
|
Conditions: []api.NodeCondition{
|
|
|
|
{
|
|
|
|
Type: api.NodeReady,
|
|
|
|
Status: api.ConditionFalse,
|
|
|
|
Reason: fmt.Sprintf("container runtime is down"),
|
|
|
|
LastHeartbeatTime: util.Time{},
|
|
|
|
LastTransitionTime: util.Time{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
NodeInfo: api.NodeSystemInfo{
|
|
|
|
MachineID: "123",
|
|
|
|
SystemUUID: "abc",
|
|
|
|
BootID: "1b3",
|
|
|
|
KernelVersion: "3.16.0-0.bpo.4-amd64",
|
|
|
|
OsImage: "Debian GNU/Linux 7 (wheezy)",
|
|
|
|
ContainerRuntimeVersion: "docker://1.5.0",
|
|
|
|
KubeletVersion: version.Get().String(),
|
|
|
|
KubeProxyVersion: version.Get().String(),
|
|
|
|
},
|
|
|
|
Capacity: api.ResourceList{
|
|
|
|
api.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
|
|
|
|
api.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
kubelet.runtimeUpThreshold = time.Duration(0)
|
|
|
|
kubelet.updateRuntimeUp()
|
|
|
|
if err := kubelet.updateNodeStatus(); err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if len(kubeClient.Actions) != 2 || kubeClient.Actions[1].Action != "update-status-node" {
|
|
|
|
t.Fatalf("unexpected actions: %v", kubeClient.Actions)
|
|
|
|
}
|
|
|
|
updatedNode, ok := kubeClient.Actions[1].Value.(*api.Node)
|
|
|
|
if !ok {
|
|
|
|
t.Errorf("unexpected object type")
|
|
|
|
}
|
|
|
|
|
|
|
|
if updatedNode.Status.Conditions[0].LastHeartbeatTime.IsZero() {
|
|
|
|
t.Errorf("unexpected zero last probe timestamp")
|
|
|
|
}
|
|
|
|
if updatedNode.Status.Conditions[0].LastTransitionTime.IsZero() {
|
|
|
|
t.Errorf("unexpected zero last transition timestamp")
|
|
|
|
}
|
|
|
|
updatedNode.Status.Conditions[0].LastHeartbeatTime = util.Time{}
|
|
|
|
updatedNode.Status.Conditions[0].LastTransitionTime = util.Time{}
|
|
|
|
if !reflect.DeepEqual(expectedNode, updatedNode) {
|
|
|
|
t.Errorf("unexpected objects: %s", util.ObjectDiff(expectedNode, updatedNode))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-23 21:04:45 +00:00
|
|
|
func TestUpdateNodeStatusError(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
// No matching node for the kubelet
|
2015-04-06 23:27:53 +00:00
|
|
|
testKubelet.fakeKubeClient.ReactFn = testclient.NewSimpleFake(&api.NodeList{Items: []api.Node{}}).ReactFn
|
2015-02-23 21:04:45 +00:00
|
|
|
|
|
|
|
if err := kubelet.updateNodeStatus(); err == nil {
|
2015-03-31 22:32:02 +00:00
|
|
|
t.Errorf("unexpected non error: %v", err)
|
2015-02-23 21:04:45 +00:00
|
|
|
}
|
2015-04-06 23:27:53 +00:00
|
|
|
if len(testKubelet.fakeKubeClient.Actions) != nodeStatusUpdateRetry {
|
|
|
|
t.Errorf("unexpected actions: %v", testKubelet.fakeKubeClient.Actions)
|
2015-02-23 21:04:45 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-09 22:46:47 +00:00
|
|
|
|
|
|
|
func TestCreateMirrorPod(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kl := testKubelet.kubelet
|
2015-03-23 19:17:12 +00:00
|
|
|
manager := testKubelet.fakeMirrorClient
|
2015-04-03 22:51:50 +00:00
|
|
|
pod := &api.Pod{
|
2015-03-09 22:46:47 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "bar",
|
|
|
|
Namespace: "foo",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "file",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{pod}
|
2015-03-21 00:22:02 +00:00
|
|
|
kl.podManager.SetPods(pods)
|
2015-04-03 22:51:50 +00:00
|
|
|
err := kl.syncPod(pod, nil, container.Pod{})
|
2015-03-09 22:46:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
podFullName := kubecontainer.GetPodFullName(pod)
|
2015-03-09 22:46:47 +00:00
|
|
|
if !manager.HasPod(podFullName) {
|
|
|
|
t.Errorf("expected mirror pod %q to be created", podFullName)
|
|
|
|
}
|
|
|
|
if manager.NumOfPods() != 1 || !manager.HasPod(podFullName) {
|
|
|
|
t.Errorf("expected one mirror pod %q, got %v", podFullName, manager.GetPods())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 20:28:33 +00:00
|
|
|
func TestDeleteOutdatedMirrorPod(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-04-08 20:28:33 +00:00
|
|
|
kl := testKubelet.kubelet
|
|
|
|
manager := testKubelet.fakeMirrorClient
|
2015-04-03 22:51:50 +00:00
|
|
|
pod := &api.Pod{
|
2015-04-08 20:28:33 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "file",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234", Image: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
// Mirror pod has an outdated spec.
|
2015-04-03 22:51:50 +00:00
|
|
|
mirrorPod := &api.Pod{
|
2015-04-08 20:28:33 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "11111111",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "api",
|
|
|
|
ConfigMirrorAnnotationKey: "mirror",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "1234", Image: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{pod, mirrorPod}
|
2015-04-08 20:28:33 +00:00
|
|
|
kl.podManager.SetPods(pods)
|
2015-04-03 22:51:50 +00:00
|
|
|
err := kl.syncPod(pod, mirrorPod, container.Pod{})
|
2015-04-08 20:28:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
name := kubecontainer.GetPodFullName(pod)
|
2015-04-08 20:28:33 +00:00
|
|
|
creates, deletes := manager.GetCounts(name)
|
|
|
|
if creates != 0 || deletes != 1 {
|
|
|
|
t.Errorf("expected 0 creation and 1 deletion of %q, got %d, %d", name, creates, deletes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-09 22:46:47 +00:00
|
|
|
func TestDeleteOrphanedMirrorPods(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
2015-03-16 12:50:00 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-03-09 22:46:47 +00:00
|
|
|
kl := testKubelet.kubelet
|
2015-03-23 19:17:12 +00:00
|
|
|
manager := testKubelet.fakeMirrorClient
|
2015-04-03 22:51:50 +00:00
|
|
|
orphanPods := []*api.Pod{
|
2015-03-20 20:55:26 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "pod1",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "api",
|
|
|
|
ConfigMirrorAnnotationKey: "mirror",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345679",
|
|
|
|
Name: "pod2",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "api",
|
|
|
|
ConfigMirrorAnnotationKey: "mirror",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-03-23 19:17:12 +00:00
|
|
|
kl.podManager.SetPods(orphanPods)
|
|
|
|
pods, mirrorMap := kl.podManager.GetPodsAndMirrorMap()
|
2015-03-09 22:46:47 +00:00
|
|
|
// Sync with an empty pod list to delete all mirror pods.
|
2015-03-23 19:17:12 +00:00
|
|
|
err := kl.SyncPods(pods, emptyPodUIDs, mirrorMap, time.Now())
|
2015-03-09 22:46:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if manager.NumOfPods() != 0 {
|
|
|
|
t.Errorf("expected zero mirror pods, got %v", manager.GetPods())
|
|
|
|
}
|
2015-03-20 20:55:26 +00:00
|
|
|
for _, pod := range orphanPods {
|
2015-04-03 22:51:50 +00:00
|
|
|
name := kubecontainer.GetPodFullName(pod)
|
2015-03-09 22:46:47 +00:00
|
|
|
creates, deletes := manager.GetCounts(name)
|
|
|
|
if creates != 0 || deletes != 1 {
|
|
|
|
t.Errorf("expected 0 creation and one deletion of %q, got %d, %d", name, creates, deletes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-20 20:55:26 +00:00
|
|
|
|
|
|
|
func TestGetContainerInfoForMirrorPods(t *testing.T) {
|
|
|
|
// pods contain one static and one mirror pod with the same name but
|
|
|
|
// different UIDs.
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-20 20:55:26 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "1234",
|
|
|
|
Name: "qux",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "file",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "5678",
|
|
|
|
Name: "qux",
|
|
|
|
Namespace: "ns",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "api",
|
|
|
|
ConfigMirrorAnnotationKey: "mirror",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
containerID := "ab2cdf"
|
|
|
|
containerPath := fmt.Sprintf("/docker/%v", containerID)
|
|
|
|
containerInfo := cadvisorApi.ContainerInfo{
|
|
|
|
ContainerReference: cadvisorApi.ContainerReference{
|
|
|
|
Name: containerPath,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
mockCadvisor := testKubelet.fakeCadvisor
|
|
|
|
cadvisorReq := &cadvisorApi.ContainerInfoRequest{}
|
|
|
|
mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)
|
|
|
|
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
ID: containerID,
|
|
|
|
Names: []string{"/k8s_foo_qux_ns_1234_42"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-03-21 00:22:02 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-03-20 20:55:26 +00:00
|
|
|
// Use the mirror pod UID to retrieve the stats.
|
|
|
|
stats, err := kubelet.GetContainerInfo("qux_ns", "5678", "foo", cadvisorReq)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if stats == nil {
|
|
|
|
t.Fatalf("stats should not be nil")
|
|
|
|
}
|
|
|
|
mockCadvisor.AssertExpectations(t)
|
|
|
|
}
|
2015-03-24 23:52:38 +00:00
|
|
|
|
|
|
|
func TestDoNotCacheStatusForStaticPods(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-03-24 23:52:38 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-03-24 23:52:38 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: "file",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2015-03-24 23:52:38 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
podFullName := kubecontainer.GetPodFullName(pods[0])
|
2015-03-24 23:52:38 +00:00
|
|
|
status, ok := kubelet.statusManager.GetPodStatus(podFullName)
|
|
|
|
if ok {
|
|
|
|
t.Errorf("unexpected status %#v found for static pod %q", status, podFullName)
|
|
|
|
}
|
|
|
|
}
|
2015-03-24 23:09:16 +00:00
|
|
|
|
|
|
|
func TestHostNetworkAllowed(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
|
|
|
|
capabilities.SetForTests(capabilities.Capabilities{
|
|
|
|
HostNetworkSources: []string{ApiserverSource, FileSource},
|
|
|
|
})
|
|
|
|
pod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: FileSource,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
HostNetwork: true,
|
|
|
|
},
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
kubelet.podManager.SetPods([]*api.Pod{pod})
|
2015-03-26 00:36:04 +00:00
|
|
|
err := kubelet.syncPod(pod, nil, container.Pod{})
|
2015-03-24 23:09:16 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("expected pod infra creation to succeed: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestHostNetworkDisallowed(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
|
|
|
|
capabilities.SetForTests(capabilities.Capabilities{
|
|
|
|
HostNetworkSources: []string{},
|
|
|
|
})
|
|
|
|
pod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
Annotations: map[string]string{
|
|
|
|
ConfigSourceAnnotationKey: FileSource,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo"},
|
|
|
|
},
|
|
|
|
HostNetwork: true,
|
|
|
|
},
|
|
|
|
}
|
2015-03-26 00:36:04 +00:00
|
|
|
err := kubelet.syncPod(pod, nil, container.Pod{})
|
2015-03-24 23:09:16 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected pod infra creation to fail")
|
|
|
|
}
|
|
|
|
}
|
2015-04-08 02:03:43 +00:00
|
|
|
|
2015-05-09 21:17:36 +00:00
|
|
|
func TestPrivilegeContainerAllowed(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
|
|
|
|
capabilities.SetForTests(capabilities.Capabilities{
|
|
|
|
AllowPrivileged: true,
|
|
|
|
})
|
|
|
|
privileged := true
|
|
|
|
pod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo", SecurityContext: &api.SecurityContext{Privileged: &privileged}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
kubelet.podManager.SetPods([]*api.Pod{pod})
|
|
|
|
err := kubelet.syncPod(pod, nil, container.Pod{})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("expected pod infra creation to succeed: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPrivilegeContainerDisallowed(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
|
|
|
|
capabilities.SetForTests(capabilities.Capabilities{
|
|
|
|
AllowPrivileged: false,
|
|
|
|
})
|
|
|
|
privileged := true
|
|
|
|
pod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{
|
|
|
|
{Name: "foo", SecurityContext: &api.SecurityContext{Privileged: &privileged}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err := kubelet.syncPod(pod, nil, container.Pod{})
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected pod infra creation to fail")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 02:03:43 +00:00
|
|
|
func TestSyncPodsWithRestartPolicy(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-04-08 02:03:43 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
|
|
|
|
containers := []api.Container{
|
|
|
|
{Name: "succeeded"},
|
|
|
|
{Name: "failed"},
|
|
|
|
}
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-13 17:02:58 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: containers,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2015-04-08 02:03:43 +00:00
|
|
|
|
|
|
|
runningAPIContainers := []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_0"},
|
2015-04-08 02:03:43 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
exitedAPIContainers := []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_succeeded." + strconv.FormatUint(dockertools.HashContainer(&containers[0]), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_failed." + strconv.FormatUint(dockertools.HashContainer(&containers[1]), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "5678",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
containerMap := map[string]*docker.Container{
|
2015-04-13 17:02:58 +00:00
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Name: "POD",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
Running: true,
|
|
|
|
},
|
|
|
|
},
|
2015-04-08 02:03:43 +00:00
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Name: "succeeded",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"5678": {
|
|
|
|
ID: "5678",
|
|
|
|
Name: "failed",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
policy api.RestartPolicy
|
|
|
|
calls []string
|
|
|
|
created []string
|
|
|
|
stopped []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
api.RestartPolicyAlways,
|
2015-05-08 18:48:26 +00:00
|
|
|
[]string{"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Restart both containers.
|
|
|
|
"create", "start", "create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
},
|
2015-04-08 02:03:43 +00:00
|
|
|
[]string{"succeeded", "failed"},
|
|
|
|
[]string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
api.RestartPolicyOnFailure,
|
2015-05-08 18:48:26 +00:00
|
|
|
[]string{"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Restart the failed container.
|
|
|
|
"create", "start",
|
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
},
|
2015-04-08 02:03:43 +00:00
|
|
|
[]string{"failed"},
|
|
|
|
[]string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
api.RestartPolicyNever,
|
2015-05-08 18:48:26 +00:00
|
|
|
[]string{"list", "list",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
2015-04-17 23:12:08 +00:00
|
|
|
// Check the pod infra container.
|
|
|
|
"inspect_container",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Stop the last pod infra container.
|
2015-05-06 03:50:45 +00:00
|
|
|
"inspect_container", "stop",
|
2015-04-13 17:02:58 +00:00
|
|
|
// Get pod status.
|
2015-05-08 18:48:26 +00:00
|
|
|
"list", "inspect_container", "inspect_container", "inspect_container",
|
|
|
|
// Get pods for deleting orphaned volumes.
|
|
|
|
"list",
|
|
|
|
},
|
2015-04-08 02:03:43 +00:00
|
|
|
[]string{},
|
|
|
|
[]string{"9876"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
fakeDocker.ContainerList = runningAPIContainers
|
|
|
|
fakeDocker.ExitedContainerList = exitedAPIContainers
|
|
|
|
fakeDocker.ContainerMap = containerMap
|
|
|
|
fakeDocker.ClearCalls()
|
2015-04-13 17:02:58 +00:00
|
|
|
pods[0].Spec.RestartPolicy = tt.policy
|
|
|
|
|
2015-04-08 02:03:43 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2015-04-08 02:03:43 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%d: unexpected error: %v", i, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 'stop' is because the pod infra container is killed when no container is running.
|
|
|
|
verifyCalls(t, fakeDocker, tt.calls)
|
|
|
|
|
|
|
|
if err := fakeDocker.AssertCreated(tt.created); err != nil {
|
|
|
|
t.Errorf("%d: %v", i, err)
|
|
|
|
}
|
|
|
|
if err := fakeDocker.AssertStopped(tt.stopped); err != nil {
|
|
|
|
t.Errorf("%d: %v", i, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-08 18:53:31 +00:00
|
|
|
|
|
|
|
func TestGetPodStatusWithLastTermination(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
2015-04-08 18:53:31 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
|
|
|
|
containers := []api.Container{
|
|
|
|
{Name: "succeeded"},
|
|
|
|
{Name: "failed"},
|
|
|
|
}
|
|
|
|
|
|
|
|
exitedAPIContainers := []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_succeeded." + strconv.FormatUint(dockertools.HashContainer(&containers[0]), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
Names: []string{"/k8s_failed." + strconv.FormatUint(dockertools.HashContainer(&containers[1]), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "5678",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
containerMap := map[string]*docker.Container{
|
2015-04-13 17:02:58 +00:00
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
Name: "POD",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
State: docker.State{
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
Running: true,
|
|
|
|
},
|
|
|
|
},
|
2015-04-08 18:53:31 +00:00
|
|
|
"1234": {
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "1234",
|
|
|
|
Name: "succeeded",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2015-04-08 18:53:31 +00:00
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"5678": {
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "5678",
|
|
|
|
Name: "failed",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
HostConfig: &docker.HostConfig{},
|
2015-04-08 18:53:31 +00:00
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
policy api.RestartPolicy
|
|
|
|
created []string
|
|
|
|
stopped []string
|
|
|
|
lastTerminations []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
api.RestartPolicyAlways,
|
|
|
|
[]string{"succeeded", "failed"},
|
|
|
|
[]string{},
|
|
|
|
[]string{"docker://1234", "docker://5678"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
api.RestartPolicyOnFailure,
|
|
|
|
[]string{"failed"},
|
|
|
|
[]string{},
|
|
|
|
[]string{"docker://5678"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
api.RestartPolicyNever,
|
|
|
|
[]string{},
|
|
|
|
[]string{"9876"},
|
|
|
|
[]string{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
fakeDocker.ExitedContainerList = exitedAPIContainers
|
|
|
|
fakeDocker.ContainerMap = containerMap
|
|
|
|
fakeDocker.ClearCalls()
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{
|
2015-04-08 18:53:31 +00:00
|
|
|
{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: containers,
|
|
|
|
RestartPolicy: tt.policy,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
// pod infra container
|
2015-04-03 22:51:50 +00:00
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pods[0]), 16) + "_foo_new_12345678_0"},
|
2015-04-13 17:02:58 +00:00
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
2015-04-08 18:53:31 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-04-20 18:20:53 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
2015-04-08 18:53:31 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%d: unexpected error: %v", i, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we can retrieve the pod status from GetPodStatus().
|
2015-04-03 22:51:50 +00:00
|
|
|
podName := kubecontainer.GetPodFullName(pods[0])
|
2015-04-08 18:53:31 +00:00
|
|
|
status, err := kubelet.GetPodStatus(podName)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to retrieve pod status for pod %q: %#v.", podName, err)
|
|
|
|
} else {
|
|
|
|
terminatedContainers := []string{}
|
|
|
|
for _, cs := range status.ContainerStatuses {
|
|
|
|
if cs.LastTerminationState.Termination != nil {
|
|
|
|
terminatedContainers = append(terminatedContainers, cs.LastTerminationState.Termination.ContainerID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.StringSlice(terminatedContainers).Sort()
|
|
|
|
sort.StringSlice(tt.lastTerminations).Sort()
|
|
|
|
if !reflect.DeepEqual(terminatedContainers, tt.lastTerminations) {
|
|
|
|
t.Errorf("Expected(sorted): %#v, Actual(sorted): %#v", tt.lastTerminations, terminatedContainers)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := fakeDocker.AssertCreated(tt.created); err != nil {
|
|
|
|
t.Errorf("%d: %v", i, err)
|
|
|
|
}
|
|
|
|
if err := fakeDocker.AssertStopped(tt.stopped); err != nil {
|
|
|
|
t.Errorf("%d: %v", i, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-09 18:57:53 +00:00
|
|
|
|
|
|
|
func TestGetPodCreationFailureReason(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
2015-05-08 18:54:44 +00:00
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-04-09 18:57:53 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
2015-05-08 18:54:44 +00:00
|
|
|
|
|
|
|
// Inject the creation failure error to docker.
|
2015-04-09 18:57:53 +00:00
|
|
|
failureReason := "creation failure"
|
2015-04-13 17:02:58 +00:00
|
|
|
fakeDocker.Errors = map[string]error{
|
|
|
|
"create": fmt.Errorf("%s", failureReason),
|
|
|
|
}
|
2015-05-08 18:54:44 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pod := &api.Pod{
|
2015-04-09 18:57:53 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
2015-05-08 18:54:44 +00:00
|
|
|
Name: "foo",
|
2015-04-09 18:57:53 +00:00
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
2015-05-08 18:54:44 +00:00
|
|
|
Containers: []api.Container{{Name: "bar"}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pretend that the pod infra container has already been created, so that
|
|
|
|
// we can run the user containers.
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
Config: &docker.Config{},
|
2015-04-09 18:57:53 +00:00
|
|
|
},
|
|
|
|
}
|
2015-05-08 18:54:44 +00:00
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
pods := []*api.Pod{pod}
|
2015-04-09 18:57:53 +00:00
|
|
|
kubelet.podManager.SetPods(pods)
|
2015-05-06 23:50:57 +00:00
|
|
|
kubelet.volumeManager.SetVolumes(pod.UID, kubecontainer.VolumeMap{})
|
2015-05-08 18:54:44 +00:00
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
status, err := kubelet.GetPodStatus(kubecontainer.GetPodFullName(pod))
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
if len(status.ContainerStatuses) < 1 {
|
|
|
|
t.Errorf("expected 1 container status, got %d", len(status.ContainerStatuses))
|
|
|
|
} else {
|
|
|
|
state := status.ContainerStatuses[0].State
|
|
|
|
if state.Waiting == nil {
|
|
|
|
t.Errorf("expected waiting state, got %#v", state)
|
|
|
|
} else if state.Waiting.Reason != failureReason {
|
|
|
|
t.Errorf("expected reason %q, got %q", failureReason, state.Waiting.Reason)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetPodPullImageFailureReason(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
|
|
|
|
// Initialize the FakeDockerPuller so that it'd try to pull non-existent
|
|
|
|
// images.
|
2015-05-01 22:25:11 +00:00
|
|
|
dm := kubelet.containerRuntime.(*dockertools.DockerManager)
|
2015-05-08 18:54:44 +00:00
|
|
|
puller := dm.Puller.(*dockertools.FakeDockerPuller)
|
|
|
|
puller.HasImages = []string{}
|
|
|
|
// Inject the pull image failure error.
|
|
|
|
failureReason := "pull image faiulre"
|
|
|
|
puller.ErrorsToInject = []error{fmt.Errorf("%s", failureReason)}
|
|
|
|
|
|
|
|
pod := &api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: []api.Container{{Name: "bar", Image: "realImage", ImagePullPolicy: api.PullAlways}},
|
|
|
|
},
|
2015-04-09 18:57:53 +00:00
|
|
|
}
|
2015-05-08 18:54:44 +00:00
|
|
|
|
|
|
|
// Pretend that the pod infra container has already been created, so that
|
|
|
|
// we can run the user containers.
|
|
|
|
fakeDocker.ContainerList = []docker.APIContainers{
|
|
|
|
{
|
|
|
|
Names: []string{"/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0"},
|
|
|
|
ID: "9876",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = map[string]*docker.Container{
|
|
|
|
"9876": {
|
|
|
|
ID: "9876",
|
|
|
|
HostConfig: &docker.HostConfig{},
|
|
|
|
Config: &docker.Config{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
pods := []*api.Pod{pod}
|
|
|
|
kubelet.podManager.SetPods(pods)
|
|
|
|
kubelet.volumeManager.SetVolumes(pod.UID, kubecontainer.VolumeMap{})
|
|
|
|
err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]*api.Pod{}, time.Now())
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-04-03 22:51:50 +00:00
|
|
|
status, err := kubelet.GetPodStatus(kubecontainer.GetPodFullName(pod))
|
2015-04-09 18:57:53 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
if len(status.ContainerStatuses) < 1 {
|
|
|
|
t.Errorf("expected 1 container status, got %d", len(status.ContainerStatuses))
|
|
|
|
} else {
|
|
|
|
state := status.ContainerStatuses[0].State
|
|
|
|
if state.Waiting == nil {
|
|
|
|
t.Errorf("expected waiting state, got %#v", state)
|
|
|
|
} else if state.Waiting.Reason != failureReason {
|
2015-04-16 00:40:07 +00:00
|
|
|
t.Errorf("expected reason %q, got %q", failureReason, state.Waiting.Reason)
|
2015-04-09 18:57:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Kubelet: persist restart count of a container
Currently, restart count are generated by examine dead docker containers, which
are subject to background garbage collection. Therefore, the restart count is
capped at 5 and can decrement if GC happens.
This change leverages the container statuses recorded in the pod status as a
reference point. If a container finished after the last observation, restart
count is incremented on top of the last observed count. If container is created
after last observation, but GC'd before the current observation time, kubelet
would not be aware of the existence of such a container, and would not increase
the restart count accordingly. However, the chance of this should be low, given
that pod statuses are reported frequently. Also, the restart cound would still
be increasing monotonically (with the exception of container insepct error).
2015-04-11 05:33:45 +00:00
|
|
|
|
|
|
|
func TestGetRestartCount(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil)
|
2015-05-12 08:24:08 +00:00
|
|
|
testKubelet.fakeCadvisor.On("DockerImagesFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
|
|
|
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorApiv2.FsInfo{}, nil)
|
Kubelet: persist restart count of a container
Currently, restart count are generated by examine dead docker containers, which
are subject to background garbage collection. Therefore, the restart count is
capped at 5 and can decrement if GC happens.
This change leverages the container statuses recorded in the pod status as a
reference point. If a container finished after the last observation, restart
count is incremented on top of the last observed count. If container is created
after last observation, but GC'd before the current observation time, kubelet
would not be aware of the existence of such a container, and would not increase
the restart count accordingly. However, the chance of this should be low, given
that pod statuses are reported frequently. Also, the restart cound would still
be increasing monotonically (with the exception of container insepct error).
2015-04-11 05:33:45 +00:00
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
fakeDocker := testKubelet.fakeDocker
|
|
|
|
|
|
|
|
containers := []api.Container{
|
|
|
|
{Name: "bar"},
|
|
|
|
}
|
|
|
|
pod := api.Pod{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
UID: "12345678",
|
|
|
|
Name: "foo",
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
Containers: containers,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// format is // k8s_<container-id>_<pod-fullname>_<pod-uid>
|
|
|
|
names := []string{"/k8s_bar." + strconv.FormatUint(dockertools.HashContainer(&containers[0]), 16) + "_foo_new_12345678_0"}
|
|
|
|
currTime := time.Now()
|
|
|
|
containerMap := map[string]*docker.Container{
|
|
|
|
"1234": {
|
|
|
|
ID: "1234",
|
|
|
|
Name: "bar",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: currTime.Add(-60 * time.Second),
|
|
|
|
FinishedAt: currTime.Add(-60 * time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"5678": {
|
|
|
|
ID: "5678",
|
|
|
|
Name: "bar",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: currTime.Add(-30 * time.Second),
|
|
|
|
FinishedAt: currTime.Add(-30 * time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"9101": {
|
|
|
|
ID: "9101",
|
|
|
|
Name: "bar",
|
|
|
|
Config: &docker.Config{},
|
|
|
|
State: docker.State{
|
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: currTime.Add(30 * time.Minute),
|
|
|
|
FinishedAt: currTime.Add(30 * time.Minute),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fakeDocker.ContainerMap = containerMap
|
|
|
|
|
|
|
|
// Helper function for verifying the restart count.
|
|
|
|
verifyRestartCount := func(pod *api.Pod, expectedCount int) api.PodStatus {
|
|
|
|
status, err := kubelet.generatePodStatus(pod)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
restartCount := status.ContainerStatuses[0].RestartCount
|
|
|
|
if restartCount != expectedCount {
|
|
|
|
t.Errorf("expected %d restart count, got %d", expectedCount, restartCount)
|
|
|
|
}
|
|
|
|
return status
|
|
|
|
}
|
|
|
|
|
|
|
|
// Container "bar" has failed twice; create two dead docker containers.
|
|
|
|
// TODO: container lists are expected to be sorted reversely by time.
|
|
|
|
// We should fix FakeDockerClient to sort the list before returning.
|
|
|
|
fakeDocker.ExitedContainerList = []docker.APIContainers{{Names: names, ID: "5678"}, {Names: names, ID: "1234"}}
|
|
|
|
pod.Status = verifyRestartCount(&pod, 1)
|
|
|
|
|
|
|
|
// Found a new dead container. The restart count should be incremented.
|
|
|
|
fakeDocker.ExitedContainerList = []docker.APIContainers{
|
|
|
|
{Names: names, ID: "9101"}, {Names: names, ID: "5678"}, {Names: names, ID: "1234"}}
|
|
|
|
pod.Status = verifyRestartCount(&pod, 2)
|
|
|
|
|
|
|
|
// All dead containers have been GC'd. The restart count should persist
|
|
|
|
// (i.e., remain the same).
|
|
|
|
fakeDocker.ExitedContainerList = []docker.APIContainers{}
|
|
|
|
verifyRestartCount(&pod, 2)
|
|
|
|
}
|
2015-04-24 18:20:23 +00:00
|
|
|
|
|
|
|
func TestFilterOutTerminatedPods(t *testing.T) {
|
|
|
|
testKubelet := newTestKubelet(t)
|
|
|
|
kubelet := testKubelet.kubelet
|
|
|
|
pods := newTestPods(5)
|
|
|
|
pods[0].Status.Phase = api.PodFailed
|
|
|
|
pods[1].Status.Phase = api.PodSucceeded
|
|
|
|
pods[2].Status.Phase = api.PodRunning
|
|
|
|
pods[3].Status.Phase = api.PodPending
|
|
|
|
|
|
|
|
expected := []*api.Pod{pods[2], pods[3], pods[4]}
|
|
|
|
kubelet.podManager.SetPods(pods)
|
|
|
|
actual := kubelet.filterOutTerminatedPods(pods)
|
|
|
|
if !reflect.DeepEqual(expected, actual) {
|
|
|
|
t.Errorf("expected %#v, got %#v", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
2015-05-12 23:54:39 +00:00
|
|
|
|
|
|
|
func TestMakePortMappings(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
container *api.Container
|
|
|
|
expectedPortMappings []kubecontainer.PortMapping
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
&api.Container{
|
|
|
|
Name: "fooContainer",
|
|
|
|
Ports: []api.ContainerPort{
|
|
|
|
{
|
|
|
|
Protocol: api.ProtocolTCP,
|
|
|
|
ContainerPort: 80,
|
|
|
|
HostPort: 8080,
|
|
|
|
HostIP: "127.0.0.1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Protocol: api.ProtocolTCP,
|
|
|
|
ContainerPort: 443,
|
|
|
|
HostPort: 4343,
|
|
|
|
HostIP: "192.168.0.1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "foo",
|
|
|
|
Protocol: api.ProtocolUDP,
|
|
|
|
ContainerPort: 555,
|
|
|
|
HostPort: 5555,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "foo", // Duplicated, should be ignored.
|
|
|
|
Protocol: api.ProtocolUDP,
|
|
|
|
ContainerPort: 888,
|
|
|
|
HostPort: 8888,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Protocol: api.ProtocolTCP, // Duplicated, should be ignored.
|
|
|
|
ContainerPort: 80,
|
|
|
|
HostPort: 8888,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
[]kubecontainer.PortMapping{
|
|
|
|
{
|
|
|
|
Name: "fooContainer-TCP:80",
|
|
|
|
Protocol: api.ProtocolTCP,
|
|
|
|
ContainerPort: 80,
|
|
|
|
HostPort: 8080,
|
|
|
|
HostIP: "127.0.0.1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "fooContainer-TCP:443",
|
|
|
|
Protocol: api.ProtocolTCP,
|
|
|
|
ContainerPort: 443,
|
|
|
|
HostPort: 4343,
|
|
|
|
HostIP: "192.168.0.1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "fooContainer-foo",
|
|
|
|
Protocol: api.ProtocolUDP,
|
|
|
|
ContainerPort: 555,
|
|
|
|
HostPort: 5555,
|
|
|
|
HostIP: "",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
actual := makePortMappings(tt.container)
|
|
|
|
if !reflect.DeepEqual(tt.expectedPortMappings, actual) {
|
|
|
|
t.Errorf("%d: Expected: %#v, saw: %#v", i, tt.expectedPortMappings, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|