mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
kubelet: more tests for generic ephemeral volumes
This simulates various error scenarios (PVC not created for pod, feature disabled) and switching between feature disabled and enabled.
This commit is contained in:
parent
edb9a8584c
commit
68370c8aa6
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -454,6 +455,124 @@ func TestFindAndRemoveNonattachableVolumes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEphemeralVolumeOwnerCheck(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, true)()
|
||||||
|
|
||||||
|
// create dswp
|
||||||
|
pod, pv, pvc := createEphemeralVolumeObjects("dswp-test-pod", "dswp-test-volume-name", false /* not owned */)
|
||||||
|
dswp, fakePodManager, _ := createDswpWithVolume(t, pv, pvc)
|
||||||
|
fakePodManager.AddPod(pod)
|
||||||
|
|
||||||
|
podName := util.GetUniquePodName(pod)
|
||||||
|
|
||||||
|
dswp.findAndAddNewPods()
|
||||||
|
if dswp.pods.processedPods[podName] {
|
||||||
|
t.Fatalf("%s should not have been processed by the populator", podName)
|
||||||
|
}
|
||||||
|
require.Equal(t,
|
||||||
|
[]string{fmt.Sprintf("error processing PVC %s/%s: not the ephemeral PVC for the pod", pvc.Namespace, pvc.Name)},
|
||||||
|
dswp.desiredStateOfWorld.PopPodErrors(podName),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEphemeralVolumeEnablement(t *testing.T) {
|
||||||
|
// create dswp
|
||||||
|
pod, pv, pvc := createEphemeralVolumeObjects("dswp-test-pod", "dswp-test-volume-name", true /* owned */)
|
||||||
|
dswp, fakePodManager, fakesDSW := createDswpWithVolume(t, pv, pvc)
|
||||||
|
fakePodManager.AddPod(pod)
|
||||||
|
|
||||||
|
podName := util.GetUniquePodName(pod)
|
||||||
|
volumeName := pod.Spec.Volumes[0].Name
|
||||||
|
generatedVolumeName := "fake-plugin/" + volumeName
|
||||||
|
|
||||||
|
// Feature disabled -> refuse to process pod.
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, false)()
|
||||||
|
dswp.findAndAddNewPods()
|
||||||
|
if dswp.pods.processedPods[podName] {
|
||||||
|
t.Fatalf("%s should not have been processed by the populator", podName)
|
||||||
|
}
|
||||||
|
require.Equal(t,
|
||||||
|
[]string{fmt.Sprintf("volume %s is a generic ephemeral volume, but that feature is disabled in kubelet", volumeName)},
|
||||||
|
dswp.desiredStateOfWorld.PopPodErrors(podName),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enabled -> process pod.
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, true)()
|
||||||
|
dswp.findAndAddNewPods()
|
||||||
|
if !dswp.pods.processedPods[podName] {
|
||||||
|
t.Fatalf("Failed to record that the volumes for the specified pod: %s have been processed by the populator", podName)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedVolumeName := v1.UniqueVolumeName(generatedVolumeName)
|
||||||
|
|
||||||
|
volumeExists := fakesDSW.VolumeExists(expectedVolumeName)
|
||||||
|
if !volumeExists {
|
||||||
|
t.Fatalf(
|
||||||
|
"VolumeExists(%q) failed. Expected: <true> Actual: <%v>",
|
||||||
|
expectedVolumeName,
|
||||||
|
volumeExists)
|
||||||
|
}
|
||||||
|
|
||||||
|
if podExistsInVolume := fakesDSW.PodExistsInVolume(
|
||||||
|
podName, expectedVolumeName); !podExistsInVolume {
|
||||||
|
t.Fatalf(
|
||||||
|
"DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>",
|
||||||
|
podExistsInVolume)
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyVolumeExistsInVolumesToMount(
|
||||||
|
t, v1.UniqueVolumeName(generatedVolumeName), false /* expectReportedInUse */, fakesDSW)
|
||||||
|
|
||||||
|
//let the pod be terminated
|
||||||
|
podGet, exist := fakePodManager.GetPodByName(pod.Namespace, pod.Name)
|
||||||
|
if !exist {
|
||||||
|
t.Fatalf("Failed to get pod by pod name: %s and namespace: %s", pod.Name, pod.Namespace)
|
||||||
|
}
|
||||||
|
podGet.Status.Phase = v1.PodFailed
|
||||||
|
|
||||||
|
// Pretend again that the feature is disabled.
|
||||||
|
// Removal of the pod and volumes is expected to work.
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.GenericEphemeralVolume, false)()
|
||||||
|
|
||||||
|
dswp.findAndRemoveDeletedPods()
|
||||||
|
// Although Pod status is terminated, pod still exists in pod manager and actual state does not has this pod and volume information
|
||||||
|
// desired state populator will fail to delete this pod and volume first
|
||||||
|
volumeExists = fakesDSW.VolumeExists(expectedVolumeName)
|
||||||
|
if !volumeExists {
|
||||||
|
t.Fatalf(
|
||||||
|
"VolumeExists(%q) failed. Expected: <true> Actual: <%v>",
|
||||||
|
expectedVolumeName,
|
||||||
|
volumeExists)
|
||||||
|
}
|
||||||
|
|
||||||
|
if podExistsInVolume := fakesDSW.PodExistsInVolume(
|
||||||
|
podName, expectedVolumeName); !podExistsInVolume {
|
||||||
|
t.Fatalf(
|
||||||
|
"DSW PodExistsInVolume returned incorrect value. Expected: <true> Actual: <%v>",
|
||||||
|
podExistsInVolume)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconcile with actual state so that volume is added into the actual state
|
||||||
|
// desired state populator now can successfully delete the pod and volume
|
||||||
|
fakeASW := dswp.actualStateOfWorld
|
||||||
|
reconcileASW(fakeASW, fakesDSW, t)
|
||||||
|
dswp.findAndRemoveDeletedPods()
|
||||||
|
volumeExists = fakesDSW.VolumeExists(expectedVolumeName)
|
||||||
|
if volumeExists {
|
||||||
|
t.Fatalf(
|
||||||
|
"VolumeExists(%q) failed. Expected: <false> Actual: <%v>",
|
||||||
|
expectedVolumeName,
|
||||||
|
volumeExists)
|
||||||
|
}
|
||||||
|
|
||||||
|
if podExistsInVolume := fakesDSW.PodExistsInVolume(
|
||||||
|
podName, expectedVolumeName); podExistsInVolume {
|
||||||
|
t.Fatalf(
|
||||||
|
"DSW PodExistsInVolume returned incorrect value. Expected: <false> Actual: <%v>",
|
||||||
|
podExistsInVolume)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFindAndAddNewPods_FindAndRemoveDeletedPods_Valid_Block_VolumeDevices(t *testing.T) {
|
func TestFindAndAddNewPods_FindAndRemoveDeletedPods_Valid_Block_VolumeDevices(t *testing.T) {
|
||||||
// create dswp
|
// create dswp
|
||||||
mode := v1.PersistentVolumeBlock
|
mode := v1.PersistentVolumeBlock
|
||||||
@ -1076,6 +1195,74 @@ func createPodWithVolume(pod, pv, pvc string, containers []v1.Container) *v1.Pod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createEphemeralVolumeObjects(podName, volumeName string, owned bool) (pod *v1.Pod, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) {
|
||||||
|
pod = &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
UID: "dswp-test-pod-uid",
|
||||||
|
Namespace: "dswp-test",
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Volumes: []v1.Volume{
|
||||||
|
{
|
||||||
|
Name: volumeName,
|
||||||
|
VolumeSource: v1.VolumeSource{
|
||||||
|
Ephemeral: &v1.EphemeralVolumeSource{
|
||||||
|
VolumeClaimTemplate: &v1.PersistentVolumeClaimTemplate{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
VolumeMounts: []v1.VolumeMount{
|
||||||
|
{
|
||||||
|
Name: volumeName,
|
||||||
|
MountPath: "/mnt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: v1.PodStatus{
|
||||||
|
Phase: v1.PodPhase("Running"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mode := v1.PersistentVolumeFilesystem
|
||||||
|
pv = &v1.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: volumeName,
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeSpec{
|
||||||
|
ClaimRef: &v1.ObjectReference{Namespace: "ns", Name: "file-bound"},
|
||||||
|
VolumeMode: &mode,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pvc = &v1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName + "-" + volumeName,
|
||||||
|
Namespace: pod.Namespace,
|
||||||
|
},
|
||||||
|
Spec: v1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "dswp-test-volume-name",
|
||||||
|
},
|
||||||
|
Status: v1.PersistentVolumeClaimStatus{
|
||||||
|
Phase: v1.ClaimBound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if owned {
|
||||||
|
controller := true
|
||||||
|
pvc.OwnerReferences = []metav1.OwnerReference{
|
||||||
|
{
|
||||||
|
UID: pod.UID,
|
||||||
|
Name: podName,
|
||||||
|
Controller: &controller,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func createDswpWithVolume(t *testing.T, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) (*desiredStateOfWorldPopulator, kubepod.Manager, cache.DesiredStateOfWorld) {
|
func createDswpWithVolume(t *testing.T, pv *v1.PersistentVolume, pvc *v1.PersistentVolumeClaim) (*desiredStateOfWorldPopulator, kubepod.Manager, cache.DesiredStateOfWorld) {
|
||||||
fakeVolumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t)
|
fakeVolumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t)
|
||||||
dswp, fakePodManager, fakesDSW := createDswpWithVolumeWithCustomPluginMgr(t, pv, pvc, fakeVolumePluginMgr)
|
dswp, fakePodManager, fakesDSW := createDswpWithVolumeWithCustomPluginMgr(t, pv, pvc, fakeVolumePluginMgr)
|
||||||
|
Loading…
Reference in New Issue
Block a user