2017-12-29 05:43:38 -05:00
/ *
Copyright 2017 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 .
* /
2019-11-06 22:59:05 -05:00
package e2enode
2017-12-29 05:43:38 -05:00
import (
2020-02-07 21:16:47 -05:00
"context"
2017-12-29 05:43:38 -05:00
"path/filepath"
"time"
2019-12-09 03:09:29 -05:00
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
2020-03-24 21:57:32 -04:00
e2etestfiles "k8s.io/kubernetes/test/e2e/framework/testfiles"
2019-12-09 03:09:29 -05:00
2017-12-29 05:43:38 -05:00
"regexp"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2018-01-24 12:06:07 -05:00
"k8s.io/apimachinery/pkg/util/uuid"
2020-10-10 19:03:31 -04:00
kubeletpodresourcesv1 "k8s.io/kubelet/pkg/apis/podresources/v1"
2020-06-30 01:13:45 -04:00
kubeletpodresourcesv1alpha1 "k8s.io/kubelet/pkg/apis/podresources/v1alpha1"
2017-12-29 05:43:38 -05:00
"k8s.io/kubernetes/test/e2e/framework"
2018-08-28 02:41:42 -04:00
e2enode "k8s.io/kubernetes/test/e2e/framework/node"
2019-05-07 20:09:50 -04:00
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
2017-12-29 05:43:38 -05:00
2019-07-28 00:49:36 -04:00
"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
2017-12-29 05:43:38 -05:00
)
2018-01-11 01:41:45 -05:00
const (
2019-12-09 03:09:29 -05:00
// sampleResourceName is the name of the example resource which is used in the e2e test
sampleResourceName = "example.com/resource"
// sampleDevicePluginDSYAML is the path of the daemonset template of the sample device plugin. // TODO: Parametrize it by making it a feature in TestFramework.
sampleDevicePluginDSYAML = "test/e2e/testing-manifests/sample-device-plugin.yaml"
// sampleDevicePluginName is the name of the device plugin pod
sampleDevicePluginName = "sample-device-plugin"
2018-01-11 01:41:45 -05:00
// fake resource name
2018-08-28 02:41:42 -04:00
resourceName = "example.com/resource"
envVarNamePluginSockDir = "PLUGIN_SOCK_DIR"
2018-01-11 01:41:45 -05:00
)
2019-12-09 03:09:29 -05:00
var (
appsScheme = runtime . NewScheme ( )
appsCodecs = serializer . NewCodecFactory ( appsScheme )
)
2018-01-11 01:41:45 -05:00
// Serial because the test restarts Kubelet
2021-02-22 13:53:33 -05:00
var _ = SIGDescribe ( "Device Plugin [Feature:DevicePluginProbe][NodeFeature:DevicePluginProbe][Serial]" , func ( ) {
2018-01-24 12:06:07 -05:00
f := framework . NewDefaultFramework ( "device-plugin-errors" )
2019-03-12 15:58:23 -04:00
testDevicePlugin ( f , "/var/lib/kubelet/plugins_registry" )
2018-01-24 12:06:07 -05:00
} )
2018-01-11 01:41:45 -05:00
2019-12-09 03:09:29 -05:00
// numberOfSampleResources returns the number of resources advertised by a node.
func numberOfSampleResources ( node * v1 . Node ) int64 {
val , ok := node . Status . Capacity [ sampleResourceName ]
if ! ok {
return 0
}
return val . Value ( )
}
// getSampleDevicePluginPod returns the Device Plugin pod for sample resources in e2e tests.
func getSampleDevicePluginPod ( ) * v1 . Pod {
2020-06-22 18:33:41 -04:00
data , err := e2etestfiles . Read ( sampleDevicePluginDSYAML )
if err != nil {
framework . Fail ( err . Error ( ) )
}
ds := readDaemonSetV1OrDie ( data )
2019-12-09 03:09:29 -05:00
p := & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta {
Name : sampleDevicePluginName ,
Namespace : metav1 . NamespaceSystem ,
} ,
Spec : ds . Spec . Template . Spec ,
}
return p
}
// readDaemonSetV1OrDie reads daemonset object from bytes. Panics on error.
func readDaemonSetV1OrDie ( objBytes [ ] byte ) * appsv1 . DaemonSet {
appsv1 . AddToScheme ( appsScheme )
requiredObj , err := runtime . Decode ( appsCodecs . UniversalDecoder ( appsv1 . SchemeGroupVersion ) , objBytes )
if err != nil {
panic ( err )
}
return requiredObj . ( * appsv1 . DaemonSet )
}
2019-03-12 15:58:23 -04:00
func testDevicePlugin ( f * framework . Framework , pluginSockDir string ) {
2018-12-05 02:26:15 -05:00
pluginSockDir = filepath . Join ( pluginSockDir ) + "/"
2019-07-28 00:49:36 -04:00
ginkgo . Context ( "DevicePlugin" , func ( ) {
2021-07-28 13:39:30 -04:00
ginkgo . It ( "[Flaky] Verifies the Kubelet device plugin functionality." , func ( ) {
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Wait for node is ready to start with" )
2018-08-28 02:41:42 -04:00
e2enode . WaitForNodeToBeReady ( f . ClientSet , framework . TestContext . NodeName , 5 * time . Minute )
2019-12-09 03:09:29 -05:00
dp := getSampleDevicePluginPod ( )
2018-08-28 02:41:42 -04:00
for i := range dp . Spec . Containers [ 0 ] . Env {
if dp . Spec . Containers [ 0 ] . Env [ i ] . Name == envVarNamePluginSockDir {
dp . Spec . Containers [ 0 ] . Env [ i ] . Value = pluginSockDir
}
2018-01-11 01:41:45 -05:00
}
2019-08-27 05:18:43 -04:00
framework . Logf ( "env %v" , dp . Spec . Containers [ 0 ] . Env )
2018-08-28 02:41:42 -04:00
dp . Spec . NodeName = framework . TestContext . NodeName
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Create sample device plugin pod" )
2020-02-08 12:30:21 -05:00
devicePluginPod , err := f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Create ( context . TODO ( ) , dp , metav1 . CreateOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for devices to become available on the local node" )
gomega . Eventually ( func ( ) bool {
2019-12-09 03:09:29 -05:00
return numberOfSampleResources ( getLocalNode ( f ) ) > 0
2019-07-28 00:49:36 -04:00
} , 5 * time . Minute , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2019-08-27 05:18:43 -04:00
framework . Logf ( "Successfully created device plugin pod" )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for the resource exported by the sample device plugin to become available on the local node" )
2018-08-28 02:41:42 -04:00
// TODO(vikasc): Instead of hard-coding number of devices, provide number of devices in the sample-device-plugin using configmap
// and then use the same here
devsLen := int64 ( 2 )
2019-07-28 00:49:36 -04:00
gomega . Eventually ( func ( ) bool {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-04-25 03:44:27 -04:00
return numberOfDevicesCapacity ( node , resourceName ) == devsLen &&
numberOfDevicesAllocatable ( node , resourceName ) == devsLen
2019-07-28 00:49:36 -04:00
} , 30 * time . Second , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Creating one pod on node with at least one fake-device" )
2018-01-11 01:41:45 -05:00
podRECMD := "devs=$(ls /tmp/ | egrep '^Dev-[0-9]+$') && echo stub devices: $devs"
pod1 := f . PodClient ( ) . CreateSync ( makeBusyboxPod ( resourceName , podRECMD ) )
deviceIDRE := "stub devices: (Dev-[0-9]+)"
2019-11-06 22:59:05 -05:00
devID1 := parseLog ( f , pod1 . Name , pod1 . Name , deviceIDRE )
2019-12-04 21:14:13 -05:00
gomega . Expect ( devID1 ) . To ( gomega . Not ( gomega . Equal ( "" ) ) )
2018-01-11 01:41:45 -05:00
2020-10-10 19:03:31 -04:00
v1alphaPodResources , err := getV1alpha1NodeDevices ( )
2019-12-04 22:01:32 -05:00
framework . ExpectNoError ( err )
2020-10-10 19:03:31 -04:00
framework . Logf ( "v1alpha pod resources %v" , v1alphaPodResources )
v1PodResources , err := getV1NodeDevices ( )
framework . ExpectNoError ( err )
framework . Logf ( "v1 pod resources %v" , v1PodResources )
framework . ExpectEqual ( len ( v1alphaPodResources . PodResources ) , 2 )
framework . ExpectEqual ( len ( v1PodResources . PodResources ) , 2 )
var v1alphaResourcesForOurPod * kubeletpodresourcesv1alpha1 . PodResources
for _ , res := range v1alphaPodResources . GetPodResources ( ) {
if res . Name == pod1 . Name {
v1alphaResourcesForOurPod = res
}
}
framework . Logf ( "v1alphaResourcesForOurPod %v" , v1alphaResourcesForOurPod )
var v1ResourcesForOurPod * kubeletpodresourcesv1 . PodResources
for _ , res := range v1PodResources . GetPodResources ( ) {
2018-08-28 02:41:42 -04:00
if res . Name == pod1 . Name {
2020-10-10 19:03:31 -04:00
v1ResourcesForOurPod = res
2018-08-28 02:41:42 -04:00
}
}
2020-10-10 19:03:31 -04:00
framework . Logf ( "v1ResourcesForOurPod %v" , v1ResourcesForOurPod )
gomega . Expect ( v1alphaResourcesForOurPod ) . NotTo ( gomega . BeNil ( ) )
gomega . Expect ( v1ResourcesForOurPod ) . NotTo ( gomega . BeNil ( ) )
framework . ExpectEqual ( v1alphaResourcesForOurPod . Name , pod1 . Name )
framework . ExpectEqual ( v1ResourcesForOurPod . Name , pod1 . Name )
framework . ExpectEqual ( v1alphaResourcesForOurPod . Namespace , pod1 . Namespace )
framework . ExpectEqual ( v1ResourcesForOurPod . Namespace , pod1 . Namespace )
framework . ExpectEqual ( len ( v1alphaResourcesForOurPod . Containers ) , 1 )
framework . ExpectEqual ( len ( v1ResourcesForOurPod . Containers ) , 1 )
framework . ExpectEqual ( v1alphaResourcesForOurPod . Containers [ 0 ] . Name , pod1 . Spec . Containers [ 0 ] . Name )
framework . ExpectEqual ( v1ResourcesForOurPod . Containers [ 0 ] . Name , pod1 . Spec . Containers [ 0 ] . Name )
framework . ExpectEqual ( len ( v1alphaResourcesForOurPod . Containers [ 0 ] . Devices ) , 1 )
framework . ExpectEqual ( len ( v1ResourcesForOurPod . Containers [ 0 ] . Devices ) , 1 )
framework . ExpectEqual ( v1alphaResourcesForOurPod . Containers [ 0 ] . Devices [ 0 ] . ResourceName , resourceName )
framework . ExpectEqual ( v1ResourcesForOurPod . Containers [ 0 ] . Devices [ 0 ] . ResourceName , resourceName )
framework . ExpectEqual ( len ( v1alphaResourcesForOurPod . Containers [ 0 ] . Devices [ 0 ] . DeviceIds ) , 1 )
framework . ExpectEqual ( len ( v1ResourcesForOurPod . Containers [ 0 ] . Devices [ 0 ] . DeviceIds ) , 1 )
2018-11-13 22:25:56 -05:00
2020-02-07 21:16:47 -05:00
pod1 , err = f . PodClient ( ) . Get ( context . TODO ( ) , pod1 . Name , metav1 . GetOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-04-25 03:44:27 -04:00
ensurePodContainerRestart ( f , pod1 . Name , pod1 . Name )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Confirming that device assignment persists even after container restart" )
2019-11-06 22:59:05 -05:00
devIDAfterRestart := parseLog ( f , pod1 . Name , pod1 . Name , deviceIDRE )
framework . ExpectEqual ( devIDAfterRestart , devID1 )
2018-04-25 03:44:27 -04:00
2018-08-24 13:29:10 -04:00
restartTime := time . Now ( )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Restarting Kubelet" )
2021-10-06 11:45:22 -04:00
restartKubelet ( true )
2018-01-11 01:41:45 -05:00
2018-08-24 13:29:10 -04:00
// We need to wait for node to be ready before re-registering stub device plugin.
// Otherwise, Kubelet DeviceManager may remove the re-registered sockets after it starts.
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Wait for node is ready" )
gomega . Eventually ( func ( ) bool {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-08-24 13:29:10 -04:00
framework . ExpectNoError ( err )
for _ , cond := range node . Status . Conditions {
if cond . Type == v1 . NodeReady && cond . Status == v1 . ConditionTrue && cond . LastHeartbeatTime . After ( restartTime ) {
return true
}
}
return false
2019-07-28 00:49:36 -04:00
} , 5 * time . Minute , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Re-Register resources and deleting the pods and waiting for container removal" )
2018-08-28 02:41:42 -04:00
getOptions := metav1 . GetOptions { }
gp := int64 ( 0 )
deleteOptions := metav1 . DeleteOptions {
GracePeriodSeconds : & gp ,
}
2020-03-01 12:24:42 -05:00
err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Delete ( context . TODO ( ) , dp . Name , deleteOptions )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-08-28 02:41:42 -04:00
waitForContainerRemoval ( devicePluginPod . Spec . Containers [ 0 ] . Name , devicePluginPod . Name , devicePluginPod . Namespace )
2020-02-07 21:16:47 -05:00
_ , err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Get ( context . TODO ( ) , dp . Name , getOptions )
2019-08-27 05:18:43 -04:00
framework . Logf ( "Trying to get dp pod after deletion. err must be non-nil. err: %v" , err )
2018-08-28 02:41:42 -04:00
framework . ExpectError ( err )
2018-01-11 01:41:45 -05:00
2020-02-08 12:30:21 -05:00
devicePluginPod , err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Create ( context . TODO ( ) , dp , metav1 . CreateOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-08-24 13:29:10 -04:00
ensurePodContainerRestart ( f , pod1 . Name , pod1 . Name )
2021-01-24 03:42:34 -05:00
ginkgo . By ( "Confirming that after a kubelet restart, fake-device assignment is kept" )
2019-11-06 22:59:05 -05:00
devIDRestart1 := parseLog ( f , pod1 . Name , pod1 . Name , deviceIDRE )
framework . ExpectEqual ( devIDRestart1 , devID1 )
2018-08-24 13:29:10 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for resource to become available on the local node after re-registration" )
gomega . Eventually ( func ( ) bool {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-04-25 03:44:27 -04:00
return numberOfDevicesCapacity ( node , resourceName ) == devsLen &&
numberOfDevicesAllocatable ( node , resourceName ) == devsLen
2019-07-28 00:49:36 -04:00
} , 30 * time . Second , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Creating another pod" )
2018-01-11 01:41:45 -05:00
pod2 := f . PodClient ( ) . CreateSync ( makeBusyboxPod ( resourceName , podRECMD ) )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Checking that pod got a different fake device" )
2019-11-06 22:59:05 -05:00
devID2 := parseLog ( f , pod2 . Name , pod2 . Name , deviceIDRE )
2018-01-11 01:41:45 -05:00
2019-12-04 21:14:13 -05:00
gomega . Expect ( devID1 ) . To ( gomega . Not ( gomega . Equal ( devID2 ) ) )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "By deleting the pods and waiting for container removal" )
2020-03-01 12:24:42 -05:00
err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Delete ( context . TODO ( ) , dp . Name , deleteOptions )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-08-28 02:41:42 -04:00
waitForContainerRemoval ( devicePluginPod . Spec . Containers [ 0 ] . Name , devicePluginPod . Name , devicePluginPod . Namespace )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for stub device plugin to become unhealthy on the local node" )
gomega . Eventually ( func ( ) int64 {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-01-11 01:41:45 -05:00
framework . ExpectNoError ( err )
2018-04-25 03:44:27 -04:00
return numberOfDevicesAllocatable ( node , resourceName )
2019-07-28 00:49:36 -04:00
} , 30 * time . Second , framework . Poll ) . Should ( gomega . Equal ( int64 ( 0 ) ) )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Checking that scheduled pods can continue to run even after we delete device plugin." )
2018-04-25 03:44:27 -04:00
ensurePodContainerRestart ( f , pod1 . Name , pod1 . Name )
2019-11-06 22:59:05 -05:00
devIDRestart1 = parseLog ( f , pod1 . Name , pod1 . Name , deviceIDRE )
framework . ExpectEqual ( devIDRestart1 , devID1 )
2018-04-25 03:44:27 -04:00
ensurePodContainerRestart ( f , pod2 . Name , pod2 . Name )
2019-11-06 22:59:05 -05:00
devIDRestart2 := parseLog ( f , pod2 . Name , pod2 . Name , deviceIDRE )
framework . ExpectEqual ( devIDRestart2 , devID2 )
2018-01-11 01:41:45 -05:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Re-register resources" )
2020-02-08 12:30:21 -05:00
devicePluginPod , err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Create ( context . TODO ( ) , dp , metav1 . CreateOptions { } )
2018-04-25 03:44:27 -04:00
framework . ExpectNoError ( err )
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for the resource exported by the stub device plugin to become healthy on the local node" )
gomega . Eventually ( func ( ) int64 {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-04-25 03:44:27 -04:00
framework . ExpectNoError ( err )
return numberOfDevicesAllocatable ( node , resourceName )
2019-07-28 00:49:36 -04:00
} , 30 * time . Second , framework . Poll ) . Should ( gomega . Equal ( devsLen ) )
2018-04-25 03:44:27 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "by deleting the pods and waiting for container removal" )
2020-03-01 12:24:42 -05:00
err = f . ClientSet . CoreV1 ( ) . Pods ( metav1 . NamespaceSystem ) . Delete ( context . TODO ( ) , dp . Name , deleteOptions )
2018-04-25 03:44:27 -04:00
framework . ExpectNoError ( err )
2018-08-28 02:41:42 -04:00
waitForContainerRemoval ( devicePluginPod . Spec . Containers [ 0 ] . Name , devicePluginPod . Name , devicePluginPod . Namespace )
2018-04-25 03:44:27 -04:00
2019-07-28 00:49:36 -04:00
ginkgo . By ( "Waiting for stub device plugin to become unavailable on the local node" )
gomega . Eventually ( func ( ) bool {
2020-02-07 21:16:47 -05:00
node , err := f . ClientSet . CoreV1 ( ) . Nodes ( ) . Get ( context . TODO ( ) , framework . TestContext . NodeName , metav1 . GetOptions { } )
2018-04-25 03:44:27 -04:00
framework . ExpectNoError ( err )
return numberOfDevicesCapacity ( node , resourceName ) <= 0
2019-07-28 00:49:36 -04:00
} , 10 * time . Minute , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2018-04-25 03:44:27 -04:00
2018-01-11 01:41:45 -05:00
// Cleanup
2020-03-01 12:34:30 -05:00
f . PodClient ( ) . DeleteSync ( pod1 . Name , metav1 . DeleteOptions { } , framework . DefaultPodDeletionTimeout )
f . PodClient ( ) . DeleteSync ( pod2 . Name , metav1 . DeleteOptions { } , framework . DefaultPodDeletionTimeout )
2018-01-11 01:41:45 -05:00
} )
} )
2018-01-24 12:06:07 -05:00
}
2018-01-11 01:41:45 -05:00
// makeBusyboxPod returns a simple Pod spec with a busybox container
2017-12-29 05:43:38 -05:00
// that requests resourceName and runs the specified command.
func makeBusyboxPod ( resourceName , cmd string ) * v1 . Pod {
podName := "device-plugin-test-" + string ( uuid . NewUUID ( ) )
rl := v1 . ResourceList { v1 . ResourceName ( resourceName ) : * resource . NewQuantity ( 1 , resource . DecimalSI ) }
return & v1 . Pod {
ObjectMeta : metav1 . ObjectMeta { Name : podName } ,
Spec : v1 . PodSpec {
RestartPolicy : v1 . RestartPolicyAlways ,
Containers : [ ] v1 . Container { {
Image : busyboxImage ,
Name : podName ,
// Runs the specified command in the test pod.
Command : [ ] string { "sh" , "-c" , cmd } ,
Resources : v1 . ResourceRequirements {
Limits : rl ,
Requests : rl ,
} ,
} } ,
} ,
}
}
2018-04-25 03:44:27 -04:00
// ensurePodContainerRestart confirms that pod container has restarted at least once
func ensurePodContainerRestart ( f * framework . Framework , podName string , contName string ) {
var initialCount int32
var currentCount int32
2020-02-07 21:16:47 -05:00
p , err := f . PodClient ( ) . Get ( context . TODO ( ) , podName , metav1 . GetOptions { } )
2018-04-25 03:44:27 -04:00
if err != nil || len ( p . Status . ContainerStatuses ) < 1 {
2019-08-27 05:18:43 -04:00
framework . Failf ( "ensurePodContainerRestart failed for pod %q: %v" , podName , err )
2018-04-25 03:44:27 -04:00
}
initialCount = p . Status . ContainerStatuses [ 0 ] . RestartCount
2019-07-28 00:49:36 -04:00
gomega . Eventually ( func ( ) bool {
2020-02-07 21:16:47 -05:00
p , err = f . PodClient ( ) . Get ( context . TODO ( ) , podName , metav1 . GetOptions { } )
2017-12-29 05:43:38 -05:00
if err != nil || len ( p . Status . ContainerStatuses ) < 1 {
return false
}
2018-04-25 03:44:27 -04:00
currentCount = p . Status . ContainerStatuses [ 0 ] . RestartCount
2019-08-27 05:18:43 -04:00
framework . Logf ( "initial %v, current %v" , initialCount , currentCount )
2018-04-25 03:44:27 -04:00
return currentCount > initialCount
2019-07-28 00:49:36 -04:00
} , 5 * time . Minute , framework . Poll ) . Should ( gomega . BeTrue ( ) )
2018-04-25 03:44:27 -04:00
}
2018-01-11 01:41:45 -05:00
2018-04-25 03:44:27 -04:00
// parseLog returns the matching string for the specified regular expression parsed from the container logs.
func parseLog ( f * framework . Framework , podName string , contName string , re string ) string {
2019-05-07 20:09:50 -04:00
logs , err := e2epod . GetPodLogs ( f . ClientSet , f . Namespace . Name , podName , contName )
2017-12-29 05:43:38 -05:00
if err != nil {
2019-08-27 05:18:43 -04:00
framework . Failf ( "GetPodLogs for pod %q failed: %v" , podName , err )
2017-12-29 05:43:38 -05:00
}
2018-01-11 01:41:45 -05:00
2019-08-27 05:18:43 -04:00
framework . Logf ( "got pod logs: %v" , logs )
2017-12-29 05:43:38 -05:00
regex := regexp . MustCompile ( re )
matches := regex . FindStringSubmatch ( logs )
if len ( matches ) < 2 {
2018-04-25 03:44:27 -04:00
return ""
2017-12-29 05:43:38 -05:00
}
2018-01-11 01:41:45 -05:00
2018-04-25 03:44:27 -04:00
return matches [ 1 ]
2017-12-29 05:43:38 -05:00
}
2018-04-25 03:44:27 -04:00
// numberOfDevicesCapacity returns the number of devices of resourceName advertised by a node capacity
func numberOfDevicesCapacity ( node * v1 . Node , resourceName string ) int64 {
2017-12-29 05:43:38 -05:00
val , ok := node . Status . Capacity [ v1 . ResourceName ( resourceName ) ]
if ! ok {
return 0
}
return val . Value ( )
}
2018-01-11 01:41:45 -05:00
2018-04-25 03:44:27 -04:00
// numberOfDevicesAllocatable returns the number of devices of resourceName advertised by a node allocatable
func numberOfDevicesAllocatable ( node * v1 . Node , resourceName string ) int64 {
val , ok := node . Status . Allocatable [ v1 . ResourceName ( resourceName ) ]
if ! ok {
return 0
}
return val . Value ( )
}