Merge pull request #71276 from jingxu97/Oct/uncertain
Handle failed attach operation leave uncertain volume attach state
This commit is contained in:
@@ -46,9 +46,19 @@ 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
|
||||
// for the first attach call. The following call will return sucesssfully.
|
||||
UncertainAttachNode = "uncertain-attach-node"
|
||||
// The node is marked as timeout. The attach operation will always fail and return timeout error
|
||||
// but the operation is actually succeeded.
|
||||
TimeoutAttachNode = "timeout-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 +283,20 @@ var _ DeviceMountableVolumePlugin = &FakeVolumePlugin{}
|
||||
var _ FSResizableVolumePlugin = &FakeVolumePlugin{}
|
||||
|
||||
func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume {
|
||||
volumeList := *list
|
||||
if list != nil && len(volumeList) > 0 {
|
||||
volume := volumeList[0]
|
||||
volume.Lock()
|
||||
defer volume.Unlock()
|
||||
volume.WaitForAttachHook = plugin.WaitForAttachHook
|
||||
volume.UnmountDeviceHook = plugin.UnmountDeviceHook
|
||||
return volume
|
||||
}
|
||||
volume := &FakeVolume{
|
||||
WaitForAttachHook: plugin.WaitForAttachHook,
|
||||
UnmountDeviceHook: plugin.UnmountDeviceHook,
|
||||
}
|
||||
volume.VolumesAttached = make(map[string]types.NodeName)
|
||||
*list = append(*list, volume)
|
||||
return volume
|
||||
}
|
||||
@@ -333,6 +353,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
|
||||
@@ -350,6 +372,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
|
||||
@@ -368,6 +392,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
|
||||
}
|
||||
@@ -388,6 +414,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
|
||||
@@ -428,7 +456,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) {
|
||||
@@ -657,6 +694,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)
|
||||
@@ -677,6 +715,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,
|
||||
@@ -822,6 +874,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 "/dev/vdb-test", nil
|
||||
}
|
||||
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 || nodeName == TimeoutAttachNode {
|
||||
return "", fmt.Errorf("Timed out to attach volume %q to node %q", volumeName, nodeName)
|
||||
}
|
||||
return "/dev/vdb-test", nil
|
||||
}
|
||||
|
||||
@@ -871,6 +942,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
|
||||
}
|
||||
|
||||
@@ -1037,7 +1112,7 @@ func VerifyAttachCallCount(
|
||||
fakeVolumePlugin *FakeVolumePlugin) error {
|
||||
for _, attacher := range fakeVolumePlugin.GetAttachers() {
|
||||
actualCallCount := attacher.GetAttachCallCount()
|
||||
if actualCallCount == expectedAttachCallCount {
|
||||
if actualCallCount >= expectedAttachCallCount {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1070,7 +1145,7 @@ func VerifyWaitForAttachCallCount(
|
||||
fakeVolumePlugin *FakeVolumePlugin) error {
|
||||
for _, attacher := range fakeVolumePlugin.GetAttachers() {
|
||||
actualCallCount := attacher.GetWaitForAttachCallCount()
|
||||
if actualCallCount == expectedWaitForAttachCallCount {
|
||||
if actualCallCount >= expectedWaitForAttachCallCount {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +1178,7 @@ func VerifyMountDeviceCallCount(
|
||||
fakeVolumePlugin *FakeVolumePlugin) error {
|
||||
for _, attacher := range fakeVolumePlugin.GetAttachers() {
|
||||
actualCallCount := attacher.GetMountDeviceCallCount()
|
||||
if actualCallCount == expectedMountDeviceCallCount {
|
||||
if actualCallCount >= expectedMountDeviceCallCount {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user