2015-03-31 02:56:34 +00:00
|
|
|
/*
|
2016-06-03 00:25:58 +00:00
|
|
|
Copyright 2014 The Kubernetes Authors.
|
2015-03-31 02:56:34 +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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package dockertools
|
|
|
|
|
|
|
|
import (
|
2016-12-15 00:47:53 +00:00
|
|
|
"flag"
|
2015-04-30 23:04:32 +00:00
|
|
|
"fmt"
|
2015-06-05 22:37:53 +00:00
|
|
|
"io/ioutil"
|
2016-07-19 04:20:04 +00:00
|
|
|
"net"
|
2015-05-26 23:45:38 +00:00
|
|
|
"net/http"
|
2015-06-05 22:37:53 +00:00
|
|
|
"os"
|
2015-04-29 20:09:03 +00:00
|
|
|
"reflect"
|
2015-05-26 23:45:38 +00:00
|
|
|
"regexp"
|
2015-04-29 20:09:03 +00:00
|
|
|
"sort"
|
2015-05-26 23:45:38 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2015-03-31 02:56:34 +00:00
|
|
|
"testing"
|
2015-05-01 22:25:11 +00:00
|
|
|
"time"
|
2015-03-31 02:56:34 +00:00
|
|
|
|
2016-04-04 08:56:49 +00:00
|
|
|
dockertypes "github.com/docker/engine-api/types"
|
2016-04-04 22:27:20 +00:00
|
|
|
dockercontainer "github.com/docker/engine-api/types/container"
|
2016-04-14 17:36:13 +00:00
|
|
|
dockerstrslice "github.com/docker/engine-api/types/strslice"
|
2016-07-19 04:20:04 +00:00
|
|
|
"github.com/golang/mock/gomock"
|
2015-10-16 03:00:28 +00:00
|
|
|
cadvisorapi "github.com/google/cadvisor/info/v1"
|
2016-02-10 22:45:03 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2017-02-03 02:10:05 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2017-01-25 13:39:54 +00:00
|
|
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
2017-01-17 03:38:19 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2017-01-11 14:09:48 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
kubetypes "k8s.io/apimachinery/pkg/types"
|
2017-01-27 20:42:17 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
2017-01-11 14:09:48 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
2017-01-30 18:39:54 +00:00
|
|
|
"k8s.io/client-go/tools/record"
|
2017-01-23 18:37:22 +00:00
|
|
|
"k8s.io/client-go/util/clock"
|
|
|
|
"k8s.io/client-go/util/flowcontrol"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/testapi"
|
2016-11-18 20:50:58 +00:00
|
|
|
"k8s.io/kubernetes/pkg/api/v1"
|
2016-03-31 22:20:04 +00:00
|
|
|
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
2015-08-05 22:03:47 +00:00
|
|
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
2016-02-25 23:40:44 +00:00
|
|
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
2016-07-19 22:42:21 +00:00
|
|
|
"k8s.io/kubernetes/pkg/kubelet/images"
|
2015-08-05 22:03:47 +00:00
|
|
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
2016-02-25 23:40:44 +00:00
|
|
|
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
2015-10-19 22:15:59 +00:00
|
|
|
proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
|
2016-05-22 05:00:38 +00:00
|
|
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
2015-08-05 22:03:47 +00:00
|
|
|
uexec "k8s.io/kubernetes/pkg/util/exec"
|
2015-03-31 02:56:34 +00:00
|
|
|
)
|
|
|
|
|
2016-12-15 00:47:53 +00:00
|
|
|
var testTempDir string
|
|
|
|
|
|
|
|
func TestMain(m *testing.M) {
|
|
|
|
dir, err := ioutil.TempDir("", "dockertools")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
testTempDir = dir
|
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
status := m.Run()
|
|
|
|
os.RemoveAll(testTempDir)
|
|
|
|
os.Exit(status)
|
|
|
|
}
|
|
|
|
|
2015-05-26 23:45:38 +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
|
|
|
|
}
|
|
|
|
|
2016-09-21 23:20:07 +00:00
|
|
|
type fakeImageManager struct{}
|
|
|
|
|
|
|
|
func newFakeImageManager() images.ImageManager {
|
|
|
|
return &fakeImageManager{}
|
|
|
|
}
|
|
|
|
|
2016-12-29 07:26:03 +00:00
|
|
|
func (m *fakeImageManager) EnsureImageExists(pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret) (string, string, error) {
|
|
|
|
return container.Image, "", nil
|
2016-09-21 23:20:07 +00:00
|
|
|
}
|
|
|
|
|
2016-04-18 04:27:39 +00:00
|
|
|
func createTestDockerManager(fakeHTTPClient *fakeHTTP, fakeDocker *FakeDockerClient) (*DockerManager, *FakeDockerClient) {
|
|
|
|
if fakeHTTPClient == nil {
|
|
|
|
fakeHTTPClient = &fakeHTTP{}
|
|
|
|
}
|
|
|
|
if fakeDocker == nil {
|
|
|
|
fakeDocker = NewFakeDockerClient()
|
|
|
|
}
|
2015-04-29 20:09:03 +00:00
|
|
|
fakeRecorder := &record.FakeRecorder{}
|
|
|
|
containerRefManager := kubecontainer.NewRefManager()
|
2016-07-22 21:41:44 +00:00
|
|
|
networkPlugin, _ := network.InitNetworkPlugin(
|
|
|
|
[]network.NetworkPlugin{},
|
|
|
|
"",
|
|
|
|
nettest.NewFakeHost(nil),
|
|
|
|
componentconfig.HairpinNone,
|
2016-08-10 16:09:43 +00:00
|
|
|
"10.0.0.0/8",
|
|
|
|
network.UseDefaultMTU)
|
2016-07-22 21:41:44 +00:00
|
|
|
|
2015-05-01 22:25:11 +00:00
|
|
|
dockerManager := NewFakeDockerManager(
|
2015-04-29 20:09:03 +00:00
|
|
|
fakeDocker,
|
|
|
|
fakeRecorder,
|
2015-10-19 22:15:59 +00:00
|
|
|
proberesults.NewManager(),
|
2015-04-29 20:09:03 +00:00
|
|
|
containerRefManager,
|
2015-10-16 03:00:28 +00:00
|
|
|
&cadvisorapi.MachineInfo{},
|
2016-06-20 18:38:37 +00:00
|
|
|
"",
|
2015-04-29 20:09:03 +00:00
|
|
|
0, 0, "",
|
2016-04-21 01:21:41 +00:00
|
|
|
&containertest.FakeOS{},
|
2015-04-29 20:09:03 +00:00
|
|
|
networkPlugin,
|
2017-02-27 04:07:49 +00:00
|
|
|
&containertest.FakeRuntimeHelper{},
|
2015-10-02 13:45:46 +00:00
|
|
|
fakeHTTPClient,
|
2016-03-09 02:58:24 +00:00
|
|
|
flowcontrol.NewBackOff(time.Second, 300*time.Second))
|
2015-04-29 20:09:03 +00:00
|
|
|
|
|
|
|
return dockerManager, fakeDocker
|
|
|
|
}
|
|
|
|
|
2016-09-21 23:20:07 +00:00
|
|
|
func createTestDockerManagerWithFakeImageManager(fakeHTTPClient *fakeHTTP, fakeDocker *FakeDockerClient) (*DockerManager, *FakeDockerClient) {
|
|
|
|
dm, fd := createTestDockerManager(fakeHTTPClient, fakeDocker)
|
|
|
|
dm.imagePuller = newFakeImageManager()
|
|
|
|
return dm, fd
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTestDockerManagerWithRealImageManager() (*DockerManager, *FakeDockerClient) {
|
|
|
|
return createTestDockerManager(nil, nil)
|
|
|
|
}
|
2016-02-23 21:27:28 +00:00
|
|
|
func newTestDockerManagerWithHTTPClient(fakeHTTPClient *fakeHTTP) (*DockerManager, *FakeDockerClient) {
|
2016-09-21 23:20:07 +00:00
|
|
|
return createTestDockerManagerWithFakeImageManager(fakeHTTPClient, nil)
|
2016-04-18 04:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newTestDockerManagerWithVersion(version, apiVersion string) (*DockerManager, *FakeDockerClient) {
|
2017-01-12 21:24:35 +00:00
|
|
|
fakeDocker := NewFakeDockerClient().WithVersion(version, apiVersion)
|
2016-09-21 23:20:07 +00:00
|
|
|
return createTestDockerManagerWithFakeImageManager(nil, fakeDocker)
|
2016-02-23 21:27:28 +00:00
|
|
|
}
|
|
|
|
|
2015-06-01 19:30:51 +00:00
|
|
|
func newTestDockerManager() (*DockerManager, *FakeDockerClient) {
|
2016-09-21 23:20:07 +00:00
|
|
|
return createTestDockerManagerWithFakeImageManager(nil, nil)
|
2015-06-01 19:30:51 +00:00
|
|
|
}
|
|
|
|
|
2015-05-26 23:45:38 +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
|
|
|
|
}
|
|
|
|
|
2015-03-31 02:56:34 +00:00
|
|
|
func TestSetEntrypointAndCommand(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
2016-11-18 20:50:58 +00:00
|
|
|
container *v1.Container
|
2015-05-22 22:21:03 +00:00
|
|
|
envs []kubecontainer.EnvVar
|
2016-04-14 17:36:13 +00:00
|
|
|
expected *dockertypes.ContainerCreateConfig
|
2015-03-31 02:56:34 +00:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "none",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{},
|
2015-03-31 02:56:34 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "command",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-03-31 02:56:34 +00:00
|
|
|
Command: []string{"foo", "bar"},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Entrypoint: dockerstrslice.StrSlice([]string{"foo", "bar"}),
|
2015-03-31 02:56:34 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-05-22 22:21:03 +00:00
|
|
|
{
|
|
|
|
name: "command expanded",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-05-22 22:21:03 +00:00
|
|
|
Command: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
|
|
|
|
},
|
|
|
|
envs: []kubecontainer.EnvVar{
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST",
|
|
|
|
Value: "zoo",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST2",
|
|
|
|
Value: "boo",
|
|
|
|
},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Entrypoint: dockerstrslice.StrSlice([]string{"foo", "zoo", "boo"}),
|
2015-05-22 22:21:03 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-03-31 02:56:34 +00:00
|
|
|
{
|
|
|
|
name: "args",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-03-31 02:56:34 +00:00
|
|
|
Args: []string{"foo", "bar"},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
2015-03-31 02:56:34 +00:00
|
|
|
Cmd: []string{"foo", "bar"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-05-22 22:21:03 +00:00
|
|
|
{
|
|
|
|
name: "args expanded",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-05-22 22:21:03 +00:00
|
|
|
Args: []string{"zap", "$(VAR_TEST)", "$(VAR_TEST2)"},
|
|
|
|
},
|
|
|
|
envs: []kubecontainer.EnvVar{
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST",
|
|
|
|
Value: "hap",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST2",
|
|
|
|
Value: "trap",
|
|
|
|
},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Cmd: dockerstrslice.StrSlice([]string{"zap", "hap", "trap"}),
|
2015-05-22 22:21:03 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-03-31 02:56:34 +00:00
|
|
|
{
|
|
|
|
name: "both",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-03-31 02:56:34 +00:00
|
|
|
Command: []string{"foo"},
|
|
|
|
Args: []string{"bar", "baz"},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Entrypoint: dockerstrslice.StrSlice([]string{"foo"}),
|
|
|
|
Cmd: dockerstrslice.StrSlice([]string{"bar", "baz"}),
|
2015-03-31 02:56:34 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-05-22 22:21:03 +00:00
|
|
|
{
|
|
|
|
name: "both expanded",
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2015-05-22 22:21:03 +00:00
|
|
|
Command: []string{"$(VAR_TEST2)--$(VAR_TEST)", "foo", "$(VAR_TEST3)"},
|
|
|
|
Args: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
|
|
|
|
},
|
|
|
|
envs: []kubecontainer.EnvVar{
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST",
|
|
|
|
Value: "zoo",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST2",
|
|
|
|
Value: "boo",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "VAR_TEST3",
|
|
|
|
Value: "roo",
|
|
|
|
},
|
|
|
|
},
|
2016-04-14 17:36:13 +00:00
|
|
|
expected: &dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Entrypoint: dockerstrslice.StrSlice([]string{"boo--zoo", "foo", "roo"}),
|
|
|
|
Cmd: dockerstrslice.StrSlice([]string{"foo", "zoo", "boo"}),
|
2015-05-22 22:21:03 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-03-31 02:56:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
2015-05-22 22:21:03 +00:00
|
|
|
opts := &kubecontainer.RunContainerOptions{
|
|
|
|
Envs: tc.envs,
|
|
|
|
}
|
|
|
|
|
2016-04-14 17:36:13 +00:00
|
|
|
actualOpts := dockertypes.ContainerCreateConfig{
|
|
|
|
Config: &dockercontainer.Config{},
|
2015-03-31 02:56:34 +00:00
|
|
|
}
|
2015-05-22 22:21:03 +00:00
|
|
|
setEntrypointAndCommand(tc.container, opts, actualOpts)
|
2015-03-31 02:56:34 +00:00
|
|
|
|
2017-01-25 13:39:54 +00:00
|
|
|
if e, a := tc.expected.Config.Entrypoint, actualOpts.Config.Entrypoint; !apiequality.Semantic.DeepEqual(e, a) {
|
2015-03-31 02:56:34 +00:00
|
|
|
t.Errorf("%v: unexpected entrypoint: expected %v, got %v", tc.name, e, a)
|
|
|
|
}
|
2017-01-25 13:39:54 +00:00
|
|
|
if e, a := tc.expected.Config.Cmd, actualOpts.Config.Cmd; !apiequality.Semantic.DeepEqual(e, a) {
|
2015-03-31 02:56:34 +00:00
|
|
|
t.Errorf("%v: unexpected command: expected %v, got %v", tc.name, e, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-29 20:09:03 +00:00
|
|
|
|
|
|
|
// verifyPods returns true if the two pod slices are equal.
|
|
|
|
func verifyPods(a, b []*kubecontainer.Pod) bool {
|
|
|
|
if len(a) != len(b) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the containers within a pod.
|
|
|
|
for i := range a {
|
|
|
|
sort.Sort(containersByID(a[i].Containers))
|
|
|
|
}
|
|
|
|
for i := range b {
|
|
|
|
sort.Sort(containersByID(b[i].Containers))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort the pods by UID.
|
|
|
|
sort.Sort(podsByID(a))
|
|
|
|
sort.Sort(podsByID(b))
|
|
|
|
|
|
|
|
return reflect.DeepEqual(a, b)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetPods(t *testing.T) {
|
2015-05-01 22:25:11 +00:00
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2016-04-04 22:27:20 +00:00
|
|
|
dockerContainers := []*FakeContainer{
|
2015-04-29 20:09:03 +00:00
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "1111",
|
|
|
|
Name: "/k8s_foo_qux_new_1234_42",
|
2015-04-29 20:09:03 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "2222",
|
|
|
|
Name: "/k8s_bar_qux_new_1234_42",
|
2015-04-29 20:09:03 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "3333",
|
|
|
|
Name: "/k8s_bar_jlk_wen_5678_42",
|
2015-04-29 20:09:03 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the docker containers. This does not affect the test coverage
|
2015-04-30 17:12:23 +00:00
|
|
|
// because the conversion is tested separately in convert_test.go
|
2015-04-29 20:09:03 +00:00
|
|
|
containers := make([]*kubecontainer.Container, len(dockerContainers))
|
|
|
|
for i := range containers {
|
2016-04-04 08:56:49 +00:00
|
|
|
c, err := toRuntimeContainer(&dockertypes.Container{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: dockerContainers[i].ID,
|
|
|
|
Names: []string{dockerContainers[i].Name},
|
|
|
|
})
|
2015-04-29 20:09:03 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
containers[i] = c
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := []*kubecontainer.Pod{
|
|
|
|
{
|
2016-05-22 05:00:38 +00:00
|
|
|
ID: kubetypes.UID("1234"),
|
2015-04-29 20:09:03 +00:00
|
|
|
Name: "qux",
|
|
|
|
Namespace: "new",
|
|
|
|
Containers: []*kubecontainer.Container{containers[0], containers[1]},
|
|
|
|
},
|
|
|
|
{
|
2016-05-22 05:00:38 +00:00
|
|
|
ID: kubetypes.UID("5678"),
|
2015-04-29 20:09:03 +00:00
|
|
|
Name: "jlk",
|
|
|
|
Namespace: "wen",
|
|
|
|
Containers: []*kubecontainer.Container{containers[2]},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-11-19 21:59:18 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers(dockerContainers)
|
2015-04-29 20:09:03 +00:00
|
|
|
actual, err := manager.GetPods(false)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
if !verifyPods(expected, actual) {
|
|
|
|
t.Errorf("expected %#v, got %#v", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
2015-04-30 17:12:23 +00:00
|
|
|
|
|
|
|
func TestListImages(t *testing.T) {
|
2015-05-01 22:25:11 +00:00
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2016-04-03 15:40:22 +00:00
|
|
|
dockerImages := []dockertypes.Image{{ID: "1111"}, {ID: "2222"}, {ID: "3333"}}
|
2015-09-09 17:45:01 +00:00
|
|
|
expected := sets.NewString([]string{"1111", "2222", "3333"}...)
|
2015-04-30 17:12:23 +00:00
|
|
|
|
|
|
|
fakeDocker.Images = dockerImages
|
|
|
|
actualImages, err := manager.ListImages()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v", err)
|
|
|
|
}
|
2015-09-09 17:45:01 +00:00
|
|
|
actual := sets.NewString()
|
2015-04-30 17:12:23 +00:00
|
|
|
for _, i := range actualImages {
|
|
|
|
actual.Insert(i.ID)
|
|
|
|
}
|
|
|
|
// We can compare the two sets directly because util.StringSet.List()
|
|
|
|
// returns a "sorted" list.
|
|
|
|
if !reflect.DeepEqual(expected.List(), actual.List()) {
|
|
|
|
t.Errorf("expected %#v, got %#v", expected.List(), actual.List())
|
|
|
|
}
|
|
|
|
}
|
2015-04-30 23:04:32 +00:00
|
|
|
|
2016-07-20 00:36:48 +00:00
|
|
|
func TestDeleteImage(t *testing.T) {
|
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2017-03-02 01:18:02 +00:00
|
|
|
fakeDocker.InjectImages([]dockertypes.Image{{ID: "1111", RepoTags: []string{"foo"}}})
|
2016-07-20 00:36:48 +00:00
|
|
|
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
2016-10-08 04:35:18 +00:00
|
|
|
fakeDocker.AssertCallDetails(NewCalledDetail("inspect_image", nil), NewCalledDetail("remove_image",
|
|
|
|
[]interface{}{"1111", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
2016-07-20 00:36:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteImageWithMultipleTags(t *testing.T) {
|
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2017-03-02 01:18:02 +00:00
|
|
|
fakeDocker.InjectImages([]dockertypes.Image{{ID: "1111", RepoTags: []string{"foo", "bar"}}})
|
2016-07-20 00:36:48 +00:00
|
|
|
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
2016-10-08 04:35:18 +00:00
|
|
|
fakeDocker.AssertCallDetails(NewCalledDetail("inspect_image", nil),
|
|
|
|
NewCalledDetail("remove_image", []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}),
|
|
|
|
NewCalledDetail("remove_image", []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
2016-07-20 00:36:48 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 23:04:32 +00:00
|
|
|
func TestKillContainerInPod(t *testing.T) {
|
2015-05-01 22:25:11 +00:00
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2015-04-30 23:04:32 +00:00
|
|
|
|
2016-08-29 15:36:33 +00:00
|
|
|
pod := makePod("qux", nil)
|
2016-04-04 22:27:20 +00:00
|
|
|
containers := []*FakeContainer{
|
2015-04-30 23:04:32 +00:00
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "1111",
|
|
|
|
Name: "/k8s_foo_qux_new_1234_42",
|
2015-04-30 23:04:32 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "2222",
|
|
|
|
Name: "/k8s_bar_qux_new_1234_42",
|
2015-04-30 23:04:32 +00:00
|
|
|
},
|
|
|
|
}
|
2015-11-19 21:59:18 +00:00
|
|
|
containerToKill := containers[0]
|
|
|
|
containerToSpare := containers[1]
|
|
|
|
|
|
|
|
fakeDocker.SetFakeRunningContainers(containers)
|
2015-04-30 23:04:32 +00:00
|
|
|
|
2016-04-27 03:30:59 +00:00
|
|
|
if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container in pod.", nil); err != nil {
|
2015-04-30 23:04:32 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
// Assert the container has been stopped.
|
|
|
|
if err := fakeDocker.AssertStopped([]string{containerToKill.ID}); err != nil {
|
|
|
|
t.Errorf("container was not stopped correctly: %v", err)
|
|
|
|
}
|
2015-08-25 17:39:41 +00:00
|
|
|
// Assert the container has been spared.
|
|
|
|
if err := fakeDocker.AssertStopped([]string{containerToSpare.ID}); err == nil {
|
|
|
|
t.Errorf("container unexpectedly stopped: %v", containerToSpare.ID)
|
2015-04-30 23:04:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-06 03:50:45 +00:00
|
|
|
func TestKillContainerInPodWithPreStop(t *testing.T) {
|
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2016-04-17 19:58:47 +00:00
|
|
|
fakeDocker.ExecInspect = &dockertypes.ContainerExecInspect{
|
2015-05-06 03:50:45 +00:00
|
|
|
Running: false,
|
|
|
|
ExitCode: 0,
|
|
|
|
}
|
|
|
|
expectedCmd := []string{"foo.sh", "bar"}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("qux", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{
|
|
|
|
Name: "foo",
|
2016-11-18 20:50:58 +00:00
|
|
|
Lifecycle: &v1.Lifecycle{
|
|
|
|
PreStop: &v1.Handler{
|
|
|
|
Exec: &v1.ExecAction{
|
2016-08-29 15:36:33 +00:00
|
|
|
Command: expectedCmd,
|
2015-05-06 03:50:45 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
},
|
|
|
|
{Name: "bar"}}})
|
|
|
|
|
2016-01-22 05:06:52 +00:00
|
|
|
podString, err := runtime.Encode(testapi.Default.Codec(), pod)
|
2015-05-06 03:50:45 +00:00
|
|
|
if err != nil {
|
2015-08-08 01:52:23 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
2015-05-06 03:50:45 +00:00
|
|
|
}
|
2016-04-04 22:27:20 +00:00
|
|
|
containers := []*FakeContainer{
|
2015-05-06 03:50:45 +00:00
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "1111",
|
|
|
|
Name: "/k8s_foo_qux_new_1234_42",
|
2016-04-04 22:27:20 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-11-19 21:59:18 +00:00
|
|
|
Labels: map[string]string{
|
2016-05-22 05:00:38 +00:00
|
|
|
kubernetesPodLabel: string(podString),
|
|
|
|
types.KubernetesContainerNameLabel: "foo",
|
2015-11-19 21:59:18 +00:00
|
|
|
},
|
|
|
|
},
|
2015-05-06 03:50:45 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "2222",
|
|
|
|
Name: "/k8s_bar_qux_new_1234_42",
|
2015-05-06 03:50:45 +00:00
|
|
|
},
|
|
|
|
}
|
2015-11-19 21:59:18 +00:00
|
|
|
containerToKill := containers[0]
|
|
|
|
fakeDocker.SetFakeRunningContainers(containers)
|
2015-05-06 03:50:45 +00:00
|
|
|
|
2016-04-27 03:30:59 +00:00
|
|
|
if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container with preStop.", nil); err != nil {
|
2015-05-06 03:50:45 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
// Assert the container has been stopped.
|
|
|
|
if err := fakeDocker.AssertStopped([]string{containerToKill.ID}); err != nil {
|
|
|
|
t.Errorf("container was not stopped correctly: %v", err)
|
|
|
|
}
|
2016-04-28 09:33:15 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{"list", "inspect_container", "create_exec", "start_exec", "stop"})
|
2015-05-06 03:50:45 +00:00
|
|
|
if !reflect.DeepEqual(expectedCmd, fakeDocker.execCmd) {
|
|
|
|
t.Errorf("expected: %v, got %v", expectedCmd, fakeDocker.execCmd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-30 23:04:32 +00:00
|
|
|
func TestKillContainerInPodWithError(t *testing.T) {
|
2015-05-01 22:25:11 +00:00
|
|
|
manager, fakeDocker := newTestDockerManager()
|
2015-04-30 23:04:32 +00:00
|
|
|
|
2016-08-29 15:36:33 +00:00
|
|
|
pod := makePod("qux", nil)
|
2016-04-04 22:27:20 +00:00
|
|
|
containers := []*FakeContainer{
|
2015-04-30 23:04:32 +00:00
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "1111",
|
|
|
|
Name: "/k8s_foo_qux_new_1234_42",
|
2015-04-30 23:04:32 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-19 21:59:18 +00:00
|
|
|
ID: "2222",
|
|
|
|
Name: "/k8s_bar_qux_new_1234_42",
|
2015-04-30 23:04:32 +00:00
|
|
|
},
|
|
|
|
}
|
2015-11-19 21:59:18 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers(containers)
|
2016-03-03 10:01:15 +00:00
|
|
|
fakeDocker.InjectError("stop", fmt.Errorf("sample error"))
|
2015-04-30 23:04:32 +00:00
|
|
|
|
2016-04-27 03:30:59 +00:00
|
|
|
if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container with error.", nil); err == nil {
|
2015-04-30 23:04:32 +00:00
|
|
|
t.Errorf("expected error, found nil")
|
|
|
|
}
|
|
|
|
}
|
2015-05-01 22:25:11 +00:00
|
|
|
|
2015-05-08 16:48:31 +00:00
|
|
|
func TestIsAExitError(t *testing.T) {
|
|
|
|
var err error
|
|
|
|
err = &dockerExitError{nil}
|
|
|
|
_, ok := err.(uexec.ExitError)
|
|
|
|
if !ok {
|
|
|
|
t.Error("couldn't cast dockerExitError to exec.ExitError")
|
|
|
|
}
|
|
|
|
}
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
func generatePodInfraContainerHash(pod *v1.Pod) uint64 {
|
|
|
|
var ports []v1.ContainerPort
|
|
|
|
if pod.Spec.SecurityContext == nil || !pod.Spec.HostNetwork {
|
2015-05-26 23:45:38 +00:00
|
|
|
for _, container := range pod.Spec.Containers {
|
|
|
|
ports = append(ports, container.Ports...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
container := &v1.Container{
|
2015-06-09 00:53:24 +00:00
|
|
|
Name: PodInfraContainerName,
|
2016-06-20 18:38:37 +00:00
|
|
|
Image: "",
|
2015-06-09 00:53:24 +00:00
|
|
|
Ports: ports,
|
|
|
|
ImagePullPolicy: podInfraContainerImagePullPolicy,
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
2017-01-25 23:01:41 +00:00
|
|
|
return kubecontainer.HashContainerLegacy(container)
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// runSyncPod is a helper function to retrieve the running pods from the fake
|
|
|
|
// docker client and runs SyncPod for the given pod.
|
2016-11-18 20:50:58 +00:00
|
|
|
func runSyncPod(t *testing.T, dm *DockerManager, fakeDocker *FakeDockerClient, pod *v1.Pod, backOff *flowcontrol.Backoff, expectErr bool) kubecontainer.PodSyncResult {
|
2016-01-18 09:31:18 +00:00
|
|
|
podStatus, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
|
2015-05-27 18:00:20 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-05-26 23:45:38 +00:00
|
|
|
fakeDocker.ClearCalls()
|
2015-08-13 12:59:15 +00:00
|
|
|
if backOff == nil {
|
2016-03-09 02:58:24 +00:00
|
|
|
backOff = flowcontrol.NewBackOff(time.Second, time.Minute)
|
2015-08-13 12:59:15 +00:00
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
// v1.PodStatus is not used in SyncPod now, pass in an empty one.
|
|
|
|
result := dm.SyncPod(pod, v1.PodStatus{}, podStatus, []v1.Secret{}, backOff)
|
2016-01-12 10:19:13 +00:00
|
|
|
err = result.Error()
|
2015-09-02 17:18:11 +00:00
|
|
|
if err != nil && !expectErr {
|
2015-05-26 23:45:38 +00:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
2015-09-02 17:18:11 +00:00
|
|
|
} else if err == nil && expectErr {
|
|
|
|
t.Errorf("expected error didn't occur")
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
2016-02-10 22:45:03 +00:00
|
|
|
return result
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodCreateNetAndContainer(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2015-06-09 00:53:24 +00:00
|
|
|
dm.podInfraContainerImage = "pod_infra_image"
|
2015-11-19 21:59:18 +00:00
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create pod infra container.
|
2015-09-11 21:23:15 +00:00
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
// Create container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
fakeDocker.Lock()
|
|
|
|
|
|
|
|
found := false
|
2016-04-04 08:56:49 +00:00
|
|
|
for _, c := range fakeDocker.RunningContainerList {
|
2015-06-09 00:53:24 +00:00
|
|
|
if c.Image == "pod_infra_image" && strings.HasPrefix(c.Names[0], "/k8s_POD") {
|
2015-05-26 23:45:38 +00:00
|
|
|
found = true
|
2016-07-23 05:49:04 +00:00
|
|
|
break
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
2016-04-04 08:56:49 +00:00
|
|
|
t.Errorf("Custom pod infra container not found: %v", fakeDocker.RunningContainerList)
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
2017-02-18 15:06:24 +00:00
|
|
|
fakeDocker.Unlock()
|
2017-02-28 20:54:51 +00:00
|
|
|
|
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByNameWithOrder([]string{"POD", "bar"}))
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodCreatesNetAndContainerPullsImage(t *testing.T) {
|
2016-09-21 23:20:07 +00:00
|
|
|
dm, fakeDocker := newTestDockerManagerWithRealImageManager()
|
|
|
|
dm.podInfraContainerImage = "foo/infra_image:v1"
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-09-21 23:20:07 +00:00
|
|
|
{Name: "bar", Image: "foo/something:v0", ImagePullPolicy: "IfNotPresent"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create pod infra container.
|
2017-03-02 01:18:02 +00:00
|
|
|
"inspect_image", "pull", "inspect_image", "create", "start", "inspect_container", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
// Create container.
|
2017-03-02 01:18:02 +00:00
|
|
|
"inspect_image", "pull", "inspect_image", "create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
|
2017-03-02 01:18:02 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertImagesPulled([]string{"foo/infra_image:v1", "foo/something:v0"}))
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByNameWithOrder([]string{"POD", "bar"}))
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodWithPodInfraCreatesContainer(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
// Pod infra container.
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
}})
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByName([]string{"bar"}))
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodDeletesWithNoPodInfraContainer(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo1", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar1"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "1234",
|
|
|
|
Name: "/k8s_bar1_foo1_new_12345678_0",
|
|
|
|
}})
|
2015-10-23 20:02:32 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Kill the container since pod infra container is not running.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop",
|
2015-05-26 23:45:38 +00:00
|
|
|
// Create pod infra container.
|
2015-09-11 21:23:15 +00:00
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
// Create container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertStopped([]string{"1234"}))
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodDeletesDuplicate(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("bar", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "foo"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
2015-05-26 23:45:38 +00:00
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "1234",
|
|
|
|
Name: "/k8s_foo_bar_new_12345678_1111",
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_bar_new_12345678_2222",
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "4567",
|
|
|
|
Name: "/k8s_foo_bar_new_12345678_3333",
|
|
|
|
}})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Kill the duplicated container.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
// Expect one of the duplicates to be killed.
|
|
|
|
if len(fakeDocker.Stopped) != 1 || (fakeDocker.Stopped[0] != "1234" && fakeDocker.Stopped[0] != "4567") {
|
|
|
|
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodBadHash(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar"},
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
2015-05-26 23:45:38 +00:00
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "1234",
|
|
|
|
Name: "/k8s_bar.1234_foo_new_12345678_42",
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
|
|
|
|
}})
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Kill and restart the bad hash container.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop", "create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if err := fakeDocker.AssertStopped([]string{"1234"}); err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodsUnhealthy(t *testing.T) {
|
2015-10-19 22:15:59 +00:00
|
|
|
const (
|
|
|
|
unhealthyContainerID = "1234"
|
|
|
|
infraContainerID = "9876"
|
|
|
|
)
|
2015-05-26 23:45:38 +00:00
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{{Name: "unhealthy"}},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
2015-05-26 23:45:38 +00:00
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: unhealthyContainerID,
|
|
|
|
Name: "/k8s_unhealthy_foo_new_12345678_42",
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: infraContainerID,
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
|
|
|
|
}})
|
2016-02-12 05:02:31 +00:00
|
|
|
dm.livenessManager.Set(kubecontainer.DockerID(unhealthyContainerID).ContainerID(), proberesults.Failure, pod)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Kill the unhealthy container.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop",
|
2015-05-26 23:45:38 +00:00
|
|
|
// Restart the unhealthy container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-05-26 23:45:38 +00:00
|
|
|
})
|
|
|
|
|
2015-10-19 22:15:59 +00:00
|
|
|
if err := fakeDocker.AssertStopped([]string{unhealthyContainerID}); err != nil {
|
2015-05-26 23:45:38 +00:00
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodsDoesNothing(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
container := v1.Container{Name: "bar"}
|
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
container,
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
2015-05-26 23:45:38 +00:00
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "1234",
|
2017-01-25 23:01:41 +00:00
|
|
|
Name: "/k8s_bar." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&container), 16) + "_foo_new_12345678_0",
|
2015-05-26 23:45:38 +00:00
|
|
|
},
|
|
|
|
{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
}})
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-26 23:45:38 +00:00
|
|
|
|
2016-02-01 22:56:56 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{})
|
2015-05-26 23:45:38 +00:00
|
|
|
}
|
2015-05-27 18:00:20 +00:00
|
|
|
|
|
|
|
func TestSyncPodWithRestartPolicy(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
containers := []v1.Container{
|
2015-05-27 18:00:20 +00:00
|
|
|
{Name: "succeeded"},
|
|
|
|
{Name: "failed"},
|
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
2016-08-29 15:36:33 +00:00
|
|
|
Containers: containers,
|
|
|
|
})
|
2016-04-04 22:27:20 +00:00
|
|
|
dockerContainers := []*FakeContainer{
|
2015-05-27 18:00:20 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
Running: true,
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
2015-11-11 00:51:35 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "1234",
|
2017-01-25 23:01:41 +00:00
|
|
|
Name: "/k8s_succeeded." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&containers[0]), 16) + "_foo_new_12345678_0",
|
2016-04-04 22:27:20 +00:00
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
2015-11-11 00:51:35 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "5678",
|
2017-01-25 23:01:41 +00:00
|
|
|
Name: "/k8s_failed." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&containers[1]), 16) + "_foo_new_12345678_0",
|
2016-04-04 22:27:20 +00:00
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
2015-11-11 00:51:35 +00:00
|
|
|
}}
|
2015-05-27 18:00:20 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
2016-11-18 20:50:58 +00:00
|
|
|
policy v1.RestartPolicy
|
2015-05-27 18:00:20 +00:00
|
|
|
calls []string
|
|
|
|
created []string
|
|
|
|
stopped []string
|
|
|
|
}{
|
|
|
|
{
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.RestartPolicyAlways,
|
2015-05-27 18:00:20 +00:00
|
|
|
[]string{
|
|
|
|
// Restart both containers.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container", "create", "start", "inspect_container",
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
|
|
|
[]string{"succeeded", "failed"},
|
|
|
|
[]string{},
|
|
|
|
},
|
|
|
|
{
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.RestartPolicyOnFailure,
|
2015-05-27 18:00:20 +00:00
|
|
|
[]string{
|
|
|
|
// Restart the failed container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
|
|
|
[]string{"failed"},
|
|
|
|
[]string{},
|
|
|
|
},
|
|
|
|
{
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.RestartPolicyNever,
|
2015-05-27 18:00:20 +00:00
|
|
|
[]string{
|
|
|
|
// Check the pod infra container.
|
2016-02-01 22:56:56 +00:00
|
|
|
"inspect_container", "inspect_container",
|
2015-05-27 18:00:20 +00:00
|
|
|
// Stop the last pod infra container.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop",
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
|
|
|
[]string{},
|
|
|
|
[]string{"9876"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
2015-11-11 00:51:35 +00:00
|
|
|
fakeDocker.SetFakeContainers(dockerContainers)
|
2015-05-27 18:00:20 +00:00
|
|
|
pod.Spec.RestartPolicy = tt.policy
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-05-27 18:00:20 +00:00
|
|
|
// 'stop' is because the pod infra container is killed when no container is running.
|
|
|
|
verifyCalls(t, fakeDocker, tt.calls)
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
if err := fakeDocker.AssertCreatedByName(tt.created); err != nil {
|
2016-01-22 21:14:41 +00:00
|
|
|
t.Errorf("case [%d]: %v", i, err)
|
2015-05-27 18:00:20 +00:00
|
|
|
}
|
|
|
|
if err := fakeDocker.AssertStopped(tt.stopped); err != nil {
|
2016-01-22 21:14:41 +00:00
|
|
|
t.Errorf("case [%d]: %v", i, err)
|
2015-05-27 18:00:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 12:59:15 +00:00
|
|
|
func TestSyncPodBackoff(t *testing.T) {
|
2016-05-26 03:08:56 +00:00
|
|
|
var fakeClock = clock.NewFakeClock(time.Now())
|
2015-08-13 12:59:15 +00:00
|
|
|
startTime := fakeClock.Now()
|
|
|
|
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
containers := []v1.Container{
|
2015-08-13 12:59:15 +00:00
|
|
|
{Name: "good"},
|
|
|
|
{Name: "bad"},
|
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("podfoo", &v1.PodSpec{
|
2016-08-29 15:36:33 +00:00
|
|
|
Containers: containers,
|
|
|
|
})
|
2015-08-13 12:59:15 +00:00
|
|
|
|
2017-01-25 23:01:41 +00:00
|
|
|
stableId := "k8s_bad." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&containers[1]), 16) + "_podfoo_new_12345678"
|
2016-04-04 22:27:20 +00:00
|
|
|
dockerContainers := []*FakeContainer{
|
2015-11-11 00:51:35 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "9876",
|
2016-08-29 15:36:33 +00:00
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_podfoo_new_12345678_0",
|
2016-04-04 22:27:20 +00:00
|
|
|
StartedAt: startTime,
|
|
|
|
Running: true,
|
2015-08-13 12:59:15 +00:00
|
|
|
},
|
2015-11-11 00:51:35 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "1234",
|
2017-01-25 23:01:41 +00:00
|
|
|
Name: "/k8s_good." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&containers[0]), 16) + "_podfoo_new_12345678_0",
|
2016-04-04 22:27:20 +00:00
|
|
|
StartedAt: startTime,
|
|
|
|
Running: true,
|
2015-08-13 12:59:15 +00:00
|
|
|
},
|
2015-11-11 00:51:35 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: "5678",
|
2017-01-25 23:01:41 +00:00
|
|
|
Name: "/k8s_bad." + strconv.FormatUint(kubecontainer.HashContainerLegacy(&containers[1]), 16) + "_podfoo_new_12345678_0",
|
2016-04-04 22:27:20 +00:00
|
|
|
ExitCode: 42,
|
|
|
|
StartedAt: startTime,
|
|
|
|
FinishedAt: fakeClock.Now(),
|
2015-08-13 12:59:15 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2016-02-01 22:56:56 +00:00
|
|
|
startCalls := []string{"create", "start", "inspect_container"}
|
|
|
|
backOffCalls := []string{}
|
2016-03-23 23:45:24 +00:00
|
|
|
startResult := &kubecontainer.SyncResult{Action: kubecontainer.StartContainer, Target: "bad", Error: nil, Message: ""}
|
|
|
|
backoffResult := &kubecontainer.SyncResult{Action: kubecontainer.StartContainer, Target: "bad", Error: kubecontainer.ErrCrashLoopBackOff, Message: ""}
|
2015-08-13 12:59:15 +00:00
|
|
|
tests := []struct {
|
|
|
|
tick int
|
|
|
|
backoff int
|
|
|
|
killDelay int
|
|
|
|
result []string
|
2015-09-02 17:18:11 +00:00
|
|
|
expectErr bool
|
2015-08-13 12:59:15 +00:00
|
|
|
}{
|
2015-09-02 17:18:11 +00:00
|
|
|
{1, 1, 1, startCalls, false},
|
|
|
|
{2, 2, 2, startCalls, false},
|
|
|
|
{3, 2, 3, backOffCalls, true},
|
|
|
|
{4, 4, 4, startCalls, false},
|
|
|
|
{5, 4, 5, backOffCalls, true},
|
|
|
|
{6, 4, 6, backOffCalls, true},
|
|
|
|
{7, 4, 7, backOffCalls, true},
|
|
|
|
{8, 8, 129, startCalls, false},
|
|
|
|
{130, 1, 0, startCalls, false},
|
2015-08-13 12:59:15 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 02:58:24 +00:00
|
|
|
backOff := flowcontrol.NewBackOff(time.Second, time.Minute)
|
2015-08-13 12:59:15 +00:00
|
|
|
backOff.Clock = fakeClock
|
|
|
|
for _, c := range tests {
|
2015-11-11 00:51:35 +00:00
|
|
|
fakeDocker.SetFakeContainers(dockerContainers)
|
2016-02-01 18:50:05 +00:00
|
|
|
fakeClock.SetTime(startTime.Add(time.Duration(c.tick) * time.Second))
|
2015-08-13 12:59:15 +00:00
|
|
|
|
2016-02-10 22:45:03 +00:00
|
|
|
result := runSyncPod(t, dm, fakeDocker, pod, backOff, c.expectErr)
|
2015-08-13 12:59:15 +00:00
|
|
|
verifyCalls(t, fakeDocker, c.result)
|
|
|
|
|
2016-02-10 22:45:03 +00:00
|
|
|
// Verify whether the correct sync pod result is generated
|
|
|
|
if c.expectErr {
|
|
|
|
verifySyncResults(t, []*kubecontainer.SyncResult{backoffResult}, result)
|
|
|
|
} else {
|
|
|
|
verifySyncResults(t, []*kubecontainer.SyncResult{startResult}, result)
|
|
|
|
}
|
|
|
|
|
2015-08-13 12:59:15 +00:00
|
|
|
if backOff.Get(stableId) != time.Duration(c.backoff)*time.Second {
|
|
|
|
t.Errorf("At tick %s expected backoff=%s got=%s", time.Duration(c.tick)*time.Second, time.Duration(c.backoff)*time.Second, backOff.Get(stableId))
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fakeDocker.Created) > 0 {
|
|
|
|
// pretend kill the container
|
|
|
|
fakeDocker.Created = nil
|
2016-04-04 22:27:20 +00:00
|
|
|
dockerContainers[2].FinishedAt = startTime.Add(time.Duration(c.killDelay) * time.Second)
|
2015-08-13 12:59:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-27 18:00:20 +00:00
|
|
|
|
|
|
|
func TestGetRestartCount(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-01-27 01:46:15 +00:00
|
|
|
containerName := "bar"
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := *makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: containerName},
|
2015-05-27 18:00:20 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
RestartPolicy: "Always",
|
|
|
|
})
|
2016-11-18 20:50:58 +00:00
|
|
|
pod.Status = v1.PodStatus{
|
|
|
|
ContainerStatuses: []v1.ContainerStatus{
|
2016-08-29 15:36:33 +00:00
|
|
|
{
|
|
|
|
Name: containerName,
|
|
|
|
RestartCount: 3,
|
2016-01-27 01:46:15 +00:00
|
|
|
},
|
|
|
|
},
|
2015-05-27 18:00:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function for verifying the restart count.
|
2016-11-18 20:50:58 +00:00
|
|
|
verifyRestartCount := func(pod *v1.Pod, expectedCount int) {
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2016-01-27 01:46:15 +00:00
|
|
|
status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
|
2015-05-27 18:00:20 +00:00
|
|
|
if err != nil {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Fatalf("unexpected error %v", err)
|
2015-05-27 18:00:20 +00:00
|
|
|
}
|
2016-01-27 01:46:15 +00:00
|
|
|
cs := status.FindContainerStatusByName(containerName)
|
|
|
|
if cs == nil {
|
2016-03-23 00:26:50 +00:00
|
|
|
t.Fatalf("Can't find status for container %q", containerName)
|
2016-01-27 01:46:15 +00:00
|
|
|
}
|
|
|
|
restartCount := cs.RestartCount
|
2015-05-27 18:00:20 +00:00
|
|
|
if restartCount != expectedCount {
|
|
|
|
t.Errorf("expected %d restart count, got %d", expectedCount, restartCount)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
killOneContainer := func(pod *v1.Pod) {
|
2016-01-27 01:46:15 +00:00
|
|
|
status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
|
2015-10-23 20:02:32 +00:00
|
|
|
if err != nil {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Fatalf("unexpected error %v", err)
|
2015-10-23 20:02:32 +00:00
|
|
|
}
|
2016-01-27 01:46:15 +00:00
|
|
|
cs := status.FindContainerStatusByName(containerName)
|
|
|
|
if cs == nil {
|
2016-03-23 00:26:50 +00:00
|
|
|
t.Fatalf("Can't find status for container %q", containerName)
|
2016-01-27 01:46:15 +00:00
|
|
|
}
|
2016-04-27 03:30:59 +00:00
|
|
|
dm.KillContainerInPod(cs.ID, &pod.Spec.Containers[0], pod, "test container restart count.", nil)
|
2015-10-23 20:02:32 +00:00
|
|
|
}
|
|
|
|
// Container "bar" starts the first time.
|
2015-05-27 18:00:20 +00:00
|
|
|
// TODO: container lists are expected to be sorted reversely by time.
|
|
|
|
// We should fix FakeDockerClient to sort the list before returning.
|
2015-10-23 20:02:32 +00:00
|
|
|
// (randome-liu) Just partially sorted now.
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 0)
|
2015-10-23 20:02:32 +00:00
|
|
|
killOneContainer(&pod)
|
|
|
|
|
|
|
|
// Poor container "bar" has been killed, and should be restarted with restart count 1
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 1)
|
2015-10-23 20:02:32 +00:00
|
|
|
killOneContainer(&pod)
|
2015-05-27 18:00:20 +00:00
|
|
|
|
2015-10-23 20:02:32 +00:00
|
|
|
// Poor container "bar" has been killed again, and should be restarted with restart count 2
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 2)
|
2015-10-23 20:02:32 +00:00
|
|
|
killOneContainer(&pod)
|
|
|
|
|
|
|
|
// Poor container "bar" has been killed again ang again, and should be restarted with restart count 3
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 3)
|
2015-10-23 20:02:32 +00:00
|
|
|
|
|
|
|
// The oldest container has been garbage collected
|
|
|
|
exitedContainers := fakeDocker.ExitedContainerList
|
|
|
|
fakeDocker.ExitedContainerList = exitedContainers[:len(exitedContainers)-1]
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 3)
|
2015-05-27 18:00:20 +00:00
|
|
|
|
2015-10-23 20:02:32 +00:00
|
|
|
// The last two oldest containers have been garbage collected
|
|
|
|
fakeDocker.ExitedContainerList = exitedContainers[:len(exitedContainers)-2]
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 3)
|
2015-10-23 20:02:32 +00:00
|
|
|
|
2016-01-27 01:46:15 +00:00
|
|
|
// All exited containers have been garbage collected, restart count should be got from old api pod status
|
2016-04-04 08:56:49 +00:00
|
|
|
fakeDocker.ExitedContainerList = []dockertypes.Container{}
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 3)
|
2015-10-23 20:02:32 +00:00
|
|
|
killOneContainer(&pod)
|
|
|
|
|
|
|
|
// Poor container "bar" has been killed again ang again and again, and should be restarted with restart count 4
|
2016-01-27 01:46:15 +00:00
|
|
|
verifyRestartCount(&pod, 4)
|
2015-05-27 18:00:20 +00:00
|
|
|
}
|
2015-06-01 19:30:51 +00:00
|
|
|
|
2015-11-02 22:32:58 +00:00
|
|
|
func TestGetTerminationMessagePath(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
containers := []v1.Container{
|
2015-11-02 22:32:58 +00:00
|
|
|
{
|
|
|
|
Name: "bar",
|
|
|
|
TerminationMessagePath: "/dev/somepath",
|
|
|
|
},
|
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
2016-08-29 15:36:33 +00:00
|
|
|
Containers: containers,
|
|
|
|
})
|
2015-11-02 22:32:58 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-11-02 22:32:58 +00:00
|
|
|
|
2016-04-04 08:56:49 +00:00
|
|
|
containerList := fakeDocker.RunningContainerList
|
2015-11-02 22:32:58 +00:00
|
|
|
if len(containerList) != 2 {
|
|
|
|
// One for infra container, one for container "bar"
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Fatalf("unexpected container list length %d", len(containerList))
|
2015-11-02 22:32:58 +00:00
|
|
|
}
|
2016-04-04 22:27:20 +00:00
|
|
|
inspectResult, err := fakeDocker.InspectContainer(containerList[0].ID)
|
2015-11-02 22:32:58 +00:00
|
|
|
if err != nil {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Fatalf("unexpected inspect error: %v", err)
|
2015-11-13 19:37:33 +00:00
|
|
|
}
|
2015-12-30 07:46:52 +00:00
|
|
|
containerInfo := getContainerInfoFromLabel(inspectResult.Config.Labels)
|
2015-11-13 19:37:33 +00:00
|
|
|
terminationMessagePath := containerInfo.TerminationMessagePath
|
2015-11-02 22:32:58 +00:00
|
|
|
if terminationMessagePath != containers[0].TerminationMessagePath {
|
|
|
|
t.Errorf("expected termination message path %s, got %s", containers[0].TerminationMessagePath, terminationMessagePath)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-01 19:30:51 +00:00
|
|
|
func TestSyncPodWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
|
|
|
|
fakeHTTPClient := &fakeHTTP{}
|
|
|
|
dm, fakeDocker := newTestDockerManagerWithHTTPClient(fakeHTTPClient)
|
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{
|
|
|
|
Name: "bar",
|
2016-11-18 20:50:58 +00:00
|
|
|
Lifecycle: &v1.Lifecycle{
|
|
|
|
PostStart: &v1.Handler{
|
|
|
|
HTTPGet: &v1.HTTPGetAction{
|
2016-08-29 15:36:33 +00:00
|
|
|
Host: "foo",
|
|
|
|
Port: intstr.FromInt(8080),
|
|
|
|
Path: "bar",
|
2015-06-01 19:30:51 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
}})
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-06-01 19:30:51 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create container.
|
2015-06-15 21:38:45 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-06-01 19:30:51 +00:00
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByName([]string{"bar"}))
|
|
|
|
|
2015-06-01 19:30:51 +00:00
|
|
|
if fakeHTTPClient.url != "http://foo:8080/bar" {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Errorf("unexpected handler: %q", fakeHTTPClient.url)
|
2015-06-01 19:30:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodEventHandlerFails(t *testing.T) {
|
|
|
|
// Simulate HTTP failure.
|
|
|
|
fakeHTTPClient := &fakeHTTP{err: fmt.Errorf("test error")}
|
|
|
|
dm, fakeDocker := newTestDockerManagerWithHTTPClient(fakeHTTPClient)
|
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar",
|
2016-11-18 20:50:58 +00:00
|
|
|
Lifecycle: &v1.Lifecycle{
|
|
|
|
PostStart: &v1.Handler{
|
|
|
|
HTTPGet: &v1.HTTPGetAction{
|
2016-08-29 15:36:33 +00:00
|
|
|
Host: "does.no.exist",
|
|
|
|
Port: intstr.FromInt(8080),
|
|
|
|
Path: "bar",
|
2015-06-01 19:30:51 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-06-01 19:30:51 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
|
2015-11-11 00:51:35 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
}})
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, true)
|
2015-06-01 19:30:51 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create the container.
|
|
|
|
"create", "start",
|
|
|
|
// Kill the container since event handler fails.
|
2015-08-20 01:57:58 +00:00
|
|
|
"stop",
|
2015-06-01 19:30:51 +00:00
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertStoppedByName([]string{"bar"}))
|
2015-06-01 19:30:51 +00:00
|
|
|
}
|
2015-06-05 21:10:45 +00:00
|
|
|
|
2015-09-22 20:29:51 +00:00
|
|
|
type fakeReadWriteCloser struct{}
|
|
|
|
|
|
|
|
func (*fakeReadWriteCloser) Read([]byte) (int, error) { return 0, nil }
|
|
|
|
func (*fakeReadWriteCloser) Write([]byte) (int, error) { return 0, nil }
|
|
|
|
func (*fakeReadWriteCloser) Close() error { return nil }
|
|
|
|
|
2015-06-05 21:10:45 +00:00
|
|
|
func TestPortForwardNoSuchContainer(t *testing.T) {
|
|
|
|
dm, _ := newTestDockerManager()
|
|
|
|
|
|
|
|
podName, podNamespace := "podName", "podNamespace"
|
|
|
|
err := dm.PortForward(
|
|
|
|
&kubecontainer.Pod{
|
|
|
|
ID: "podID",
|
|
|
|
Name: podName,
|
|
|
|
Namespace: podNamespace,
|
|
|
|
Containers: nil,
|
|
|
|
},
|
|
|
|
5000,
|
2015-09-22 20:29:51 +00:00
|
|
|
// need a valid io.ReadWriteCloser here
|
|
|
|
&fakeReadWriteCloser{},
|
2015-06-05 21:10:45 +00:00
|
|
|
)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("unexpected non-error")
|
|
|
|
}
|
|
|
|
expectedErr := noPodInfraContainerError(podName, podNamespace)
|
|
|
|
if !reflect.DeepEqual(err, expectedErr) {
|
|
|
|
t.Fatalf("expected %v, but saw %v", expectedErr, err)
|
|
|
|
}
|
|
|
|
}
|
2015-06-05 22:37:53 +00:00
|
|
|
|
|
|
|
func TestSyncPodWithTerminationLog(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2017-02-27 04:07:49 +00:00
|
|
|
// Set test pod container directory.
|
|
|
|
testPodContainerDir := "test/pod/container/dir"
|
|
|
|
dm.runtimeHelper.(*containertest.FakeRuntimeHelper).PodContainerDir = testPodContainerDir
|
2016-11-18 20:50:58 +00:00
|
|
|
container := v1.Container{
|
2015-06-05 22:37:53 +00:00
|
|
|
Name: "bar",
|
|
|
|
TerminationMessagePath: "/dev/somepath",
|
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
container,
|
2015-06-05 22:37:53 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-06-05 22:37:53 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-06-05 22:37:53 +00:00
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create pod infra container.
|
2015-09-11 21:23:15 +00:00
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
2015-06-05 22:37:53 +00:00
|
|
|
// Create container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
defer os.Remove(testPodContainerDir)
|
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByNameWithOrder([]string{"POD", "bar"}))
|
|
|
|
|
2015-11-19 21:59:18 +00:00
|
|
|
newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
parts := strings.Split(newContainer.HostConfig.Binds[0], ":")
|
2016-02-04 00:40:04 +00:00
|
|
|
if !matchString(t, testPodContainerDir+"/[a-f0-9]", parts[0]) {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Errorf("unexpected host path: %s", parts[0])
|
2015-06-05 22:37:53 +00:00
|
|
|
}
|
|
|
|
if parts[1] != "/dev/somepath" {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Errorf("unexpected container path: %s", parts[1])
|
2015-06-05 22:37:53 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-21 03:57:22 +00:00
|
|
|
|
2015-08-19 08:56:19 +00:00
|
|
|
func TestSyncPodWithHostNetwork(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar"},
|
2015-08-19 08:56:19 +00:00
|
|
|
},
|
2016-11-19 23:32:10 +00:00
|
|
|
HostNetwork: true,
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2015-08-19 08:56:19 +00:00
|
|
|
|
2015-09-02 17:18:11 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
2015-08-19 08:56:19 +00:00
|
|
|
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create pod infra container.
|
2016-02-01 22:56:56 +00:00
|
|
|
"create", "start", "inspect_container",
|
2015-08-19 08:56:19 +00:00
|
|
|
// Create container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
})
|
|
|
|
|
2017-02-28 20:54:51 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertCreatedByNameWithOrder([]string{"POD", "bar"}))
|
2015-08-19 08:56:19 +00:00
|
|
|
|
2015-11-19 21:59:18 +00:00
|
|
|
newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %v", err)
|
|
|
|
}
|
|
|
|
utsMode := newContainer.HostConfig.UTSMode
|
2015-08-19 08:56:19 +00:00
|
|
|
if utsMode != "host" {
|
|
|
|
t.Errorf("Pod with host network must have \"host\" utsMode, actual: \"%v\"", utsMode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-10 17:30:34 +00:00
|
|
|
func TestVerifyNonRoot(t *testing.T) {
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
|
|
|
|
|
|
|
// setup test cases.
|
|
|
|
var rootUid int64 = 0
|
|
|
|
var nonRootUid int64 = 1
|
|
|
|
|
|
|
|
tests := map[string]struct {
|
2016-11-18 20:50:58 +00:00
|
|
|
container *v1.Container
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage *dockertypes.ImageInspect
|
2015-08-10 17:30:34 +00:00
|
|
|
expectedError string
|
|
|
|
}{
|
|
|
|
// success cases
|
|
|
|
"non-root runAsUser": {
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2017-03-02 01:18:02 +00:00
|
|
|
Image: "foobar",
|
2016-11-18 20:50:58 +00:00
|
|
|
SecurityContext: &v1.SecurityContext{
|
2015-08-10 17:30:34 +00:00
|
|
|
RunAsUser: &nonRootUid,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"numeric non-root image user": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage: &dockertypes.ImageInspect{
|
2017-03-02 01:18:02 +00:00
|
|
|
ID: "foobar",
|
2016-04-06 15:06:37 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-08-10 17:30:34 +00:00
|
|
|
User: "1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"numeric non-root image user with gid": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage: &dockertypes.ImageInspect{
|
2017-03-02 01:18:02 +00:00
|
|
|
ID: "foobar",
|
2016-04-06 15:06:37 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-08-10 17:30:34 +00:00
|
|
|
User: "1:2",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
// failure cases
|
|
|
|
"root runAsUser": {
|
2016-11-18 20:50:58 +00:00
|
|
|
container: &v1.Container{
|
2017-03-02 01:18:02 +00:00
|
|
|
Image: "foobar",
|
2016-11-18 20:50:58 +00:00
|
|
|
SecurityContext: &v1.SecurityContext{
|
2015-08-10 17:30:34 +00:00
|
|
|
RunAsUser: &rootUid,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedError: "container's runAsUser breaks non-root policy",
|
|
|
|
},
|
|
|
|
"non-numeric image user": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage: &dockertypes.ImageInspect{
|
2017-03-02 01:18:02 +00:00
|
|
|
ID: "foobar",
|
2016-04-06 15:06:37 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-08-10 17:30:34 +00:00
|
|
|
User: "foo",
|
|
|
|
},
|
|
|
|
},
|
2016-01-26 00:31:32 +00:00
|
|
|
expectedError: "non-numeric user",
|
2015-08-10 17:30:34 +00:00
|
|
|
},
|
|
|
|
"numeric root image user": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage: &dockertypes.ImageInspect{
|
2017-03-02 01:18:02 +00:00
|
|
|
ID: "foobar",
|
2016-04-06 15:06:37 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-08-10 17:30:34 +00:00
|
|
|
User: "0",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedError: "container has no runAsUser and image will run as root",
|
|
|
|
},
|
|
|
|
"numeric root image user with gid": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-04-06 14:15:38 +00:00
|
|
|
inspectImage: &dockertypes.ImageInspect{
|
2017-03-02 01:18:02 +00:00
|
|
|
ID: "foobar",
|
2016-04-06 15:06:37 +00:00
|
|
|
Config: &dockercontainer.Config{
|
2015-08-10 17:30:34 +00:00
|
|
|
User: "0:1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedError: "container has no runAsUser and image will run as root",
|
|
|
|
},
|
|
|
|
"nil image in inspect": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
2016-10-08 04:35:18 +00:00
|
|
|
inspectImage: nil,
|
2017-03-02 01:18:02 +00:00
|
|
|
expectedError: ImageNotFoundError{"foobar"}.Error(),
|
2015-08-10 17:30:34 +00:00
|
|
|
},
|
|
|
|
"nil config in image inspect": {
|
2017-03-02 01:18:02 +00:00
|
|
|
container: &v1.Container{Image: "foobar"},
|
|
|
|
inspectImage: &dockertypes.ImageInspect{ID: "foobar"},
|
2015-08-10 17:30:34 +00:00
|
|
|
expectedError: "unable to inspect image",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range tests {
|
2017-03-02 01:18:02 +00:00
|
|
|
fakeDocker.ResetImages()
|
|
|
|
if v.inspectImage != nil {
|
|
|
|
fakeDocker.InjectImageInspects([]dockertypes.ImageInspect{*v.inspectImage})
|
|
|
|
}
|
2015-08-10 17:30:34 +00:00
|
|
|
err := dm.verifyNonRoot(v.container)
|
|
|
|
if v.expectedError == "" && err != nil {
|
2016-01-26 00:31:32 +00:00
|
|
|
t.Errorf("case[%q]: unexpected error: %v", k, err)
|
2015-08-10 17:30:34 +00:00
|
|
|
}
|
|
|
|
if v.expectedError != "" && !strings.Contains(err.Error(), v.expectedError) {
|
2016-01-26 00:31:32 +00:00
|
|
|
t.Errorf("case[%q]: expected: %q, got: %q", k, v.expectedError, err.Error())
|
2015-08-10 17:30:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-08 07:35:11 +00:00
|
|
|
func TestGetUserFromImageUser(t *testing.T) {
|
2015-08-10 17:30:34 +00:00
|
|
|
tests := map[string]struct {
|
|
|
|
input string
|
|
|
|
expect string
|
|
|
|
}{
|
|
|
|
"no gid": {
|
|
|
|
input: "0",
|
|
|
|
expect: "0",
|
|
|
|
},
|
|
|
|
"uid/gid": {
|
|
|
|
input: "0:1",
|
|
|
|
expect: "0",
|
|
|
|
},
|
|
|
|
"empty input": {
|
|
|
|
input: "",
|
|
|
|
expect: "",
|
|
|
|
},
|
|
|
|
"multiple spearators": {
|
|
|
|
input: "1:2:3",
|
|
|
|
expect: "1",
|
|
|
|
},
|
2016-11-08 07:35:11 +00:00
|
|
|
"root username": {
|
|
|
|
input: "root:root",
|
|
|
|
expect: "root",
|
|
|
|
},
|
|
|
|
"username": {
|
|
|
|
input: "test:test",
|
|
|
|
expect: "test",
|
|
|
|
},
|
2015-08-10 17:30:34 +00:00
|
|
|
}
|
|
|
|
for k, v := range tests {
|
2016-11-08 07:35:11 +00:00
|
|
|
actual := GetUserFromImageUser(v.input)
|
2015-08-10 17:30:34 +00:00
|
|
|
if actual != v.expect {
|
|
|
|
t.Errorf("%s failed. Expected %s but got %s", k, v.expect, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-15 16:43:59 +00:00
|
|
|
|
|
|
|
func TestGetPidMode(t *testing.T) {
|
|
|
|
// test false
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := &v1.Pod{}
|
2015-09-15 16:43:59 +00:00
|
|
|
pidMode := getPidMode(pod)
|
|
|
|
|
|
|
|
if pidMode != "" {
|
|
|
|
t.Errorf("expected empty pid mode for pod but got %v", pidMode)
|
|
|
|
}
|
|
|
|
|
|
|
|
// test true
|
2016-11-18 20:50:58 +00:00
|
|
|
pod.Spec.SecurityContext = &v1.PodSecurityContext{}
|
|
|
|
pod.Spec.HostPID = true
|
2015-09-15 16:43:59 +00:00
|
|
|
pidMode = getPidMode(pod)
|
|
|
|
if pidMode != "host" {
|
|
|
|
t.Errorf("expected host pid mode for pod but got %v", pidMode)
|
|
|
|
}
|
|
|
|
}
|
2015-08-10 08:14:01 +00:00
|
|
|
|
|
|
|
func TestGetIPCMode(t *testing.T) {
|
|
|
|
// test false
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := &v1.Pod{}
|
2015-09-21 15:34:02 +00:00
|
|
|
ipcMode := getIPCMode(pod)
|
2015-08-10 08:14:01 +00:00
|
|
|
|
|
|
|
if ipcMode != "" {
|
|
|
|
t.Errorf("expected empty ipc mode for pod but got %v", ipcMode)
|
|
|
|
}
|
|
|
|
|
|
|
|
// test true
|
2016-11-18 20:50:58 +00:00
|
|
|
pod.Spec.SecurityContext = &v1.PodSecurityContext{}
|
|
|
|
pod.Spec.HostIPC = true
|
2015-09-21 15:34:02 +00:00
|
|
|
ipcMode = getIPCMode(pod)
|
2015-08-10 08:14:01 +00:00
|
|
|
if ipcMode != "host" {
|
|
|
|
t.Errorf("expected host ipc mode for pod but got %v", ipcMode)
|
|
|
|
}
|
|
|
|
}
|
2016-01-27 01:46:15 +00:00
|
|
|
|
2016-02-10 22:45:03 +00:00
|
|
|
func TestSyncPodWithPullPolicy(t *testing.T) {
|
2016-09-21 23:20:07 +00:00
|
|
|
dm, fakeDocker := newTestDockerManagerWithRealImageManager()
|
2017-03-02 01:18:02 +00:00
|
|
|
fakeDocker.InjectImages([]dockertypes.Image{{ID: "foo/existing_one:v1"}, {ID: "foo/want:latest"}})
|
|
|
|
|
2016-09-21 23:20:07 +00:00
|
|
|
dm.podInfraContainerImage = "foo/infra_image:v1"
|
2016-02-10 22:45:03 +00:00
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
|
|
|
{Name: "bar", Image: "foo/pull_always_image:v1", ImagePullPolicy: v1.PullAlways},
|
|
|
|
{Name: "bar2", Image: "foo/pull_if_not_present_image:v1", ImagePullPolicy: v1.PullIfNotPresent},
|
|
|
|
{Name: "bar3", Image: "foo/existing_one:v1", ImagePullPolicy: v1.PullIfNotPresent},
|
|
|
|
{Name: "bar4", Image: "foo/want:latest", ImagePullPolicy: v1.PullIfNotPresent},
|
|
|
|
{Name: "bar5", Image: "foo/pull_never_image:v1", ImagePullPolicy: v1.PullNever},
|
2016-02-10 22:45:03 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-02-10 22:45:03 +00:00
|
|
|
|
|
|
|
expectedResults := []*kubecontainer.SyncResult{
|
|
|
|
//Sync result for infra container
|
|
|
|
{kubecontainer.StartContainer, PodInfraContainerName, nil, ""},
|
|
|
|
{kubecontainer.SetupNetwork, kubecontainer.GetPodFullName(pod), nil, ""},
|
|
|
|
//Sync result for user containers
|
|
|
|
{kubecontainer.StartContainer, "bar", nil, ""},
|
|
|
|
{kubecontainer.StartContainer, "bar2", nil, ""},
|
|
|
|
{kubecontainer.StartContainer, "bar3", nil, ""},
|
|
|
|
{kubecontainer.StartContainer, "bar4", nil, ""},
|
2016-07-19 22:42:21 +00:00
|
|
|
{kubecontainer.StartContainer, "bar5", images.ErrImageNeverPull,
|
2016-09-21 23:20:07 +00:00
|
|
|
"Container image \"foo/pull_never_image:v1\" is not present with pull policy of Never"},
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result := runSyncPod(t, dm, fakeDocker, pod, nil, true)
|
|
|
|
verifySyncResults(t, expectedResults, result)
|
|
|
|
|
2017-03-02 01:18:02 +00:00
|
|
|
assert.NoError(t, fakeDocker.AssertImagesPulled([]string{"foo/infra_image:v1", "foo/pull_always_image:v1", "foo/pull_if_not_present_image:v1"}))
|
|
|
|
|
2016-02-10 22:45:03 +00:00
|
|
|
fakeDocker.Lock()
|
|
|
|
defer fakeDocker.Unlock()
|
|
|
|
|
|
|
|
if len(fakeDocker.Created) != 5 {
|
2016-02-23 21:27:28 +00:00
|
|
|
t.Errorf("unexpected containers created %v", fakeDocker.Created)
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test only covers SyncPod with PullImageFailure, CreateContainerFailure and StartContainerFailure.
|
|
|
|
// There are still quite a few failure cases not covered.
|
|
|
|
// TODO(random-liu): Better way to test the SyncPod failures.
|
|
|
|
func TestSyncPodWithFailure(t *testing.T) {
|
2016-08-29 15:36:33 +00:00
|
|
|
pod := makePod("foo", nil)
|
2016-02-10 22:45:03 +00:00
|
|
|
tests := map[string]struct {
|
2016-11-18 20:50:58 +00:00
|
|
|
container v1.Container
|
2016-02-10 22:45:03 +00:00
|
|
|
dockerError map[string]error
|
|
|
|
expected []*kubecontainer.SyncResult
|
|
|
|
}{
|
|
|
|
"PullImageFailure": {
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.Container{Name: "bar", Image: "foo/real_image:v1", ImagePullPolicy: v1.PullAlways},
|
2017-03-02 01:18:02 +00:00
|
|
|
map[string]error{"pull": fmt.Errorf("can't pull image")},
|
2016-07-19 22:42:21 +00:00
|
|
|
[]*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", images.ErrImagePull, "can't pull image"}},
|
2016-02-10 22:45:03 +00:00
|
|
|
},
|
|
|
|
"CreateContainerFailure": {
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.Container{Name: "bar", Image: "foo/already_present:v2"},
|
2016-02-10 22:45:03 +00:00
|
|
|
map[string]error{"create": fmt.Errorf("can't create container")},
|
|
|
|
[]*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", kubecontainer.ErrRunContainer, "can't create container"}},
|
|
|
|
},
|
|
|
|
"StartContainerFailure": {
|
2016-11-18 20:50:58 +00:00
|
|
|
v1.Container{Name: "bar", Image: "foo/already_present:v2"},
|
2016-02-10 22:45:03 +00:00
|
|
|
map[string]error{"start": fmt.Errorf("can't start container")},
|
|
|
|
[]*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", kubecontainer.ErrRunContainer, "can't start container"}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2016-09-21 23:20:07 +00:00
|
|
|
dm, fakeDocker := newTestDockerManagerWithRealImageManager()
|
2017-03-02 01:18:02 +00:00
|
|
|
fakeDocker.InjectImages([]dockertypes.Image{{ID: test.container.Image}})
|
2016-02-23 04:34:33 +00:00
|
|
|
// Pretend that the pod infra container has already been created, so that
|
|
|
|
// we can run the user containers.
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
|
2016-02-23 04:34:33 +00:00
|
|
|
ID: "9876",
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
|
|
|
|
}})
|
2016-03-03 10:01:15 +00:00
|
|
|
fakeDocker.InjectErrors(test.dockerError)
|
2016-11-18 20:50:58 +00:00
|
|
|
pod.Spec.Containers = []v1.Container{test.container}
|
2016-02-10 22:45:03 +00:00
|
|
|
result := runSyncPod(t, dm, fakeDocker, pod, nil, true)
|
|
|
|
verifySyncResults(t, test.expected, result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify whether all the expected results appear exactly only once in real result.
|
|
|
|
func verifySyncResults(t *testing.T, expectedResults []*kubecontainer.SyncResult, realResult kubecontainer.PodSyncResult) {
|
|
|
|
if len(expectedResults) != len(realResult.SyncResults) {
|
|
|
|
t.Errorf("expected sync result number %d, got %d", len(expectedResults), len(realResult.SyncResults))
|
|
|
|
for _, r := range expectedResults {
|
2016-06-14 12:04:38 +00:00
|
|
|
t.Errorf("expected result: %#v", r)
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
for _, r := range realResult.SyncResults {
|
|
|
|
t.Errorf("real result: %+v", r)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// The container start order is not fixed, because SyncPod() uses a map to store the containers to start.
|
|
|
|
// Here we should make sure each expected result appears only once in the real result.
|
|
|
|
for _, expectR := range expectedResults {
|
|
|
|
found := 0
|
|
|
|
for _, realR := range realResult.SyncResults {
|
|
|
|
// For the same action of the same container, the result should be the same
|
|
|
|
if realR.Target == expectR.Target && realR.Action == expectR.Action {
|
|
|
|
// We use Contains() here because the message format may be changed, but at least we should
|
|
|
|
// make sure that the expected message is contained.
|
|
|
|
if realR.Error != expectR.Error || !strings.Contains(realR.Message, expectR.Message) {
|
2016-06-14 12:04:38 +00:00
|
|
|
t.Errorf("expected sync result %#v, got %+v", expectR, realR)
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
found++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if found == 0 {
|
2016-06-14 12:04:38 +00:00
|
|
|
t.Errorf("not found expected result %#v", expectR)
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
if found > 1 {
|
2016-06-14 12:04:38 +00:00
|
|
|
t.Errorf("got %d duplicate expected result %#v", found, expectR)
|
2016-02-10 22:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-03 02:10:05 +00:00
|
|
|
func TestGetDockerOptSeparator(t *testing.T) {
|
2016-06-28 12:53:40 +00:00
|
|
|
dm110, _ := newTestDockerManagerWithVersion("1.10.1", "1.22")
|
|
|
|
dm111, _ := newTestDockerManagerWithVersion("1.11.0", "1.23")
|
|
|
|
|
2017-02-03 02:10:05 +00:00
|
|
|
sep, err := dm110.getDockerOptSeparator()
|
|
|
|
require.NoError(t, err, "error getting docker opt separator for 1.10.1")
|
|
|
|
assert.Equal(t, SecurityOptSeparatorOld, sep, "security opt separator for docker 1.10")
|
|
|
|
|
|
|
|
sep, err = dm111.getDockerOptSeparator()
|
|
|
|
require.NoError(t, err, "error getting docker opt separator for 1.11.1")
|
|
|
|
assert.Equal(t, SecurityOptSeparatorNew, sep, "security opt separator for docker 1.11")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFmtDockerOpts(t *testing.T) {
|
2016-08-26 22:32:48 +00:00
|
|
|
secOpts := []dockerOpt{{"seccomp", "unconfined", ""}}
|
2016-06-28 12:53:40 +00:00
|
|
|
|
2017-02-03 02:10:05 +00:00
|
|
|
opts := FmtDockerOpts(secOpts, ':')
|
|
|
|
assert.Len(t, opts, 1)
|
|
|
|
assert.Contains(t, opts, "seccomp:unconfined", "Docker 1.10")
|
|
|
|
|
|
|
|
opts = FmtDockerOpts(secOpts, '=')
|
|
|
|
assert.Len(t, opts, 1)
|
|
|
|
assert.Contains(t, opts, "seccomp=unconfined", "Docker 1.11")
|
2016-06-28 12:53:40 +00:00
|
|
|
}
|
|
|
|
|
2016-03-03 10:01:15 +00:00
|
|
|
func TestCheckVersionCompatibility(t *testing.T) {
|
|
|
|
type test struct {
|
|
|
|
version string
|
|
|
|
compatible bool
|
|
|
|
}
|
|
|
|
tests := []test{
|
|
|
|
// Minimum apiversion
|
|
|
|
{minimumDockerAPIVersion, true},
|
|
|
|
// Invalid apiversion
|
|
|
|
{"invalid_api_version", false},
|
|
|
|
// Older apiversion
|
2016-04-18 04:27:39 +00:00
|
|
|
{"1.0.0", false},
|
|
|
|
// Newer apiversion
|
|
|
|
// NOTE(random-liu): We need to bump up the newer apiversion,
|
|
|
|
// if docker apiversion really reaches "9.9.9" someday. But I
|
|
|
|
// really doubt whether the test could live that long.
|
|
|
|
{"9.9.9", true},
|
2016-03-03 10:01:15 +00:00
|
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
|
|
testCase := fmt.Sprintf("test case #%d test version %q", i, tt.version)
|
2016-04-18 04:27:39 +00:00
|
|
|
dm, fakeDocker := newTestDockerManagerWithVersion("", tt.version)
|
2016-03-03 10:01:15 +00:00
|
|
|
err := dm.checkVersionCompatibility()
|
|
|
|
assert.Equal(t, tt.compatible, err == nil, testCase)
|
|
|
|
if tt.compatible == true {
|
|
|
|
// Get docker version error
|
|
|
|
fakeDocker.InjectError("version", fmt.Errorf("injected version error"))
|
|
|
|
err := dm.checkVersionCompatibility()
|
|
|
|
assert.NotNil(t, err, testCase+" version error check")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-05 01:33:23 +00:00
|
|
|
|
2016-08-26 22:32:48 +00:00
|
|
|
func expectEvent(recorder *record.FakeRecorder, eventType, reason, msg string) error {
|
|
|
|
expected := fmt.Sprintf("%s %s %s", eventType, reason, msg)
|
|
|
|
var events []string
|
|
|
|
// Drain the event channel.
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case event := <-recorder.Events:
|
|
|
|
if event == expected {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
events = append(events, event)
|
|
|
|
default:
|
|
|
|
// No more events!
|
|
|
|
return fmt.Errorf("Event %q not found in [%s]", expected, strings.Join(events, ", "))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-29 20:44:16 +00:00
|
|
|
func TestNewDockerVersion(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
value string
|
|
|
|
out string
|
|
|
|
err bool
|
|
|
|
}{
|
|
|
|
{value: "1", err: true},
|
|
|
|
{value: "1.8", err: true},
|
|
|
|
{value: "1.8.1", out: "1.8.1"},
|
|
|
|
{value: "1.8.1-fc21.other", out: "1.8.1-fc21.other"},
|
|
|
|
{value: "1.8.1-beta.12", out: "1.8.1-beta.12"},
|
|
|
|
}
|
|
|
|
for _, test := range cases {
|
|
|
|
v, err := newDockerVersion(test.value)
|
|
|
|
switch {
|
|
|
|
case err != nil && test.err:
|
|
|
|
continue
|
|
|
|
case (err != nil) != test.err:
|
|
|
|
t.Errorf("error for %q: expected %t, got %v", test.value, test.err, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if v.String() != test.out {
|
|
|
|
t.Errorf("unexpected parsed version %q for %q", v, test.value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDockerVersionComparison(t *testing.T) {
|
|
|
|
v, err := newDockerVersion("1.10.3")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for i, test := range []struct {
|
|
|
|
version string
|
|
|
|
compare int
|
|
|
|
err bool
|
|
|
|
}{
|
|
|
|
{version: "1.9.2", compare: 1},
|
|
|
|
{version: "1.9.2-rc2", compare: 1},
|
|
|
|
{version: "1.10.3", compare: 0},
|
|
|
|
{version: "1.10.3-rc3", compare: 1},
|
|
|
|
{version: "1.10.4", compare: -1},
|
|
|
|
{version: "1.10.4-rc1", compare: -1},
|
|
|
|
{version: "1.11.1", compare: -1},
|
|
|
|
{version: "1.11.1-rc4", compare: -1},
|
2016-10-22 17:28:17 +00:00
|
|
|
{version: "invalid", err: true},
|
2016-06-29 20:44:16 +00:00
|
|
|
} {
|
|
|
|
testCase := fmt.Sprintf("test case #%d test version %q", i, test.version)
|
|
|
|
res, err := v.Compare(test.version)
|
|
|
|
assert.Equal(t, test.err, err != nil, testCase)
|
2016-10-22 17:28:17 +00:00
|
|
|
if !test.err {
|
|
|
|
assert.Equal(t, test.compare, res, testCase)
|
|
|
|
}
|
2016-06-29 20:44:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-18 04:27:39 +00:00
|
|
|
func TestVersion(t *testing.T) {
|
|
|
|
expectedVersion := "1.8.1"
|
|
|
|
expectedAPIVersion := "1.20"
|
|
|
|
dm, _ := newTestDockerManagerWithVersion(expectedVersion, expectedAPIVersion)
|
|
|
|
version, err := dm.Version()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("got error while getting docker server version - %v", err)
|
|
|
|
}
|
|
|
|
if e, a := expectedVersion, version.String(); e != a {
|
|
|
|
t.Errorf("expect docker server version %q, got %q", e, a)
|
|
|
|
}
|
|
|
|
|
|
|
|
apiVersion, err := dm.APIVersion()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("got error while getting docker api version - %v", err)
|
|
|
|
}
|
|
|
|
if e, a := expectedAPIVersion, apiVersion.String(); e != a {
|
|
|
|
t.Errorf("expect docker api version %q, got %q", e, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-05 01:33:23 +00:00
|
|
|
func TestGetPodStatusNoSuchContainer(t *testing.T) {
|
|
|
|
const (
|
|
|
|
noSuchContainerID = "nosuchcontainer"
|
|
|
|
infraContainerID = "9876"
|
|
|
|
)
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{{Name: "nosuchcontainer"}},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-03-05 01:33:23 +00:00
|
|
|
|
2016-04-04 22:27:20 +00:00
|
|
|
fakeDocker.SetFakeContainers([]*FakeContainer{
|
2016-03-05 01:33:23 +00:00
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: noSuchContainerID,
|
|
|
|
Name: "/k8s_nosuchcontainer_foo_new_12345678_42",
|
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
Running: false,
|
2016-03-05 01:33:23 +00:00
|
|
|
},
|
|
|
|
{
|
2016-04-04 22:27:20 +00:00
|
|
|
ID: infraContainerID,
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
|
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
})
|
2017-01-26 23:17:56 +00:00
|
|
|
fakeDocker.InjectErrors(map[string]error{"inspect_container": fmt.Errorf("Error: No such container: %s", noSuchContainerID)})
|
2016-03-05 01:33:23 +00:00
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
|
|
|
|
|
|
|
// Verify that we will try to start new contrainers even if the inspections
|
|
|
|
// failed.
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
2017-01-16 19:26:38 +00:00
|
|
|
// Inspect dead infra container for possible network teardown
|
|
|
|
"inspect_container",
|
|
|
|
// Start a new infra container.
|
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
|
|
|
// Start a new container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncPodDeadInfraContainerTeardown(t *testing.T) {
|
|
|
|
const (
|
|
|
|
noSuchContainerID = "nosuchcontainer"
|
|
|
|
infraContainerID = "9876"
|
|
|
|
)
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
|
|
|
dm.podInfraContainerImage = "pod_infra_image"
|
|
|
|
ctrl := gomock.NewController(t)
|
|
|
|
defer ctrl.Finish()
|
|
|
|
fnp := nettest.NewMockNetworkPlugin(ctrl)
|
|
|
|
dm.network = network.NewPluginManager(fnp)
|
|
|
|
|
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{{Name: noSuchContainerID}},
|
|
|
|
})
|
|
|
|
|
|
|
|
fakeDocker.SetFakeContainers([]*FakeContainer{
|
|
|
|
{
|
|
|
|
ID: infraContainerID,
|
|
|
|
Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
|
|
|
|
ExitCode: 0,
|
|
|
|
StartedAt: time.Now(),
|
|
|
|
FinishedAt: time.Now(),
|
|
|
|
Running: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
// Can be called multiple times due to GetPodStatus
|
|
|
|
fnp.EXPECT().Name().Return("someNetworkPlugin").AnyTimes()
|
|
|
|
fnp.EXPECT().TearDownPod("new", "foo", gomock.Any()).Return(nil)
|
|
|
|
fnp.EXPECT().GetPodNetworkStatus("new", "foo", gomock.Any()).Return(&network.PodNetworkStatus{IP: net.ParseIP("1.1.1.1")}, nil).AnyTimes()
|
|
|
|
fnp.EXPECT().SetUpPod("new", "foo", gomock.Any()).Return(nil)
|
|
|
|
|
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
|
|
|
|
|
|
|
// Verify that we will try to start new contrainers even if the inspections
|
|
|
|
// failed.
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Inspect dead infra container for possible network teardown
|
|
|
|
"inspect_container",
|
2016-03-05 01:33:23 +00:00
|
|
|
// Start a new infra container.
|
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
|
|
|
// Start a new container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
})
|
|
|
|
}
|
2016-05-23 17:13:13 +00:00
|
|
|
|
|
|
|
func TestPruneInitContainers(t *testing.T) {
|
|
|
|
dm, fake := newTestDockerManager()
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("", &v1.PodSpec{
|
|
|
|
InitContainers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "init1"},
|
|
|
|
{Name: "init2"},
|
2016-05-23 17:13:13 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-05-23 17:13:13 +00:00
|
|
|
status := &kubecontainer.PodStatus{
|
|
|
|
ContainerStatuses: []*kubecontainer.ContainerStatus{
|
|
|
|
{Name: "init2", ID: kubecontainer.ContainerID{ID: "init2-new-1"}, State: kubecontainer.ContainerStateExited},
|
|
|
|
{Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-new-1"}, State: kubecontainer.ContainerStateExited},
|
|
|
|
{Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-new-2"}, State: kubecontainer.ContainerStateExited},
|
|
|
|
{Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-old-1"}, State: kubecontainer.ContainerStateExited},
|
|
|
|
{Name: "init2", ID: kubecontainer.ContainerID{ID: "init2-old-1"}, State: kubecontainer.ContainerStateExited},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
fake.ExitedContainerList = []dockertypes.Container{
|
|
|
|
{ID: "init1-new-1"},
|
|
|
|
{ID: "init1-new-2"},
|
|
|
|
{ID: "init1-old-1"},
|
|
|
|
{ID: "init2-new-1"},
|
|
|
|
{ID: "init2-old-1"},
|
|
|
|
}
|
|
|
|
keep := map[kubecontainer.DockerID]int{}
|
|
|
|
dm.pruneInitContainersBeforeStart(pod, status, keep)
|
|
|
|
sort.Sort(sort.StringSlice(fake.Removed))
|
|
|
|
if !reflect.DeepEqual([]string{"init1-new-2", "init1-old-1", "init2-old-1"}, fake.Removed) {
|
|
|
|
t.Fatal(fake.Removed)
|
|
|
|
}
|
|
|
|
}
|
2016-07-19 04:20:04 +00:00
|
|
|
|
|
|
|
func TestSyncPodGetsPodIPFromNetworkPlugin(t *testing.T) {
|
|
|
|
const (
|
|
|
|
containerID = "123"
|
|
|
|
infraContainerID = "9876"
|
|
|
|
fakePodIP = "10.10.10.10"
|
|
|
|
)
|
|
|
|
dm, fakeDocker := newTestDockerManager()
|
|
|
|
dm.podInfraContainerImage = "pod_infra_image"
|
|
|
|
ctrl := gomock.NewController(t)
|
|
|
|
defer ctrl.Finish()
|
2016-12-13 19:54:08 +00:00
|
|
|
fnp := nettest.NewMockNetworkPlugin(ctrl)
|
2016-12-06 21:58:44 +00:00
|
|
|
dm.network = network.NewPluginManager(fnp)
|
2016-07-19 04:20:04 +00:00
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := makePod("foo", &v1.PodSpec{
|
|
|
|
Containers: []v1.Container{
|
2016-08-29 15:36:33 +00:00
|
|
|
{Name: "bar"},
|
2016-07-19 04:20:04 +00:00
|
|
|
},
|
2016-08-29 15:36:33 +00:00
|
|
|
})
|
2016-07-19 04:20:04 +00:00
|
|
|
|
|
|
|
// Can be called multiple times due to GetPodStatus
|
|
|
|
fnp.EXPECT().Name().Return("someNetworkPlugin").AnyTimes()
|
|
|
|
fnp.EXPECT().GetPodNetworkStatus("new", "foo", gomock.Any()).Return(&network.PodNetworkStatus{IP: net.ParseIP(fakePodIP)}, nil).AnyTimes()
|
|
|
|
fnp.EXPECT().SetUpPod("new", "foo", gomock.Any()).Return(nil)
|
|
|
|
|
|
|
|
runSyncPod(t, dm, fakeDocker, pod, nil, false)
|
|
|
|
verifyCalls(t, fakeDocker, []string{
|
|
|
|
// Create pod infra container.
|
|
|
|
"create", "start", "inspect_container", "inspect_container",
|
|
|
|
// Create container.
|
|
|
|
"create", "start", "inspect_container",
|
|
|
|
})
|
|
|
|
}
|
2016-07-18 07:02:02 +00:00
|
|
|
|
|
|
|
// only test conditions "if inspect == nil || inspect.Config == nil || inspect.Config.Labels == nil" now
|
|
|
|
func TestContainerAndPodFromLabels(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
inspect *dockertypes.ContainerJSON
|
|
|
|
expectedError error
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
inspect: nil,
|
|
|
|
expectedError: errNoPodOnContainer,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
inspect: &dockertypes.ContainerJSON{},
|
|
|
|
expectedError: errNoPodOnContainer,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
inspect: &dockertypes.ContainerJSON{
|
|
|
|
Config: &dockercontainer.Config{
|
|
|
|
Hostname: "foo",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expectedError: errNoPodOnContainer,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range tests {
|
|
|
|
pod, container, err := containerAndPodFromLabels(v.inspect)
|
|
|
|
if pod != nil || container != nil || err != v.expectedError {
|
|
|
|
t.Errorf("case[%q]: expected: nil, nil, %v, got: %v, %v, %v", k, v.expectedError, pod, container, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-29 15:36:33 +00:00
|
|
|
|
2016-11-18 20:50:58 +00:00
|
|
|
func makePod(name string, spec *v1.PodSpec) *v1.Pod {
|
2016-08-29 15:36:33 +00:00
|
|
|
if spec == nil {
|
2016-11-18 20:50:58 +00:00
|
|
|
spec = &v1.PodSpec{Containers: []v1.Container{{Name: "foo"}, {Name: "bar"}}}
|
2016-08-29 15:36:33 +00:00
|
|
|
}
|
2016-11-18 20:50:58 +00:00
|
|
|
pod := &v1.Pod{
|
2017-01-17 03:38:19 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
2016-08-29 15:36:33 +00:00
|
|
|
UID: "12345678",
|
|
|
|
Name: name,
|
|
|
|
Namespace: "new",
|
|
|
|
},
|
|
|
|
Spec: *spec,
|
|
|
|
}
|
|
|
|
return pod
|
|
|
|
}
|