Skip to content

Commit

Permalink
Merge pull request kubernetes#21675 from gnufied/fix-device-path-empty
Browse files Browse the repository at this point in the history
UPSTREAM: 71074: fix device path being empty

Origin-commit: f129e1f66f6da7a33f66d8382ab6b3341eccdf48
  • Loading branch information
k8s-publishing-bot committed Jan 29, 2019
2 parents d0b8cfd + 28a9bab commit b21b3d9
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 3 deletions.
4 changes: 3 additions & 1 deletion pkg/kubelet/volumemanager/cache/actual_state_of_world.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,9 @@ func (asw *actualStateOfWorld) SetVolumeGloballyMounted(

volumeObj.globallyMounted = globallyMounted
volumeObj.deviceMountPath = deviceMountPath
volumeObj.devicePath = devicePath
if devicePath != "" {
volumeObj.devicePath = devicePath
}
asw.attachedVolumes[volumeName] = volumeObj
return nil
}
Expand Down
1 change: 1 addition & 0 deletions pkg/kubelet/volumemanager/reconciler/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ go_test(
"//pkg/volume/util:go_default_library",
"//pkg/volume/util/operationexecutor:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
Expand Down
96 changes: 95 additions & 1 deletion pkg/kubelet/volumemanager/reconciler/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"
"time"

"github.com/golang/glog"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
Expand Down Expand Up @@ -1129,7 +1130,7 @@ func createTestClient() *fake.Clientset {
VolumesAttached: []v1.AttachedVolume{
{
Name: "fake-plugin/fake-device1",
DevicePath: "fake/path",
DevicePath: "/fake/path",
},
}},
}, nil
Expand Down Expand Up @@ -1170,3 +1171,96 @@ func createtestClientWithPVPVC(pv *v1.PersistentVolume, pvc *v1.PersistentVolume
})
return fakeClient
}

func Test_Run_Positive_VolumeMountControllerAttachEnabledRace(t *testing.T) {
// Arrange
volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)

dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr)
kubeClient := createTestClient()
fakeRecorder := &record.FakeRecorder{}
fakeHandler := volumetesting.NewBlockVolumePathHandler()
oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
kubeClient,
volumePluginMgr,
fakeRecorder,
false, /* checkNodeCapabilitiesBeforeMount */
fakeHandler))
reconciler := NewReconciler(
kubeClient,
true, /* controllerAttachDetachEnabled */
reconcilerLoopSleepDuration,
reconcilerSyncStatesSleepPeriod,
waitForAttachTimeout,
nodeName,
dsw,
asw,
hasAddedPods,
oex,
&mount.FakeMounter{},
volumePluginMgr,
kubeletPodsDir)
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod1",
UID: "pod1uid",
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{
Name: "volume-name",
VolumeSource: v1.VolumeSource{
GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
PDName: "fake-device1",
},
},
},
},
},
}

// Some steps are executes out of order in callbacks, follow the numbers.

// 1. Add a volume to DSW and wait until it's mounted
volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
podName := util.GetUniquePodName(pod)
generatedVolumeName, err := dsw.AddPodToVolume(
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName})

if err != nil {
t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
}
runReconciler(reconciler)
waitForMount(t, fakePlugin, generatedVolumeName, asw)

finished := make(chan interface{})
fakePlugin.UnmountDeviceHook = func(mountPath string) error {
// Act:
// 3. While a volume is being unmounted, add it back to the desired state of world
glog.Infof("UnmountDevice called")
generatedVolumeName, err = dsw.AddPodToVolume(
podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */)
dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{generatedVolumeName})
return nil
}

fakePlugin.WaitForAttachHook = func(spec *volume.Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) {
// Assert
// 4. When the volume is mounted again, expect that UnmountDevice operation did not clear devicePath
if devicePath == "" {
t.Errorf("Expected WaitForAttach called with devicePath from Node.Status")
close(finished)
return "", fmt.Errorf("Expected devicePath from Node.Status")
}
close(finished)
return devicePath, nil
}

// 2. Delete the volume from DSW (and wait for callbacks)
dsw.DeletePodFromVolume(podName, generatedVolumeName)

<-finished
waitForMount(t, fakePlugin, generatedVolumeName, asw)
}
19 changes: 18 additions & 1 deletion pkg/volume/testing/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ type FakeVolumePlugin struct {
NewAttacherCallCount int
NewDetacherCallCount int

// Add callbacks as needed
WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error)
UnmountDeviceHook func(globalMountPath string) error

Mounters []*FakeVolume
Unmounters []*FakeVolume
Attachers []*FakeVolume
Expand All @@ -247,7 +251,10 @@ var _ ProvisionableVolumePlugin = &FakeVolumePlugin{}
var _ AttachableVolumePlugin = &FakeVolumePlugin{}

func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume {
volume := &FakeVolume{}
volume := &FakeVolume{
WaitForAttachHook: plugin.WaitForAttachHook,
UnmountDeviceHook: plugin.UnmountDeviceHook,
}
*list = append(*list, volume)
return volume
}
Expand Down Expand Up @@ -509,6 +516,10 @@ type FakeVolume struct {
Plugin *FakeVolumePlugin
MetricsNil

// Add callbacks as needed
WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error)
UnmountDeviceHook func(globalMountPath string) error

SetUpCallCount int
TearDownCallCount int
AttachCallCount int
Expand Down Expand Up @@ -682,6 +693,9 @@ func (fv *FakeVolume) WaitForAttach(spec *Spec, devicePath string, pod *v1.Pod,
fv.Lock()
defer fv.Unlock()
fv.WaitForAttachCallCount++
if fv.WaitForAttachHook != nil {
return fv.WaitForAttachHook(spec, devicePath, pod, spectimeout)
}
return "/dev/sdb", nil
}

Expand Down Expand Up @@ -734,6 +748,9 @@ func (fv *FakeVolume) UnmountDevice(globalMountPath string) error {
fv.Lock()
defer fv.Unlock()
fv.UnmountDeviceCallCount++
if fv.UnmountDeviceHook != nil {
return fv.UnmountDeviceHook(globalMountPath)
}
return nil
}

Expand Down

0 comments on commit b21b3d9

Please sign in to comment.