k8s.io/kubernetes@v1.29.3/test/e2e_node/log_path_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package e2enode
    18  
    19  import (
    20  	"context"
    21  
    22  	v1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/util/uuid"
    25  	"k8s.io/kubernetes/pkg/kubelet"
    26  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    27  	"k8s.io/kubernetes/test/e2e/framework"
    28  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    29  	admissionapi "k8s.io/pod-security-admission/api"
    30  
    31  	"github.com/onsi/ginkgo/v2"
    32  )
    33  
    34  const (
    35  	logString        = "This is the expected log content of this node e2e test"
    36  	logContainerName = "logger"
    37  )
    38  
    39  var _ = SIGDescribe("ContainerLogPath", framework.WithNodeConformance(), func() {
    40  	f := framework.NewDefaultFramework("kubelet-container-log-path")
    41  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    42  	var podClient *e2epod.PodClient
    43  
    44  	ginkgo.Describe("Pod with a container", func() {
    45  		ginkgo.Context("printed log to stdout", func() {
    46  			makeLogPod := func(podName, log string) *v1.Pod {
    47  				return &v1.Pod{
    48  					ObjectMeta: metav1.ObjectMeta{
    49  						Name: podName,
    50  					},
    51  					Spec: v1.PodSpec{
    52  						// this pod is expected to exit successfully
    53  						RestartPolicy: v1.RestartPolicyNever,
    54  						Containers: []v1.Container{
    55  							{
    56  								Image:   busyboxImage,
    57  								Name:    logContainerName,
    58  								Command: []string{"sh", "-c", "echo " + log},
    59  							},
    60  						},
    61  					},
    62  				}
    63  			}
    64  
    65  			makeLogCheckPod := func(podName, log, expectedLogPath string) *v1.Pod {
    66  				hostPathType := new(v1.HostPathType)
    67  				*hostPathType = v1.HostPathType(string(v1.HostPathFileOrCreate))
    68  
    69  				return &v1.Pod{
    70  					ObjectMeta: metav1.ObjectMeta{
    71  						Name: podName,
    72  					},
    73  					Spec: v1.PodSpec{
    74  						// this pod is expected to exit successfully
    75  						RestartPolicy: v1.RestartPolicyNever,
    76  						Containers: []v1.Container{
    77  							{
    78  								Image: busyboxImage,
    79  								SecurityContext: &v1.SecurityContext{
    80  									SELinuxOptions: &v1.SELinuxOptions{
    81  										Type: "container_logreader_t",
    82  									},
    83  								},
    84  								Name: podName,
    85  								// If we find expected log file and contains right content, exit 0
    86  								// else, keep checking until test timeout
    87  								Command: []string{"sh", "-c", "while true; do if [ -e " + expectedLogPath + " ] && grep -q " + log + " " + expectedLogPath + "; then exit 0; fi; sleep 1; done"},
    88  								VolumeMounts: []v1.VolumeMount{
    89  									{
    90  										Name: "logdir",
    91  										// mount ContainerLogsDir to the same path in container
    92  										MountPath: expectedLogPath,
    93  										ReadOnly:  true,
    94  									},
    95  								},
    96  							},
    97  						},
    98  						Volumes: []v1.Volume{
    99  							{
   100  								Name: "logdir",
   101  								VolumeSource: v1.VolumeSource{
   102  									HostPath: &v1.HostPathVolumeSource{
   103  										Path: expectedLogPath,
   104  										Type: hostPathType,
   105  									},
   106  								},
   107  							},
   108  						},
   109  					},
   110  				}
   111  			}
   112  
   113  			createAndWaitPod := func(ctx context.Context, pod *v1.Pod) error {
   114  				podClient.Create(ctx, pod)
   115  				return e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)
   116  			}
   117  
   118  			var logPodName string
   119  			ginkgo.BeforeEach(func(ctx context.Context) {
   120  				podClient = e2epod.NewPodClient(f)
   121  				logPodName = "log-pod-" + string(uuid.NewUUID())
   122  				err := createAndWaitPod(ctx, makeLogPod(logPodName, logString))
   123  				framework.ExpectNoError(err, "Failed waiting for pod: %s to enter success state", logPodName)
   124  			})
   125  			ginkgo.It("should print log to correct log path", func(ctx context.Context) {
   126  
   127  				logDir := kubelet.ContainerLogsDir
   128  
   129  				// get containerID from created Pod
   130  				createdLogPod, err := podClient.Get(ctx, logPodName, metav1.GetOptions{})
   131  				logContainerID := kubecontainer.ParseContainerID(createdLogPod.Status.ContainerStatuses[0].ContainerID)
   132  				framework.ExpectNoError(err, "Failed to get pod: %s", logPodName)
   133  
   134  				// build log file path
   135  				expectedlogFile := logDir + "/" + logPodName + "_" + f.Namespace.Name + "_" + logContainerName + "-" + logContainerID.ID + ".log"
   136  
   137  				logCheckPodName := "log-check-" + string(uuid.NewUUID())
   138  				err = createAndWaitPod(ctx, makeLogCheckPod(logCheckPodName, logString, expectedlogFile))
   139  				framework.ExpectNoError(err, "Failed waiting for pod: %s to enter success state", logCheckPodName)
   140  			})
   141  
   142  			ginkgo.It("should print log to correct cri log path", func(ctx context.Context) {
   143  
   144  				logCRIDir := "/var/log/pods"
   145  
   146  				// get podID from created Pod
   147  				createdLogPod, err := podClient.Get(ctx, logPodName, metav1.GetOptions{})
   148  				framework.ExpectNoError(err, "Failed to get pod: %s", logPodName)
   149  				podNs := createdLogPod.Namespace
   150  				podName := createdLogPod.Name
   151  				podID := string(createdLogPod.UID)
   152  
   153  				// build log cri file path
   154  				expectedCRILogFile := logCRIDir + "/" + podNs + "_" + podName + "_" + podID + "/" + logContainerName + "/0.log"
   155  
   156  				logCRICheckPodName := "log-cri-check-" + string(uuid.NewUUID())
   157  				err = createAndWaitPod(ctx, makeLogCheckPod(logCRICheckPodName, logString, expectedCRILogFile))
   158  				framework.ExpectNoError(err, "Failed waiting for pod: %s to enter success state", logCRICheckPodName)
   159  			})
   160  		})
   161  	})
   162  })