Skip to content

Commit 345e58b

Browse files
authored
Merge pull request kubernetes#75071 from mkimuram/issue/74552e2e
Fix volume reconstruction and add e2e tests
2 parents 16d9a65 + c130b77 commit 345e58b

File tree

16 files changed

+389
-83
lines changed

16 files changed

+389
-83
lines changed

pkg/kubelet/volumemanager/reconciler/reconciler.go

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,11 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
470470
if err != nil {
471471
return nil, err
472472
}
473+
// TODO: remove feature gate check after no longer needed
474+
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && volume.volumeMode == v1.PersistentVolumeBlock && mapperPlugin == nil {
475+
return nil, fmt.Errorf("Could not find block volume plugin %q (spec.Name: %q) pod %q (UID: %q)", volume.pluginName, volume.volumeSpecName, volume.podName, pod.UID)
476+
}
477+
473478
volumeSpec, err := rc.operationExecutor.ReconstructVolumeOperation(
474479
volume.volumeMode,
475480
plugin,
@@ -493,22 +498,48 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
493498
uniqueVolumeName = util.GetUniqueVolumeNameFromSpecWithPod(volume.podName, plugin, volumeSpec)
494499
}
495500

496-
volumeMounter, newMounterErr := plugin.NewMounter(
497-
volumeSpec,
498-
pod,
499-
volumepkg.VolumeOptions{})
500-
if newMounterErr != nil {
501-
return nil, fmt.Errorf(
502-
"reconstructVolume.NewMounter failed for volume %q (spec.Name: %q) pod %q (UID: %q) with: %v",
503-
uniqueVolumeName,
504-
volumeSpec.Name(),
505-
volume.podName,
506-
pod.UID,
507-
newMounterErr)
501+
var volumeMapper volumepkg.BlockVolumeMapper
502+
var volumeMounter volumepkg.Mounter
503+
// Path to the mount or block device to check
504+
var checkPath string
505+
506+
// TODO: remove feature gate check after no longer needed
507+
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && volume.volumeMode == v1.PersistentVolumeBlock {
508+
var newMapperErr error
509+
volumeMapper, newMapperErr = mapperPlugin.NewBlockVolumeMapper(
510+
volumeSpec,
511+
pod,
512+
volumepkg.VolumeOptions{})
513+
if newMapperErr != nil {
514+
return nil, fmt.Errorf(
515+
"reconstructVolume.NewBlockVolumeMapper failed for volume %q (spec.Name: %q) pod %q (UID: %q) with: %v",
516+
uniqueVolumeName,
517+
volumeSpec.Name(),
518+
volume.podName,
519+
pod.UID,
520+
newMapperErr)
521+
}
522+
checkPath, _ = volumeMapper.GetPodDeviceMapPath()
523+
} else {
524+
var err error
525+
volumeMounter, err = plugin.NewMounter(
526+
volumeSpec,
527+
pod,
528+
volumepkg.VolumeOptions{})
529+
if err != nil {
530+
return nil, fmt.Errorf(
531+
"reconstructVolume.NewMounter failed for volume %q (spec.Name: %q) pod %q (UID: %q) with: %v",
532+
uniqueVolumeName,
533+
volumeSpec.Name(),
534+
volume.podName,
535+
pod.UID,
536+
err)
537+
}
538+
checkPath = volumeMounter.GetPath()
508539
}
509540

510541
// Check existence of mount point for filesystem volume or symbolic link for block volume
511-
isExist, checkErr := rc.operationExecutor.CheckVolumeExistenceOperation(volumeSpec, volumeMounter.GetPath(), volumeSpec.Name(), rc.mounter, uniqueVolumeName, volume.podName, pod.UID, attachablePlugin)
542+
isExist, checkErr := rc.operationExecutor.CheckVolumeExistenceOperation(volumeSpec, checkPath, volumeSpec.Name(), rc.mounter, uniqueVolumeName, volume.podName, pod.UID, attachablePlugin)
512543
if checkErr != nil {
513544
return nil, checkErr
514545
}
@@ -517,27 +548,6 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
517548
return nil, fmt.Errorf("Volume: %q is not mounted", uniqueVolumeName)
518549
}
519550

