2016-09-23 15:58:44 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
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 kubelet
import (
"bytes"
"errors"
2016-08-25 20:45:38 +00:00
"fmt"
2017-07-31 18:44:47 +00:00
"io/ioutil"
2016-09-23 15:58:44 +00:00
"net"
2017-07-31 18:44:47 +00:00
"os"
"path/filepath"
2016-09-23 15:58:44 +00:00
"sort"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2017-06-22 18:24:23 +00:00
"k8s.io/api/core/v1"
2017-01-17 00:30:22 +00:00
apierrors "k8s.io/apimachinery/pkg/api/errors"
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/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
2017-08-29 08:01:04 +00:00
utilfeature "k8s.io/apiserver/pkg/util/feature"
2017-01-25 20:07:10 +00:00
core "k8s.io/client-go/testing"
2017-03-07 14:19:49 +00:00
"k8s.io/client-go/tools/record"
2017-07-07 20:00:40 +00:00
// TODO: remove this import if
// api.Registry.GroupOrDie(v1.GroupName).GroupVersion.String() is changed
// to "v1"?
_ "k8s.io/kubernetes/pkg/api/install"
2017-10-16 11:41:50 +00:00
"k8s.io/kubernetes/pkg/api/legacyscheme"
2017-08-29 08:01:04 +00:00
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
2016-09-23 15:58:44 +00:00
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
2017-01-07 05:06:19 +00:00
"k8s.io/kubernetes/pkg/kubelet/server/portforward"
2016-11-03 00:42:00 +00:00
"k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
2016-09-23 15:58:44 +00:00
)
func TestMakeMounts ( t * testing . T ) {
2017-08-29 08:01:04 +00:00
bTrue := true
propagationHostToContainer := v1 . MountPropagationHostToContainer
propagationBidirectional := v1 . MountPropagationBidirectional
2017-06-10 13:48:42 +00:00
testCases := map [ string ] struct {
container v1 . Container
podVolumes kubecontainer . VolumeMap
expectErr bool
expectedErrMsg string
expectedMounts [ ] kubecontainer . Mount
} {
2017-08-29 08:01:04 +00:00
"valid mounts in unprivileged container" : {
2017-06-10 13:48:42 +00:00
podVolumes : kubecontainer . VolumeMap {
"disk" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/disk" } } ,
"disk4" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/host" } } ,
"disk5" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/var/lib/kubelet/podID/volumes/empty/disk5" } } ,
} ,
container : v1 . Container {
2017-08-29 08:01:04 +00:00
Name : "container1" ,
2017-06-10 13:48:42 +00:00
VolumeMounts : [ ] v1 . VolumeMount {
{
2017-08-29 08:01:04 +00:00
MountPath : "/etc/hosts" ,
Name : "disk" ,
ReadOnly : false ,
MountPropagation : & propagationHostToContainer ,
2017-06-10 13:48:42 +00:00
} ,
{
MountPath : "/mnt/path3" ,
Name : "disk" ,
ReadOnly : true ,
} ,
{
MountPath : "/mnt/path4" ,
Name : "disk4" ,
ReadOnly : false ,
} ,
{
MountPath : "/mnt/path5" ,
Name : "disk5" ,
ReadOnly : false ,
} ,
} ,
2016-09-23 15:58:44 +00:00
} ,
2017-06-10 13:48:42 +00:00
expectedMounts : [ ] kubecontainer . Mount {
{
Name : "disk" ,
ContainerPath : "/etc/hosts" ,
HostPath : "/mnt/disk" ,
ReadOnly : false ,
SELinuxRelabel : false ,
2017-08-29 08:01:04 +00:00
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
2017-06-10 13:48:42 +00:00
} ,
{
Name : "disk" ,
ContainerPath : "/mnt/path3" ,
HostPath : "/mnt/disk" ,
ReadOnly : true ,
SELinuxRelabel : false ,
2017-08-29 08:01:04 +00:00
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
2017-06-10 13:48:42 +00:00
} ,
{
Name : "disk4" ,
ContainerPath : "/mnt/path4" ,
HostPath : "/mnt/host" ,
ReadOnly : false ,
SELinuxRelabel : false ,
2017-08-29 08:01:04 +00:00
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
2017-06-10 13:48:42 +00:00
} ,
{
Name : "disk5" ,
ContainerPath : "/mnt/path5" ,
HostPath : "/var/lib/kubelet/podID/volumes/empty/disk5" ,
ReadOnly : false ,
SELinuxRelabel : false ,
2017-08-29 08:01:04 +00:00
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
} ,
} ,
expectErr : false ,
} ,
"valid mounts in privileged container" : {
podVolumes : kubecontainer . VolumeMap {
"disk" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/disk" } } ,
"disk4" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/host" } } ,
"disk5" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/var/lib/kubelet/podID/volumes/empty/disk5" } } ,
} ,
container : v1 . Container {
Name : "container1" ,
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : "/etc/hosts" ,
Name : "disk" ,
ReadOnly : false ,
MountPropagation : & propagationBidirectional ,
} ,
{
MountPath : "/mnt/path3" ,
Name : "disk" ,
ReadOnly : true ,
MountPropagation : & propagationHostToContainer ,
} ,
{
MountPath : "/mnt/path4" ,
Name : "disk4" ,
ReadOnly : false ,
} ,
} ,
SecurityContext : & v1 . SecurityContext {
Privileged : & bTrue ,
} ,
} ,
expectedMounts : [ ] kubecontainer . Mount {
{
Name : "disk" ,
ContainerPath : "/etc/hosts" ,
HostPath : "/mnt/disk" ,
ReadOnly : false ,
SELinuxRelabel : false ,
Propagation : runtimeapi . MountPropagation_PROPAGATION_BIDIRECTIONAL ,
} ,
{
Name : "disk" ,
ContainerPath : "/mnt/path3" ,
HostPath : "/mnt/disk" ,
ReadOnly : true ,
SELinuxRelabel : false ,
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
} ,
{
Name : "disk4" ,
ContainerPath : "/mnt/path4" ,
HostPath : "/mnt/host" ,
ReadOnly : false ,
SELinuxRelabel : false ,
Propagation : runtimeapi . MountPropagation_PROPAGATION_HOST_TO_CONTAINER ,
2017-06-10 13:48:42 +00:00
} ,
2016-09-23 15:58:44 +00:00
} ,
2017-06-10 13:48:42 +00:00
expectErr : false ,
} ,
"invalid absolute SubPath" : {
podVolumes : kubecontainer . VolumeMap {
"disk" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/disk" } } ,
2016-09-23 15:58:44 +00:00
} ,
2017-06-10 13:48:42 +00:00
container : v1 . Container {
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : "/mnt/path3" ,
SubPath : "/must/not/be/absolute" ,
Name : "disk" ,
ReadOnly : true ,
} ,
} ,
2016-09-23 15:58:44 +00:00
} ,
2017-06-10 13:48:42 +00:00
expectErr : true ,
expectedErrMsg : "error SubPath `/must/not/be/absolute` must not be an absolute path" ,
} ,
"invalid SubPath with backsteps" : {
podVolumes : kubecontainer . VolumeMap {
"disk" : kubecontainer . VolumeInfo { Mounter : & stubVolume { path : "/mnt/disk" } } ,
} ,
container : v1 . Container {
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : "/mnt/path3" ,
SubPath : "no/backsteps/../allowed" ,
Name : "disk" ,
ReadOnly : true ,
} ,
} ,
} ,
expectErr : true ,
expectedErrMsg : "unable to provision SubPath `no/backsteps/../allowed`: must not contain '..'" ,
2016-09-23 15:58:44 +00:00
} ,
2017-10-04 16:30:48 +00:00
"volume doesn't exist" : {
podVolumes : kubecontainer . VolumeMap { } ,
container : v1 . Container {
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : "/mnt/path3" ,
Name : "disk" ,
ReadOnly : true ,
} ,
} ,
} ,
expectErr : true ,
expectedErrMsg : "cannot find volume \"disk\" to mount into container \"\"" ,
} ,
"volume mounter is nil" : {
podVolumes : kubecontainer . VolumeMap {
"disk" : kubecontainer . VolumeInfo { } ,
} ,
container : v1 . Container {
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : "/mnt/path3" ,
Name : "disk" ,
ReadOnly : true ,
} ,
} ,
} ,
expectErr : true ,
expectedErrMsg : "cannot find volume \"disk\" to mount into container \"\"" ,
} ,
2016-09-23 15:58:44 +00:00
}
2017-06-10 13:48:42 +00:00
for name , tc := range testCases {
t . Run ( name , func ( t * testing . T ) {
pod := v1 . Pod {
Spec : v1 . PodSpec {
HostNetwork : true ,
} ,
}
2017-08-29 08:01:04 +00:00
// test makeMounts with enabled mount propagation
err := utilfeature . DefaultFeatureGate . Set ( "MountPropagation=true" )
if err != nil {
t . Errorf ( "Failed to enable feature gate for MountPropagation: %v" , err )
return
}
2016-09-23 15:58:44 +00:00
2017-06-10 13:48:42 +00:00
mounts , err := makeMounts ( & pod , "/pod" , & tc . container , "fakepodname" , "" , "" , tc . podVolumes )
2016-09-23 15:58:44 +00:00
2017-06-10 13:48:42 +00:00
// validate only the error if we expect an error
if tc . expectErr {
if err == nil || err . Error ( ) != tc . expectedErrMsg {
t . Fatalf ( "expected error message `%s` but got `%v`" , tc . expectedErrMsg , err )
}
return
}
2016-09-23 15:58:44 +00:00
2017-06-10 13:48:42 +00:00
// otherwise validate the mounts
if err != nil {
t . Fatal ( err )
}
assert . Equal ( t , tc . expectedMounts , mounts , "mounts of container %+v" , tc . container )
2017-08-29 08:01:04 +00:00
// test makeMounts with disabled mount propagation
err = utilfeature . DefaultFeatureGate . Set ( "MountPropagation=false" )
if err != nil {
t . Errorf ( "Failed to enable feature gate for MountPropagation: %v" , err )
return
}
mounts , err = makeMounts ( & pod , "/pod" , & tc . container , "fakepodname" , "" , "" , tc . podVolumes )
if ! tc . expectErr {
expectedPrivateMounts := [ ] kubecontainer . Mount { }
for _ , mount := range tc . expectedMounts {
// all mounts are expected to be private when mount
// propagation is disabled
mount . Propagation = runtimeapi . MountPropagation_PROPAGATION_PRIVATE
expectedPrivateMounts = append ( expectedPrivateMounts , mount )
}
assert . Equal ( t , expectedPrivateMounts , mounts , "mounts of container %+v" , tc . container )
}
2017-06-10 13:48:42 +00:00
} )
2016-09-23 15:58:44 +00:00
}
}
2017-07-31 18:44:47 +00:00
func TestNodeHostsFileContent ( t * testing . T ) {
testCases := [ ] struct {
2017-08-14 21:44:21 +00:00
hostsFileName string
hostAliases [ ] v1 . HostAlias
rawHostsFileContent string
expectedHostsFileContent string
2017-07-31 18:44:47 +00:00
} {
{
"hosts_test_file1" ,
2017-08-14 21:44:21 +00:00
[ ] v1 . HostAlias { } ,
` # hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
123.45 .67 .89 some . domain
` ,
2017-07-31 18:44:47 +00:00
` # hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
123.45 .67 .89 some . domain
` ,
} ,
{
"hosts_test_file2" ,
2017-08-14 21:44:21 +00:00
[ ] v1 . HostAlias { } ,
` # another hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
12.34 .56 .78 another . domain
` ,
` # another hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
12.34 .56 .78 another . domain
` ,
} ,
{
"hosts_test_file1_with_host_aliases" ,
[ ] v1 . HostAlias {
{ IP : "123.45.67.89" , Hostnames : [ ] string { "foo" , "bar" , "baz" } } ,
} ,
` # hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
123.45 .67 .89 some . domain
` ,
` # hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
123.45 .67 .89 some . domain
# Entries added by HostAliases .
123.45 .67 .89 foo
123.45 .67 .89 bar
123.45 .67 .89 baz
` ,
} ,
{
"hosts_test_file2_with_host_aliases" ,
[ ] v1 . HostAlias {
{ IP : "123.45.67.89" , Hostnames : [ ] string { "foo" , "bar" , "baz" } } ,
{ IP : "456.78.90.123" , Hostnames : [ ] string { "park" , "doo" , "boo" } } ,
} ,
2017-07-31 18:44:47 +00:00
` # another hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
12.34 .56 .78 another . domain
2017-08-14 21:44:21 +00:00
` ,
` # another hosts file for testing .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
12.34 .56 .78 another . domain
# Entries added by HostAliases .
123.45 .67 .89 foo
123.45 .67 .89 bar
123.45 .67 .89 baz
456.78 .90 .123 park
456.78 .90 .123 doo
456.78 .90 .123 boo
2017-07-31 18:44:47 +00:00
` ,
} ,
}
for _ , testCase := range testCases {
2017-08-14 21:44:21 +00:00
tmpdir , err := writeHostsFile ( testCase . hostsFileName , testCase . rawHostsFileContent )
2017-07-31 18:44:47 +00:00
require . NoError ( t , err , "could not create a temp hosts file" )
defer os . RemoveAll ( tmpdir )
2017-08-14 21:44:21 +00:00
actualContent , fileReadErr := nodeHostsFileContent ( filepath . Join ( tmpdir , testCase . hostsFileName ) , testCase . hostAliases )
2017-07-31 18:44:47 +00:00
require . NoError ( t , fileReadErr , "could not create read hosts file" )
2017-08-14 21:44:21 +00:00
assert . Equal ( t , testCase . expectedHostsFileContent , string ( actualContent ) , "hosts file content not expected" )
2017-07-31 18:44:47 +00:00
}
}
// writeHostsFile will write a hosts file into a temporary dir, and return that dir.
// Caller is responsible for deleting the dir and its contents.
func writeHostsFile ( filename string , cfg string ) ( string , error ) {
tmpdir , err := ioutil . TempDir ( "" , "kubelet=kubelet_pods_test.go=" )
if err != nil {
return "" , err
}
return tmpdir , ioutil . WriteFile ( filepath . Join ( tmpdir , filename ) , [ ] byte ( cfg ) , 0644 )
}
func TestManagedHostsFileContent ( t * testing . T ) {
2017-04-15 00:33:25 +00:00
testCases := [ ] struct {
hostIP string
hostName string
hostDomainName string
2017-04-28 06:12:39 +00:00
hostAliases [ ] v1 . HostAlias
2017-04-15 00:33:25 +00:00
expectedContent string
} {
{
"123.45.67.89" ,
"podFoo" ,
"" ,
2017-04-28 06:12:39 +00:00
[ ] v1 . HostAlias { } ,
2017-04-15 00:33:25 +00:00
` # Kubernetes - managed hosts file .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
123.45 .67 .89 podFoo
` ,
} ,
{
"203.0.113.1" ,
"podFoo" ,
"domainFoo" ,
2017-04-28 06:12:39 +00:00
[ ] v1 . HostAlias { } ,
2017-04-15 00:33:25 +00:00
` # Kubernetes - managed hosts file .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
203.0 .113 .1 podFoo . domainFoo podFoo
2017-04-28 06:12:39 +00:00
` ,
} ,
{
"203.0.113.1" ,
"podFoo" ,
"domainFoo" ,
[ ] v1 . HostAlias {
{ IP : "123.45.67.89" , Hostnames : [ ] string { "foo" , "bar" , "baz" } } ,
} ,
` # Kubernetes - managed hosts file .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
203.0 .113 .1 podFoo . domainFoo podFoo
2017-08-14 21:37:27 +00:00
# Entries added by HostAliases .
2017-04-28 06:12:39 +00:00
123.45 .67 .89 foo
123.45 .67 .89 bar
123.45 .67 .89 baz
` ,
} ,
{
"203.0.113.1" ,
"podFoo" ,
"domainFoo" ,
[ ] v1 . HostAlias {
{ IP : "123.45.67.89" , Hostnames : [ ] string { "foo" , "bar" , "baz" } } ,
{ IP : "456.78.90.123" , Hostnames : [ ] string { "park" , "doo" , "boo" } } ,
} ,
` # Kubernetes - managed hosts file .
127.0 .0 .1 localhost
: : 1 localhost ip6 - localhost ip6 - loopback
fe00 : : 0 ip6 - localnet
fe00 : : 0 ip6 - mcastprefix
fe00 : : 1 ip6 - allnodes
fe00 : : 2 ip6 - allrouters
203.0 .113 .1 podFoo . domainFoo podFoo
2017-08-14 21:37:27 +00:00
# Entries added by HostAliases .
2017-04-28 06:12:39 +00:00
123.45 .67 .89 foo
123.45 .67 .89 bar
123.45 .67 .89 baz
456.78 .90 .123 park
456.78 .90 .123 doo
456.78 .90 .123 boo
2017-04-15 00:33:25 +00:00
` ,
} ,
}
for _ , testCase := range testCases {
2017-07-31 18:44:47 +00:00
actualContent := managedHostsFileContent ( testCase . hostIP , testCase . hostName , testCase . hostDomainName , testCase . hostAliases )
assert . Equal ( t , testCase . expectedContent , string ( actualContent ) , "hosts file content not expected" )
2017-04-15 00:33:25 +00:00
}
}
2016-09-23 15:58:44 +00:00
func TestRunInContainerNoSuchPod ( t * testing . T ) {
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-09-23 15:58:44 +00:00
kubelet := testKubelet . kubelet
fakeRuntime := testKubelet . fakeRuntime
fakeRuntime . PodList = [ ] * containertest . FakePod { }
podName := "podFoo"
podNamespace := "nsFoo"
containerName := "containerFoo"
output , err := kubelet . RunInContainer (
2017-01-17 03:38:19 +00:00
kubecontainer . GetPodFullName ( & v1 . Pod { ObjectMeta : metav1 . ObjectMeta { Name : podName , Namespace : podNamespace } } ) ,
2016-09-23 15:58:44 +00:00
"" ,
containerName ,
[ ] string { "ls" } )
assert . Error ( t , err )
assert . Nil ( t , output , "output should be nil" )
}
func TestRunInContainer ( t * testing . T ) {
2016-11-03 00:42:00 +00:00
for _ , testError := range [ ] error { nil , errors . New ( "bar" ) } {
2016-09-23 15:58:44 +00:00
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-09-23 15:58:44 +00:00
kubelet := testKubelet . kubelet
fakeRuntime := testKubelet . fakeRuntime
2016-11-03 00:42:00 +00:00
fakeCommandRunner := containertest . FakeContainerCommandRunner {
Err : testError ,
Stdout : "foo" ,
2016-09-23 15:58:44 +00:00
}
kubelet . runner = & fakeCommandRunner
containerID := kubecontainer . ContainerID { Type : "test" , ID : "abc1234" }
fakeRuntime . PodList = [ ] * containertest . FakePod {
{ Pod : & kubecontainer . Pod {
ID : "12345678" ,
Name : "podFoo" ,
Namespace : "nsFoo" ,
Containers : [ ] * kubecontainer . Container {
{ Name : "containerFoo" ,
ID : containerID ,
} ,
} ,
} } ,
}
cmd := [ ] string { "ls" }
actualOutput , err := kubelet . RunInContainer ( "podFoo_nsFoo" , "" , "containerFoo" , cmd )
2016-11-03 00:42:00 +00:00
assert . Equal ( t , containerID , fakeCommandRunner . ContainerID , "(testError=%v) ID" , testError )
2016-09-23 15:58:44 +00:00
assert . Equal ( t , cmd , fakeCommandRunner . Cmd , "(testError=%v) command" , testError )
// this isn't 100% foolproof as a bug in a real ContainerCommandRunner where it fails to copy to stdout/stderr wouldn't be caught by this test
2016-11-03 00:42:00 +00:00
assert . Equal ( t , "foo" , string ( actualOutput ) , "(testError=%v) output" , testError )
assert . Equal ( t , err , testError , "(testError=%v) err" , testError )
2016-09-23 15:58:44 +00:00
}
}
func TestGenerateRunContainerOptions_DNSConfigurationParams ( t * testing . T ) {
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-09-23 15:58:44 +00:00
kubelet := testKubelet . kubelet
clusterNS := "203.0.113.1"
kubelet . clusterDomain = "kubernetes.io"
2017-01-03 09:28:38 +00:00
kubelet . clusterDNS = [ ] net . IP { net . ParseIP ( clusterNS ) }
2016-09-23 15:58:44 +00:00
2016-08-05 08:19:17 +00:00
pods := newTestPods ( 4 )
pods [ 0 ] . Spec . DNSPolicy = v1 . DNSClusterFirstWithHostNet
pods [ 1 ] . Spec . DNSPolicy = v1 . DNSClusterFirst
pods [ 2 ] . Spec . DNSPolicy = v1 . DNSClusterFirst
pods [ 2 ] . Spec . HostNetwork = false
pods [ 3 ] . Spec . DNSPolicy = v1 . DNSDefault
options := make ( [ ] * kubecontainer . RunContainerOptions , 4 )
2016-09-23 15:58:44 +00:00
for i , pod := range pods {
var err error
2017-03-28 16:07:17 +00:00
options [ i ] , _ , err = kubelet . GenerateRunContainerOptions ( pod , & v1 . Container { } , "" )
2016-09-23 15:58:44 +00:00
if err != nil {
t . Fatalf ( "failed to generate container options: %v" , err )
}
}
if len ( options [ 0 ] . DNS ) != 1 || options [ 0 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %+v" , clusterNS , options [ 0 ] . DNS )
}
if len ( options [ 0 ] . DNSSearch ) == 0 || options [ 0 ] . DNSSearch [ 0 ] != ".svc." + kubelet . clusterDomain {
t . Errorf ( "expected search %s, got %+v" , ".svc." + kubelet . clusterDomain , options [ 0 ] . DNSSearch )
}
if len ( options [ 1 ] . DNS ) != 1 || options [ 1 ] . DNS [ 0 ] != "127.0.0.1" {
t . Errorf ( "expected nameserver 127.0.0.1, got %+v" , options [ 1 ] . DNS )
}
if len ( options [ 1 ] . DNSSearch ) != 1 || options [ 1 ] . DNSSearch [ 0 ] != "." {
t . Errorf ( "expected search \".\", got %+v" , options [ 1 ] . DNSSearch )
}
2016-08-05 08:19:17 +00:00
if len ( options [ 2 ] . DNS ) != 1 || options [ 2 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %+v" , clusterNS , options [ 2 ] . DNS )
}
if len ( options [ 2 ] . DNSSearch ) == 0 || options [ 2 ] . DNSSearch [ 0 ] != ".svc." + kubelet . clusterDomain {
t . Errorf ( "expected search %s, got %+v" , ".svc." + kubelet . clusterDomain , options [ 2 ] . DNSSearch )
}
if len ( options [ 3 ] . DNS ) != 1 || options [ 3 ] . DNS [ 0 ] != "127.0.0.1" {
t . Errorf ( "expected nameserver 127.0.0.1, got %+v" , options [ 3 ] . DNS )
}
if len ( options [ 3 ] . DNSSearch ) != 1 || options [ 3 ] . DNSSearch [ 0 ] != "." {
t . Errorf ( "expected search \".\", got %+v" , options [ 3 ] . DNSSearch )
}
2016-09-23 15:58:44 +00:00
kubelet . resolverConfig = "/etc/resolv.conf"
for i , pod := range pods {
var err error
2017-03-28 16:07:17 +00:00
options [ i ] , _ , err = kubelet . GenerateRunContainerOptions ( pod , & v1 . Container { } , "" )
2016-09-23 15:58:44 +00:00
if err != nil {
t . Fatalf ( "failed to generate container options: %v" , err )
}
}
t . Logf ( "nameservers %+v" , options [ 1 ] . DNS )
if len ( options [ 0 ] . DNS ) != 1 {
t . Errorf ( "expected cluster nameserver only, got %+v" , options [ 0 ] . DNS )
} else if options [ 0 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %v" , clusterNS , options [ 0 ] . DNS [ 0 ] )
}
2016-07-27 08:53:18 +00:00
expLength := len ( options [ 1 ] . DNSSearch ) + 3
if expLength > 6 {
expLength = 6
}
if len ( options [ 0 ] . DNSSearch ) != expLength {
2016-09-23 15:58:44 +00:00
t . Errorf ( "expected prepend of cluster domain, got %+v" , options [ 0 ] . DNSSearch )
} else if options [ 0 ] . DNSSearch [ 0 ] != ".svc." + kubelet . clusterDomain {
t . Errorf ( "expected domain %s, got %s" , ".svc." + kubelet . clusterDomain , options [ 0 ] . DNSSearch )
}
2016-08-05 08:19:17 +00:00
if len ( options [ 2 ] . DNS ) != 1 {
t . Errorf ( "expected cluster nameserver only, got %+v" , options [ 2 ] . DNS )
} else if options [ 2 ] . DNS [ 0 ] != clusterNS {
t . Errorf ( "expected nameserver %s, got %v" , clusterNS , options [ 2 ] . DNS [ 0 ] )
}
if len ( options [ 2 ] . DNSSearch ) != expLength {
t . Errorf ( "expected prepend of cluster domain, got %+v" , options [ 2 ] . DNSSearch )
} else if options [ 2 ] . DNSSearch [ 0 ] != ".svc." + kubelet . clusterDomain {
t . Errorf ( "expected domain %s, got %s" , ".svc." + kubelet . clusterDomain , options [ 0 ] . DNSSearch )
}
2016-09-23 15:58:44 +00:00
}
type testServiceLister struct {
2016-11-18 20:50:58 +00:00
services [ ] * v1 . Service
2016-09-23 15:58:44 +00:00
}
2016-11-18 20:50:58 +00:00
func ( ls testServiceLister ) List ( labels . Selector ) ( [ ] * v1 . Service , error ) {
2016-09-23 15:58:44 +00:00
return ls . services , nil
}
type envs [ ] kubecontainer . EnvVar
func ( e envs ) Len ( ) int {
return len ( e )
}
func ( e envs ) Swap ( i , j int ) { e [ i ] , e [ j ] = e [ j ] , e [ i ] }
func ( e envs ) Less ( i , j int ) bool { return e [ i ] . Name < e [ j ] . Name }
2016-11-18 20:50:58 +00:00
func buildService ( name , namespace , clusterIP , protocol string , port int ) * v1 . Service {
return & v1 . Service {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : name , Namespace : namespace } ,
2016-11-18 20:50:58 +00:00
Spec : v1 . ServiceSpec {
Ports : [ ] v1 . ServicePort { {
Protocol : v1 . Protocol ( protocol ) ,
2016-09-23 15:58:44 +00:00
Port : int32 ( port ) ,
} } ,
ClusterIP : clusterIP ,
} ,
}
}
func TestMakeEnvironmentVariables ( t * testing . T ) {
2017-01-17 00:30:22 +00:00
trueVal := true
2016-11-18 20:50:58 +00:00
services := [ ] * v1 . Service {
2017-01-22 03:36:02 +00:00
buildService ( "kubernetes" , metav1 . NamespaceDefault , "1.2.3.1" , "TCP" , 8081 ) ,
2016-09-23 15:58:44 +00:00
buildService ( "test" , "test1" , "1.2.3.3" , "TCP" , 8083 ) ,
buildService ( "kubernetes" , "test2" , "1.2.3.4" , "TCP" , 8084 ) ,
buildService ( "test" , "test2" , "1.2.3.5" , "TCP" , 8085 ) ,
buildService ( "test" , "test2" , "None" , "TCP" , 8085 ) ,
buildService ( "test" , "test2" , "" , "TCP" , 8085 ) ,
buildService ( "kubernetes" , "kubernetes" , "1.2.3.6" , "TCP" , 8086 ) ,
buildService ( "not-special" , "kubernetes" , "1.2.3.8" , "TCP" , 8088 ) ,
buildService ( "not-special" , "kubernetes" , "None" , "TCP" , 8088 ) ,
buildService ( "not-special" , "kubernetes" , "" , "TCP" , 8088 ) ,
}
testCases := [ ] struct {
name string // the name of the test case
ns string // the namespace to generate environment for
2016-11-18 20:50:58 +00:00
container * v1 . Container // the container to use
2016-09-23 15:58:44 +00:00
masterServiceNs string // the namespace to read master service info from
nilLister bool // whether the lister should be nil
2016-11-30 02:57:35 +00:00
configMap * v1 . ConfigMap // an optional ConfigMap to pull from
2017-01-04 20:50:11 +00:00
secret * v1 . Secret // an optional Secret to pull from
2016-09-23 15:58:44 +00:00
expectedEnvs [ ] kubecontainer . EnvVar // a set of expected environment vars
2016-11-30 02:57:35 +00:00
expectedError bool // does the test fail
2017-03-07 14:19:49 +00:00
expectedEvent string // does the test emit an event
2016-09-23 15:58:44 +00:00
} {
{
name : "api server = Y, kubelet = Y" ,
ns : "test1" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{ Name : "FOO" , Value : "BAR" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.3" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8083_TCP_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT_8083_TCP_ADDR" , Value : "1.2.3.3" } ,
} ,
} ,
2017-01-22 03:36:02 +00:00
masterServiceNs : metav1 . NamespaceDefault ,
2016-09-23 15:58:44 +00:00
nilLister : false ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "FOO" , Value : "BAR" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.3" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8083_TCP_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT_8083_TCP_ADDR" , Value : "1.2.3.3" } ,
{ Name : "KUBERNETES_SERVICE_PORT" , Value : "8081" } ,
{ Name : "KUBERNETES_SERVICE_HOST" , Value : "1.2.3.1" } ,
{ Name : "KUBERNETES_PORT" , Value : "tcp://1.2.3.1:8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP" , Value : "tcp://1.2.3.1:8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_PROTO" , Value : "tcp" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_PORT" , Value : "8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_ADDR" , Value : "1.2.3.1" } ,
} ,
} ,
{
name : "api server = Y, kubelet = N" ,
ns : "test1" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{ Name : "FOO" , Value : "BAR" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.3" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8083_TCP_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT_8083_TCP_ADDR" , Value : "1.2.3.3" } ,
} ,
} ,
2017-01-22 03:36:02 +00:00
masterServiceNs : metav1 . NamespaceDefault ,
2016-09-23 15:58:44 +00:00
nilLister : true ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "FOO" , Value : "BAR" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.3" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8083_TCP_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT_8083_TCP_ADDR" , Value : "1.2.3.3" } ,
} ,
} ,
{
name : "api server = N; kubelet = Y" ,
ns : "test1" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{ Name : "FOO" , Value : "BAZ" } ,
} ,
} ,
2017-01-22 03:36:02 +00:00
masterServiceNs : metav1 . NamespaceDefault ,
2016-09-23 15:58:44 +00:00
nilLister : false ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "FOO" , Value : "BAZ" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.3" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP" , Value : "tcp://1.2.3.3:8083" } ,
{ Name : "TEST_PORT_8083_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8083_TCP_PORT" , Value : "8083" } ,
{ Name : "TEST_PORT_8083_TCP_ADDR" , Value : "1.2.3.3" } ,
{ Name : "KUBERNETES_SERVICE_HOST" , Value : "1.2.3.1" } ,
{ Name : "KUBERNETES_SERVICE_PORT" , Value : "8081" } ,
{ Name : "KUBERNETES_PORT" , Value : "tcp://1.2.3.1:8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP" , Value : "tcp://1.2.3.1:8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_PROTO" , Value : "tcp" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_PORT" , Value : "8081" } ,
{ Name : "KUBERNETES_PORT_8081_TCP_ADDR" , Value : "1.2.3.1" } ,
} ,
} ,
{
name : "master service in pod ns" ,
ns : "test2" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{ Name : "FOO" , Value : "ZAP" } ,
} ,
} ,
masterServiceNs : "kubernetes" ,
nilLister : false ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "FOO" , Value : "ZAP" } ,
{ Name : "TEST_SERVICE_HOST" , Value : "1.2.3.5" } ,
{ Name : "TEST_SERVICE_PORT" , Value : "8085" } ,
{ Name : "TEST_PORT" , Value : "tcp://1.2.3.5:8085" } ,
{ Name : "TEST_PORT_8085_TCP" , Value : "tcp://1.2.3.5:8085" } ,
{ Name : "TEST_PORT_8085_TCP_PROTO" , Value : "tcp" } ,
{ Name : "TEST_PORT_8085_TCP_PORT" , Value : "8085" } ,
{ Name : "TEST_PORT_8085_TCP_ADDR" , Value : "1.2.3.5" } ,
{ Name : "KUBERNETES_SERVICE_HOST" , Value : "1.2.3.4" } ,
{ Name : "KUBERNETES_SERVICE_PORT" , Value : "8084" } ,
{ Name : "KUBERNETES_PORT" , Value : "tcp://1.2.3.4:8084" } ,
{ Name : "KUBERNETES_PORT_8084_TCP" , Value : "tcp://1.2.3.4:8084" } ,
{ Name : "KUBERNETES_PORT_8084_TCP_PROTO" , Value : "tcp" } ,
{ Name : "KUBERNETES_PORT_8084_TCP_PORT" , Value : "8084" } ,
{ Name : "KUBERNETES_PORT_8084_TCP_ADDR" , Value : "1.2.3.4" } ,
} ,
} ,
{
name : "pod in master service ns" ,
ns : "kubernetes" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container { } ,
2016-09-23 15:58:44 +00:00
masterServiceNs : "kubernetes" ,
nilLister : false ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "NOT_SPECIAL_SERVICE_HOST" , Value : "1.2.3.8" } ,
{ Name : "NOT_SPECIAL_SERVICE_PORT" , Value : "8088" } ,
{ Name : "NOT_SPECIAL_PORT" , Value : "tcp://1.2.3.8:8088" } ,
{ Name : "NOT_SPECIAL_PORT_8088_TCP" , Value : "tcp://1.2.3.8:8088" } ,
{ Name : "NOT_SPECIAL_PORT_8088_TCP_PROTO" , Value : "tcp" } ,
{ Name : "NOT_SPECIAL_PORT_8088_TCP_PORT" , Value : "8088" } ,
{ Name : "NOT_SPECIAL_PORT_8088_TCP_ADDR" , Value : "1.2.3.8" } ,
{ Name : "KUBERNETES_SERVICE_HOST" , Value : "1.2.3.6" } ,
{ Name : "KUBERNETES_SERVICE_PORT" , Value : "8086" } ,
{ Name : "KUBERNETES_PORT" , Value : "tcp://1.2.3.6:8086" } ,
{ Name : "KUBERNETES_PORT_8086_TCP" , Value : "tcp://1.2.3.6:8086" } ,
{ Name : "KUBERNETES_PORT_8086_TCP_PROTO" , Value : "tcp" } ,
{ Name : "KUBERNETES_PORT_8086_TCP_PORT" , Value : "8086" } ,
{ Name : "KUBERNETES_PORT_8086_TCP_ADDR" , Value : "1.2.3.6" } ,
} ,
} ,
{
name : "downward api pod" ,
ns : "downward-api" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{
Name : "POD_NAME" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "metadata.name" ,
} ,
} ,
} ,
{
Name : "POD_NAMESPACE" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "metadata.namespace" ,
} ,
} ,
} ,
{
Name : "POD_NODE_NAME" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "spec.nodeName" ,
} ,
} ,
} ,
{
Name : "POD_SERVICE_ACCOUNT_NAME" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "spec.serviceAccountName" ,
} ,
} ,
} ,
{
Name : "POD_IP" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "status.podIP" ,
} ,
} ,
} ,
2017-03-14 00:13:32 +00:00
{
Name : "HOST_IP" ,
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2017-03-14 00:13:32 +00:00
FieldPath : "status.hostIP" ,
} ,
} ,
} ,
2016-09-23 15:58:44 +00:00
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : true ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{ Name : "POD_NAME" , Value : "dapi-test-pod-name" } ,
{ Name : "POD_NAMESPACE" , Value : "downward-api" } ,
{ Name : "POD_NODE_NAME" , Value : "node-name" } ,
{ Name : "POD_SERVICE_ACCOUNT_NAME" , Value : "special" } ,
{ Name : "POD_IP" , Value : "1.2.3.4" } ,
2017-03-28 16:07:17 +00:00
{ Name : "HOST_IP" , Value : testKubeletHostIP } ,
2016-09-23 15:58:44 +00:00
} ,
} ,
{
name : "env expansion" ,
ns : "test1" ,
2016-11-18 20:50:58 +00:00
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
2016-09-23 15:58:44 +00:00
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "POD_NAME" ,
2016-11-18 20:50:58 +00:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2017-10-16 11:41:50 +00:00
APIVersion : legacyscheme . Registry . GroupOrDie ( v1 . GroupName ) . GroupVersion . String ( ) ,
2016-09-23 15:58:44 +00:00
FieldPath : "metadata.name" ,
} ,
} ,
} ,
{
Name : "OUT_OF_ORDER_TEST" ,
Value : "$(OUT_OF_ORDER_TARGET)" ,
} ,
{
Name : "OUT_OF_ORDER_TARGET" ,
Value : "FOO" ,
} ,
{
Name : "EMPTY_VAR" ,
} ,
{
Name : "EMPTY_TEST" ,
Value : "foo-$(EMPTY_VAR)" ,
} ,
{
Name : "POD_NAME_TEST2" ,
Value : "test2-$(POD_NAME)" ,
} ,
{
Name : "POD_NAME_TEST3" ,
Value : "$(POD_NAME_TEST2)-3" ,
} ,
{
Name : "LITERAL_TEST" ,
Value : "literal-$(TEST_LITERAL)" ,
} ,
{
Name : "SERVICE_VAR_TEST" ,
Value : "$(TEST_SERVICE_HOST):$(TEST_SERVICE_PORT)" ,
} ,
{
Name : "TEST_UNDEFINED" ,
Value : "$(UNDEFINED_VAR)" ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : false ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "POD_NAME" ,
Value : "dapi-test-pod-name" ,
} ,
{
Name : "POD_NAME_TEST2" ,
Value : "test2-dapi-test-pod-name" ,
} ,
{
Name : "POD_NAME_TEST3" ,
Value : "test2-dapi-test-pod-name-3" ,
} ,
{
Name : "LITERAL_TEST" ,
Value : "literal-test-test-test" ,
} ,
{
Name : "TEST_SERVICE_HOST" ,
Value : "1.2.3.3" ,
} ,
{
Name : "TEST_SERVICE_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PROTO" ,
Value : "tcp" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_ADDR" ,
Value : "1.2.3.3" ,
} ,
{
Name : "SERVICE_VAR_TEST" ,
Value : "1.2.3.3:8083" ,
} ,
{
Name : "OUT_OF_ORDER_TEST" ,
Value : "$(OUT_OF_ORDER_TARGET)" ,
} ,
{
Name : "OUT_OF_ORDER_TARGET" ,
Value : "FOO" ,
} ,
{
Name : "TEST_UNDEFINED" ,
Value : "$(UNDEFINED_VAR)" ,
} ,
{
Name : "EMPTY_VAR" ,
} ,
{
Name : "EMPTY_TEST" ,
Value : "foo-" ,
} ,
} ,
} ,
2017-01-17 00:30:22 +00:00
{
name : "configmapkeyref_missing_optional" ,
ns : "test" ,
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
{
Name : "POD_NAME" ,
ValueFrom : & v1 . EnvVarSource {
ConfigMapKeyRef : & v1 . ConfigMapKeySelector {
LocalObjectReference : v1 . LocalObjectReference { Name : "missing-config-map" } ,
Key : "key" ,
Optional : & trueVal ,
} ,
} ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedEnvs : nil ,
} ,
{
name : "configmapkeyref_missing_key_optional" ,
ns : "test" ,
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
{
Name : "POD_NAME" ,
ValueFrom : & v1 . EnvVarSource {
ConfigMapKeyRef : & v1 . ConfigMapKeySelector {
LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } ,
Key : "key" ,
Optional : & trueVal ,
} ,
} ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : true ,
configMap : & v1 . ConfigMap {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "test1" ,
Name : "test-configmap" ,
} ,
Data : map [ string ] string {
"a" : "b" ,
} ,
} ,
expectedEnvs : nil ,
} ,
{
name : "secretkeyref_missing_optional" ,
ns : "test" ,
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
{
Name : "POD_NAME" ,
ValueFrom : & v1 . EnvVarSource {
SecretKeyRef : & v1 . SecretKeySelector {
LocalObjectReference : v1 . LocalObjectReference { Name : "missing-secret" } ,
Key : "key" ,
Optional : & trueVal ,
} ,
} ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedEnvs : nil ,
} ,
{
name : "secretkeyref_missing_key_optional" ,
ns : "test" ,
container : & v1 . Container {
Env : [ ] v1 . EnvVar {
{
Name : "POD_NAME" ,
ValueFrom : & v1 . EnvVarSource {
SecretKeyRef : & v1 . SecretKeySelector {
LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } ,
Key : "key" ,
Optional : & trueVal ,
} ,
} ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : true ,
secret : & v1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "test1" ,
Name : "test-secret" ,
} ,
Data : map [ string ] [ ] byte {
"a" : [ ] byte ( "b" ) ,
} ,
} ,
expectedEnvs : nil ,
} ,
2016-11-30 02:57:35 +00:00
{
name : "configmap" ,
ns : "test1" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{
ConfigMapRef : & v1 . ConfigMapEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } } ,
} ,
{
Prefix : "p_" ,
ConfigMapRef : & v1 . ConfigMapEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } } ,
} ,
} ,
Env : [ ] v1 . EnvVar {
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "EXPANSION_TEST" ,
Value : "$(REPLACE_ME)" ,
} ,
{
Name : "DUPE_TEST" ,
Value : "ENV_VAR" ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : false ,
configMap : & v1 . ConfigMap {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-11-30 02:57:35 +00:00
Namespace : "test1" ,
Name : "test-configmap" ,
} ,
Data : map [ string ] string {
"REPLACE_ME" : "FROM_CONFIG_MAP" ,
"DUPE_TEST" : "CONFIG_MAP" ,
} ,
} ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "TEST_SERVICE_HOST" ,
Value : "1.2.3.3" ,
} ,
{
Name : "TEST_SERVICE_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PROTO" ,
Value : "tcp" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_ADDR" ,
Value : "1.2.3.3" ,
} ,
{
Name : "REPLACE_ME" ,
Value : "FROM_CONFIG_MAP" ,
} ,
{
Name : "EXPANSION_TEST" ,
Value : "FROM_CONFIG_MAP" ,
} ,
{
Name : "DUPE_TEST" ,
Value : "ENV_VAR" ,
} ,
{
Name : "p_REPLACE_ME" ,
Value : "FROM_CONFIG_MAP" ,
} ,
{
Name : "p_DUPE_TEST" ,
Value : "CONFIG_MAP" ,
} ,
} ,
} ,
{
name : "configmap_missing" ,
ns : "test1" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ ConfigMapRef : & v1 . ConfigMapEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } } } ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedError : true ,
} ,
2017-01-17 00:30:22 +00:00
{
name : "configmap_missing_optional" ,
ns : "test" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ ConfigMapRef : & v1 . ConfigMapEnvSource {
Optional : & trueVal ,
LocalObjectReference : v1 . LocalObjectReference { Name : "missing-config-map" } } } ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedEnvs : nil ,
} ,
2016-11-30 02:57:35 +00:00
{
name : "configmap_invalid_keys" ,
2017-03-07 14:19:49 +00:00
ns : "test" ,
2016-11-30 02:57:35 +00:00
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ ConfigMapRef : & v1 . ConfigMapEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } } } ,
} ,
} ,
masterServiceNs : "nothing" ,
configMap : & v1 . ConfigMap {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-11-30 02:57:35 +00:00
Namespace : "test1" ,
Name : "test-configmap" ,
} ,
Data : map [ string ] string {
2017-01-04 13:26:05 +00:00
"1234" : "abc" ,
2017-03-07 14:19:49 +00:00
"1z" : "abc" ,
"key" : "value" ,
2016-11-30 02:57:35 +00:00
} ,
} ,
2017-03-07 14:19:49 +00:00
expectedEnvs : [ ] kubecontainer . EnvVar {
{
Name : "key" ,
Value : "value" ,
} ,
} ,
expectedEvent : "Warning InvalidEnvironmentVariableNames Keys [1234, 1z] from the EnvFrom configMap test/test-config-map were skipped since they are considered invalid environment variable names." ,
2016-11-30 02:57:35 +00:00
} ,
2017-01-04 13:26:05 +00:00
{
name : "configmap_invalid_keys_valid" ,
ns : "test" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{
Prefix : "p_" ,
ConfigMapRef : & v1 . ConfigMapEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-config-map" } } ,
} ,
} ,
} ,
masterServiceNs : "" ,
configMap : & v1 . ConfigMap {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2017-01-04 13:26:05 +00:00
Namespace : "test1" ,
Name : "test-configmap" ,
} ,
Data : map [ string ] string {
"1234" : "abc" ,
} ,
} ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
Name : "p_1234" ,
Value : "abc" ,
} ,
} ,
} ,
2017-01-04 20:50:11 +00:00
{
name : "secret" ,
ns : "test1" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{
SecretRef : & v1 . SecretEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } } ,
} ,
{
Prefix : "p_" ,
SecretRef : & v1 . SecretEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } } ,
} ,
} ,
Env : [ ] v1 . EnvVar {
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "EXPANSION_TEST" ,
Value : "$(REPLACE_ME)" ,
} ,
{
Name : "DUPE_TEST" ,
Value : "ENV_VAR" ,
} ,
} ,
} ,
masterServiceNs : "nothing" ,
nilLister : false ,
secret : & v1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "test1" ,
Name : "test-secret" ,
} ,
Data : map [ string ] [ ] byte {
"REPLACE_ME" : [ ] byte ( "FROM_SECRET" ) ,
"DUPE_TEST" : [ ] byte ( "SECRET" ) ,
} ,
} ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
Name : "TEST_LITERAL" ,
Value : "test-test-test" ,
} ,
{
Name : "TEST_SERVICE_HOST" ,
Value : "1.2.3.3" ,
} ,
{
Name : "TEST_SERVICE_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP" ,
Value : "tcp://1.2.3.3:8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PROTO" ,
Value : "tcp" ,
} ,
{
Name : "TEST_PORT_8083_TCP_PORT" ,
Value : "8083" ,
} ,
{
Name : "TEST_PORT_8083_TCP_ADDR" ,
Value : "1.2.3.3" ,
} ,
{
Name : "REPLACE_ME" ,
Value : "FROM_SECRET" ,
} ,
{
Name : "EXPANSION_TEST" ,
Value : "FROM_SECRET" ,
} ,
{
Name : "DUPE_TEST" ,
Value : "ENV_VAR" ,
} ,
{
Name : "p_REPLACE_ME" ,
Value : "FROM_SECRET" ,
} ,
{
Name : "p_DUPE_TEST" ,
Value : "SECRET" ,
} ,
} ,
} ,
{
name : "secret_missing" ,
ns : "test1" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ SecretRef : & v1 . SecretEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } } } ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedError : true ,
} ,
2017-01-17 00:30:22 +00:00
{
name : "secret_missing_optional" ,
ns : "test" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ SecretRef : & v1 . SecretEnvSource {
LocalObjectReference : v1 . LocalObjectReference { Name : "missing-secret" } ,
Optional : & trueVal } } ,
} ,
} ,
masterServiceNs : "nothing" ,
expectedEnvs : nil ,
} ,
2017-01-04 20:50:11 +00:00
{
name : "secret_invalid_keys" ,
2017-03-07 14:19:49 +00:00
ns : "test" ,
2017-01-04 20:50:11 +00:00
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{ SecretRef : & v1 . SecretEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } } } ,
} ,
} ,
masterServiceNs : "nothing" ,
secret : & v1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "test1" ,
Name : "test-secret" ,
} ,
Data : map [ string ] [ ] byte {
2017-06-17 22:34:22 +00:00
"1234" : [ ] byte ( "abc" ) ,
"1z" : [ ] byte ( "abc" ) ,
"key.1" : [ ] byte ( "value" ) ,
2017-03-07 14:19:49 +00:00
} ,
} ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
2017-06-17 22:34:22 +00:00
Name : "key.1" ,
2017-03-07 14:19:49 +00:00
Value : "value" ,
2017-01-04 20:50:11 +00:00
} ,
} ,
2017-03-07 14:19:49 +00:00
expectedEvent : "Warning InvalidEnvironmentVariableNames Keys [1234, 1z] from the EnvFrom secret test/test-secret were skipped since they are considered invalid environment variable names." ,
2017-01-04 20:50:11 +00:00
} ,
{
name : "secret_invalid_keys_valid" ,
ns : "test" ,
container : & v1 . Container {
EnvFrom : [ ] v1 . EnvFromSource {
{
Prefix : "p_" ,
SecretRef : & v1 . SecretEnvSource { LocalObjectReference : v1 . LocalObjectReference { Name : "test-secret" } } ,
} ,
} ,
} ,
masterServiceNs : "" ,
secret : & v1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Namespace : "test1" ,
Name : "test-secret" ,
} ,
Data : map [ string ] [ ] byte {
2017-06-17 22:34:22 +00:00
"1234.name" : [ ] byte ( "abc" ) ,
2017-01-04 20:50:11 +00:00
} ,
} ,
expectedEnvs : [ ] kubecontainer . EnvVar {
{
2017-06-17 22:34:22 +00:00
Name : "p_1234.name" ,
2017-01-04 20:50:11 +00:00
Value : "abc" ,
} ,
} ,
} ,
2016-09-23 15:58:44 +00:00
}
for _ , tc := range testCases {
2017-03-07 14:19:49 +00:00
fakeRecorder := record . NewFakeRecorder ( 1 )
2016-09-23 15:58:44 +00:00
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2017-03-07 14:19:49 +00:00
testKubelet . kubelet . recorder = fakeRecorder
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-09-23 15:58:44 +00:00
kl := testKubelet . kubelet
kl . masterServiceNamespace = tc . masterServiceNs
if tc . nilLister {
kl . serviceLister = nil
} else {
kl . serviceLister = testServiceLister { services }
}
2016-11-30 02:57:35 +00:00
testKubelet . fakeKubeClient . AddReactor ( "get" , "configmaps" , func ( action core . Action ) ( bool , runtime . Object , error ) {
var err error
if tc . configMap == nil {
2017-01-17 00:30:22 +00:00
err = apierrors . NewNotFound ( action . GetResource ( ) . GroupResource ( ) , "configmap-name" )
2016-11-30 02:57:35 +00:00
}
return true , tc . configMap , err
} )
2017-01-17 00:30:22 +00:00
testKubelet . fakeKubeClient . AddReactor ( "get" , "secrets" , func ( action core . Action ) ( bool , runtime . Object , error ) {
var err error
if tc . secret == nil {
err = apierrors . NewNotFound ( action . GetResource ( ) . GroupResource ( ) , "secret-name" )
}
return true , tc . secret , err
} )
2016-11-30 02:57:35 +00:00
2017-01-04 20:50:11 +00:00
testKubelet . fakeKubeClient . AddReactor ( "get" , "secrets" , func ( action core . Action ) ( bool , runtime . Object , error ) {
var err error
if tc . secret == nil {
err = errors . New ( "no secret defined" )
}
return true , tc . secret , err
} )
2016-11-18 20:50:58 +00:00
testPod := & v1 . Pod {
2017-01-17 03:38:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2016-09-23 15:58:44 +00:00
Namespace : tc . ns ,
Name : "dapi-test-pod-name" ,
} ,
2016-11-18 20:50:58 +00:00
Spec : v1 . PodSpec {
2016-09-23 15:58:44 +00:00
ServiceAccountName : "special" ,
NodeName : "node-name" ,
} ,
}
podIP := "1.2.3.4"
2017-03-28 16:07:17 +00:00
result , err := kl . makeEnvironmentVariables ( testPod , tc . container , podIP )
2017-03-07 14:19:49 +00:00
select {
case e := <- fakeRecorder . Events :
assert . Equal ( t , tc . expectedEvent , e )
default :
assert . Equal ( t , "" , tc . expectedEvent )
}
2016-11-30 02:57:35 +00:00
if tc . expectedError {
assert . Error ( t , err , tc . name )
} else {
assert . NoError ( t , err , "[%s]" , tc . name )
2016-09-23 15:58:44 +00:00
2016-11-30 02:57:35 +00:00
sort . Sort ( envs ( result ) )
sort . Sort ( envs ( tc . expectedEnvs ) )
assert . Equal ( t , tc . expectedEnvs , result , "[%s] env entries" , tc . name )
}
2016-09-23 15:58:44 +00:00
}
}
2016-11-18 20:50:58 +00:00
func waitingState ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Waiting : & v1 . ContainerStateWaiting { } ,
2016-09-23 15:58:44 +00:00
} ,
}
}
2016-11-18 20:50:58 +00:00
func waitingStateWithLastTermination ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Waiting : & v1 . ContainerStateWaiting { } ,
2016-09-23 15:58:44 +00:00
} ,
2016-11-18 20:50:58 +00:00
LastTerminationState : v1 . ContainerState {
Terminated : & v1 . ContainerStateTerminated {
2016-09-23 15:58:44 +00:00
ExitCode : 0 ,
} ,
} ,
}
}
2016-11-18 20:50:58 +00:00
func runningState ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Running : & v1 . ContainerStateRunning { } ,
2016-09-23 15:58:44 +00:00
} ,
}
}
2016-11-18 20:50:58 +00:00
func stoppedState ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Terminated : & v1 . ContainerStateTerminated { } ,
2016-09-23 15:58:44 +00:00
} ,
}
}
2016-11-18 20:50:58 +00:00
func succeededState ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Terminated : & v1 . ContainerStateTerminated {
2016-09-23 15:58:44 +00:00
ExitCode : 0 ,
} ,
} ,
}
}
2016-11-18 20:50:58 +00:00
func failedState ( cName string ) v1 . ContainerStatus {
return v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
Name : cName ,
2016-11-18 20:50:58 +00:00
State : v1 . ContainerState {
Terminated : & v1 . ContainerStateTerminated {
2016-09-23 15:58:44 +00:00
ExitCode : - 1 ,
} ,
} ,
}
}
func TestPodPhaseWithRestartAlways ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
desiredState := v1 . PodSpec {
2016-09-23 15:58:44 +00:00
NodeName : "machine" ,
2016-11-18 20:50:58 +00:00
Containers : [ ] v1 . Container {
2016-09-23 15:58:44 +00:00
{ Name : "containerA" } ,
{ Name : "containerB" } ,
} ,
2016-11-18 20:50:58 +00:00
RestartPolicy : v1 . RestartPolicyAlways ,
2016-09-23 15:58:44 +00:00
}
tests := [ ] struct {
2016-11-18 20:50:58 +00:00
pod * v1 . Pod
status v1 . PodPhase
2016-09-23 15:58:44 +00:00
test string
} {
2016-11-18 20:50:58 +00:00
{ & v1 . Pod { Spec : desiredState , Status : v1 . PodStatus { } } , v1 . PodPending , "waiting" } ,
2016-09-23 15:58:44 +00:00
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
runningState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"all running" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
stoppedState ( "containerA" ) ,
stoppedState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"all stopped with restart always" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
stoppedState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"mixed state #1 with restart always" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #2 with restart always" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
waitingState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #3 with restart always" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
waitingStateWithLastTermination ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"backoff crashloop container with restart always" ,
} ,
}
for _ , test := range tests {
status := GetPhase ( & test . pod . Spec , test . pod . Status . ContainerStatuses )
assert . Equal ( t , test . status , status , "[test %s]" , test . test )
}
}
func TestPodPhaseWithRestartNever ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
desiredState := v1 . PodSpec {
2016-09-23 15:58:44 +00:00
NodeName : "machine" ,
2016-11-18 20:50:58 +00:00
Containers : [ ] v1 . Container {
2016-09-23 15:58:44 +00:00
{ Name : "containerA" } ,
{ Name : "containerB" } ,
} ,
2016-11-18 20:50:58 +00:00
RestartPolicy : v1 . RestartPolicyNever ,
2016-09-23 15:58:44 +00:00
}
tests := [ ] struct {
2016-11-18 20:50:58 +00:00
pod * v1 . Pod
status v1 . PodPhase
2016-09-23 15:58:44 +00:00
test string
} {
2016-11-18 20:50:58 +00:00
{ & v1 . Pod { Spec : desiredState , Status : v1 . PodStatus { } } , v1 . PodPending , "waiting" } ,
2016-09-23 15:58:44 +00:00
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
runningState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"all running with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
succeededState ( "containerA" ) ,
succeededState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodSucceeded ,
2016-09-23 15:58:44 +00:00
"all succeeded with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
failedState ( "containerA" ) ,
failedState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodFailed ,
2016-09-23 15:58:44 +00:00
"all failed with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
succeededState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"mixed state #1 with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #2 with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
waitingState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #3 with restart never" ,
} ,
}
for _ , test := range tests {
status := GetPhase ( & test . pod . Spec , test . pod . Status . ContainerStatuses )
assert . Equal ( t , test . status , status , "[test %s]" , test . test )
}
}
func TestPodPhaseWithRestartOnFailure ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
desiredState := v1 . PodSpec {
2016-09-23 15:58:44 +00:00
NodeName : "machine" ,
2016-11-18 20:50:58 +00:00
Containers : [ ] v1 . Container {
2016-09-23 15:58:44 +00:00
{ Name : "containerA" } ,
{ Name : "containerB" } ,
} ,
2016-11-18 20:50:58 +00:00
RestartPolicy : v1 . RestartPolicyOnFailure ,
2016-09-23 15:58:44 +00:00
}
tests := [ ] struct {
2016-11-18 20:50:58 +00:00
pod * v1 . Pod
status v1 . PodPhase
2016-09-23 15:58:44 +00:00
test string
} {
2016-11-18 20:50:58 +00:00
{ & v1 . Pod { Spec : desiredState , Status : v1 . PodStatus { } } , v1 . PodPending , "waiting" } ,
2016-09-23 15:58:44 +00:00
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
runningState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"all running with restart onfailure" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
succeededState ( "containerA" ) ,
succeededState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodSucceeded ,
2016-09-23 15:58:44 +00:00
"all succeeded with restart onfailure" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
failedState ( "containerA" ) ,
failedState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"all failed with restart never" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
succeededState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"mixed state #1 with restart onfailure" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #2 with restart onfailure" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
waitingState ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodPending ,
2016-09-23 15:58:44 +00:00
"mixed state #3 with restart onfailure" ,
} ,
{
2016-11-18 20:50:58 +00:00
& v1 . Pod {
2016-09-23 15:58:44 +00:00
Spec : desiredState ,
2016-11-18 20:50:58 +00:00
Status : v1 . PodStatus {
ContainerStatuses : [ ] v1 . ContainerStatus {
2016-09-23 15:58:44 +00:00
runningState ( "containerA" ) ,
waitingStateWithLastTermination ( "containerB" ) ,
} ,
} ,
} ,
2016-11-18 20:50:58 +00:00
v1 . PodRunning ,
2016-09-23 15:58:44 +00:00
"backoff crashloop container with restart onfailure" ,
} ,
}
for _ , test := range tests {
status := GetPhase ( & test . pod . Spec , test . pod . Status . ContainerStatuses )
assert . Equal ( t , test . status , status , "[test %s]" , test . test )
}
}
type fakeReadWriteCloser struct { }
func ( f * fakeReadWriteCloser ) Write ( data [ ] byte ) ( int , error ) {
return 0 , nil
}
func ( f * fakeReadWriteCloser ) Read ( data [ ] byte ) ( int , error ) {
return 0 , nil
}
func ( f * fakeReadWriteCloser ) Close ( ) error {
return nil
}
2016-11-03 00:42:00 +00:00
func TestExec ( t * testing . T ) {
const (
podName = "podFoo"
podNamespace = "nsFoo"
podUID types . UID = "12345678"
containerID = "containerFoo"
tty = true
)
var (
2017-06-12 02:03:59 +00:00
podFullName = kubecontainer . GetPodFullName ( podWithUIDNameNs ( podUID , podName , podNamespace ) )
2016-11-03 00:42:00 +00:00
command = [ ] string { "ls" }
stdin = & bytes . Buffer { }
stdout = & fakeReadWriteCloser { }
stderr = & fakeReadWriteCloser { }
2016-09-23 15:58:44 +00:00
)
2016-11-03 00:42:00 +00:00
testcases := [ ] struct {
description string
podFullName string
container string
expectError bool
} { {
description : "success case" ,
podFullName : podFullName ,
container : containerID ,
} , {
description : "no such pod" ,
podFullName : "bar" + podFullName ,
container : containerID ,
expectError : true ,
} , {
description : "no such container" ,
podFullName : podFullName ,
container : "containerBar" ,
expectError : true ,
} }
for _ , tc := range testcases {
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-11-03 00:42:00 +00:00
kubelet := testKubelet . kubelet
testKubelet . fakeRuntime . PodList = [ ] * containertest . FakePod {
{ Pod : & kubecontainer . Pod {
ID : podUID ,
Name : podName ,
Namespace : podNamespace ,
Containers : [ ] * kubecontainer . Container {
{ Name : containerID ,
ID : kubecontainer . ContainerID { Type : "test" , ID : containerID } ,
} ,
} ,
} } ,
}
2016-09-23 15:58:44 +00:00
2016-11-03 00:42:00 +00:00
{ // No streaming case
description := "no streaming - " + tc . description
redirect , err := kubelet . GetExec ( tc . podFullName , podUID , tc . container , command , remotecommand . Options { } )
assert . Error ( t , err , description )
assert . Nil ( t , redirect , description )
2016-09-23 15:58:44 +00:00
2016-06-23 17:44:26 +00:00
err = kubelet . ExecInContainer ( tc . podFullName , podUID , tc . container , command , stdin , stdout , stderr , tty , nil , 0 )
2016-11-03 00:42:00 +00:00
assert . Error ( t , err , description )
}
{ // Direct streaming case
description := "direct streaming - " + tc . description
fakeRuntime := & containertest . FakeDirectStreamingRuntime { FakeRuntime : testKubelet . fakeRuntime }
kubelet . containerRuntime = fakeRuntime
redirect , err := kubelet . GetExec ( tc . podFullName , podUID , tc . container , command , remotecommand . Options { } )
assert . NoError ( t , err , description )
assert . Nil ( t , redirect , description )
2016-06-23 17:44:26 +00:00
err = kubelet . ExecInContainer ( tc . podFullName , podUID , tc . container , command , stdin , stdout , stderr , tty , nil , 0 )
2016-11-03 00:42:00 +00:00
if tc . expectError {
assert . Error ( t , err , description )
} else {
assert . NoError ( t , err , description )
assert . Equal ( t , fakeRuntime . Args . ContainerID . ID , containerID , description + ": ID" )
assert . Equal ( t , fakeRuntime . Args . Cmd , command , description + ": Command" )
assert . Equal ( t , fakeRuntime . Args . Stdin , stdin , description + ": Stdin" )
assert . Equal ( t , fakeRuntime . Args . Stdout , stdout , description + ": Stdout" )
assert . Equal ( t , fakeRuntime . Args . Stderr , stderr , description + ": Stderr" )
assert . Equal ( t , fakeRuntime . Args . TTY , tty , description + ": TTY" )
}
}
{ // Indirect streaming case
description := "indirect streaming - " + tc . description
fakeRuntime := & containertest . FakeIndirectStreamingRuntime { FakeRuntime : testKubelet . fakeRuntime }
kubelet . containerRuntime = fakeRuntime
redirect , err := kubelet . GetExec ( tc . podFullName , podUID , tc . container , command , remotecommand . Options { } )
if tc . expectError {
assert . Error ( t , err , description )
} else {
assert . NoError ( t , err , description )
assert . Equal ( t , containertest . FakeHost , redirect . Host , description + ": redirect" )
}
2016-06-23 17:44:26 +00:00
err = kubelet . ExecInContainer ( tc . podFullName , podUID , tc . container , command , stdin , stdout , stderr , tty , nil , 0 )
2016-11-03 00:42:00 +00:00
assert . Error ( t , err , description )
}
}
2016-09-23 15:58:44 +00:00
}
func TestPortForward ( t * testing . T ) {
2016-11-03 00:42:00 +00:00
const (
podName = "podFoo"
podNamespace = "nsFoo"
podUID types . UID = "12345678"
2017-01-07 05:06:19 +00:00
port int32 = 5000
2016-11-03 00:42:00 +00:00
)
var (
stream = & fakeReadWriteCloser { }
)
2016-09-23 15:58:44 +00:00
2016-11-03 00:42:00 +00:00
testcases := [ ] struct {
description string
podName string
expectError bool
} { {
description : "success case" ,
podName : podName ,
} , {
description : "no such pod" ,
podName : "bar" ,
expectError : true ,
} }
for _ , tc := range testcases {
testKubelet := newTestKubelet ( t , false /* controllerAttachDetachEnabled */ )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-11-03 00:42:00 +00:00
kubelet := testKubelet . kubelet
testKubelet . fakeRuntime . PodList = [ ] * containertest . FakePod {
{ Pod : & kubecontainer . Pod {
ID : podUID ,
Name : podName ,
Namespace : podNamespace ,
Containers : [ ] * kubecontainer . Container {
{ Name : "foo" ,
ID : kubecontainer . ContainerID { Type : "test" , ID : "foo" } ,
} ,
2016-09-23 15:58:44 +00:00
} ,
2016-11-03 00:42:00 +00:00
} } ,
}
2017-06-12 02:03:59 +00:00
podFullName := kubecontainer . GetPodFullName ( podWithUIDNameNs ( podUID , tc . podName , podNamespace ) )
2016-11-03 00:42:00 +00:00
{ // No streaming case
description := "no streaming - " + tc . description
2017-01-07 05:06:19 +00:00
redirect , err := kubelet . GetPortForward ( tc . podName , podNamespace , podUID , portforward . V4Options { } )
2016-11-03 00:42:00 +00:00
assert . Error ( t , err , description )
assert . Nil ( t , redirect , description )
err = kubelet . PortForward ( podFullName , podUID , port , stream )
assert . Error ( t , err , description )
}
{ // Direct streaming case
description := "direct streaming - " + tc . description
fakeRuntime := & containertest . FakeDirectStreamingRuntime { FakeRuntime : testKubelet . fakeRuntime }
kubelet . containerRuntime = fakeRuntime
2017-01-07 05:06:19 +00:00
redirect , err := kubelet . GetPortForward ( tc . podName , podNamespace , podUID , portforward . V4Options { } )
2016-11-03 00:42:00 +00:00
assert . NoError ( t , err , description )
assert . Nil ( t , redirect , description )
err = kubelet . PortForward ( podFullName , podUID , port , stream )
if tc . expectError {
assert . Error ( t , err , description )
} else {
assert . NoError ( t , err , description )
require . Equal ( t , fakeRuntime . Args . Pod . ID , podUID , description + ": Pod UID" )
require . Equal ( t , fakeRuntime . Args . Port , port , description + ": Port" )
require . Equal ( t , fakeRuntime . Args . Stream , stream , description + ": stream" )
}
}
{ // Indirect streaming case
description := "indirect streaming - " + tc . description
fakeRuntime := & containertest . FakeIndirectStreamingRuntime { FakeRuntime : testKubelet . fakeRuntime }
kubelet . containerRuntime = fakeRuntime
2017-01-07 05:06:19 +00:00
redirect , err := kubelet . GetPortForward ( tc . podName , podNamespace , podUID , portforward . V4Options { } )
2016-11-03 00:42:00 +00:00
if tc . expectError {
assert . Error ( t , err , description )
} else {
assert . NoError ( t , err , description )
assert . Equal ( t , containertest . FakeHost , redirect . Host , description + ": redirect" )
}
err = kubelet . PortForward ( podFullName , podUID , port , stream )
assert . Error ( t , err , description )
}
2016-09-23 15:58:44 +00:00
}
}
// Tests that identify the host port conflicts are detected correctly.
func TestGetHostPortConflicts ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
pods := [ ] * v1 . Pod {
{ Spec : v1 . PodSpec { Containers : [ ] v1 . Container { { Ports : [ ] v1 . ContainerPort { { HostPort : 80 } } } } } } ,
{ Spec : v1 . PodSpec { Containers : [ ] v1 . Container { { Ports : [ ] v1 . ContainerPort { { HostPort : 81 } } } } } } ,
{ Spec : v1 . PodSpec { Containers : [ ] v1 . Container { { Ports : [ ] v1 . ContainerPort { { HostPort : 82 } } } } } } ,
{ Spec : v1 . PodSpec { Containers : [ ] v1 . Container { { Ports : [ ] v1 . ContainerPort { { HostPort : 83 } } } } } } ,
2016-09-23 15:58:44 +00:00
}
// Pods should not cause any conflict.
assert . False ( t , hasHostPortConflicts ( pods ) , "Should not have port conflicts" )
2016-11-18 20:50:58 +00:00
expected := & v1 . Pod {
Spec : v1 . PodSpec { Containers : [ ] v1 . Container { { Ports : [ ] v1 . ContainerPort { { HostPort : 81 } } } } } ,
2016-09-23 15:58:44 +00:00
}
// The new pod should cause conflict and be reported.
pods = append ( pods , expected )
assert . True ( t , hasHostPortConflicts ( pods ) , "Should have port conflicts" )
}
2016-10-31 08:05:02 +00:00
2016-08-25 20:45:38 +00:00
func TestHasHostMountPVC ( t * testing . T ) {
tests := map [ string ] struct {
pvError error
pvcError error
expected bool
podHasPVC bool
pvcIsHostPath bool
} {
"no pvc" : { podHasPVC : false , expected : false } ,
"error fetching pvc" : {
podHasPVC : true ,
pvcError : fmt . Errorf ( "foo" ) ,
expected : false ,
} ,
"error fetching pv" : {
podHasPVC : true ,
pvError : fmt . Errorf ( "foo" ) ,
expected : false ,
} ,
"host path pvc" : {
podHasPVC : true ,
pvcIsHostPath : true ,
expected : true ,
} ,
"non host path pvc" : {
podHasPVC : true ,
pvcIsHostPath : false ,
expected : false ,
} ,
}
for k , v := range tests {
testKubelet := newTestKubelet ( t , false )
2016-12-14 22:31:01 +00:00
defer testKubelet . Cleanup ( )
2016-11-18 20:50:58 +00:00
pod := & v1 . Pod {
Spec : v1 . PodSpec { } ,
2016-08-25 20:45:38 +00:00
}
2016-11-18 20:50:58 +00:00
volumeToReturn := & v1 . PersistentVolume {
Spec : v1 . PersistentVolumeSpec { } ,
2016-08-25 20:45:38 +00:00
}
if v . podHasPVC {
2016-11-18 20:50:58 +00:00
pod . Spec . Volumes = [ ] v1 . Volume {
2016-08-25 20:45:38 +00:00
{
2016-11-18 20:50:58 +00:00
VolumeSource : v1 . VolumeSource {
PersistentVolumeClaim : & v1 . PersistentVolumeClaimVolumeSource { } ,
2016-08-25 20:45:38 +00:00
} ,
} ,
}
if v . pvcIsHostPath {
2016-11-18 20:50:58 +00:00
volumeToReturn . Spec . PersistentVolumeSource = v1 . PersistentVolumeSource {
HostPath : & v1 . HostPathVolumeSource { } ,
2016-08-25 20:45:38 +00:00
}
}
}
testKubelet . fakeKubeClient . AddReactor ( "get" , "persistentvolumeclaims" , func ( action core . Action ) ( bool , runtime . Object , error ) {
2016-11-18 20:50:58 +00:00
return true , & v1 . PersistentVolumeClaim {
Spec : v1 . PersistentVolumeClaimSpec {
2016-08-25 20:45:38 +00:00
VolumeName : "foo" ,
} ,
} , v . pvcError
} )
testKubelet . fakeKubeClient . AddReactor ( "get" , "persistentvolumes" , func ( action core . Action ) ( bool , runtime . Object , error ) {
return true , volumeToReturn , v . pvError
} )
actual := testKubelet . kubelet . hasHostMountPVC ( pod )
if actual != v . expected {
t . Errorf ( "%s expected %t but got %t" , k , v . expected , actual )
}
}
}
func TestHasNonNamespacedCapability ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
createPodWithCap := func ( caps [ ] v1 . Capability ) * v1 . Pod {
pod := & v1 . Pod {
Spec : v1 . PodSpec {
Containers : [ ] v1 . Container { { } } ,
2016-08-25 20:45:38 +00:00
} ,
}
if len ( caps ) > 0 {
2016-11-18 20:50:58 +00:00
pod . Spec . Containers [ 0 ] . SecurityContext = & v1 . SecurityContext {
Capabilities : & v1 . Capabilities {
2016-08-25 20:45:38 +00:00
Add : caps ,
} ,
}
}
return pod
}
2016-11-18 20:50:58 +00:00
nilCaps := createPodWithCap ( [ ] v1 . Capability { v1 . Capability ( "foo" ) } )
2016-08-25 20:45:38 +00:00
nilCaps . Spec . Containers [ 0 ] . SecurityContext = nil
tests := map [ string ] struct {
2016-11-18 20:50:58 +00:00
pod * v1 . Pod
2016-08-25 20:45:38 +00:00
expected bool
} {
"nil security contxt" : { createPodWithCap ( nil ) , false } ,
"nil caps" : { nilCaps , false } ,
2016-11-18 20:50:58 +00:00
"namespaced cap" : { createPodWithCap ( [ ] v1 . Capability { v1 . Capability ( "foo" ) } ) , false } ,
"non-namespaced cap MKNOD" : { createPodWithCap ( [ ] v1 . Capability { v1 . Capability ( "MKNOD" ) } ) , true } ,
"non-namespaced cap SYS_TIME" : { createPodWithCap ( [ ] v1 . Capability { v1 . Capability ( "SYS_TIME" ) } ) , true } ,
"non-namespaced cap SYS_MODULE" : { createPodWithCap ( [ ] v1 . Capability { v1 . Capability ( "SYS_MODULE" ) } ) , true } ,
2016-08-25 20:45:38 +00:00
}
for k , v := range tests {
actual := hasNonNamespacedCapability ( v . pod )
if actual != v . expected {
t . Errorf ( "%s failed, expected %t but got %t" , k , v . expected , actual )
}
}
}
func TestHasHostVolume ( t * testing . T ) {
2016-11-18 20:50:58 +00:00
pod := & v1 . Pod {
Spec : v1 . PodSpec {
Volumes : [ ] v1 . Volume {
2016-08-25 20:45:38 +00:00
{
2016-11-18 20:50:58 +00:00
VolumeSource : v1 . VolumeSource {
HostPath : & v1 . HostPathVolumeSource { } ,
2016-08-25 20:45:38 +00:00
} ,
} ,
} ,
} ,
}
result := hasHostVolume ( pod )
if ! result {
t . Errorf ( "expected host volume to enable host user namespace" )
}
pod . Spec . Volumes [ 0 ] . VolumeSource . HostPath = nil
result = hasHostVolume ( pod )
if result {
t . Errorf ( "expected nil host volume to not enable host user namespace" )
}
}
func TestHasHostNamespace ( t * testing . T ) {
tests := map [ string ] struct {
2016-11-18 20:50:58 +00:00
ps v1 . PodSpec
2016-08-25 20:45:38 +00:00
expected bool
} {
2016-11-18 20:50:58 +00:00
"nil psc" : {
ps : v1 . PodSpec { } ,
expected : false } ,
2016-08-25 20:45:38 +00:00
"host pid true" : {
2016-11-18 20:50:58 +00:00
ps : v1 . PodSpec {
HostPID : true ,
SecurityContext : & v1 . PodSecurityContext { } ,
2016-08-25 20:45:38 +00:00
} ,
expected : true ,
} ,
"host ipc true" : {
2016-11-18 20:50:58 +00:00
ps : v1 . PodSpec {
HostIPC : true ,
SecurityContext : & v1 . PodSecurityContext { } ,
2016-08-25 20:45:38 +00:00
} ,
expected : true ,
} ,
"host net true" : {
2016-11-18 20:50:58 +00:00
ps : v1 . PodSpec {
HostNetwork : true ,
SecurityContext : & v1 . PodSecurityContext { } ,
2016-08-25 20:45:38 +00:00
} ,
expected : true ,
} ,
"no host ns" : {
2016-11-18 20:50:58 +00:00
ps : v1 . PodSpec {
SecurityContext : & v1 . PodSecurityContext { } ,
} ,
2016-08-25 20:45:38 +00:00
expected : false ,
} ,
}
for k , v := range tests {
2016-11-18 20:50:58 +00:00
pod := & v1 . Pod {
Spec : v . ps ,
2016-08-25 20:45:38 +00:00
}
actual := hasHostNamespace ( pod )
if actual != v . expected {
t . Errorf ( "%s failed, expected %t but got %t" , k , v . expected , actual )
}
}
}
2016-11-17 01:42:39 +00:00
func TestTruncatePodHostname ( t * testing . T ) {
for c , test := range map [ string ] struct {
input string
output string
} {
"valid hostname" : {
input : "test.pod.hostname" ,
output : "test.pod.hostname" ,
} ,
"too long hostname" : {
input : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.1234567.1234567." , // 8*9=72 chars
output : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.1234567" , //8*8-1=63 chars
} ,
"hostname end with ." : {
input : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.123456.1234567." , // 8*9-1=71 chars
output : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.123456" , //8*8-2=62 chars
} ,
"hostname end with -" : {
input : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.123456-1234567." , // 8*9-1=71 chars
output : "1234567.1234567.1234567.1234567.1234567.1234567.1234567.123456" , //8*8-2=62 chars
} ,
} {
t . Logf ( "TestCase: %q" , c )
output , err := truncatePodHostnameIfNeeded ( "test-pod" , test . input )
assert . NoError ( t , err )
assert . Equal ( t , test . output , output )
}
}