2018-08-23 22:23:15 -04: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 .
* /
2021-03-03 01:57:20 -05:00
package node
2018-08-23 22:23:15 -04:00
import (
2020-02-07 21:16:47 -05:00
"context"
2018-08-23 22:23:15 -04:00
"fmt"
2021-10-29 18:41:02 -04:00
"os"
2018-08-23 22:23:15 -04:00
"path"
"time"
2019-05-03 12:44:04 -04:00
v1 "k8s.io/api/core/v1"
2020-02-08 12:30:21 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-08-23 22:23:15 -04:00
"k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/kubernetes/pkg/kubelet/images"
"k8s.io/kubernetes/test/e2e/framework"
2022-08-25 14:56:04 -04:00
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
2019-05-15 02:09:47 -04:00
imageutils "k8s.io/kubernetes/test/utils/image"
2022-01-30 07:37:24 -05:00
admissionapi "k8s.io/pod-security-admission/api"
2018-08-23 22:23:15 -04:00
2022-03-29 02:12:12 -04:00
"github.com/onsi/ginkgo/v2"
2019-05-14 02:10:31 -04:00
"github.com/onsi/gomega"
2018-08-23 22:23:15 -04:00
gomegatypes "github.com/onsi/gomega/types"
)
2021-03-03 01:57:20 -05:00
var _ = SIGDescribe ( "Container Runtime" , func ( ) {
2018-08-23 22:23:15 -04:00
f := framework . NewDefaultFramework ( "container-runtime" )
2023-05-10 09:38:10 -04:00
f . NamespacePodSecurityLevel = admissionapi . LevelBaseline
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . Describe ( "blackbox test" , func ( ) {
ginkgo . Context ( "when starting a container that exits" , func ( ) {
2018-08-23 22:23:15 -04:00
2018-09-20 09:29:34 -04:00
/ *
2020-07-29 11:56:26 -04:00
Release : v1 .13
2018-09-20 09:29:34 -04:00
Testname : Container Runtime , Restart Policy , Pod Phases
2020-01-29 20:00:01 -05:00
Description : If the restart policy is set to ' Always ' , Pod MUST be restarted when terminated , If restart policy is ' OnFailure ' , Pod MUST be started only if it is terminated with non - zero exit code . If the restart policy is ' Never ' , Pod MUST never be restarted . All these three test cases MUST verify the restart counts accordingly .
2018-09-20 09:29:34 -04:00
* /
2023-06-20 04:27:14 -04:00
framework . ConformanceIt ( "should run with the expected status" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2018-08-23 22:23:15 -04:00
restartCountVolumeName := "restart-count"
restartCountVolumePath := "/restart-count"
testContainer := v1 . Container {
Image : framework . BusyBoxImage ,
VolumeMounts : [ ] v1 . VolumeMount {
{
MountPath : restartCountVolumePath ,
Name : restartCountVolumeName ,
} ,
} ,
}
testVolumes := [ ] v1 . Volume {
{
Name : restartCountVolumeName ,
VolumeSource : v1 . VolumeSource {
EmptyDir : & v1 . EmptyDirVolumeSource { Medium : v1 . StorageMediumMemory } ,
} ,
} ,
}
testCases := [ ] struct {
Name string
RestartPolicy v1 . RestartPolicy
Phase v1 . PodPhase
State ContainerState
RestartCount int32
Ready bool
} {
{ "terminate-cmd-rpa" , v1 . RestartPolicyAlways , v1 . PodRunning , ContainerStateRunning , 2 , true } ,
{ "terminate-cmd-rpof" , v1 . RestartPolicyOnFailure , v1 . PodSucceeded , ContainerStateTerminated , 1 , false } ,
{ "terminate-cmd-rpn" , v1 . RestartPolicyNever , v1 . PodFailed , ContainerStateTerminated , 0 , false } ,
}
for _ , testCase := range testCases {
// It failed at the 1st run, then succeeded at 2nd run, then run forever
cmdScripts := `
f = % s
count = $ ( echo ' hello ' >> $ f ; wc - l $ f | awk { ' print $ 1 ' } )
if [ $ count - eq 1 ] ; then
exit 1
fi
if [ $ count - eq 2 ] ; then
exit 0
fi
while true ; do sleep 1 ; done
`
tmpCmd := fmt . Sprintf ( cmdScripts , path . Join ( restartCountVolumePath , "restartCount" ) )
testContainer . Name = testCase . Name
testContainer . Command = [ ] string { "sh" , "-c" , tmpCmd }
terminateContainer := ConformanceContainer {
2022-08-25 14:56:04 -04:00
PodClient : e2epod . NewPodClient ( f ) ,
2018-08-23 22:23:15 -04:00
Container : testContainer ,
RestartPolicy : testCase . RestartPolicy ,
Volumes : testVolumes ,
}
2022-12-12 04:11:10 -05:00
terminateContainer . Create ( ctx )
2022-12-11 12:51:37 -05:00
ginkgo . DeferCleanup ( framework . IgnoreNotFound ( terminateContainer . Delete ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( fmt . Sprintf ( "Container '%s': should get the expected 'RestartCount'" , testContainer . Name ) )
2022-12-12 04:11:10 -05:00
gomega . Eventually ( ctx , func ( ) ( int32 , error ) {
status , err := terminateContainer . GetStatus ( ctx )
2018-08-23 22:23:15 -04:00
return status . RestartCount , err
2019-05-14 02:10:31 -04:00
} , ContainerStatusRetryTimeout , ContainerStatusPollInterval ) . Should ( gomega . Equal ( testCase . RestartCount ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( fmt . Sprintf ( "Container '%s': should get the expected 'Phase'" , testContainer . Name ) )
2022-12-12 04:11:10 -05:00
gomega . Eventually ( ctx , terminateContainer . GetPhase , ContainerStatusRetryTimeout , ContainerStatusPollInterval ) . Should ( gomega . Equal ( testCase . Phase ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( fmt . Sprintf ( "Container '%s': should get the expected 'Ready' condition" , testContainer . Name ) )
2022-12-12 04:11:10 -05:00
isReady , err := terminateContainer . IsReady ( ctx )
2023-07-21 03:20:09 -04:00
gomega . Expect ( isReady ) . To ( gomega . Equal ( testCase . Ready ) )
2019-07-07 08:55:38 -04:00
framework . ExpectNoError ( err )
2018-08-23 22:23:15 -04:00
2022-12-12 04:11:10 -05:00
status , err := terminateContainer . GetStatus ( ctx )
2019-05-09 14:54:37 -04:00
framework . ExpectNoError ( err )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( fmt . Sprintf ( "Container '%s': should get the expected 'State'" , testContainer . Name ) )
2023-07-21 03:20:09 -04:00
gomega . Expect ( GetContainerState ( status . State ) ) . To ( gomega . Equal ( testCase . State ) )
2018-08-23 22:23:15 -04:00
2023-06-20 04:27:14 -04:00
ginkgo . By ( fmt . Sprintf ( "Container '%s': should be possible to delete" , testContainer . Name ) )
2022-12-12 04:11:10 -05:00
gomega . Expect ( terminateContainer . Delete ( ctx ) ) . To ( gomega . Succeed ( ) )
gomega . Eventually ( ctx , terminateContainer . Present , ContainerStatusRetryTimeout , ContainerStatusPollInterval ) . Should ( gomega . BeFalse ( ) )
2018-08-23 22:23:15 -04:00
}
} )
2019-02-27 02:15:04 -05:00
} )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . Context ( "on terminated container" , func ( ) {
2018-08-23 22:23:15 -04:00
rootUser := int64 ( 0 )
nonRootUser := int64 ( 10000 )
2019-07-05 08:23:04 -04:00
adminUserName := "ContainerAdministrator"
nonAdminUserName := "ContainerUser"
2018-08-23 22:23:15 -04:00
2019-02-27 02:15:04 -05:00
// Create and then terminate the container under defined PodPhase to verify if termination message matches the expected output. Lastly delete the created container.
2022-12-12 04:11:10 -05:00
matchTerminationMessage := func ( ctx context . Context , container v1 . Container , expectedPhase v1 . PodPhase , expectedMsg gomegatypes . GomegaMatcher ) {
2019-02-27 02:15:04 -05:00
container . Name = "termination-message-container"
c := ConformanceContainer {
2022-08-25 14:56:04 -04:00
PodClient : e2epod . NewPodClient ( f ) ,
2019-02-27 02:15:04 -05:00
Container : container ,
RestartPolicy : v1 . RestartPolicyNever ,
}
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( "create the container" )
2022-12-12 04:11:10 -05:00
c . Create ( ctx )
2022-12-11 12:51:37 -05:00
ginkgo . DeferCleanup ( framework . IgnoreNotFound ( c . Delete ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( fmt . Sprintf ( "wait for the container to reach %s" , expectedPhase ) )
2022-12-12 04:11:10 -05:00
gomega . Eventually ( ctx , c . GetPhase , ContainerStatusRetryTimeout , ContainerStatusPollInterval ) . Should ( gomega . Equal ( expectedPhase ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( "get the container status" )
2022-12-12 04:11:10 -05:00
status , err := c . GetStatus ( ctx )
2019-05-09 14:54:37 -04:00
framework . ExpectNoError ( err )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( "the container should be terminated" )
2023-07-21 03:20:09 -04:00
gomega . Expect ( GetContainerState ( status . State ) ) . To ( gomega . Equal ( ContainerStateTerminated ) )
2018-08-23 22:23:15 -04:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( "the termination message should be set" )
2019-09-25 22:45:07 -04:00
framework . Logf ( "Expected: %v to match Container's Termination Message: %v --" , expectedMsg , status . State . Terminated . Message )
2019-05-14 02:10:31 -04:00
gomega . Expect ( status . State . Terminated . Message ) . Should ( expectedMsg )
2019-02-27 02:15:04 -05:00
2019-05-14 02:10:31 -04:00
ginkgo . By ( "delete the container" )
2022-12-12 04:11:10 -05:00
gomega . Expect ( c . Delete ( ctx ) ) . To ( gomega . Succeed ( ) )
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
2023-06-20 04:27:14 -04:00
f . It ( "should report termination message if TerminationMessagePath is set" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-02-27 02:15:04 -05:00
container := v1 . Container {
Image : framework . BusyBoxImage ,
Command : [ ] string { "/bin/sh" , "-c" } ,
Args : [ ] string { "/bin/echo -n DONE > /dev/termination-log" } ,
TerminationMessagePath : "/dev/termination-log" ,
2019-07-05 08:23:04 -04:00
SecurityContext : & v1 . SecurityContext { } ,
}
if framework . NodeOSDistroIs ( "windows" ) {
container . SecurityContext . WindowsOptions = & v1 . WindowsSecurityContextOptions { RunAsUserName : & adminUserName }
} else {
container . SecurityContext . RunAsUser = & rootUser
2019-02-27 02:15:04 -05:00
}
2022-12-12 04:11:10 -05:00
matchTerminationMessage ( ctx , container , v1 . PodSucceeded , gomega . Equal ( "DONE" ) )
2019-02-27 02:15:04 -05:00
} )
2019-04-03 21:39:17 -04:00
/ *
Release : v1 .15
2020-03-06 15:57:01 -05:00
Testname : Container Runtime , TerminationMessagePath , non - root user and non - default path
2019-04-03 21:39:17 -04:00
Description : Create a pod with a container to run it as a non - root user with a custom TerminationMessagePath set . Pod redirects the output to the provided path successfully . When the container is terminated , the termination message MUST match the expected output logged in the provided custom path .
* /
2023-06-20 04:27:14 -04:00
framework . ConformanceIt ( "should report termination message if TerminationMessagePath is set as non-root user and at a non-default path" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-02-27 02:15:04 -05:00
container := v1 . Container {
Image : framework . BusyBoxImage ,
Command : [ ] string { "/bin/sh" , "-c" } ,
Args : [ ] string { "/bin/echo -n DONE > /dev/termination-custom-log" } ,
TerminationMessagePath : "/dev/termination-custom-log" ,
2019-07-05 08:23:04 -04:00
SecurityContext : & v1 . SecurityContext { } ,
}
if framework . NodeOSDistroIs ( "windows" ) {
container . SecurityContext . WindowsOptions = & v1 . WindowsSecurityContextOptions { RunAsUserName : & nonAdminUserName }
} else {
container . SecurityContext . RunAsUser = & nonRootUser
2019-02-27 02:15:04 -05:00
}
2022-12-12 04:11:10 -05:00
matchTerminationMessage ( ctx , container , v1 . PodSucceeded , gomega . Equal ( "DONE" ) )
2019-02-27 02:15:04 -05:00
} )
2019-03-28 09:15:17 -04:00
/ *
Release : v1 .15
2020-03-06 15:57:01 -05:00
Testname : Container Runtime , TerminationMessage , from container ' s log output of failing container
2019-03-28 09:15:17 -04:00
Description : Create a pod with an container . Container ' s output is recorded in log and container exits with an error . When container is terminated , termination message MUST match the expected output recorded from container ' s log .
* /
2023-06-20 04:27:14 -04:00
framework . ConformanceIt ( "should report termination message from log output if TerminationMessagePolicy FallbackToLogsOnError is set" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-02-27 02:15:04 -05:00
container := v1 . Container {
Image : framework . BusyBoxImage ,
Command : [ ] string { "/bin/sh" , "-c" } ,
Args : [ ] string { "/bin/echo -n DONE; /bin/false" } ,
TerminationMessagePath : "/dev/termination-log" ,
TerminationMessagePolicy : v1 . TerminationMessageFallbackToLogsOnError ,
}
2022-12-12 04:11:10 -05:00
matchTerminationMessage ( ctx , container , v1 . PodFailed , gomega . Equal ( "DONE" ) )
2019-02-27 02:15:04 -05:00
} )
2019-03-28 09:15:17 -04:00
/ *
Release : v1 .15
2020-03-06 15:57:01 -05:00
Testname : Container Runtime , TerminationMessage , from log output of succeeding container
2019-03-28 09:15:17 -04:00
Description : Create a pod with an container . Container ' s output is recorded in log and container exits successfully without an error . When container is terminated , terminationMessage MUST have no content as container succeed .
* /
2023-06-20 04:27:14 -04:00
framework . ConformanceIt ( "should report termination message as empty when pod succeeds and TerminationMessagePolicy FallbackToLogsOnError is set" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-02-27 02:15:04 -05:00
container := v1 . Container {
Image : framework . BusyBoxImage ,
Command : [ ] string { "/bin/sh" , "-c" } ,
2019-03-28 09:15:17 -04:00
Args : [ ] string { "/bin/echo -n DONE; /bin/true" } ,
2019-02-27 02:15:04 -05:00
TerminationMessagePath : "/dev/termination-log" ,
TerminationMessagePolicy : v1 . TerminationMessageFallbackToLogsOnError ,
}
2022-12-12 04:11:10 -05:00
matchTerminationMessage ( ctx , container , v1 . PodSucceeded , gomega . Equal ( "" ) )
2019-02-27 02:15:04 -05:00
} )
2019-03-28 09:15:17 -04:00
/ *
Release : v1 .15
2020-03-06 15:57:01 -05:00
Testname : Container Runtime , TerminationMessage , from file of succeeding container
2019-03-28 09:15:17 -04:00
Description : Create a pod with an container . Container ' s output is recorded in a file and the container exits successfully without an error . When container is terminated , terminationMessage MUST match with the content from file .
* /
2023-06-20 04:27:14 -04:00
framework . ConformanceIt ( "should report termination message from file when pod succeeds and TerminationMessagePolicy FallbackToLogsOnError is set" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-02-27 02:15:04 -05:00
container := v1 . Container {
Image : framework . BusyBoxImage ,
Command : [ ] string { "/bin/sh" , "-c" } ,
Args : [ ] string { "/bin/echo -n OK > /dev/termination-log; /bin/echo DONE; /bin/true" } ,
TerminationMessagePath : "/dev/termination-log" ,
TerminationMessagePolicy : v1 . TerminationMessageFallbackToLogsOnError ,
}
2022-12-12 04:11:10 -05:00
matchTerminationMessage ( ctx , container , v1 . PodSucceeded , gomega . Equal ( "OK" ) )
2019-02-27 02:15:04 -05:00
} )
2018-08-23 22:23:15 -04:00
} )
2019-05-14 02:10:31 -04:00
ginkgo . Context ( "when running a container with a new image" , func ( ) {
2019-02-27 02:15:04 -05:00
2020-06-19 16:55:18 -04:00
// Images used for ConformanceContainer are not added into NodePrePullImageList, because this test is
2019-02-27 02:15:04 -05:00
// testing image pulling, these images don't need to be prepulled. The ImagePullPolicy
2020-06-19 16:55:18 -04:00
// is v1.PullAlways, so it won't be blocked by framework image pre-pull list check.
2022-12-12 04:11:10 -05:00
imagePullTest := func ( ctx context . Context , image string , hasSecret bool , expectedPhase v1 . PodPhase , expectedPullStatus bool , windowsImage bool ) {
2019-02-26 12:19:53 -05:00
command := [ ] string { "/bin/sh" , "-c" , "while true; do sleep 1; done" }
if windowsImage {
// -t: Ping the specified host until stopped.
command = [ ] string { "ping" , "-t" , "localhost" }
}
2019-02-27 02:15:04 -05:00
container := ConformanceContainer {
2022-08-25 14:56:04 -04:00
PodClient : e2epod . NewPodClient ( f ) ,
2019-02-27 02:15:04 -05:00
Container : v1 . Container {
Name : "image-pull-test" ,
Image : image ,
2019-02-26 12:19:53 -05:00
Command : command ,
2019-02-27 02:15:04 -05:00
ImagePullPolicy : v1 . PullAlways ,
} ,
RestartPolicy : v1 . RestartPolicyNever ,
}
if hasSecret {
// The service account only has pull permission
auth := `
2018-08-23 22:23:15 -04:00
{
"auths" : {
"https://gcr.io" : {
"auth" : "X2pzb25fa2V5OnsKICAidHlwZSI6ICJzZXJ2aWNlX2FjY291bnQiLAogICJwcm9qZWN0X2lkIjogImF1dGhlbnRpY2F0ZWQtaW1hZ2UtcHVsbGluZyIsCiAgInByaXZhdGVfa2V5X2lkIjogImI5ZjJhNjY0YWE5YjIwNDg0Y2MxNTg2MDYzZmVmZGExOTIyNGFjM2IiLAogICJwcml2YXRlX2tleSI6ICItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cbk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzdTSG5LVEVFaVlMamZcbkpmQVBHbUozd3JCY2VJNTBKS0xxS21GWE5RL3REWGJRK2g5YVl4aldJTDhEeDBKZTc0bVovS01uV2dYRjVLWlNcbm9BNktuSU85Yi9SY1NlV2VpSXRSekkzL1lYVitPNkNjcmpKSXl4anFWam5mVzJpM3NhMzd0OUE5VEZkbGZycm5cbjR6UkpiOWl4eU1YNGJMdHFGR3ZCMDNOSWl0QTNzVlo1ODhrb1FBZmgzSmhhQmVnTWorWjRSYko0aGVpQlFUMDNcbnZVbzViRWFQZVQ5RE16bHdzZWFQV2dydDZOME9VRGNBRTl4bGNJek11MjUzUG4vSzgySFpydEx4akd2UkhNVXhcbng0ZjhwSnhmQ3h4QlN3Z1NORit3OWpkbXR2b0wwRmE3ZGducFJlODZWRDY2ejNZenJqNHlLRXRqc2hLZHl5VWRcbkl5cVhoN1JSQWdNQkFBRUNnZ0VBT3pzZHdaeENVVlFUeEFka2wvSTVTRFVidi9NazRwaWZxYjJEa2FnbmhFcG9cbjFJajJsNGlWMTByOS9uenJnY2p5VlBBd3pZWk1JeDFBZVF0RDdoUzRHWmFweXZKWUc3NkZpWFpQUm9DVlB6b3VcbmZyOGRDaWFwbDV0enJDOWx2QXNHd29DTTdJWVRjZmNWdDdjRTEyRDNRS3NGNlo3QjJ6ZmdLS251WVBmK0NFNlRcbmNNMHkwaCtYRS9kMERvSERoVy96YU1yWEhqOFRvd2V1eXRrYmJzNGYvOUZqOVBuU2dET1lQd2xhbFZUcitGUWFcbkpSd1ZqVmxYcEZBUW14M0Jyd25rWnQzQ2lXV2lGM2QrSGk5RXRVYnRWclcxYjZnK1JRT0licWFtcis4YlJuZFhcbjZWZ3FCQWtKWjhSVnlkeFVQMGQxMUdqdU9QRHhCbkhCbmM0UW9rSXJFUUtCZ1FEMUNlaWN1ZGhXdGc0K2dTeGJcbnplanh0VjFONDFtZHVjQnpvMmp5b1dHbzNQVDh3ckJPL3lRRTM0cU9WSi9pZCs4SThoWjRvSWh1K0pBMDBzNmdcblRuSXErdi9kL1RFalk4MW5rWmlDa21SUFdiWHhhWXR4UjIxS1BYckxOTlFKS2ttOHRkeVh5UHFsOE1veUdmQ1dcbjJ2aVBKS05iNkhabnY5Q3lqZEo5ZzJMRG5RS0JnUUREcVN2eURtaGViOTIzSW96NGxlZ01SK205Z2xYVWdTS2dcbkVzZlllbVJmbU5XQitDN3ZhSXlVUm1ZNU55TXhmQlZXc3dXRldLYXhjK0krYnFzZmx6elZZdFpwMThNR2pzTURcbmZlZWZBWDZCWk1zVXQ3Qmw3WjlWSjg1bnRFZHFBQ0xwWitaLzN0SVJWdWdDV1pRMWhrbmxHa0dUMDI0SkVFKytcbk55SDFnM2QzUlFLQmdRQ1J2MXdKWkkwbVBsRklva0tGTkh1YTBUcDNLb1JTU1hzTURTVk9NK2xIckcxWHJtRjZcbkMwNGNTKzQ0N0dMUkxHOFVUaEpKbTRxckh0Ti9aK2dZOTYvMm1xYjRIakpORDM3TVhKQnZFYTN5ZUxTOHEvK1JcbjJGOU1LamRRaU5LWnhQcG84VzhOSlREWTVOa1BaZGh4a2pzSHdVNGRTNjZwMVRESUU0MGd0TFpaRFFLQmdGaldcbktyblFpTnEzOS9iNm5QOFJNVGJDUUFKbmR3anhTUU5kQTVmcW1rQTlhRk9HbCtqamsxQ1BWa0tNSWxLSmdEYkpcbk9heDl2OUc2Ui9NSTFIR1hmV3QxWU56VnRocjRIdHNyQTB0U3BsbWhwZ05XRTZWejZuQURqdGZQSnMyZUdqdlhcbmpQUnArdjhjY21MK3dTZzhQTGprM3ZsN2VlNXJsWWxNQndNdUdjUHhBb0dBZWRueGJXMVJMbVZubEFpSEx1L0xcbmxtZkF3RFdtRWlJMFVnK1BMbm9Pdk81dFE1ZDRXMS94RU44bFA0cWtzcGtmZk1Rbk5oNFNZR0VlQlQzMlpxQ1RcbkpSZ2YwWGpveXZ2dXA5eFhqTWtYcnBZL3ljMXpmcVRaQzBNTzkvMVVjMWJSR2RaMmR5M2xSNU5XYXA3T1h5Zk9cblBQcE5Gb1BUWGd2M3FDcW5sTEhyR3pNPVxuLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVxuIiwKICAiY2xpZW50X2VtYWlsIjogImltYWdlLXB1bGxpbmdAYXV0aGVudGljYXRlZC1pbWFnZS1wdWxsaW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwKICAiY2xpZW50X2lkIjogIjExMzc5NzkxNDUzMDA3MzI3ODcxMiIsCiAgImF1dGhfdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi9hdXRoIiwKICAidG9rZW5fdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsCiAgImF1dGhfcHJvdmlkZXJfeDUwOV9jZXJ0X3VybCI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9vYXV0aDIvdjEvY2VydHMiLAogICJjbGllbnRfeDUwOV9jZXJ0X3VybCI6ICJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9yb2JvdC92MS9tZXRhZGF0YS94NTA5L2ltYWdlLXB1bGxpbmclNDBhdXRoZW50aWNhdGVkLWltYWdlLXB1bGxpbmcuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iCn0=" ,
"email" : "image-pulling@authenticated-image-pulling.iam.gserviceaccount.com"
}
}
} `
2020-02-22 00:22:44 -05:00
// we might be told to use a different docker config JSON.
if framework . TestContext . DockerConfigFile != "" {
2021-10-29 18:41:02 -04:00
contents , err := os . ReadFile ( framework . TestContext . DockerConfigFile )
2020-02-22 00:22:44 -05:00
framework . ExpectNoError ( err )
auth = string ( contents )
}
2019-02-27 02:15:04 -05:00
secret := & v1 . Secret {
Data : map [ string ] [ ] byte { v1 . DockerConfigJsonKey : [ ] byte ( auth ) } ,
Type : v1 . SecretTypeDockerConfigJson ,
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
secret . Name = "image-pull-secret-" + string ( uuid . NewUUID ( ) )
2019-05-14 02:10:31 -04:00
ginkgo . By ( "create image pull secret" )
2022-12-12 04:11:10 -05:00
_ , err := f . ClientSet . CoreV1 ( ) . Secrets ( f . Namespace . Name ) . Create ( ctx , secret , metav1 . CreateOptions { } )
2019-05-09 14:54:37 -04:00
framework . ExpectNoError ( err )
2022-12-11 12:51:37 -05:00
ginkgo . DeferCleanup ( f . ClientSet . CoreV1 ( ) . Secrets ( f . Namespace . Name ) . Delete , secret . Name , metav1 . DeleteOptions { } )
2019-02-27 02:15:04 -05:00
container . ImagePullSecrets = [ ] string { secret . Name }
}
// checkContainerStatus checks whether the container status matches expectation.
2022-12-12 04:11:10 -05:00
checkContainerStatus := func ( ctx context . Context ) error {
status , err := container . GetStatus ( ctx )
2019-02-27 02:15:04 -05:00
if err != nil {
2023-01-31 02:22:39 -05:00
return fmt . Errorf ( "failed to get container status: %w" , err )
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
// We need to check container state first. The default pod status is pending, If we check pod phase first,
// and the expected pod phase is Pending, the container status may not even show up when we check it.
// Check container state
if ! expectedPullStatus {
if status . State . Running == nil {
return fmt . Errorf ( "expected container state: Running, got: %q" ,
GetContainerState ( status . State ) )
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
}
if expectedPullStatus {
if status . State . Waiting == nil {
return fmt . Errorf ( "expected container state: Waiting, got: %q" ,
GetContainerState ( status . State ) )
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
reason := status . State . Waiting . Reason
if reason != images . ErrImagePull . Error ( ) &&
reason != images . ErrImagePullBackOff . Error ( ) {
return fmt . Errorf ( "unexpected waiting reason: %q" , reason )
2018-08-23 22:23:15 -04:00
}
}
2019-02-27 02:15:04 -05:00
// Check pod phase
2022-12-12 04:11:10 -05:00
phase , err := container . GetPhase ( ctx )
2019-02-27 02:15:04 -05:00
if err != nil {
2023-01-31 02:22:39 -05:00
return fmt . Errorf ( "failed to get pod phase: %w" , err )
2019-02-27 02:15:04 -05:00
}
if phase != expectedPhase {
return fmt . Errorf ( "expected pod phase: %q, got: %q" , expectedPhase , phase )
}
return nil
}
// The image registry is not stable, which sometimes causes the test to fail. Add retry mechanism to make this less flaky.
const flakeRetry = 3
for i := 1 ; i <= flakeRetry ; i ++ {
var err error
2019-05-14 02:10:31 -04:00
ginkgo . By ( "create the container" )
2022-12-12 04:11:10 -05:00
container . Create ( ctx )
2019-05-14 02:10:31 -04:00
ginkgo . By ( "check the container status" )
2019-02-27 02:15:04 -05:00
for start := time . Now ( ) ; time . Since ( start ) < ContainerStatusRetryTimeout ; time . Sleep ( ContainerStatusPollInterval ) {
2022-12-12 04:11:10 -05:00
if err = checkContainerStatus ( ctx ) ; err == nil {
2018-08-23 22:23:15 -04:00
break
}
}
2019-05-14 02:10:31 -04:00
ginkgo . By ( "delete the container" )
2022-12-12 04:11:10 -05:00
_ = container . Delete ( ctx )
2019-02-27 02:15:04 -05:00
if err == nil {
break
}
if i < flakeRetry {
2019-09-25 22:45:07 -04:00
framework . Logf ( "No.%d attempt failed: %v, retrying..." , i , err )
2019-02-27 02:15:04 -05:00
} else {
2019-09-25 22:45:07 -04:00
framework . Failf ( "All %d attempts failed: %v" , flakeRetry , err )
2019-02-27 02:15:04 -05:00
}
}
2018-08-23 22:23:15 -04:00
}
2019-02-27 02:15:04 -05:00
2023-06-20 04:27:14 -04:00
f . It ( "should not be able to pull image from invalid registry" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-05-15 02:09:47 -04:00
image := imageutils . GetE2EImage ( imageutils . InvalidRegistryImage )
2022-12-12 04:11:10 -05:00
imagePullTest ( ctx , image , false , v1 . PodPending , true , false )
2019-02-27 02:15:04 -05:00
} )
2023-06-20 04:27:14 -04:00
f . It ( "should be able to pull image" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-09-16 08:52:33 -04:00
// NOTE(claudiub): The agnhost image is supposed to work on both Linux and Windows.
image := imageutils . GetE2EImage ( imageutils . Agnhost )
2022-12-12 04:11:10 -05:00
imagePullTest ( ctx , image , false , v1 . PodRunning , false , false )
2019-02-27 02:15:04 -05:00
} )
2023-06-20 04:27:14 -04:00
f . It ( "should not be able to pull from private registry without secret" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-05-15 02:09:47 -04:00
image := imageutils . GetE2EImage ( imageutils . AuthenticatedAlpine )
2022-12-12 04:11:10 -05:00
imagePullTest ( ctx , image , false , v1 . PodPending , true , false )
2019-02-27 02:15:04 -05:00
} )
2023-06-20 04:27:14 -04:00
f . It ( "should be able to pull from private registry with secret" , f . WithNodeConformance ( ) , func ( ctx context . Context ) {
2019-04-08 19:14:40 -04:00
image := imageutils . GetE2EImage ( imageutils . AuthenticatedAlpine )
isWindows := false
if framework . NodeOSDistroIs ( "windows" ) {
image = imageutils . GetE2EImage ( imageutils . AuthenticatedWindowsNanoServer )
isWindows = true
}
2022-12-12 04:11:10 -05:00
imagePullTest ( ctx , image , true , v1 . PodRunning , false , isWindows )
2019-02-27 14:20:24 -05:00
} )
2018-08-23 22:23:15 -04:00
} )
} )
} )