2021-08-12 17:13:11 -04:00
//go:build cgo && linux
2017-03-14 12:45:05 -04:00
// +build cgo,linux
2016-06-01 15:57:32 -04:00
/ *
2016-06-02 20:25:58 -04:00
Copyright 2016 The Kubernetes Authors .
2016-06-01 15:57:32 -04:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2019-11-06 22:59:05 -05:00
package e2enode
2016-06-01 15:57:32 -04:00
import (
2020-01-27 21:19:44 -05:00
"context"
2016-06-01 15:57:32 -04:00
"fmt"
2017-02-18 01:54:52 -05:00
"os"
"path"
2016-06-01 15:57:32 -04:00
"time"
2022-03-29 02:12:12 -04:00
"github.com/onsi/ginkgo/v2"
2020-10-30 10:32:10 -04:00
"github.com/onsi/gomega"
2020-01-27 21:19:44 -05:00
v1 "k8s.io/api/core/v1"
2017-01-11 09:09:48 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-01-19 09:50:16 -05:00
"k8s.io/apimachinery/pkg/fields"
2017-01-11 09:09:48 -05:00
"k8s.io/apimachinery/pkg/labels"
2017-01-16 15:13:59 -05:00
"k8s.io/apimachinery/pkg/types"
2017-01-24 09:35:22 -05:00
"k8s.io/apimachinery/pkg/util/uuid"
2017-06-23 16:56:37 -04:00
clientset "k8s.io/client-go/kubernetes"
coreclientset "k8s.io/client-go/kubernetes/typed/core/v1"
2022-04-04 08:00:06 -04:00
admissionapi "k8s.io/pod-security-admission/api"
2020-10-30 10:32:10 -04:00
2018-12-05 18:07:52 -05:00
"k8s.io/kubernetes/pkg/kubelet/util"
2016-06-01 15:57:32 -04:00
"k8s.io/kubernetes/test/e2e/framework"
2019-05-07 20:09:50 -04:00
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
2019-02-26 14:05:32 -05:00
testutils "k8s.io/kubernetes/test/utils"
2016-06-01 15:57:32 -04:00
)
2021-02-22 13:53:33 -05:00
var _ = SIGDescribe ( "NodeProblemDetector [NodeFeature:NodeProblemDetector] [Serial]" , func ( ) {
2016-06-01 15:57:32 -04:00
const (
pollInterval = 1 * time . Second
pollConsistent = 5 * time . Second
pollTimeout = 1 * time . Minute
)
f := framework . NewDefaultFramework ( "node-problem-detector" )
2022-04-04 08:00:06 -04:00
f . NamespacePodSecurityEnforceLevel = admissionapi . LevelPrivileged
2016-10-18 09:00:38 -04:00
var c clientset . Interface
2016-06-01 15:57:32 -04:00
var uid string
var ns , name , configName , eventNamespace string
2017-02-06 15:12:31 -05:00
var bootTime , nodeTime time . Time
2019-02-07 18:41:16 -05:00
var image string
2019-07-28 00:49:36 -04:00
ginkgo . BeforeEach ( func ( ) {
2016-10-18 09:00:38 -04:00
c = f . ClientSet
2016-06-01 15:57:32 -04:00
ns = f . Namespace . Name
2016-07-26 11:13:18 -04:00
uid = string ( uuid . NewUUID ( ) )
2016-06-01 15:57:32 -04:00
name = "node-problem-detector-" + uid
configName = "node-problem-detector-config-" + uid
// There is no namespace for Node, event recorder will set default namespace for node events.
2017-01-21 22:36:02 -05:00
eventNamespace = metav1 . NamespaceDefault
2019-02-07 18:41:16 -05:00
image = getNodeProblemDetectorImage ( )
2019-07-28 00:49:36 -04:00
ginkgo . By ( fmt . Sprintf ( "Using node-problem-detector image: %s" , image ) )
2016-06-01 15:57:32 -04:00
} )
2017-02-06 15:12:31 -05:00
// Test system log monitor. We may add other tests if we have more problem daemons in the future.
2021-02-22 13:53:33 -05:00
ginkgo . Describe ( "SystemLogMonitor" , func ( ) {
2016-06-01 15:57:32 -04:00
const (
2017-02-18 01:54:52 -05:00
// Use test condition to avoid changing the real node condition in use.
2018-02-09 01:53:53 -05:00
// TODO(random-liu): Now node condition could be arbitrary string, consider whether we need to
2016-06-01 15:57:32 -04:00
// add TestCondition when switching to predefined condition list.
2017-02-18 01:54:52 -05:00
condition = v1 . NodeConditionType ( "TestCondition" )
2016-11-03 00:21:11 -04:00
// File paths used in the test.
2020-11-05 07:35:02 -05:00
logFile = "/log/test.log"
configFile = "/config/testconfig.json"
kubeConfigFile = "/config/kubeconfig"
etcLocaltime = "/etc/localtime"
2016-11-03 00:21:11 -04:00
// Volumes used in the test.
configVolume = "config"
logVolume = "log"
localtimeVolume = "localtime"
// Reasons and messages used in the test.
2016-06-01 15:57:32 -04:00
defaultReason = "Default"
defaultMessage = "default message"
tempReason = "Temporary"
tempMessage = "temporary error"
2017-02-06 15:12:31 -05:00
permReason1 = "Permanent1"
permMessage1 = "permanent error 1"
permReason2 = "Permanent2"
permMessage2 = "permanent error 2"
2016-06-01 15:57:32 -04:00
)
2017-03-20 17:18:18 -04:00
var source , config , hostLogFile string
2017-02-06 15:12:31 -05:00
var lookback time . Duration
2017-01-21 22:36:02 -05:00
var eventListOptions metav1 . ListOptions
2016-06-01 15:57:32 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . BeforeEach ( func ( ) {
ginkgo . By ( "Calculate Lookback duration" )
2017-02-18 01:54:52 -05:00
var err error
2018-12-05 18:07:52 -05:00
nodeTime = time . Now ( )
bootTime , err = util . GetBootTime ( )
2019-12-04 22:01:32 -05:00
framework . ExpectNoError ( err )
2018-12-05 18:07:52 -05:00
2017-02-06 15:12:31 -05:00
// Set lookback duration longer than node up time.
// Assume the test won't take more than 1 hour, in fact it usually only takes 90 seconds.
lookback = nodeTime . Sub ( bootTime ) + time . Hour
2017-02-18 01:54:52 -05:00
// Randomize the source name
2016-06-01 15:57:32 -04:00
source = "kernel-monitor-" + uid
config = `
{
2017-02-06 15:12:31 -05:00
"plugin" : "filelog" ,
"pluginConfig" : {
"timestamp" : "^.{15}" ,
"message" : "kernel: \\[.*\\] (.*)" ,
"timestampFormat" : "` + time.Stamp + `"
} ,
2017-02-18 01:54:52 -05:00
"logPath" : "` + logFile + `" ,
2016-11-03 00:21:11 -04:00
"lookback" : "` + lookback.String() + `" ,
2016-06-01 15:57:32 -04:00
"bufferSize" : 10 ,
"source" : "` + source + `" ,
"conditions" : [
{
"type" : "` + string(condition) + `" ,
"reason" : "` + defaultReason + `" ,
"message" : "` + defaultMessage + `"
}
] ,
"rules" : [
{
"type" : "temporary" ,
"reason" : "` + tempReason + `" ,
"pattern" : "` + tempMessage + `"
} ,
{
"type" : "permanent" ,
"condition" : "` + string(condition) + `" ,
2017-02-06 15:12:31 -05:00
"reason" : "` + permReason1 + `" ,
"pattern" : "` + permMessage1 + " . * " + `"
} ,
{
"type" : "permanent" ,
"condition" : "` + string(condition) + `" ,
"reason" : "` + permReason2 + `" ,
"pattern" : "` + permMessage2 + " . * " + `"
2016-06-01 15:57:32 -04:00
}
]
} `
2020-10-30 10:32:10 -04:00
2020-11-05 07:35:02 -05:00
// This token is known to apiserver and its group is `system:masters`.
// See also the function `generateTokenFile` in `test/e2e_node/services/apiserver.go`.
kubeConfig := fmt . Sprintf ( `
apiVersion : v1
kind : Config
users :
- name : node - problem - detector
user :
token : % s
clusters :
- cluster :
server : % s
insecure - skip - tls - verify : true
name : local
contexts :
- context :
cluster : local
user : node - problem - detector
name : local - context
current - context : local - context
` , framework . TestContext . BearerToken , framework . TestContext . Host )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Generate event list options" )
2016-06-01 15:57:32 -04:00
selector := fields . Set {
"involvedObject.kind" : "Node" ,
2017-02-18 01:54:52 -05:00
"involvedObject.name" : framework . TestContext . NodeName ,
2017-01-21 22:36:02 -05:00
"involvedObject.namespace" : metav1 . NamespaceAll ,
2016-06-01 15:57:32 -04:00
"source" : source ,
2016-11-18 15:55:17 -05:00
} . AsSelector ( ) . String ( )
2017-01-21 22:36:02 -05:00
eventListOptions = metav1 . ListOptions { FieldSelector : selector }
2020-10-30 10:32:10 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Create config map for the node problem detector" )
2020-02-07 21:16:47 -05:00
_ , err = c . CoreV1 ( ) . ConfigMaps ( ns ) . Create ( context . TODO ( ) , & v1 . ConfigMap {
2017-02-18 01:54:52 -05:00
ObjectMeta : metav1 . ObjectMeta { Name : configName } ,
2020-11-05 07:35:02 -05:00
Data : map [ string ] string {
path . Base ( configFile ) : config ,
path . Base ( kubeConfigFile ) : kubeConfig ,
2020-10-30 10:32:10 -04:00
} ,
} , metav1 . CreateOptions { } )
framework . ExpectNoError ( err )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Create the node problem detector" )
2017-06-18 05:51:10 -04:00
hostPathType := new ( v1 . HostPathType )
2020-10-30 10:32:10 -04:00
* hostPathType = v1 . HostPathFileOrCreate
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
pod := e2epod . NewPodClient ( f ) . CreateSync ( & v1 . Pod {
2017-01-16 22:38:19 -05:00
ObjectMeta : metav1 . ObjectMeta {
2016-06-01 15:57:32 -04:00
Name : name ,
} ,
2016-11-18 15:55:17 -05:00
Spec : v1 . PodSpec {
2020-10-30 10:32:10 -04:00
HostNetwork : true ,
SecurityContext : & v1 . PodSecurityContext { } ,
ServiceAccountName : name ,
2016-11-18 15:55:17 -05:00
Volumes : [ ] v1 . Volume {
2016-06-01 15:57:32 -04:00
{
Name : configVolume ,
2016-11-18 15:55:17 -05:00
VolumeSource : v1 . VolumeSource {
ConfigMap : & v1 . ConfigMapVolumeSource {
LocalObjectReference : v1 . LocalObjectReference { Name : configName } ,
2016-06-01 15:57:32 -04:00
} ,
} ,
} ,
{
Name : logVolume ,
2016-11-18 15:55:17 -05:00
VolumeSource : v1 . VolumeSource {
2017-03-20 17:18:18 -04:00
EmptyDir : & v1 . EmptyDirVolumeSource { } ,
2016-06-01 15:57:32 -04:00
} ,
} ,
2016-11-03 00:21:11 -04:00
{
Name : localtimeVolume ,
2016-11-18 15:55:17 -05:00
VolumeSource : v1 . VolumeSource {
2017-06-18 05:51:10 -04:00
HostPath : & v1 . HostPathVolumeSource {
Path : etcLocaltime ,
Type : hostPathType ,
} ,
2016-11-03 00:21:11 -04:00
} ,
} ,
2016-06-01 15:57:32 -04:00
} ,
2020-11-09 13:58:09 -05:00
InitContainers : [ ] v1 . Container {
{
Name : "init-log-file" ,
Image : "debian" ,
Command : [ ] string { "/bin/sh" } ,
Args : [ ] string {
"-c" ,
fmt . Sprintf ( "touch %s" , logFile ) ,
} ,
VolumeMounts : [ ] v1 . VolumeMount {
{
Name : logVolume ,
MountPath : path . Dir ( logFile ) ,
} ,
{
Name : localtimeVolume ,
MountPath : etcLocaltime ,
} ,
} ,
} ,
} ,
2016-11-18 15:55:17 -05:00
Containers : [ ] v1 . Container {
2016-06-01 15:57:32 -04:00
{
2017-02-18 01:54:52 -05:00
Name : name ,
Image : image ,
2020-11-09 13:58:09 -05:00
Command : [ ] string { "/node-problem-detector" } ,
Args : [ ] string {
"--logtostderr" ,
fmt . Sprintf ( "--system-log-monitors=%s" , configFile ) ,
2020-11-05 07:35:02 -05:00
// `ServiceAccount` admission controller is disabled in node e2e tests, so we could not use
// inClusterConfig here.
fmt . Sprintf ( "--apiserver-override=%s?inClusterConfig=false&auth=%s" , framework . TestContext . Host , kubeConfigFile ) ,
2020-11-09 13:58:09 -05:00
} ,
2016-11-18 15:55:17 -05:00
Env : [ ] v1 . EnvVar {
2016-11-03 00:21:11 -04:00
{
Name : "NODE_NAME" ,
2016-11-18 15:55:17 -05:00
ValueFrom : & v1 . EnvVarSource {
FieldRef : & v1 . ObjectFieldSelector {
2016-11-03 00:21:11 -04:00
APIVersion : "v1" ,
FieldPath : "spec.nodeName" ,
} ,
} ,
} ,
} ,
2016-11-18 15:55:17 -05:00
VolumeMounts : [ ] v1 . VolumeMount {
2016-06-01 15:57:32 -04:00
{
Name : logVolume ,
2017-02-18 01:54:52 -05:00
MountPath : path . Dir ( logFile ) ,
2016-06-01 15:57:32 -04:00
} ,
2016-11-03 00:21:11 -04:00
{
Name : localtimeVolume ,
MountPath : etcLocaltime ,
} ,
2016-06-01 15:57:32 -04:00
{
Name : configVolume ,
2017-02-18 01:54:52 -05:00
MountPath : path . Dir ( configFile ) ,
2016-06-01 15:57:32 -04:00
} ,
} ,
} ,
} ,
} ,
} )
2017-03-20 17:18:18 -04:00
// TODO: remove hardcoded kubelet volume directory path
// framework.TestContext.KubeVolumeDir is currently not populated for node e2e
hostLogFile = "/var/lib/kubelet/pods/" + string ( pod . UID ) + "/volumes/kubernetes.io~empty-dir" + logFile
2016-06-01 15:57:32 -04:00
} )
2019-07-28 00:49:36 -04:00
ginkgo . It ( "should generate node condition and events for corresponding errors" , func ( ) {
2016-11-03 00:21:11 -04:00
for _ , test := range [ ] struct {
description string
timestamp time . Time
message string
messageNum int
2019-02-07 18:41:16 -05:00
tempEvents int // Events for temp errors
totalEvents int // Events for both temp errors and condition changes
2016-11-03 00:21:11 -04:00
conditionReason string
conditionMessage string
2016-11-18 15:55:17 -05:00
conditionType v1 . ConditionStatus
2016-11-03 00:21:11 -04:00
} {
{
description : "should generate default node condition" ,
conditionReason : defaultReason ,
conditionMessage : defaultMessage ,
2016-11-18 15:55:17 -05:00
conditionType : v1 . ConditionFalse ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should not generate events for too old log" ,
2017-02-06 15:12:31 -05:00
timestamp : bootTime . Add ( - 1 * time . Minute ) ,
2016-11-03 00:21:11 -04:00
message : tempMessage ,
messageNum : 3 ,
conditionReason : defaultReason ,
conditionMessage : defaultMessage ,
2016-11-18 15:55:17 -05:00
conditionType : v1 . ConditionFalse ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should not change node condition for too old log" ,
2017-02-06 15:12:31 -05:00
timestamp : bootTime . Add ( - 1 * time . Minute ) ,
message : permMessage1 ,
2016-11-03 00:21:11 -04:00
messageNum : 1 ,
conditionReason : defaultReason ,
conditionMessage : defaultMessage ,
2016-11-18 15:55:17 -05:00
conditionType : v1 . ConditionFalse ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should generate event for old log within lookback duration" ,
2017-02-06 15:12:31 -05:00
timestamp : nodeTime ,
2016-11-03 00:21:11 -04:00
message : tempMessage ,
messageNum : 3 ,
2019-02-07 18:41:16 -05:00
tempEvents : 3 ,
totalEvents : 3 ,
2016-11-03 00:21:11 -04:00
conditionReason : defaultReason ,
conditionMessage : defaultMessage ,
2016-11-18 15:55:17 -05:00
conditionType : v1 . ConditionFalse ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should change node condition for old log within lookback duration" ,
timestamp : nodeTime ,
2017-02-06 15:12:31 -05:00
message : permMessage1 ,
2016-11-03 00:21:11 -04:00
messageNum : 1 ,
2019-02-07 18:41:16 -05:00
tempEvents : 3 , // event number for temp errors should not change
totalEvents : 4 , // add 1 event for condition change
2017-02-06 15:12:31 -05:00
conditionReason : permReason1 ,
conditionMessage : permMessage1 ,
conditionType : v1 . ConditionTrue ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should generate event for new log" ,
timestamp : nodeTime . Add ( 5 * time . Minute ) ,
message : tempMessage ,
messageNum : 3 ,
2019-02-07 18:41:16 -05:00
tempEvents : 6 , // add 3 events for temp errors
totalEvents : 7 , // add 3 events for temp errors
2017-02-06 15:12:31 -05:00
conditionReason : permReason1 ,
conditionMessage : permMessage1 ,
conditionType : v1 . ConditionTrue ,
} ,
{
description : "should not update node condition with the same reason" ,
timestamp : nodeTime . Add ( 5 * time . Minute ) ,
message : permMessage1 + "different message" ,
messageNum : 1 ,
2019-02-07 18:41:16 -05:00
tempEvents : 6 , // event number should not change
totalEvents : 7 , // event number should not change
2017-02-06 15:12:31 -05:00
conditionReason : permReason1 ,
conditionMessage : permMessage1 ,
conditionType : v1 . ConditionTrue ,
2016-11-03 00:21:11 -04:00
} ,
{
description : "should change node condition for new log" ,
timestamp : nodeTime . Add ( 5 * time . Minute ) ,
2017-02-06 15:12:31 -05:00
message : permMessage2 ,
2016-11-03 00:21:11 -04:00
messageNum : 1 ,
2019-02-07 18:41:16 -05:00
tempEvents : 6 , // event number for temp errors should not change
totalEvents : 8 , // add 1 event for condition change
2017-02-06 15:12:31 -05:00
conditionReason : permReason2 ,
conditionMessage : permMessage2 ,
2016-11-18 15:55:17 -05:00
conditionType : v1 . ConditionTrue ,
2016-11-03 00:21:11 -04:00
} ,
} {
2019-07-28 00:49:36 -04:00
ginkgo . By ( test . description )
2016-11-03 00:21:11 -04:00
if test . messageNum > 0 {
2019-07-28 00:49:36 -04:00
ginkgo . By ( fmt . Sprintf ( "Inject %d logs: %q" , test . messageNum , test . message ) )
2017-03-20 17:18:18 -04:00
err := injectLog ( hostLogFile , test . timestamp , test . message , test . messageNum )
2019-06-08 13:44:08 -04:00
framework . ExpectNoError ( err )
2016-11-03 00:21:11 -04:00
}
2019-07-28 00:49:36 -04:00
ginkgo . By ( fmt . Sprintf ( "Wait for %d temp events generated" , test . tempEvents ) )
gomega . Eventually ( func ( ) error {
2019-02-07 18:41:16 -05:00
return verifyEvents ( c . CoreV1 ( ) . Events ( eventNamespace ) , eventListOptions , test . tempEvents , tempReason , tempMessage )
2019-07-28 00:49:36 -04:00
} , pollTimeout , pollInterval ) . Should ( gomega . Succeed ( ) )
ginkgo . By ( fmt . Sprintf ( "Wait for %d total events generated" , test . totalEvents ) )
gomega . Eventually ( func ( ) error {
2019-02-07 18:41:16 -05:00
return verifyTotalEvents ( c . CoreV1 ( ) . Events ( eventNamespace ) , eventListOptions , test . totalEvents )
2019-07-28 00:49:36 -04:00
} , pollTimeout , pollInterval ) . Should ( gomega . Succeed ( ) )
ginkgo . By ( fmt . Sprintf ( "Make sure only %d total events generated" , test . totalEvents ) )
gomega . Consistently ( func ( ) error {
2019-02-07 18:41:16 -05:00
return verifyTotalEvents ( c . CoreV1 ( ) . Events ( eventNamespace ) , eventListOptions , test . totalEvents )
2019-07-28 00:49:36 -04:00
} , pollConsistent , pollInterval ) . Should ( gomega . Succeed ( ) )
2016-11-03 00:21:11 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( fmt . Sprintf ( "Make sure node condition %q is set" , condition ) )
gomega . Eventually ( func ( ) error {
2017-10-25 11:54:32 -04:00
return verifyNodeCondition ( c . CoreV1 ( ) . Nodes ( ) , condition , test . conditionType , test . conditionReason , test . conditionMessage )
2019-07-28 00:49:36 -04:00
} , pollTimeout , pollInterval ) . Should ( gomega . Succeed ( ) )
ginkgo . By ( fmt . Sprintf ( "Make sure node condition %q is stable" , condition ) )
gomega . Consistently ( func ( ) error {
2017-10-25 11:54:32 -04:00
return verifyNodeCondition ( c . CoreV1 ( ) . Nodes ( ) , condition , test . conditionType , test . conditionReason , test . conditionMessage )
2019-07-28 00:49:36 -04:00
} , pollConsistent , pollInterval ) . Should ( gomega . Succeed ( ) )
2016-11-03 00:21:11 -04:00
}
2016-06-01 15:57:32 -04:00
} )
2019-07-28 00:49:36 -04:00
ginkgo . AfterEach ( func ( ) {
2022-04-24 04:55:25 -04:00
if ginkgo . CurrentSpecReport ( ) . Failed ( ) && framework . TestContext . DumpLogsOnFailure {
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Get node problem detector log" )
2019-05-07 20:09:50 -04:00
log , err := e2epod . GetPodLogs ( c , ns , name , name )
2019-07-28 00:49:36 -04:00
gomega . Expect ( err ) . ShouldNot ( gomega . HaveOccurred ( ) )
2019-08-27 05:18:43 -04:00
framework . Logf ( "Node Problem Detector logs:\n %s" , log )
2016-11-03 00:21:11 -04:00
}
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Delete the node problem detector" )
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
e2epod . NewPodClient ( f ) . Delete ( context . TODO ( ) , name , * metav1 . NewDeleteOptions ( 0 ) )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Wait for the node problem detector to disappear" )
gomega . Expect ( e2epod . WaitForPodToDisappear ( c , ns , name , labels . Everything ( ) , pollInterval , pollTimeout ) ) . To ( gomega . Succeed ( ) )
ginkgo . By ( "Delete the config map" )
2020-03-01 12:24:42 -05:00
c . CoreV1 ( ) . ConfigMaps ( ns ) . Delete ( context . TODO ( ) , configName , metav1 . DeleteOptions { } )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Clean up the events" )
2020-03-01 13:19:56 -05:00
gomega . Expect ( c . CoreV1 ( ) . Events ( eventNamespace ) . DeleteCollection ( context . TODO ( ) , * metav1 . NewDeleteOptions ( 0 ) , eventListOptions ) ) . To ( gomega . Succeed ( ) )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Clean up the node condition" )
2016-06-01 15:57:32 -04:00
patch := [ ] byte ( fmt . Sprintf ( ` { "status": { "conditions":[ { "$patch":"delete","type":"%s"}]}} ` , condition ) )
2020-01-27 21:19:44 -05:00
c . CoreV1 ( ) . RESTClient ( ) . Patch ( types . StrategicMergePatchType ) . Resource ( "nodes" ) . Name ( framework . TestContext . NodeName ) . SubResource ( "status" ) . Body ( patch ) . Do ( context . TODO ( ) )
2016-06-01 15:57:32 -04:00
} )
} )
} )
2017-02-18 01:54:52 -05:00
// injectLog injects kernel log into specified file.
func injectLog ( file string , timestamp time . Time , log string , num int ) error {
f , err := os . OpenFile ( file , os . O_RDWR | os . O_APPEND , 0666 )
2017-02-06 15:12:31 -05:00
if err != nil {
2017-02-18 01:54:52 -05:00
return err
2017-02-06 15:12:31 -05:00
}
2017-05-22 09:51:11 -04:00
defer f . Close ( )
2017-02-18 01:54:52 -05:00
for i := 0 ; i < num ; i ++ {
_ , err := f . WriteString ( fmt . Sprintf ( "%s kernel: [0.000000] %s\n" , timestamp . Format ( time . Stamp ) , log ) )
if err != nil {
return err
}
2017-02-06 15:12:31 -05:00
}
2017-02-18 01:54:52 -05:00
return nil
}
2019-02-07 18:41:16 -05:00
// verifyEvents verifies there are num specific events generated with given reason and message.
2017-01-21 22:36:02 -05:00
func verifyEvents ( e coreclientset . EventInterface , options metav1 . ListOptions , num int , reason , message string ) error {
2020-02-07 21:16:47 -05:00
events , err := e . List ( context . TODO ( ) , options )
2016-06-01 15:57:32 -04:00
if err != nil {
return err
}
count := 0
for _ , event := range events . Items {
if event . Reason != reason || event . Message != message {
2019-02-07 18:41:16 -05:00
continue
2016-06-01 15:57:32 -04:00
}
count += int ( event . Count )
}
if count != num {
2020-07-08 09:31:41 -04:00
return fmt . Errorf ( "expected %d events with reason set to %s and message set to %s\nbut %d actual events occurred. Events : %v" , num , reason , message , count , events . Items )
2016-06-01 15:57:32 -04:00
}
return nil
}
2019-02-07 18:41:16 -05:00
// verifyTotalEvents verifies there are num events in total.
func verifyTotalEvents ( e coreclientset . EventInterface , options metav1 . ListOptions , num int ) error {
2020-02-07 21:16:47 -05:00
events , err := e . List ( context . TODO ( ) , options )
2016-06-01 15:57:32 -04:00
if err != nil {
return err
}
2019-02-07 18:41:16 -05:00
count := 0
for _ , event := range events . Items {
count += int ( event . Count )
}
if count != num {
2020-07-08 08:10:50 -04:00
return fmt . Errorf ( "expected total number of events was %d, actual events counted was %d\nEvents : %v" , num , count , events . Items )
2016-06-01 15:57:32 -04:00
}
return nil
}
2017-02-18 01:54:52 -05:00
// verifyNodeCondition verifies specific node condition is generated, if reason and message are empty, they will not be checked
func verifyNodeCondition ( n coreclientset . NodeInterface , condition v1 . NodeConditionType , status v1 . ConditionStatus , reason , message string ) error {
2020-02-07 21:16:47 -05:00
node , err := n . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2016-06-01 15:57:32 -04:00
if err != nil {
return err
}
2019-02-26 14:05:32 -05:00
_ , c := testutils . GetNodeCondition ( & node . Status , condition )
2016-06-01 15:57:32 -04:00
if c == nil {
return fmt . Errorf ( "node condition %q not found" , condition )
}
if c . Status != status || c . Reason != reason || c . Message != message {
return fmt . Errorf ( "unexpected node condition %q: %+v" , condition , c )
}
return nil
}