2015-03-31 02:56:34 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
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 (
2015-04-30 23:04:32 +00:00
"fmt"
2015-06-05 22:37:53 +00:00
"io/ioutil"
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"
2015-08-05 22:05:17 +00:00
docker "github.com/fsouza/go-dockerclient"
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"
2016-03-25 21:45:59 +00:00
"k8s.io/kubernetes/cmd/kubelet/app/options"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
2015-09-03 21:40:58 +00:00
"k8s.io/kubernetes/pkg/client/record"
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"
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-01-22 05:06:52 +00:00
"k8s.io/kubernetes/pkg/runtime"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util"
uexec "k8s.io/kubernetes/pkg/util/exec"
2016-03-09 02:58:24 +00:00
"k8s.io/kubernetes/pkg/util/flowcontrol"
2015-11-10 06:28:45 +00:00
"k8s.io/kubernetes/pkg/util/intstr"
2015-09-09 17:45:01 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2015-03-31 02:56:34 +00:00
)
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-01-28 23:57:38 +00:00
// fakeRuntimeHelper implementes kubecontainer.RuntimeHelper inter
// faces for testing purposes.
type fakeRuntimeHelper struct { }
2015-05-26 23:45:38 +00:00
2016-01-28 23:57:38 +00:00
var _ kubecontainer . RuntimeHelper = & fakeRuntimeHelper { }
2015-05-26 23:45:38 +00:00
2015-06-05 22:37:53 +00:00
var testPodContainerDir string
2016-03-07 20:24:08 +00:00
func ( f * fakeRuntimeHelper ) GenerateRunContainerOptions ( pod * api . Pod , container * api . Container , podIP string ) ( * kubecontainer . RunContainerOptions , error ) {
2015-06-05 22:37:53 +00:00
var opts kubecontainer . RunContainerOptions
var err error
if len ( container . TerminationMessagePath ) != 0 {
testPodContainerDir , err = ioutil . TempDir ( "" , "fooPodContainerDir" )
if err != nil {
return nil , err
}
opts . PodContainerDir = testPodContainerDir
}
return & opts , nil
2015-05-26 23:45:38 +00:00
}
2016-01-28 23:57:38 +00:00
func ( f * fakeRuntimeHelper ) GetClusterDNS ( pod * api . Pod ) ( [ ] string , [ ] string , error ) {
return nil , nil , fmt . Errorf ( "not implemented" )
}
2016-03-21 21:28:57 +00:00
// This is not used by docker runtime.
func ( f * fakeRuntimeHelper ) GeneratePodHostNameAndDomain ( pod * api . Pod ) ( string , string ) {
return "" , ""
}
2016-02-23 21:27:28 +00:00
func newTestDockerManagerWithHTTPClientWithVersion ( fakeHTTPClient * fakeHTTP , version , apiVersion string ) ( * DockerManager , * FakeDockerClient ) {
fakeDocker := NewFakeDockerClientWithVersion ( version , apiVersion )
2015-04-29 20:09:03 +00:00
fakeRecorder := & record . FakeRecorder { }
containerRefManager := kubecontainer . NewRefManager ( )
2016-02-25 23:40:44 +00:00
networkPlugin , _ := network . InitNetworkPlugin ( [ ] network . NetworkPlugin { } , "" , nettest . NewFakeHost ( nil ) )
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-03-25 21:45:59 +00:00
options . GetDefaultPodInfraContainerImage ( ) ,
2015-04-29 20:09:03 +00:00
0 , 0 , "" ,
2016-02-25 23:40:44 +00:00
containertest . FakeOS { } ,
2015-04-29 20:09:03 +00:00
networkPlugin ,
2016-01-28 23:57:38 +00:00
& 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-02-23 21:27:28 +00:00
func newTestDockerManagerWithHTTPClient ( fakeHTTPClient * fakeHTTP ) ( * DockerManager , * FakeDockerClient ) {
return newTestDockerManagerWithHTTPClientWithVersion ( fakeHTTPClient , "1.8.1" , "1.20" )
}
2015-06-01 19:30:51 +00:00
func newTestDockerManager ( ) ( * DockerManager , * FakeDockerClient ) {
return newTestDockerManagerWithHTTPClient ( & fakeHTTP { } )
}
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
}
2016-02-08 17:40:19 +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" , out : "1.8.1-fc21" } ,
{ value : "1.8.1.fc21.other" , out : "1.8.1-fc21.other" } ,
{ 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 )
}
}
}
2015-03-31 02:56:34 +00:00
func TestSetEntrypointAndCommand ( t * testing . T ) {
cases := [ ] struct {
name string
container * api . 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" ,
container : & api . 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" ,
container : & api . Container {
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" ,
container : & api . Container {
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" ,
container : & api . Container {
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" ,
container : & api . Container {
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" ,
container : & api . Container {
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" ,
container : & api . Container {
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
if e , a := tc . expected . Config . Entrypoint , actualOpts . Config . Entrypoint ; ! api . Semantic . DeepEqual ( e , a ) {
t . Errorf ( "%v: unexpected entrypoint: expected %v, got %v" , tc . name , e , a )
}
if e , a := tc . expected . Config . Cmd , actualOpts . Config . Cmd ; ! api . Semantic . DeepEqual ( e , a ) {
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 {
{
ID : types . UID ( "1234" ) ,
Name : "qux" ,
Namespace : "new" ,
Containers : [ ] * kubecontainer . Container { containers [ 0 ] , containers [ 1 ] } ,
} ,
{
ID : types . UID ( "5678" ) ,
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 ( )
2015-04-30 17:12:23 +00:00
dockerImages := [ ] docker . APIImages { { 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
func TestKillContainerInPod ( t * testing . T ) {
2015-05-01 22:25:11 +00:00
manager , fakeDocker := newTestDockerManager ( )
2015-04-30 23:04:32 +00:00
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "qux" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Name : "foo" } , { Name : "bar" } } } ,
}
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
2015-10-10 09:12:47 +00:00
if err := manager . KillContainerInPod ( kubecontainer . ContainerID { } , & pod . Spec . Containers [ 0 ] , pod , "test kill container in pod." ) ; 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" }
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "qux" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "foo" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
Exec : & api . ExecAction {
Command : expectedCmd ,
} ,
} ,
} ,
} ,
{ 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 {
2015-12-30 07:46:52 +00:00
kubernetesPodLabel : string ( podString ) ,
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
2015-10-10 09:12:47 +00:00
if err := manager . KillContainerInPod ( kubecontainer . ContainerID { } , & pod . Spec . Containers [ 0 ] , pod , "test kill container with preStop." ) ; 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 )
}
2015-08-20 01:57:58 +00:00
verifyCalls ( t , fakeDocker , [ ] string { "list" , "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
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "qux" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Name : "foo" } , { Name : "bar" } } } ,
}
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
2015-10-10 09:12:47 +00:00
if err := manager . KillContainerInPod ( kubecontainer . ContainerID { } , & pod . Spec . Containers [ 0 ] , pod , "test kill container with error." ) ; 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
func generatePodInfraContainerHash ( pod * api . Pod ) uint64 {
var ports [ ] api . ContainerPort
2015-09-14 21:56:51 +00:00
if pod . Spec . SecurityContext == nil || ! pod . Spec . SecurityContext . HostNetwork {
2015-05-26 23:45:38 +00:00
for _ , container := range pod . Spec . Containers {
ports = append ( ports , container . Ports ... )
}
}
container := & api . Container {
2015-06-09 00:53:24 +00:00
Name : PodInfraContainerName ,
2016-03-25 21:45:59 +00:00
Image : options . GetDefaultPodInfraContainerImage ( ) ,
2015-06-09 00:53:24 +00:00
Ports : ports ,
ImagePullPolicy : podInfraContainerImagePullPolicy ,
2015-05-26 23:45:38 +00:00
}
return kubecontainer . HashContainer ( container )
}
// runSyncPod is a helper function to retrieve the running pods from the fake
// docker client and runs SyncPod for the given pod.
2016-03-09 02:58:24 +00:00
func runSyncPod ( t * testing . T , dm * DockerManager , fakeDocker * FakeDockerClient , pod * api . 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-01-27 03:25:35 +00:00
// api.PodStatus is not used in SyncPod now, pass in an empty one.
result := dm . SyncPod ( pod , api . PodStatus { } , podStatus , [ ] api . 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
2015-05-26 23:45:38 +00:00
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
} ,
}
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
}
}
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
}
if len ( fakeDocker . Created ) != 2 ||
2015-11-19 21:59:18 +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 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-05-26 23:45:38 +00:00
}
fakeDocker . Unlock ( )
}
func TestSyncPodCreatesNetAndContainerPullsImage ( t * testing . T ) {
dm , fakeDocker := newTestDockerManager ( )
2015-06-09 00:53:24 +00:00
dm . podInfraContainerImage = "pod_infra_image"
2015-08-10 17:28:39 +00:00
puller := dm . dockerPuller . ( * FakeDockerPuller )
2015-05-26 23:45:38 +00:00
puller . HasImages = [ ] string { }
2015-06-09 00:53:24 +00:00
dm . podInfraContainerImage = "pod_infra_image"
2015-05-26 23:45:38 +00:00
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" , Image : "something" , ImagePullPolicy : "IfNotPresent" } ,
} ,
} ,
}
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 ( )
2015-06-09 00:53:24 +00:00
if ! reflect . DeepEqual ( puller . ImagesPulled , [ ] string { "pod_infra_image" , "something" } ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected pulled containers: %v" , puller . ImagesPulled )
2015-05-26 23:45:38 +00:00
}
if len ( fakeDocker . Created ) != 2 ||
2015-11-19 21:59:18 +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 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-05-26 23:45:38 +00:00
}
fakeDocker . Unlock ( )
}
func TestSyncPodWithPodInfraCreatesContainer ( t * testing . T ) {
dm , fakeDocker := newTestDockerManager ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
} ,
}
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
} )
fakeDocker . Lock ( )
if len ( fakeDocker . Created ) != 1 ||
2015-11-19 21:59:18 +00:00
! matchString ( t , "/k8s_bar\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 0 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-05-26 23:45:38 +00:00
}
fakeDocker . Unlock ( )
}
func TestSyncPodDeletesWithNoPodInfraContainer ( t * testing . T ) {
dm , fakeDocker := newTestDockerManager ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo1" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar1" } ,
} ,
} ,
}
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
} )
// A map iteration is used to delete containers, so must not depend on
// order here.
expectedToStop := map [ string ] bool {
"1234" : true ,
}
fakeDocker . Lock ( )
if len ( fakeDocker . Stopped ) != 1 || ! expectedToStop [ fakeDocker . Stopped [ 0 ] ] {
t . Errorf ( "Wrong containers were stopped: %v" , fakeDocker . Stopped )
}
fakeDocker . Unlock ( )
}
func TestSyncPodDeletesDuplicate ( t * testing . T ) {
dm , fakeDocker := newTestDockerManager ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "bar" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "foo" } ,
} ,
} ,
}
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 ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
} ,
}
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 ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
2015-10-19 22:15:59 +00:00
Containers : [ ] api . Container { { Name : "unhealthy" } } ,
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 ( )
container := api . Container { Name : "bar" }
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
container ,
} ,
} ,
}
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." + strconv . FormatUint ( kubecontainer . HashContainer ( & 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 ( )
containers := [ ] api . Container {
{ Name : "succeeded" } ,
{ Name : "failed" } ,
}
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
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" ,
Name : "/k8s_succeeded." + strconv . FormatUint ( kubecontainer . HashContainer ( & containers [ 0 ] ) , 16 ) + "_foo_new_12345678_0" ,
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" ,
Name : "/k8s_failed." + strconv . FormatUint ( kubecontainer . HashContainer ( & containers [ 1 ] ) , 16 ) + "_foo_new_12345678_0" ,
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 {
policy api . RestartPolicy
calls [ ] string
created [ ] string
stopped [ ] string
} {
{
api . RestartPolicyAlways ,
[ ] 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 { } ,
} ,
{
api . RestartPolicyOnFailure ,
[ ] 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 { } ,
} ,
{
api . RestartPolicyNever ,
[ ] 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 )
if err := fakeDocker . AssertCreated ( 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-02-01 18:50:05 +00:00
var fakeClock = util . NewFakeClock ( time . Now ( ) )
2015-08-13 12:59:15 +00:00
startTime := fakeClock . Now ( )
dm , fakeDocker := newTestDockerManager ( )
containers := [ ] api . Container {
{ Name : "good" } ,
{ Name : "bad" } ,
}
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "podfoo" ,
Namespace : "nsnew" ,
} ,
Spec : api . PodSpec {
Containers : containers ,
} ,
}
stableId := "k8s_bad." + strconv . FormatUint ( kubecontainer . HashContainer ( & containers [ 1 ] ) , 16 ) + "_podfoo_nsnew_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" ,
Name : "/k8s_POD." + strconv . FormatUint ( generatePodInfraContainerHash ( pod ) , 16 ) + "_podfoo_nsnew_12345678_0" ,
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" ,
Name : "/k8s_good." + strconv . FormatUint ( kubecontainer . HashContainer ( & containers [ 0 ] ) , 16 ) + "_podfoo_nsnew_12345678_0" ,
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" ,
Name : "/k8s_bad." + strconv . FormatUint ( kubecontainer . HashContainer ( & containers [ 1 ] ) , 16 ) + "_podfoo_nsnew_12345678_0" ,
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"
2015-05-27 18:00:20 +00:00
pod := api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
2016-01-27 01:46:15 +00:00
Containers : [ ] api . Container {
{ Name : containerName } ,
} ,
2015-10-23 20:02:32 +00:00
RestartPolicy : "Always" ,
2015-05-27 18:00:20 +00:00
} ,
2016-01-27 01:46:15 +00:00
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : containerName ,
RestartCount : 3 ,
} ,
} ,
} ,
2015-05-27 18:00:20 +00:00
}
// Helper function for verifying the restart count.
2016-01-27 01:46:15 +00:00
verifyRestartCount := func ( pod * api . 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 )
}
}
2015-10-23 20:02:32 +00:00
killOneContainer := func ( pod * api . 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
}
dm . KillContainerInPod ( cs . ID , & pod . Spec . Containers [ 0 ] , pod , "test container restart count." )
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 ( )
containers := [ ] api . Container {
{
Name : "bar" ,
TerminationMessagePath : "/dev/somepath" ,
} ,
}
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : containers ,
} ,
}
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 )
pod := & api . Pod {
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 : "foo" ,
2015-11-10 06:28:45 +00:00
Port : intstr . FromInt ( 8080 ) ,
2015-06-01 19:30:51 +00:00
Path : "bar" ,
} ,
} ,
} ,
} ,
} ,
} ,
}
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
} )
fakeDocker . Lock ( )
if len ( fakeDocker . Created ) != 1 ||
2015-11-19 21:59:18 +00:00
! matchString ( t , "/k8s_bar\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 0 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-06-01 19:30:51 +00:00
}
fakeDocker . Unlock ( )
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 )
pod := & api . Pod {
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" ,
2015-11-10 06:28:45 +00:00
Port : intstr . FromInt ( 8080 ) ,
2015-06-01 19:30:51 +00:00
Path : "bar" ,
} ,
} ,
} ,
} ,
} ,
} ,
}
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
} )
// TODO(yifan): Check the stopped container's name.
if len ( fakeDocker . Stopped ) != 1 {
t . Fatalf ( "Wrong containers were stopped: %v" , fakeDocker . Stopped )
}
dockerName , _ , err := ParseDockerName ( fakeDocker . Stopped [ 0 ] )
if err != nil {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected error: %v" , err )
2015-06-01 19:30:51 +00:00
}
if dockerName . ContainerName != "bar" {
t . Errorf ( "Wrong stopped container, expected: bar, get: %q" , dockerName . ContainerName )
}
}
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 ( )
container := api . Container {
Name : "bar" ,
TerminationMessagePath : "/dev/somepath" ,
}
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
container ,
} ,
} ,
}
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" ,
} )
defer os . Remove ( testPodContainerDir )
fakeDocker . Lock ( )
2015-11-19 21:59:18 +00:00
if len ( fakeDocker . Created ) != 2 ||
! matchString ( t , "/k8s_POD\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 0 ] ) ||
! matchString ( t , "/k8s_bar\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 1 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-11-19 21:59:18 +00:00
}
fakeDocker . Unlock ( )
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 ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
2015-09-14 21:56:51 +00:00
SecurityContext : & api . PodSecurityContext {
HostNetwork : true ,
} ,
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" ,
} )
fakeDocker . Lock ( )
if len ( fakeDocker . Created ) != 2 ||
2015-11-19 21:59:18 +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 ] ) {
2016-02-23 21:27:28 +00:00
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
2015-08-19 08:56:19 +00:00
}
2015-11-19 21:59:18 +00:00
fakeDocker . Unlock ( )
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 {
container * api . Container
inspectImage * docker . Image
expectedError string
} {
// success cases
"non-root runAsUser" : {
container : & api . Container {
SecurityContext : & api . SecurityContext {
RunAsUser : & nonRootUid ,
} ,
} ,
} ,
"numeric non-root image user" : {
container : & api . Container { } ,
inspectImage : & docker . Image {
Config : & docker . Config {
User : "1" ,
} ,
} ,
} ,
"numeric non-root image user with gid" : {
container : & api . Container { } ,
inspectImage : & docker . Image {
Config : & docker . Config {
User : "1:2" ,
} ,
} ,
} ,
// failure cases
"root runAsUser" : {
container : & api . Container {
SecurityContext : & api . SecurityContext {
RunAsUser : & rootUid ,
} ,
} ,
expectedError : "container's runAsUser breaks non-root policy" ,
} ,
"non-numeric image user" : {
container : & api . Container { } ,
inspectImage : & docker . Image {
Config : & docker . Config {
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" : {
container : & api . Container { } ,
inspectImage : & docker . Image {
Config : & docker . Config {
User : "0" ,
} ,
} ,
expectedError : "container has no runAsUser and image will run as root" ,
} ,
"numeric root image user with gid" : {
container : & api . Container { } ,
inspectImage : & docker . Image {
Config : & docker . Config {
User : "0:1" ,
} ,
} ,
expectedError : "container has no runAsUser and image will run as root" ,
} ,
"nil image in inspect" : {
container : & api . Container { } ,
expectedError : "unable to inspect image" ,
} ,
"nil config in image inspect" : {
container : & api . Container { } ,
inspectImage : & docker . Image { } ,
expectedError : "unable to inspect image" ,
} ,
}
for k , v := range tests {
fakeDocker . Image = v . inspectImage
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
}
}
}
func TestGetUidFromUser ( t * testing . T ) {
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" ,
} ,
}
for k , v := range tests {
actual := getUidFromUser ( v . input )
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
pod := & api . Pod { }
pidMode := getPidMode ( pod )
if pidMode != "" {
t . Errorf ( "expected empty pid mode for pod but got %v" , pidMode )
}
// test true
2015-09-14 21:56:51 +00:00
pod . Spec . SecurityContext = & api . PodSecurityContext { }
pod . Spec . SecurityContext . 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
pod := & api . 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
2015-09-14 21:56:51 +00:00
pod . Spec . SecurityContext = & api . PodSecurityContext { }
pod . Spec . SecurityContext . 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 ) {
dm , fakeDocker := newTestDockerManager ( )
puller := dm . dockerPuller . ( * FakeDockerPuller )
puller . HasImages = [ ] string { "existing_one" , "want:latest" }
dm . podInfraContainerImage = "pod_infra_image"
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" , Image : "pull_always_image" , ImagePullPolicy : api . PullAlways } ,
{ 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 } ,
{ Name : "bar5" , Image : "pull_never_image" , ImagePullPolicy : api . PullNever } ,
} ,
} ,
}
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 , "" } ,
{ kubecontainer . StartContainer , "bar5" , kubecontainer . ErrImageNeverPull ,
"Container image \"pull_never_image\" is not present with pull policy of Never" } ,
}
result := runSyncPod ( t , dm , fakeDocker , pod , nil , true )
verifySyncResults ( t , expectedResults , result )
fakeDocker . Lock ( )
defer fakeDocker . Unlock ( )
pulledImageSorted := puller . ImagesPulled [ : ]
sort . Strings ( pulledImageSorted )
assert . Equal ( t , [ ] string { "pod_infra_image" , "pull_always_image" , "pull_if_not_present_image" } , pulledImageSorted )
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 ) {
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
}
tests := map [ string ] struct {
container api . Container
dockerError map [ string ] error
pullerError [ ] error
expected [ ] * kubecontainer . SyncResult
} {
"PullImageFailure" : {
api . Container { Name : "bar" , Image : "realImage" , ImagePullPolicy : api . PullAlways } ,
map [ string ] error { } ,
[ ] error { fmt . Errorf ( "can't pull image" ) } ,
[ ] * kubecontainer . SyncResult { { kubecontainer . StartContainer , "bar" , kubecontainer . ErrImagePull , "can't pull image" } } ,
} ,
"CreateContainerFailure" : {
2016-02-23 04:34:33 +00:00
api . Container { Name : "bar" , Image : "alreadyPresent" } ,
2016-02-10 22:45:03 +00:00
map [ string ] error { "create" : fmt . Errorf ( "can't create container" ) } ,
[ ] error { } ,
[ ] * kubecontainer . SyncResult { { kubecontainer . StartContainer , "bar" , kubecontainer . ErrRunContainer , "can't create container" } } ,
} ,
"StartContainerFailure" : {
2016-02-23 04:34:33 +00:00
api . Container { Name : "bar" , Image : "alreadyPresent" } ,
2016-02-10 22:45:03 +00:00
map [ string ] error { "start" : fmt . Errorf ( "can't start container" ) } ,
[ ] error { } ,
[ ] * kubecontainer . SyncResult { { kubecontainer . StartContainer , "bar" , kubecontainer . ErrRunContainer , "can't start container" } } ,
} ,
}
for _ , test := range tests {
2016-02-23 04:34:33 +00:00
dm , fakeDocker := newTestDockerManager ( )
puller := dm . dockerPuller . ( * FakeDockerPuller )
puller . HasImages = [ ] string { test . container . Image }
// 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-02-10 22:45:03 +00:00
puller . ErrorsToInject = test . pullerError
2016-02-23 04:34:33 +00:00
pod . Spec . Containers = [ ] api . 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 {
t . Errorf ( "expected result: %+v" , r )
}
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 ) {
t . Errorf ( "expected sync result %+v, got %+v" , expectR , realR )
}
found ++
}
}
if found == 0 {
t . Errorf ( "not found expected result %+v" , expectR )
}
if found > 1 {
t . Errorf ( "got %d duplicate expected result %+v" , found , expectR )
}
}
}
2016-02-23 21:27:28 +00:00
func TestSeccompIsDisabledWithDockerV110 ( t * testing . T ) {
dm , fakeDocker := newTestDockerManagerWithHTTPClientWithVersion ( & fakeHTTP { } , "1.10.1" , "1.22" )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
} ,
}
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" ,
} )
fakeDocker . Lock ( )
if len ( fakeDocker . Created ) != 2 ||
! matchString ( t , "/k8s_POD\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 0 ] ) ||
! matchString ( t , "/k8s_bar\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 1 ] ) {
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
}
fakeDocker . Unlock ( )
newContainer , err := fakeDocker . InspectContainer ( fakeDocker . Created [ 1 ] )
if err != nil {
t . Fatalf ( "unexpected error %v" , err )
}
assert . Contains ( t , newContainer . HostConfig . SecurityOpt , "seccomp:unconfined" , "Pods with Docker versions >= 1.10 must have seccomp disabled." )
}
func TestSecurityOptsAreNilWithDockerV19 ( t * testing . T ) {
dm , fakeDocker := newTestDockerManagerWithHTTPClientWithVersion ( & fakeHTTP { } , "1.9.1" , "1.21" )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container {
{ Name : "bar" } ,
} ,
} ,
}
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" ,
} )
fakeDocker . Lock ( )
if len ( fakeDocker . Created ) != 2 ||
! matchString ( t , "/k8s_POD\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 0 ] ) ||
! matchString ( t , "/k8s_bar\\.[a-f0-9]+_foo_new_" , fakeDocker . Created [ 1 ] ) {
t . Errorf ( "unexpected containers created %v" , fakeDocker . Created )
}
fakeDocker . Unlock ( )
newContainer , err := fakeDocker . InspectContainer ( fakeDocker . Created [ 1 ] )
if err != nil {
t . Fatalf ( "unexpected error %v" , err )
}
assert . NotContains ( t , newContainer . HostConfig . SecurityOpt , "seccomp:unconfined" , "Pods with Docker versions < 1.10 must not have seccomp disabled by default" )
}
2016-03-03 10:01:15 +00:00
func TestCheckVersionCompatibility ( t * testing . T ) {
apiVersion , err := docker . NewAPIVersion ( minimumDockerAPIVersion )
if err != nil {
t . Fatalf ( "unexpected error %v" , err )
}
type test struct {
version string
compatible bool
}
tests := [ ] test {
// Minimum apiversion
{ minimumDockerAPIVersion , true } ,
// Invalid apiversion
{ "invalid_api_version" , false } ,
}
for i := range apiVersion {
apiVersion [ i ] ++
// Newer apiversion
tests = append ( tests , test { apiVersion . String ( ) , true } )
apiVersion [ i ] -= 2
// Older apiversion
if apiVersion [ i ] >= 0 {
tests = append ( tests , test { apiVersion . String ( ) , false } )
}
apiVersion [ i ] ++
}
for i , tt := range tests {
testCase := fmt . Sprintf ( "test case #%d test version %q" , i , tt . version )
dm , fakeDocker := newTestDockerManagerWithHTTPClientWithVersion ( & fakeHTTP { } , "" , tt . version )
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
func TestGetPodStatusNoSuchContainer ( t * testing . T ) {
const (
noSuchContainerID = "nosuchcontainer"
infraContainerID = "9876"
)
dm , fakeDocker := newTestDockerManager ( )
pod := & api . Pod {
ObjectMeta : api . ObjectMeta {
UID : "12345678" ,
Name : "foo" ,
Namespace : "new" ,
} ,
Spec : api . PodSpec {
Containers : [ ] api . Container { { Name : "nosuchcontainer" } } ,
} ,
}
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 ,
} ,
} )
fakeDocker . InjectErrors ( map [ string ] error { "inspect_container" : containerNotFoundError { } } )
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 {
// Start a new infra container.
"create" , "start" , "inspect_container" , "inspect_container" ,
// Start a new container.
"create" , "start" , "inspect_container" ,
} )
}