Handle failed attach operation leave uncertain volume attach state

This commit adds the unit tests for the PR. It also includes some files
that are affected by the function name changes.
This commit is contained in:
Jing Xu
2018-10-08 14:37:11 -07:00
parent 47331cf0a2
commit 562d0fea53
12 changed files with 598 additions and 112 deletions

View File

@@ -46,9 +46,16 @@ import (
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
)
// A hook specified in storage class to indicate it's provisioning
// is expected to fail.
const ExpectProvisionFailureKey = "expect-provision-failure"
const (
// A hook specified in storage class to indicate it's provisioning
// is expected to fail.
ExpectProvisionFailureKey = "expect-provision-failure"
// The node is marked as uncertain. The attach operation will fail and return timeout error
// but the operation is actually succeeded.
UncertainAttachNode = "uncertain-attach-node"
// The node is marked as multi-attach which means it is allowed to attach the volume to multiple nodes.
MultiAttachNode = "multi-attach-node"
)
// fakeVolumeHost is useful for testing volume plugins.
type fakeVolumeHost struct {
@@ -273,10 +280,15 @@ var _ DeviceMountableVolumePlugin = &FakeVolumePlugin{}
var _ FSResizableVolumePlugin = &FakeVolumePlugin{}
func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume {
volumeList := *list
if list != nil && len(volumeList) > 0 {
return volumeList[0]
}
volume := &FakeVolume{
WaitForAttachHook: plugin.WaitForAttachHook,
UnmountDeviceHook: plugin.UnmountDeviceHook,
}
volume.VolumesAttached = make(map[string]types.NodeName)
*list = append(*list, volume)
return volume
}
@@ -329,6 +341,8 @@ func (plugin *FakeVolumePlugin) NewMounter(spec *Spec, pod *v1.Pod, opts VolumeO
plugin.Lock()
defer plugin.Unlock()
volume := plugin.getFakeVolume(&plugin.Mounters)
volume.Lock()
defer volume.Unlock()
volume.PodUID = pod.UID
volume.VolName = spec.Name()
volume.Plugin = plugin
@@ -346,6 +360,8 @@ func (plugin *FakeVolumePlugin) NewUnmounter(volName string, podUID types.UID) (
plugin.Lock()
defer plugin.Unlock()
volume := plugin.getFakeVolume(&plugin.Unmounters)
volume.Lock()
defer volume.Unlock()
volume.PodUID = podUID
volume.VolName = volName
volume.Plugin = plugin
@@ -364,6 +380,8 @@ func (plugin *FakeVolumePlugin) NewBlockVolumeMapper(spec *Spec, pod *v1.Pod, op
plugin.Lock()
defer plugin.Unlock()
volume := plugin.getFakeVolume(&plugin.BlockVolumeMappers)
volume.Lock()
defer volume.Unlock()
if pod != nil {
volume.PodUID = pod.UID
}
@@ -384,6 +402,8 @@ func (plugin *FakeVolumePlugin) NewBlockVolumeUnmapper(volName string, podUID ty
plugin.Lock()
defer plugin.Unlock()
volume := plugin.getFakeVolume(&plugin.BlockVolumeUnmappers)
volume.Lock()
defer volume.Unlock()
volume.PodUID = podUID
volume.VolName = volName
volume.Plugin = plugin
@@ -424,7 +444,16 @@ func (plugin *FakeVolumePlugin) NewDetacher() (Detacher, error) {
plugin.Lock()
defer plugin.Unlock()
plugin.NewDetacherCallCount = plugin.NewDetacherCallCount + 1
return plugin.getFakeVolume(&plugin.Detachers), nil
detacher := plugin.getFakeVolume(&plugin.Detachers)
attacherList := plugin.Attachers
if attacherList != nil && len(attacherList) > 0 {
detacherList := plugin.Detachers
if detacherList != nil && len(detacherList) > 0 {
detacherList[0].VolumesAttached = attacherList[0].VolumesAttached
}
}
return detacher, nil
}
func (plugin *FakeVolumePlugin) NewDeviceUnmounter() (DeviceUnmounter, error) {
@@ -557,6 +586,7 @@ type FakeVolume struct {
VolName string
Plugin *FakeVolumePlugin
MetricsNil
VolumesAttached map[string]types.NodeName
// Add callbacks as needed
WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error)
@@ -577,6 +607,20 @@ type FakeVolume struct {
PodDeviceMapPathCallCount int
}
func getUniqueVolumeName(spec *Spec) (string, error) {
var volumeName string
if spec.Volume != nil && spec.Volume.GCEPersistentDisk != nil {
volumeName = spec.Volume.GCEPersistentDisk.PDName
} else if spec.PersistentVolume != nil &&
spec.PersistentVolume.Spec.GCEPersistentDisk != nil {
volumeName = spec.PersistentVolume.Spec.GCEPersistentDisk.PDName
}
if volumeName == "" {
volumeName = spec.Name()
}
return volumeName, nil
}
func (_ *FakeVolume) GetAttributes() Attributes {
return Attributes{
ReadOnly: false,
@@ -722,6 +766,25 @@ func (fv *FakeVolume) Attach(spec *Spec, nodeName types.NodeName) (string, error
fv.Lock()
defer fv.Unlock()
fv.AttachCallCount++
volumeName, err := getUniqueVolumeName(spec)
if err != nil {
return "", err
}
volumeNode, exist := fv.VolumesAttached[volumeName]
if exist {
if nodeName == UncertainAttachNode {
return "", fmt.Errorf("Timed out to attach volume %q to node %q", volumeName, nodeName)
}
if volumeNode == nodeName || volumeNode == MultiAttachNode || nodeName == MultiAttachNode {
return "/dev/vdb-test", nil
}
return "", fmt.Errorf("volume %q trying to attach to node %q is already attached to node %q", volumeName, nodeName, volumeNode)
}
fv.VolumesAttached[volumeName] = nodeName
if nodeName == UncertainAttachNode {
return "", fmt.Errorf("Timed out to attach volume %q to node %q", volumeName, nodeName)
}
return "/dev/vdb-test", nil
}
@@ -771,6 +834,10 @@ func (fv *FakeVolume) Detach(volumeName string, nodeName types.NodeName) error {
fv.Lock()
defer fv.Unlock()
fv.DetachCallCount++
if _, exist := fv.VolumesAttached[volumeName]; !exist {
return fmt.Errorf("Trying to detach volume %q that is not attached to the node %q", volumeName, nodeName)
}
delete(fv.VolumesAttached, volumeName)
return nil
}
@@ -937,7 +1004,7 @@ func VerifyAttachCallCount(
fakeVolumePlugin *FakeVolumePlugin) error {
for _, attacher := range fakeVolumePlugin.GetAttachers() {
actualCallCount := attacher.GetAttachCallCount()
if actualCallCount == expectedAttachCallCount {
if actualCallCount >= expectedAttachCallCount {
return nil
}
}
@@ -970,7 +1037,7 @@ func VerifyWaitForAttachCallCount(
fakeVolumePlugin *FakeVolumePlugin) error {
for _, attacher := range fakeVolumePlugin.GetAttachers() {
actualCallCount := attacher.GetWaitForAttachCallCount()
if actualCallCount == expectedWaitForAttachCallCount {
if actualCallCount >= expectedWaitForAttachCallCount {
return nil
}
}
@@ -1003,7 +1070,7 @@ func VerifyMountDeviceCallCount(
fakeVolumePlugin *FakeVolumePlugin) error {
for _, attacher := range fakeVolumePlugin.GetAttachers() {
actualCallCount := attacher.GetMountDeviceCallCount()
if actualCallCount == expectedMountDeviceCallCount {
if actualCallCount >= expectedMountDeviceCallCount {
return nil
}
}