520-
// TODO: remove feature gate check after no longer needed
521-
var volumeMapper volumepkg.BlockVolumeMapper
522-
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) && volume.volumeMode == v1.PersistentVolumeBlock {
523-
var newMapperErr error
524-
if mapperPlugin != nil {
525-
volumeMapper, newMapperErr = mapperPlugin.NewBlockVolumeMapper(
526-
volumeSpec,
527-
pod,
528-
volumepkg.VolumeOptions{})
529-
if newMapperErr != nil {
530-
return nil, fmt.Errorf(
531-
"reconstructVolume.NewBlockVolumeMapper failed for volume %q (spec.Name: %q) pod %q (UID: %q) with: %v",
532-
uniqueVolumeName,
533-
volumeSpec.Name(),
534-
volume.podName,
535-
pod.UID,
536-
newMapperErr)
537-
}
538-
}
539-
}
540-
541551
reconstructedVolume := &reconstructedVolume{
542552
volumeName: uniqueVolumeName,
543553
podName: volume.podName,

pkg/volume/util/operationexecutor/operation_executor.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -543,10 +543,12 @@ type MountedVolume struct {
543543

544544
// Mounter is the volume mounter used to mount this volume. It is required
545545
// by kubelet to create container.VolumeMap.
546+
// Mounter is only required for file system volumes and not required for block volumes.
546547
Mounter volume.Mounter
547548

548549
// BlockVolumeMapper is the volume mapper used to map this volume. It is required
549550
// by kubelet to create container.VolumeMap.
551+
// BlockVolumeMapper is only required for block volumes and not required for file system volumes.
550552
BlockVolumeMapper volume.BlockVolumeMapper
551553

552554
// VolumeGidValue contains the value of the GID annotation, if present.
@@ -897,13 +899,7 @@ func (oe *operationExecutor) ReconstructVolumeOperation(
897899
// Block Volume case
898900
// Create volumeSpec from mount path
899901
klog.V(5).Infof("Starting operationExecutor.ReconstructVolume")
900-
if mapperPlugin == nil {
901-
return nil, fmt.Errorf("Could not find block volume plugin %q (spec.Name: %q) pod %q (UID: %q)",
902-
pluginName,
903-
volumeSpecName,
904-
podName,
905-
uid)
906-
}
902+
907903
// volumePath contains volumeName on the path. In the case of block volume, {volumeName} is symbolic link
908904
// corresponding to raw block device.
909905
// ex. volumePath: pods/{podUid}}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName}
@@ -935,6 +931,9 @@ func (oe *operationExecutor) CheckVolumeExistenceOperation(
935931
if attachable != nil {
936932
var isNotMount bool
937933
var mountCheckErr error
934+
if mounter == nil {
935+
return false, fmt.Errorf("mounter was not set for a filesystem volume")
936+
}
938937
if isNotMount, mountCheckErr = mounter.IsLikelyNotMountPoint(mountPath); mountCheckErr != nil {
939938
return false, fmt.Errorf("Could not check whether the volume %q (spec.Name: %q) pod %q (UID: %q) is mounted with: %v",
940939
uniqueVolumeName,

test/e2e/framework/pv_util.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ func makeNginxPod(ns string, nodeSelector map[string]string, pvclaims []*v1.Pers
833833
// MakeSecPod returns a pod definition based on the namespace. The pod references the PVC's
834834
// name. A slice of BASH commands can be supplied as args to be run by the pod.
835835
// SELinux testing requires to pass HostIPC and HostPID as booleansi arguments.
836-
func MakeSecPod(ns string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64) *v1.Pod {
836+
func MakeSecPod(ns string, pvclaims []*v1.PersistentVolumeClaim, inlineVolumeSources []*v1.VolumeSource, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64) *v1.Pod {
837837
if len(command) == 0 {
838838
command = "trap exit TERM; while true; do sleep 1; done"
839839
}
@@ -874,17 +874,27 @@ func MakeSecPod(ns string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bo
874874
}
875875
var volumeMounts = make([]v1.VolumeMount, 0)
876876
var volumeDevices = make([]v1.VolumeDevice, 0)
877-
var volumes = make([]v1.Volume, len(pvclaims))
878-
for index, pvclaim := range pvclaims {
879-
volumename := fmt.Sprintf("volume%v", index+1)
877+
var volumes = make([]v1.Volume, len(pvclaims)+len(inlineVolumeSources))
878+
volumeIndex := 0
879+
for _, pvclaim := range pvclaims {
880+
volumename := fmt.Sprintf("volume%v", volumeIndex+1)
880881
if pvclaim.Spec.VolumeMode != nil && *pvclaim.Spec.VolumeMode == v1.PersistentVolumeBlock {
881882
volumeDevices = append(volumeDevices, v1.VolumeDevice{Name: volumename, DevicePath: "/mnt/" + volumename})
882883
} else {
883884
volumeMounts = append(volumeMounts, v1.VolumeMount{Name: volumename, MountPath: "/mnt/" + volumename})
884885
}
885886

886-
volumes[index] = v1.Volume{Name: volumename, VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: pvclaim.Name, ReadOnly: false}}}
887+
volumes[volumeIndex] = v1.Volume{Name: volumename, VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: pvclaim.Name, ReadOnly: false}}}
888+
volumeIndex++
889+
}
890+
for _, src := range inlineVolumeSources {
891+
volumename := fmt.Sprintf("volume%v", volumeIndex+1)
892+
// In-line volumes can be only filesystem, not block.
893+
volumeMounts = append(volumeMounts, v1.VolumeMount{Name: volumename, MountPath: "/mnt/" + volumename})
894+
volumes[volumeIndex] = v1.Volume{Name: volumename, VolumeSource: *src}
895+
volumeIndex++
887896
}
897+
888898
podSpec.Spec.Containers[0].VolumeMounts = volumeMounts
889899
podSpec.Spec.Containers[0].VolumeDevices = volumeDevices
890900
podSpec.Spec.Volumes = volumes
@@ -933,13 +943,13 @@ func CreateNginxPod(client clientset.Interface, namespace string, nodeSelector m
933943
}
934944

935945
// CreateSecPod creates security pod with given claims
936-
func CreateSecPod(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64, timeout time.Duration) (*v1.Pod, error) {
937-
return CreateSecPodWithNodeSelection(client, namespace, pvclaims, isPrivileged, command, hostIPC, hostPID, seLinuxLabel, fsGroup, NodeSelection{}, timeout)
946+
func CreateSecPod(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, inlineVolumeSources []*v1.VolumeSource, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64, timeout time.Duration) (*v1.Pod, error) {
947+
return CreateSecPodWithNodeSelection(client, namespace, pvclaims, inlineVolumeSources, isPrivileged, command, hostIPC, hostPID, seLinuxLabel, fsGroup, NodeSelection{}, timeout)
938948
}
939949

940950
// CreateSecPodWithNodeSelection creates security pod with given claims
941-
func CreateSecPodWithNodeSelection(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64, node NodeSelection, timeout time.Duration) (*v1.Pod, error) {
942-
pod := MakeSecPod(namespace, pvclaims, isPrivileged, command, hostIPC, hostPID, seLinuxLabel, fsGroup)
951+
func CreateSecPodWithNodeSelection(client clientset.Interface, namespace string, pvclaims []*v1.PersistentVolumeClaim, inlineVolumeSources []*v1.VolumeSource, isPrivileged bool, command string, hostIPC bool, hostPID bool, seLinuxLabel *v1.SELinuxOptions, fsGroup *int64, node NodeSelection, timeout time.Duration) (*v1.Pod, error) {
952+
pod := MakeSecPod(namespace, pvclaims, inlineVolumeSources, isPrivileged, command, hostIPC, hostPID, seLinuxLabel, fsGroup)
943953
// Setting node
944954
pod.Spec.NodeName = node.Name
945955
pod.Spec.NodeSelector = node.Selector

test/e2e/framework/util.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,6 +2670,36 @@ func GetHostExternalAddress(client clientset.Interface, p *v1.Pod) (externalAddr
26702670
return
26712671
}
26722672

2673+
// GetHostAddress gets the node for a pod and returns the first
2674+
// address. Returns an error if the node the pod is on doesn't have an
2675+
// address.
2676+
func GetHostAddress(client clientset.Interface, p *v1.Pod) (string, error) {
2677+
node, err := client.CoreV1().Nodes().Get(p.Spec.NodeName, metav1.GetOptions{})
2678+
if err != nil {
2679+
return "", err
2680+
}
2681+
// Try externalAddress first
2682+
for _, address := range node.Status.Addresses {
2683+
if address.Type == v1.NodeExternalIP {
2684+
if address.Address != "" {
2685+
return address.Address, nil
2686+
}
2687+
}
2688+
}
2689+
// If no externalAddress found, try internalAddress
2690+
for _, address := range node.Status.Addresses {
2691+
if address.Type == v1.NodeInternalIP {
2692+
if address.Address != "" {
2693+
return address.Address, nil
2694+
}
2695+
}
2696+
}
2697+
2698+
// If not found, return error
2699+
return "", fmt.Errorf("No address for pod %v on node %v",
2700+
p.Name, p.Spec.NodeName)
2701+
}
2702+
26732703
type extractRT struct {
26742704
http.Header
26752705
}

test/e2e/storage/csi_volumes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var csiTestSuites = []func() testsuites.TestSuite{
4949
testsuites.InitProvisioningTestSuite,
5050
testsuites.InitSnapshottableTestSuite,
5151
testsuites.InitMultiVolumeTestSuite,
52+
testsuites.InitDisruptiveTestSuite,
5253
}
5354

5455
// This executes testSuites for csi volumes.

test/e2e/storage/external/external.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var csiTestSuites = []func() testsuites.TestSuite{
4949
testsuites.InitVolumeModeTestSuite,
5050
testsuites.InitVolumesTestSuite,
5151
testsuites.InitVolumeExpandTestSuite,
52+
testsuites.InitDisruptiveTestSuite,
5253
}
5354

5455
func init() {

test/e2e/storage/generic_persistent_volume-disruptive.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ func createPodPVCFromSC(f *framework.Framework, c clientset.Interface, ns string
102102
framework.ExpectEqual(len(pvs), 1)
103103

104104
ginkgo.By("Creating a pod with dynamically provisioned volume")
105-
pod, err := framework.CreateNginxPod(c, ns, nil, pvcClaims)
105+
pod, err := framework.CreateSecPod(c, ns, pvcClaims, nil,
106+
false, "", false, false, framework.SELinuxLabel,
107+
nil, framework.PodStartTimeout)
106108
framework.ExpectNoError(err, "While creating pods for kubelet restart test")
107109
return pod, pvc, pvs[0]
108110
}

test/e2e/storage/in_tree_volumes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ var testSuites = []func() testsuites.TestSuite{
5757
testsuites.InitProvisioningTestSuite,
5858
testsuites.InitMultiVolumeTestSuite,
5959
testsuites.InitVolumeExpandTestSuite,
60+
testsuites.InitDisruptiveTestSuite,
6061
}
6162

6263
// This executes testSuites for in-tree volumes.

test/e2e/storage/persistent_volumes-local.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
555555
pvcs = append(pvcs, pvc)
556556
}
557557

558-
pod := framework.MakeSecPod(config.ns, pvcs, false, "sleep 1", false, false, selinuxLabel, nil)
558+
pod := framework.MakeSecPod(config.ns, pvcs, nil, false, "sleep 1", false, false, selinuxLabel, nil)
559559
pod, err := config.client.CoreV1().Pods(config.ns).Create(pod)
560560
framework.ExpectNoError(err)
561561
pods[pod.Name] = pod
@@ -648,7 +648,7 @@ var _ = utils.SIGDescribe("PersistentVolumes-local ", func() {
648648
framework.ExpectNoError(err)
649649
ginkgo.By(fmt.Sprintf("Create %d pods to use this PVC", count))
650650
for i := 0; i < count; i++ {
651-
pod := framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{pvc}, false, "", false, false, selinuxLabel, nil)
651+
pod := framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{pvc}, nil, false, "", false, false, selinuxLabel, nil)
652652
pod, err := config.client.CoreV1().Pods(config.ns).Create(pod)
653653
framework.ExpectNoError(err)
654654
pods[pod.Name] = pod
@@ -939,7 +939,7 @@ func createLocalPVCsPVs(config *localTestConfig, volumes []*localTestVolume, mod
939939
}
940940

941941
func makeLocalPodWithNodeAffinity(config *localTestConfig, volume *localTestVolume, nodeName string) (pod *v1.Pod) {
942-
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, false, "", false, false, selinuxLabel, nil)
942+
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, nil, false, "", false, false, selinuxLabel, nil)
943943
if pod == nil {
944944
return
945945
}
@@ -965,7 +965,7 @@ func makeLocalPodWithNodeAffinity(config *localTestConfig, volume *localTestVolu
965965
}
966966

967967
func makeLocalPodWithNodeSelector(config *localTestConfig, volume *localTestVolume, nodeName string) (pod *v1.Pod) {
968-
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, false, "", false, false, selinuxLabel, nil)
968+
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, nil, false, "", false, false, selinuxLabel, nil)
969969
if pod == nil {
970970
return
971971
}
@@ -977,7 +977,7 @@ func makeLocalPodWithNodeSelector(config *localTestConfig, volume *localTestVolu
977977
}
978978

979979
func makeLocalPodWithNodeName(config *localTestConfig, volume *localTestVolume, nodeName string) (pod *v1.Pod) {
980-
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, false, "", false, false, selinuxLabel, nil)
980+
pod = framework.MakeSecPod(config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, nil, false, "", false, false, selinuxLabel, nil)
981981
if pod == nil {
982982
return
983983
}
@@ -987,7 +987,7 @@ func makeLocalPodWithNodeName(config *localTestConfig, volume *localTestVolume,
987987

988988
func createLocalPod(config *localTestConfig, volume *localTestVolume, fsGroup *int64) (*v1.Pod, error) {
989989
ginkgo.By("Creating a pod")
990-
return framework.CreateSecPod(config.client, config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, false, "", false, false, selinuxLabel, fsGroup, framework.PodStartShortTimeout)
990+
return framework.CreateSecPod(config.client, config.ns, []*v1.PersistentVolumeClaim{volume.pvc}, nil, false, "", false, false, selinuxLabel, fsGroup, framework.PodStartShortTimeout)
991991
}
992992

993993
func createWriteCmd(testDir string, testFile string, writeTestFileContent string, volumeType localVolumeType) string {

test/e2e/storage/testsuites/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go_library(
44
name = "go_default_library",
55
srcs = [
66
"base.go",
7+
"disruptive.go",
78
"driveroperations.go",
89
"ephemeral.go",
910
"multivolume.go",

0 commit comments

Comments
 (0)