From a795f3de88aa47babbf13b5329df7640dd48915a Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 5 Sep 2019 21:44:17 -0400 Subject: [PATCH 01/15] Add code for introducing uncertain state of mounts Add a comment about volumestate --- pkg/kubelet/volumemanager/cache/BUILD | 1 + .../cache/actual_state_of_world.go | 134 +++++++++++------- .../cache/actual_state_of_world_test.go | 133 ++++++++++++++--- pkg/kubelet/volumemanager/metrics/BUILD | 1 + .../volumemanager/metrics/metrics_test.go | 13 +- pkg/kubelet/volumemanager/populator/BUILD | 1 + .../desired_state_of_world_populator_test.go | 13 +- .../volumemanager/reconciler/reconciler.go | 40 ++++-- pkg/kubelet/volumemanager/volume_manager.go | 1 + .../operationexecutor/operation_executor.go | 42 +++++- .../operationexecutor/operation_generator.go | 42 +++--- 11 files changed, 316 insertions(+), 105 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/BUILD b/pkg/kubelet/volumemanager/cache/BUILD index 76a34e9f614..cfe44cf64a9 100644 --- a/pkg/kubelet/volumemanager/cache/BUILD +++ b/pkg/kubelet/volumemanager/cache/BUILD @@ -40,6 +40,7 @@ go_test( "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/operationexecutor:go_default_library", "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 08fe393e5a2..5d89aa5febb 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -59,7 +59,7 @@ type ActualStateOfWorld interface { // volume, reset the pod's remountRequired value. // If a volume with the name volumeName does not exist in the list of // attached volumes, an error is returned. - AddPodToVolume(podName volumetypes.UniquePodName, podUID types.UID, volumeName v1.UniqueVolumeName, mounter volume.Mounter, blockVolumeMapper volume.BlockVolumeMapper, outerVolumeSpecName string, volumeGidValue string, volumeSpec *volume.Spec) error + AddPodToVolume(operationexecutor.MarkVolumeMountedOpts) error // MarkRemountRequired marks each volume that is successfully attached and // mounted for the specified pod as requiring remount (if the plugin for the @@ -68,13 +68,13 @@ type ActualStateOfWorld interface { // pod update. MarkRemountRequired(podName volumetypes.UniquePodName) - // SetVolumeGloballyMounted sets the GloballyMounted value for the given - // volume. When set to true this value indicates that the volume is mounted - // to the underlying device at a global mount point. This global mount point - // must unmounted prior to detach. + // SetDeviceMountState sets device mount state for the given volume. When deviceMountState is set to DeviceGloballyMounted + // then device is mounted at a global mount point. When it is set to DeviceMountUncertain then also it means volume + // MAY be globally mounted at a global mount point. In both cases - the volume must be unmounted from + // global mount point prior to detach. // If a volume with the name volumeName does not exist in the list of // attached volumes, an error is returned. - SetVolumeGloballyMounted(volumeName v1.UniqueVolumeName, globallyMounted bool, devicePath, deviceMountPath string) error + SetDeviceMountState(volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error // DeletePodFromVolume removes the given pod from the given volume in the // cache indicating the volume has been successfully unmounted from the pod. @@ -127,6 +127,10 @@ type ActualStateOfWorld interface { // actual state of the world. GetMountedVolumes() []MountedVolume + // GetAllMountedVolumes returns list of all mounted volumes including + // those that are in VolumeMounted state and VolumeMountUncertain state. + GetAllMountedVolumes() []MountedVolume + // GetMountedVolumesForPod generates and returns a list of volumes that are // successfully attached and mounted for the specified pod based on the // current actual state of the world. @@ -165,10 +169,13 @@ type MountedVolume struct { type AttachedVolume struct { operationexecutor.AttachedVolume - // GloballyMounted indicates that the volume is mounted to the underlying - // device at a global mount point. This global mount point must unmounted - // prior to detach. - GloballyMounted bool + // DeviceMountState indicates if device has been globally mounted or is not. + DeviceMountState operationexecutor.DeviceMountState +} + +func (av AttachedVolume) DeviceMayBeMounted() bool { + return av.DeviceMountState == operationexecutor.DeviceGloballyMounted || + av.DeviceMountState == operationexecutor.DeviceMountUncertain } // NewActualStateOfWorld returns a new instance of ActualStateOfWorld. @@ -250,6 +257,10 @@ type attachedVolume struct { // prior to detach. globallyMounted bool + // deviceMountState stores information that tells us if device is mounted + // globally or not + deviceMountState operationexecutor.DeviceMountState + // devicePath contains the path on the node where the volume is attached for // attachable volumes devicePath string @@ -301,6 +312,12 @@ type mountedPod struct { // fsResizeRequired indicates the underlying volume has been successfully // mounted to this pod but its size has been expanded after that. fsResizeRequired bool + + // volumeMounted stores state of volume mount for the pod. if it is: + // - VolumeMounted: means volume for pod has been successfully mounted + // - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted + // - VolumeNotMounted: means volume for pod has not been mounted + volumeMounted operationexecutor.VolumeMountState } func (asw *actualStateOfWorld) MarkVolumeAsAttached( @@ -318,24 +335,8 @@ func (asw *actualStateOfWorld) MarkVolumeAsDetached( asw.DeleteVolume(volumeName) } -func (asw *actualStateOfWorld) MarkVolumeAsMounted( - podName volumetypes.UniquePodName, - podUID types.UID, - volumeName v1.UniqueVolumeName, - mounter volume.Mounter, - blockVolumeMapper volume.BlockVolumeMapper, - outerVolumeSpecName string, - volumeGidValue string, - volumeSpec *volume.Spec) error { - return asw.AddPodToVolume( - podName, - podUID, - volumeName, - mounter, - blockVolumeMapper, - outerVolumeSpecName, - volumeGidValue, - volumeSpec) +func (asw *actualStateOfWorld) MarkVolumeAsMounted(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { + return asw.AddPodToVolume(markVolumeOpts) } func (asw *actualStateOfWorld) AddVolumeToReportAsAttached(volumeName v1.UniqueVolumeName, nodeName types.NodeName) { @@ -354,12 +355,17 @@ func (asw *actualStateOfWorld) MarkVolumeAsUnmounted( func (asw *actualStateOfWorld) MarkDeviceAsMounted( volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error { - return asw.SetVolumeGloballyMounted(volumeName, true /* globallyMounted */, devicePath, deviceMountPath) + return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceGloballyMounted, devicePath, deviceMountPath) +} + +func (asw *actualStateOfWorld) MarkDeviceAsUncertain( + volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error { + return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath) } func (asw *actualStateOfWorld) MarkDeviceAsUnmounted( volumeName v1.UniqueVolumeName) error { - return asw.SetVolumeGloballyMounted(volumeName, false /* globallyMounted */, "", "") + return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "") } // addVolume adds the given volume to the cache indicating the specified @@ -405,7 +411,7 @@ func (asw *actualStateOfWorld) addVolume( mountedPods: make(map[volumetypes.UniquePodName]mountedPod), pluginName: volumePlugin.GetPluginName(), pluginIsAttachable: pluginIsAttachable, - globallyMounted: false, + deviceMountState: operationexecutor.DeviceNotMounted, devicePath: devicePath, } } else { @@ -420,15 +426,15 @@ func (asw *actualStateOfWorld) addVolume( return nil } -func (asw *actualStateOfWorld) AddPodToVolume( - podName volumetypes.UniquePodName, - podUID types.UID, - volumeName v1.UniqueVolumeName, - mounter volume.Mounter, - blockVolumeMapper volume.BlockVolumeMapper, - outerVolumeSpecName string, - volumeGidValue string, - volumeSpec *volume.Spec) error { +func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { + podName := markVolumeOpts.PodName + podUID := markVolumeOpts.PodUID + volumeName := markVolumeOpts.VolumeName + mounter := markVolumeOpts.Mounter + blockVolumeMapper := markVolumeOpts.BlockVolumeMapper + outerVolumeSpecName := markVolumeOpts.OuterVolumeSpecName + volumeGidValue := markVolumeOpts.VolumeGidVolume + volumeSpec := markVolumeOpts.VolumeSpec asw.Lock() defer asw.Unlock() @@ -449,13 +455,13 @@ func (asw *actualStateOfWorld) AddPodToVolume( outerVolumeSpecName: outerVolumeSpecName, volumeGidValue: volumeGidValue, volumeSpec: volumeSpec, + volumeMounted: markVolumeOpts.VolumeMountState, } } // If pod exists, reset remountRequired value podObj.remountRequired = false asw.attachedVolumes[volumeName].mountedPods[podName] = podObj - return nil } @@ -554,8 +560,8 @@ func (asw *actualStateOfWorld) MarkFSResizeRequired( } } -func (asw *actualStateOfWorld) SetVolumeGloballyMounted( - volumeName v1.UniqueVolumeName, globallyMounted bool, devicePath, deviceMountPath string) error { +func (asw *actualStateOfWorld) SetDeviceMountState( + volumeName v1.UniqueVolumeName, deviceMountState operationexecutor.DeviceMountState, devicePath, deviceMountPath string) error { asw.Lock() defer asw.Unlock() @@ -566,7 +572,7 @@ func (asw *actualStateOfWorld) SetVolumeGloballyMounted( volumeName) } - volumeObj.globallyMounted = globallyMounted + volumeObj.deviceMountState = deviceMountState volumeObj.deviceMountPath = deviceMountPath if devicePath != "" { volumeObj.devicePath = devicePath @@ -668,9 +674,29 @@ func (asw *actualStateOfWorld) GetMountedVolumes() []MountedVolume { mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { for _, podObj := range volumeObj.mountedPods { - mountedVolume = append( - mountedVolume, - getMountedVolume(&podObj, &volumeObj)) + if podObj.volumeMounted == operationexecutor.VolumeMounted { + mountedVolume = append( + mountedVolume, + getMountedVolume(&podObj, &volumeObj)) + } + } + } + return mountedVolume +} + +func (asw *actualStateOfWorld) GetAllMountedVolumes() []MountedVolume { + asw.RLock() + defer asw.RUnlock() + mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) + for _, volumeObj := range asw.attachedVolumes { + for _, podObj := range volumeObj.mountedPods { + if podObj.volumeMounted == operationexecutor.VolumeMounted || + podObj.volumeMounted == operationexecutor.VolumeMountUncertain { + mountedVolume = append( + mountedVolume, + getMountedVolume(&podObj, &volumeObj)) + } + } } @@ -683,10 +709,12 @@ func (asw *actualStateOfWorld) GetMountedVolumesForPod( defer asw.RUnlock() mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { - if podObj, podExists := volumeObj.mountedPods[podName]; podExists { - mountedVolume = append( - mountedVolume, - getMountedVolume(&podObj, &volumeObj)) + for mountedPodName, podObj := range volumeObj.mountedPods { + if mountedPodName == podName && podObj.volumeMounted == operationexecutor.VolumeMounted { + mountedVolume = append( + mountedVolume, + getMountedVolume(&podObj, &volumeObj)) + } } } @@ -699,7 +727,7 @@ func (asw *actualStateOfWorld) GetGloballyMountedVolumes() []AttachedVolume { globallyMountedVolumes := make( []AttachedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { - if volumeObj.globallyMounted { + if volumeObj.deviceMountState == operationexecutor.DeviceGloballyMounted { globallyMountedVolumes = append( globallyMountedVolumes, asw.newAttachedVolume(&volumeObj)) @@ -749,7 +777,7 @@ func (asw *actualStateOfWorld) newAttachedVolume( DevicePath: attachedVolume.devicePath, DeviceMountPath: attachedVolume.deviceMountPath, PluginName: attachedVolume.pluginName}, - GloballyMounted: attachedVolume.globallyMounted, + DeviceMountState: attachedVolume.deviceMountState, } } diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go index fd703f8d3df..88ae2e283e8 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/kubernetes/pkg/volume" volumetesting "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/kubernetes/pkg/volume/util" + "k8s.io/kubernetes/pkg/volume/util/operationexecutor" volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) @@ -220,9 +221,16 @@ func Test_AddPodToVolume_Positive_ExistingVolumeNewNode(t *testing.T) { } // Act - err = asw.AddPodToVolume( - podName, pod.UID, generatedVolumeName, mounter, mapper, volumeSpec.Name(), "" /* volumeGidValue */, volumeSpec) - + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName, + PodUID: pod.UID, + VolumeName: generatedVolumeName, + Mounter: mounter, + BlockVolumeMapper: mapper, + OuterVolumeSpecName: volumeSpec.Name(), + VolumeSpec: volumeSpec, + } + err = asw.AddPodToVolume(markVolumeOpts) // Assert if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) @@ -287,16 +295,22 @@ func Test_AddPodToVolume_Positive_ExistingVolumeExistingNode(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - err = asw.AddPodToVolume( - podName, pod.UID, generatedVolumeName, mounter, mapper, volumeSpec.Name(), "" /* volumeGidValue */, volumeSpec) + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName, + PodUID: pod.UID, + VolumeName: generatedVolumeName, + Mounter: mounter, + BlockVolumeMapper: mapper, + OuterVolumeSpecName: volumeSpec.Name(), + VolumeSpec: volumeSpec, + } + err = asw.AddPodToVolume(markVolumeOpts) if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) } // Act - err = asw.AddPodToVolume( - podName, pod.UID, generatedVolumeName, mounter, mapper, volumeSpec.Name(), "" /* volumeGidValue */, volumeSpec) - + err = asw.AddPodToVolume(markVolumeOpts) // Assert if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) @@ -388,8 +402,16 @@ func Test_AddTwoPodsToVolume_Positive(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - err = asw.AddPodToVolume( - podName1, pod1.UID, generatedVolumeName1, mounter1, mapper1, volumeSpec1.Name(), "" /* volumeGidValue */, volumeSpec1) + markVolumeOpts1 := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName1, + PodUID: pod1.UID, + VolumeName: generatedVolumeName1, + Mounter: mounter1, + BlockVolumeMapper: mapper1, + OuterVolumeSpecName: volumeSpec1.Name(), + VolumeSpec: volumeSpec1, + } + err = asw.AddPodToVolume(markVolumeOpts1) if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) } @@ -406,8 +428,16 @@ func Test_AddTwoPodsToVolume_Positive(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - err = asw.AddPodToVolume( - podName2, pod2.UID, generatedVolumeName1, mounter2, mapper2, volumeSpec2.Name(), "" /* volumeGidValue */, volumeSpec2) + markVolumeOpts2 := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName2, + PodUID: pod2.UID, + VolumeName: generatedVolumeName1, + Mounter: mounter2, + BlockVolumeMapper: mapper2, + OuterVolumeSpecName: volumeSpec2.Name(), + VolumeSpec: volumeSpec2, + } + err = asw.AddPodToVolume(markVolumeOpts2) if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) } @@ -421,7 +451,6 @@ func Test_AddTwoPodsToVolume_Positive(t *testing.T) { verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName2, volumeSpec2.Name(), asw) verifyVolumeSpecNameInVolumeAsw(t, podName1, []*volume.Spec{volumeSpec1}, asw) verifyVolumeSpecNameInVolumeAsw(t, podName2, []*volume.Spec{volumeSpec2}, asw) - } // Calls AddPodToVolume() to add pod to empty data struct @@ -484,9 +513,16 @@ func Test_AddPodToVolume_Negative_VolumeDoesntExist(t *testing.T) { } // Act - err = asw.AddPodToVolume( - podName, pod.UID, volumeName, mounter, mapper, volumeSpec.Name(), "" /* volumeGidValue */, volumeSpec) - + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName, + PodUID: pod.UID, + VolumeName: volumeName, + Mounter: mounter, + BlockVolumeMapper: mapper, + OuterVolumeSpecName: volumeSpec.Name(), + VolumeSpec: volumeSpec, + } + err = asw.AddPodToVolume(markVolumeOpts) // Assert if err == nil { t.Fatalf("AddPodToVolume did not fail. Expected: <\"no volume with the name ... exists in the list of attached volumes\"> Actual: ") @@ -556,6 +592,71 @@ func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) { verifyVolumeExistsInGloballyMountedVolumes(t, generatedVolumeName, asw) } +func TestGetMountedVolumesForPod(t *testing.T) { + // Arrange + volumePluginMgr, plugin := volumetesting.GetTestVolumePluginMgr(t) + asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) + devicePath := "fake/device/path" + + pod1 := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "volume-name-1", + VolumeSource: v1.VolumeSource{ + GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ + PDName: "fake-device1", + }, + }, + }, + }, + }, + } + volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]} + generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec( + plugin, volumeSpec1) + require.NoError(t, err) + + err = asw.MarkVolumeAsAttached(generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath) + if err != nil { + t.Fatalf("MarkVolumeAsAttached failed. Expected: Actual: <%v>", err) + } + podName1 := util.GetUniquePodName(pod1) + + mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{}) + if err != nil { + t.Fatalf("NewMounter failed. Expected: Actual: <%v>", err) + } + + markVolumeOpts1 := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName1, + PodUID: pod1.UID, + VolumeName: generatedVolumeName1, + Mounter: mounter1, + OuterVolumeSpecName: volumeSpec1.Name(), + VolumeSpec: volumeSpec1, + VolumeMountState: operationexecutor.VolumeMountUncertain, + } + err = asw.AddPodToVolume(markVolumeOpts1) + if err != nil { + t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) + } + mountedVolumes := asw.GetMountedVolumesForPod(podName1) + volumeFound := false + for _, volume := range mountedVolumes { + if volume.InnerVolumeSpecName == volumeSpec1.Name() { + volumeFound = true + } + } + if volumeFound { + t.Fatalf("expected volume %s to be not found in asw", volumeSpec1.Name()) + } +} + func verifyVolumeExistsInGloballyMountedVolumes( t *testing.T, expectedVolumeName v1.UniqueVolumeName, asw ActualStateOfWorld) { globallyMountedVolumes := asw.GetGloballyMountedVolumes() diff --git a/pkg/kubelet/volumemanager/metrics/BUILD b/pkg/kubelet/volumemanager/metrics/BUILD index 385d70102e1..d39ab810a23 100644 --- a/pkg/kubelet/volumemanager/metrics/BUILD +++ b/pkg/kubelet/volumemanager/metrics/BUILD @@ -37,6 +37,7 @@ go_test( "//pkg/volume:go_default_library", "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/operationexecutor:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/kubelet/volumemanager/metrics/metrics_test.go b/pkg/kubelet/volumemanager/metrics/metrics_test.go index 3c630d0061c..986fb6f0e65 100644 --- a/pkg/kubelet/volumemanager/metrics/metrics_test.go +++ b/pkg/kubelet/volumemanager/metrics/metrics_test.go @@ -27,6 +27,7 @@ import ( volumetesting "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/kubernetes/pkg/volume/util" + "k8s.io/kubernetes/pkg/volume/util/operationexecutor" ) func TestMetricCollection(t *testing.T) { @@ -77,8 +78,16 @@ func TestMetricCollection(t *testing.T) { t.Fatalf("MarkVolumeAsAttached failed. Expected: Actual: <%v>", err) } - err = asw.AddPodToVolume( - podName, pod.UID, generatedVolumeName, mounter, mapper, volumeSpec.Name(), "", volumeSpec) + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: podName, + PodUID: pod.UID, + VolumeName: generatedVolumeName, + Mounter: mounter, + BlockVolumeMapper: mapper, + OuterVolumeSpecName: volumeSpec.Name(), + VolumeSpec: volumeSpec, + } + err = asw.AddPodToVolume(markVolumeOpts) if err != nil { t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) } diff --git a/pkg/kubelet/volumemanager/populator/BUILD b/pkg/kubelet/volumemanager/populator/BUILD index 09896dcadd0..cc3044a4bbf 100644 --- a/pkg/kubelet/volumemanager/populator/BUILD +++ b/pkg/kubelet/volumemanager/populator/BUILD @@ -63,6 +63,7 @@ go_test( "//pkg/volume/csimigration:go_default_library", "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/operationexecutor:go_default_library", "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go index 7d872deb8e8..423ac509cae 100644 --- a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go +++ b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go @@ -43,6 +43,7 @@ import ( "k8s.io/kubernetes/pkg/volume/csimigration" volumetesting "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/kubernetes/pkg/volume/util" + "k8s.io/kubernetes/pkg/volume/util/operationexecutor" "k8s.io/kubernetes/pkg/volume/util/types" ) @@ -854,8 +855,16 @@ func reconcileASW(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld, t if err != nil { t.Fatalf("Unexpected error when MarkVolumeAsAttached: %v", err) } - err = asw.MarkVolumeAsMounted(volumeToMount.PodName, volumeToMount.Pod.UID, - volumeToMount.VolumeName, nil, nil, volumeToMount.OuterVolumeSpecName, volumeToMount.VolumeGidValue, volumeToMount.VolumeSpec) + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: volumeToMount.PodName, + PodUID: volumeToMount.Pod.UID, + VolumeName: volumeToMount.VolumeName, + OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, + VolumeGidVolume: volumeToMount.VolumeGidValue, + VolumeSpec: volumeToMount.VolumeSpec, + VolumeMountState: operationexecutor.VolumeMounted, + } + err = asw.MarkVolumeAsMounted(markVolumeOpts) if err != nil { t.Fatalf("Unexpected error when MarkVolumeAsMounted: %v", err) } diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler.go b/pkg/kubelet/volumemanager/reconciler/reconciler.go index 3524446d5d4..cd000065a68 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler.go @@ -164,9 +164,19 @@ func (rc *reconciler) reconcile() { // referenced by a pod that was deleted and is now referenced by another // pod is unmounted from the first pod before being mounted to the new // pod. + rc.unmountVolumes() + // Next we mount required volumes. This function could also trigger + // detach if kubelet is responsible for detaching volumes. + rc.mountAttachVolumes() + + // Ensure devices that should be detached/unmounted are detached/unmounted. + rc.unmountDetachDevices() +} + +func (rc *reconciler) unmountVolumes() { // Ensure volumes that should be unmounted are unmounted. - for _, mountedVolume := range rc.actualStateOfWorld.GetMountedVolumes() { + for _, mountedVolume := range rc.actualStateOfWorld.GetAllMountedVolumes() { if !rc.desiredStateOfWorld.PodExistsInVolume(mountedVolume.PodName, mountedVolume.VolumeName) { // Volume is mounted, unmount it klog.V(5).Infof(mountedVolume.GenerateMsgDetailed("Starting operationExecutor.UnmountVolume", "")) @@ -184,7 +194,9 @@ func (rc *reconciler) reconcile() { } } } +} +func (rc *reconciler) mountAttachVolumes() { // Ensure volumes that should be attached/mounted are attached/mounted. for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() { volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName) @@ -274,13 +286,14 @@ func (rc *reconciler) reconcile() { } } } +} - // Ensure devices that should be detached/unmounted are detached/unmounted. +func (rc *reconciler) unmountDetachDevices() { for _, attachedVolume := range rc.actualStateOfWorld.GetUnmountedVolumes() { // Check IsOperationPending to avoid marking a volume as detached if it's in the process of mounting. if !rc.desiredStateOfWorld.VolumeExists(attachedVolume.VolumeName) && !rc.operationExecutor.IsOperationPending(attachedVolume.VolumeName, nestedpendingoperations.EmptyUniquePodName) { - if attachedVolume.GloballyMounted { + if attachedVolume.DeviceMayBeMounted() { // Volume is globally mounted to device, unmount it klog.V(5).Infof(attachedVolume.GenerateMsgDetailed("Starting operationExecutor.UnmountDevice", "")) err := rc.operationExecutor.UnmountDevice( @@ -625,15 +638,18 @@ func (rc *reconciler) updateStates(volumesNeedUpdate map[v1.UniqueVolumeName]*re klog.Errorf("Could not add volume information to actual state of world: %v", err) continue } - err = rc.actualStateOfWorld.MarkVolumeAsMounted( - volume.podName, - types.UID(volume.podName), - volume.volumeName, - volume.mounter, - volume.blockVolumeMapper, - volume.outerVolumeSpecName, - volume.volumeGidValue, - volume.volumeSpec) + markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + PodName: volume.podName, + PodUID: types.UID(volume.podName), + VolumeName: volume.volumeName, + Mounter: volume.mounter, + BlockVolumeMapper: volume.blockVolumeMapper, + OuterVolumeSpecName: volume.outerVolumeSpecName, + VolumeGidVolume: volume.volumeGidValue, + VolumeSpec: volume.volumeSpec, + VolumeMountState: operationexecutor.VolumeMounted, + } + err = rc.actualStateOfWorld.MarkVolumeAsMounted(markVolumeOpts) if err != nil { klog.Errorf("Could not add pod to volume information to actual state of world: %v", err) continue diff --git a/pkg/kubelet/volumemanager/volume_manager.go b/pkg/kubelet/volumemanager/volume_manager.go index 3fe144a073f..300cf7159b8 100644 --- a/pkg/kubelet/volumemanager/volume_manager.go +++ b/pkg/kubelet/volumemanager/volume_manager.go @@ -430,6 +430,7 @@ func (vm *volumeManager) verifyVolumesMountedFunc(podName types.UniquePodName, e // getUnmountedVolumes fetches the current list of mounted volumes from // the actual state of the world, and uses it to process the list of // expectedVolumes. It returns a list of unmounted volumes. +// The list also includes volume that may be mounted in uncertain state. func (vm *volumeManager) getUnmountedVolumes(podName types.UniquePodName, expectedVolumes []string) []string { mountedVolumes := sets.NewString() for _, mountedVolume := range vm.actualStateOfWorld.GetMountedVolumesForPod(podName) { diff --git a/pkg/volume/util/operationexecutor/operation_executor.go b/pkg/volume/util/operationexecutor/operation_executor.go index c95029e6fd7..92a4e4305a3 100644 --- a/pkg/volume/util/operationexecutor/operation_executor.go +++ b/pkg/volume/util/operationexecutor/operation_executor.go @@ -160,11 +160,23 @@ func NewOperationExecutor( } } +type MarkVolumeMountedOpts struct { + PodName volumetypes.UniquePodName + PodUID types.UID + VolumeName v1.UniqueVolumeName + Mounter volume.Mounter + BlockVolumeMapper volume.BlockVolumeMapper + OuterVolumeSpecName string + VolumeGidVolume string + VolumeSpec *volume.Spec + VolumeMountState VolumeMountState +} + // ActualStateOfWorldMounterUpdater defines a set of operations updating the actual // state of the world cache after successful mount/unmount. type ActualStateOfWorldMounterUpdater interface { // Marks the specified volume as mounted to the specified pod - MarkVolumeAsMounted(podName volumetypes.UniquePodName, podUID types.UID, volumeName v1.UniqueVolumeName, mounter volume.Mounter, blockVolumeMapper volume.BlockVolumeMapper, outerVolumeSpecName string, volumeGidValue string, volumeSpec *volume.Spec) error + MarkVolumeAsMounted(markVolumeOpts MarkVolumeMountedOpts) error // Marks the specified volume as unmounted from the specified pod MarkVolumeAsUnmounted(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error @@ -172,6 +184,8 @@ type ActualStateOfWorldMounterUpdater interface { // Marks the specified volume as having been globally mounted. MarkDeviceAsMounted(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error + MarkDeviceAsUncertain(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error + // Marks the specified volume as having its global mount unmounted. MarkDeviceAsUnmounted(volumeName v1.UniqueVolumeName) error @@ -354,6 +368,32 @@ type VolumeToMount struct { DesiredSizeLimit *resource.Quantity } +// DeviceMountState represents device mount state in a global path. +type DeviceMountState string + +const ( + // DeviceGloballymounted means device has been globally mounted successfully + DeviceGloballyMounted DeviceMountState = "DeviceGloballyMounted" + + // Uncertain means device may not be mounted but a mount operation may be + // in-progress which can cause device mount to succeed. + DeviceMountUncertain DeviceMountState = "DeviceMountUncertain" + + // DeviceNotMounted means device has not been mounted globally. + DeviceNotMounted DeviceMountState = "DeviceNotMounted" +) + +// VolumeMountState represents volume mount state in a path local to the pod. +type VolumeMountState string + +const ( + VolumeMounted VolumeMountState = "VolumeMounted" + + VolumeMountUncertain VolumeMountState = "VolumeMountUncertain" + + VolumeNotMounted VolumeMountState = "VolumeNotMounted" +) + // GenerateMsgDetailed returns detailed msgs for volumes to mount func (volume *VolumeToMount) GenerateMsgDetailed(prefixMsg, suffixMsg string) (detailedMsg string) { detailedStr := fmt.Sprintf("(UniqueName: %q) pod %q (UID: %q)", volume.VolumeName, volume.Pod.Name, volume.Pod.UID) diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 91b86de990d..425a5b6f79a 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -648,15 +648,17 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Update actual state of world - markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted( - volumeToMount.PodName, - volumeToMount.Pod.UID, - volumeToMount.VolumeName, - volumeMounter, - nil, - volumeToMount.OuterVolumeSpecName, - volumeToMount.VolumeGidValue, - volumeToMount.VolumeSpec) + markOpts := MarkVolumeMountedOpts{ + PodName: volumeToMount.PodName, + PodUID: volumeToMount.Pod.UID, + VolumeName: volumeToMount.VolumeName, + Mounter: volumeMounter, + OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, + VolumeGidVolume: volumeToMount.VolumeGidValue, + VolumeSpec: volumeToMount.VolumeSpec, + VolumeMountState: VolumeMounted, + } + markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markOpts) if markVolMountedErr != nil { // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.MarkVolumeAsMounted failed", markVolMountedErr) @@ -982,16 +984,18 @@ func (og *operationGenerator) GenerateMapVolumeFunc( return volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed while expanding volume", resizeError) } - // Update actual state of world - markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted( - volumeToMount.PodName, - volumeToMount.Pod.UID, - volumeToMount.VolumeName, - nil, - blockVolumeMapper, - volumeToMount.OuterVolumeSpecName, - volumeToMount.VolumeGidValue, - volumeToMount.VolumeSpec) + markVolumeOpts := MarkVolumeMountedOpts{ + PodName: volumeToMount.PodName, + PodUID: volumeToMount.Pod.UID, + VolumeName: volumeToMount.VolumeName, + BlockVolumeMapper: blockVolumeMapper, + OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, + VolumeGidVolume: volumeToMount.VolumeGidValue, + VolumeSpec: volumeToMount.VolumeSpec, + VolumeMountState: VolumeMounted, + } + + markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markVolumeOpts) if markVolMountedErr != nil { // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed", markVolMountedErr) From 34a6007dfed9fdc52ca19d8f90820e10d33f3fdf Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 6 Sep 2019 21:15:15 -0400 Subject: [PATCH 02/15] Add code to mark volume as uncertain Update bazel files Add tests for volume mounts in uncertain state --- .../cache/actual_state_of_world.go | 40 +-- .../volumemanager/metrics/metrics_test.go | 1 + .../volumemanager/reconciler/reconciler.go | 4 +- .../reconciler/reconciler_test.go | 255 +++++++++++++++++- pkg/volume/csi/BUILD | 3 + pkg/volume/csi/csi_attacher.go | 4 +- pkg/volume/csi/csi_client.go | 36 ++- pkg/volume/csi/csi_mounter.go | 8 +- pkg/volume/testing/BUILD | 1 + pkg/volume/testing/testing.go | 30 +++ .../operationexecutor/operation_executor.go | 12 +- .../operationexecutor/operation_generator.go | 24 ++ pkg/volume/util/types/types.go | 25 ++ 13 files changed, 412 insertions(+), 31 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 5d89aa5febb..182657e1c11 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -173,6 +173,7 @@ type AttachedVolume struct { DeviceMountState operationexecutor.DeviceMountState } +// DeviceMayBeMounted returns true if device may be mounted in global path. func (av AttachedVolume) DeviceMayBeMounted() bool { return av.DeviceMountState == operationexecutor.DeviceGloballyMounted || av.DeviceMountState == operationexecutor.DeviceMountUncertain @@ -252,11 +253,6 @@ type attachedVolume struct { // this volume implements the volume.Attacher interface pluginIsAttachable bool - // globallyMounted indicates that the volume is mounted to the underlying - // device at a global mount point. This global mount point must be unmounted - // prior to detach. - globallyMounted bool - // deviceMountState stores information that tells us if device is mounted // globally or not deviceMountState operationexecutor.DeviceMountState @@ -313,11 +309,11 @@ type mountedPod struct { // mounted to this pod but its size has been expanded after that. fsResizeRequired bool - // volumeMounted stores state of volume mount for the pod. if it is: + // volumeMountStateForPod stores state of volume mount for the pod. if it is: // - VolumeMounted: means volume for pod has been successfully mounted // - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted // - VolumeNotMounted: means volume for pod has not been mounted - volumeMounted operationexecutor.VolumeMountState + volumeMountStateForPod operationexecutor.VolumeMountState } func (asw *actualStateOfWorld) MarkVolumeAsAttached( @@ -363,6 +359,11 @@ func (asw *actualStateOfWorld) MarkDeviceAsUncertain( return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath) } +func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { + markVolumeOpts.VolumeMountState = operationexecutor.VolumeMountUncertain + return asw.AddPodToVolume(markVolumeOpts) +} + func (asw *actualStateOfWorld) MarkDeviceAsUnmounted( volumeName v1.UniqueVolumeName) error { return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "") @@ -448,14 +449,14 @@ func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.M podObj, podExists := volumeObj.mountedPods[podName] if !podExists { podObj = mountedPod{ - podName: podName, - podUID: podUID, - mounter: mounter, - blockVolumeMapper: blockVolumeMapper, - outerVolumeSpecName: outerVolumeSpecName, - volumeGidValue: volumeGidValue, - volumeSpec: volumeSpec, - volumeMounted: markVolumeOpts.VolumeMountState, + podName: podName, + podUID: podUID, + mounter: mounter, + blockVolumeMapper: blockVolumeMapper, + outerVolumeSpecName: outerVolumeSpecName, + volumeGidValue: volumeGidValue, + volumeSpec: volumeSpec, + volumeMountStateForPod: markVolumeOpts.VolumeMountState, } } @@ -674,7 +675,7 @@ func (asw *actualStateOfWorld) GetMountedVolumes() []MountedVolume { mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { for _, podObj := range volumeObj.mountedPods { - if podObj.volumeMounted == operationexecutor.VolumeMounted { + if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { mountedVolume = append( mountedVolume, getMountedVolume(&podObj, &volumeObj)) @@ -684,14 +685,15 @@ func (asw *actualStateOfWorld) GetMountedVolumes() []MountedVolume { return mountedVolume } +// GetAllMountedVolumes returns all volumes which could be locally mounted for a pod. func (asw *actualStateOfWorld) GetAllMountedVolumes() []MountedVolume { asw.RLock() defer asw.RUnlock() mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { for _, podObj := range volumeObj.mountedPods { - if podObj.volumeMounted == operationexecutor.VolumeMounted || - podObj.volumeMounted == operationexecutor.VolumeMountUncertain { + if podObj.volumeMountStateForPod == operationexecutor.VolumeMounted || + podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { mountedVolume = append( mountedVolume, getMountedVolume(&podObj, &volumeObj)) @@ -710,7 +712,7 @@ func (asw *actualStateOfWorld) GetMountedVolumesForPod( mountedVolume := make([]MountedVolume, 0 /* len */, len(asw.attachedVolumes) /* cap */) for _, volumeObj := range asw.attachedVolumes { for mountedPodName, podObj := range volumeObj.mountedPods { - if mountedPodName == podName && podObj.volumeMounted == operationexecutor.VolumeMounted { + if mountedPodName == podName && podObj.volumeMountStateForPod == operationexecutor.VolumeMounted { mountedVolume = append( mountedVolume, getMountedVolume(&podObj, &volumeObj)) diff --git a/pkg/kubelet/volumemanager/metrics/metrics_test.go b/pkg/kubelet/volumemanager/metrics/metrics_test.go index 986fb6f0e65..2af2c17cdf5 100644 --- a/pkg/kubelet/volumemanager/metrics/metrics_test.go +++ b/pkg/kubelet/volumemanager/metrics/metrics_test.go @@ -86,6 +86,7 @@ func TestMetricCollection(t *testing.T) { BlockVolumeMapper: mapper, OuterVolumeSpecName: volumeSpec.Name(), VolumeSpec: volumeSpec, + VolumeMountState: operationexecutor.VolumeMounted, } err = asw.AddPodToVolume(markVolumeOpts) if err != nil { diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler.go b/pkg/kubelet/volumemanager/reconciler/reconciler.go index cd000065a68..ec46ea492ac 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler.go @@ -167,7 +167,9 @@ func (rc *reconciler) reconcile() { rc.unmountVolumes() // Next we mount required volumes. This function could also trigger - // detach if kubelet is responsible for detaching volumes. + // attach if kubelet is responsible for attaching volumes. + // If underlying PVC was resized while in-use then this function also handles volume + // resizing. rc.mountAttachVolumes() // Ensure devices that should be detached/unmounted are detached/unmounted. diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go index 0fccd8d7567..dfafd8985a1 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go @@ -336,7 +336,7 @@ func Test_Run_Positive_VolumeAttachMountUnmountDetach(t *testing.T) { // Act dsw.DeletePodFromVolume(podName, generatedVolumeName) - waitForDetach(t, fakePlugin, generatedVolumeName, asw) + waitForDetach(t, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyTearDownCallCount( @@ -428,7 +428,7 @@ func Test_Run_Positive_VolumeUnmountControllerAttachEnabled(t *testing.T) { // Act dsw.DeletePodFromVolume(podName, generatedVolumeName) - waitForDetach(t, fakePlugin, generatedVolumeName, asw) + waitForDetach(t, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyTearDownCallCount( @@ -739,7 +739,7 @@ func Test_Run_Positive_BlockVolumeAttachMapUnmapDetach(t *testing.T) { // Act dsw.DeletePodFromVolume(podName, generatedVolumeName) - waitForDetach(t, fakePlugin, generatedVolumeName, asw) + waitForDetach(t, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyTearDownDeviceCallCount( @@ -855,7 +855,7 @@ func Test_Run_Positive_VolumeUnmapControllerAttachEnabled(t *testing.T) { // Act dsw.DeletePodFromVolume(podName, generatedVolumeName) - waitForDetach(t, fakePlugin, generatedVolumeName, asw) + waitForDetach(t, generatedVolumeName, asw) // Assert assert.NoError(t, volumetesting.VerifyTearDownDeviceCallCount( @@ -1145,6 +1145,237 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) { } } +func Test_UncertainDeviceGlobalMounts(t *testing.T) { + fsMode := v1.PersistentVolumeFilesystem + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: volumetesting.TimeoutOnMountDeviceVolumeName, + UID: "pvuid", + }, + Spec: v1.PersistentVolumeSpec{ + ClaimRef: &v1.ObjectReference{Name: "pvc"}, + VolumeMode: &fsMode, + }, + } + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc", + UID: "pvcuid", + }, + Spec: v1.PersistentVolumeClaimSpec{ + VolumeName: volumetesting.TimeoutOnMountDeviceVolumeName, + }, + } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "volume-name", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvc.Name, + }, + }, + }, + }, + }, + } + + volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) + dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) + asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) + kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ + Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", volumetesting.TimeoutOnMountDeviceVolumeName)), + DevicePath: "fake/path", + }) + fakeRecorder := &record.FakeRecorder{} + fakeHandler := volumetesting.NewBlockVolumePathHandler() + oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( + kubeClient, + volumePluginMgr, + fakeRecorder, + false, /* checkNodeCapabilitiesBeforeMount */ + fakeHandler)) + + reconciler := NewReconciler( + kubeClient, + true, /* controllerAttachDetachEnabled */ + reconcilerLoopSleepDuration, + waitForAttachTimeout, + nodeName, + dsw, + asw, + hasAddedPods, + oex, + &mount.FakeMounter{}, + hostutil.NewFakeHostUtil(nil), + volumePluginMgr, + kubeletPodsDir) + volumeSpec := &volume.Spec{PersistentVolume: pv} + podName := util.GetUniquePodName(pod) + volumeName, err := dsw.AddPodToVolume( + podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) + // Assert + if err != nil { + t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) + } + dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) + + // Start the reconciler to fill ASW. + stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) + go func() { + reconciler.Run(stopChan) + close(stoppedChan) + }() + waitForVolumeToExistInASW(t, volumeName, asw) + waitForUncertainGlobalMount(t, volumeName, asw) + + dsw.DeletePodFromVolume(podName, volumeName) + waitForDetach(t, volumeName, asw) + + volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) +} + +func Test_UncertainVolumeMountState(t *testing.T) { + fsMode := v1.PersistentVolumeFilesystem + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: volumetesting.TimeoutOnSetupVolumeName, + UID: "pvuid", + }, + Spec: v1.PersistentVolumeSpec{ + ClaimRef: &v1.ObjectReference{Name: "pvc"}, + VolumeMode: &fsMode, + }, + } + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc", + UID: "pvcuid", + }, + Spec: v1.PersistentVolumeClaimSpec{ + VolumeName: volumetesting.TimeoutOnSetupVolumeName, + }, + } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "volume-name", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvc.Name, + }, + }, + }, + }, + }, + } + + volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) + dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) + asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) + kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ + Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", volumetesting.TimeoutOnSetupVolumeName)), + DevicePath: "fake/path", + }) + fakeRecorder := &record.FakeRecorder{} + fakeHandler := volumetesting.NewBlockVolumePathHandler() + oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( + kubeClient, + volumePluginMgr, + fakeRecorder, + false, /* checkNodeCapabilitiesBeforeMount */ + fakeHandler)) + + reconciler := NewReconciler( + kubeClient, + true, /* controllerAttachDetachEnabled */ + reconcilerLoopSleepDuration, + waitForAttachTimeout, + nodeName, + dsw, + asw, + hasAddedPods, + oex, + &mount.FakeMounter{}, + hostutil.NewFakeHostUtil(nil), + volumePluginMgr, + kubeletPodsDir) + volumeSpec := &volume.Spec{PersistentVolume: pv} + podName := util.GetUniquePodName(pod) + volumeName, err := dsw.AddPodToVolume( + podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) + // Assert + if err != nil { + t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) + } + dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) + + // Start the reconciler to fill ASW. + stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) + go func() { + reconciler.Run(stopChan) + close(stoppedChan) + }() + waitForVolumeToExistInASW(t, volumeName, asw) + waitForUncertainPodMount(t, volumeName, asw) + + dsw.DeletePodFromVolume(podName, volumeName) + waitForDetach(t, volumeName, asw) + + volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) + volumetesting.VerifyTearDownCallCount(1, fakePlugin) +} + +func waitForUncertainGlobalMount(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { + // check if volume is globally mounted in uncertain state + err := retryWithExponentialBackOff( + time.Duration(500*time.Millisecond), + func() (bool, error) { + unmountedVolumes := asw.GetUnmountedVolumes() + for _, v := range unmountedVolumes { + if v.VolumeName == volumeName && v.DeviceMountState == operationexecutor.DeviceMountUncertain { + return true, nil + } + } + return false, nil + }, + ) + + if err != nil { + t.Fatalf("expected volumes %s to be mounted in uncertain state globally", volumeName) + } +} + +func waitForUncertainPodMount(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { + // check if volume is locally pod mounted in uncertain state + err := retryWithExponentialBackOff( + time.Duration(500*time.Millisecond), + func() (bool, error) { + allMountedVolumes := asw.GetAllMountedVolumes() + for _, v := range allMountedVolumes { + if v.VolumeName == volumeName { + return true, nil + } + } + return false, nil + }, + ) + + if err != nil { + t.Fatalf("expected volumes %s to be mounted in uncertain state for pod", volumeName) + } +} + func waitForMount( t *testing.T, fakePlugin *volumetesting.FakeVolumePlugin, @@ -1169,9 +1400,23 @@ func waitForMount( } } +func waitForVolumeToExistInASW(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { + err := retryWithExponentialBackOff( + time.Duration(500*time.Millisecond), + func() (bool, error) { + if asw.VolumeExists(volumeName) { + return true, nil + } + return false, nil + }, + ) + if err != nil { + t.Fatalf("Timed out waiting for volume %q to be exist in asw.", volumeName) + } +} + func waitForDetach( t *testing.T, - fakePlugin *volumetesting.FakeVolumePlugin, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { err := retryWithExponentialBackOff( diff --git a/pkg/volume/csi/BUILD b/pkg/volume/csi/BUILD index 1b4bf551c8f..db1aa80e0d7 100644 --- a/pkg/volume/csi/BUILD +++ b/pkg/volume/csi/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/csi/nodeinfomanager:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", @@ -37,6 +38,8 @@ go_library( "//staging/src/k8s.io/csi-translation-lib/plugins:go_default_library", "//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/utils/strings:go_default_library", ], diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index 1ca94ddfdfa..b25aba98068 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -36,6 +36,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) const ( @@ -265,7 +266,8 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo return err } defer func() { - if err != nil { + // Only for non-timedout errors remove the mount directory + if err != nil && !volumetypes.IsOperationTimeOutError(err) { // clean up metadata klog.Errorf(log("attacher.MountDevice failed: %v", err)) if err := removeMountDir(c.plugin, deviceMountPath); err != nil { diff --git a/pkg/volume/csi/csi_client.go b/pkg/volume/csi/csi_client.go index 99c3181a0aa..6f54f871e8f 100644 --- a/pkg/volume/csi/csi_client.go +++ b/pkg/volume/csi/csi_client.go @@ -28,11 +28,14 @@ import ( csipbv1 "github.com/container-storage-interface/spec/lib/go/csi" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" api "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type csiClient interface { @@ -213,6 +216,7 @@ func (c *csiDriverClient) NodePublishVolume( if targetPath == "" { return errors.New("missing target path") } + if c.nodeV1ClientCreator == nil { return errors.New("failed to call NodePublishVolume. nodeV1ClientCreator is nil") @@ -255,7 +259,10 @@ func (c *csiDriverClient) NodePublishVolume( } _, err = nodeClient.NodePublishVolume(ctx, req) - return err + if err != nil && !isFinalError(err) { + return volumetypes.NewOperationTimedOutError(err.Error()) + } + return nil } func (c *csiDriverClient) NodeExpandVolume(ctx context.Context, volumeID, volumePath string, newSize resource.Quantity) (resource.Quantity, error) { @@ -374,6 +381,9 @@ func (c *csiDriverClient) NodeStageVolume(ctx context.Context, } _, err = nodeClient.NodeStageVolume(ctx, req) + if err != nil && !isFinalError(err) { + return volumetypes.NewOperationTimedOutError(err.Error()) + } return err } @@ -613,3 +623,27 @@ func (c *csiDriverClient) NodeGetVolumeStats(ctx context.Context, volID string, } return metrics, nil } + +func isFinalError(err error) bool { + // Sources: + // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md + // https://github.com/container-storage-interface/spec/blob/master/spec.md + st, ok := status.FromError(err) + if !ok { + // This is not gRPC error. The operation must have failed before gRPC + // method was called, otherwise we would get gRPC error. + // We don't know if any previous CreateVolume is in progress, be on the safe side. + return false + } + switch st.Code() { + case codes.Canceled, // gRPC: Client Application cancelled the request + codes.DeadlineExceeded, // gRPC: Timeout + codes.Unavailable, // gRPC: Server shutting down, TCP connection broken - previous CreateVolume() may be still in progress. + codes.ResourceExhausted, // gRPC: Server temporarily out of resources - previous CreateVolume() may be still in progress. + codes.Aborted: // CSI: Operation pending for volume + return false + } + // All other errors mean that provisioning either did not + // even start or failed. It is for sure not in progress. + return true +} diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 2cce6de579c..7fb73725da3 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -36,6 +36,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" utilstrings "k8s.io/utils/strings" ) @@ -254,8 +255,11 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error ) if err != nil { - if removeMountDirErr := removeMountDir(c.plugin, dir); removeMountDirErr != nil { - klog.Error(log("mounter.SetupAt failed to remove mount dir after a NodePublish() error [%s]: %v", dir, removeMountDirErr)) + // If error is not of type time out then we can remove the mount directory + if volumetypes.IsOperationTimeOutError(err) { + if removeMountDirErr := removeMountDir(c.plugin, dir); removeMountDirErr != nil { + klog.Error(log("mounter.SetupAt failed to remove mount dir after a NodePublish() error [%s]: %v", dir, removeMountDirErr)) + } } return errors.New(log("mounter.SetupAt failed: %v", err)) } diff --git a/pkg/volume/testing/BUILD b/pkg/volume/testing/BUILD index 8d9502fd331..b585365f1ee 100644 --- a/pkg/volume/testing/BUILD +++ b/pkg/volume/testing/BUILD @@ -18,6 +18,7 @@ go_library( "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", "//pkg/volume/util/subpath:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 0134d1b2077..e74750cb067 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -51,6 +51,7 @@ import ( "k8s.io/kubernetes/pkg/volume/util/hostutil" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" "k8s.io/kubernetes/pkg/volume/util/subpath" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -66,6 +67,10 @@ const ( 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" + // TimeoutOnSetupVolumeName will cause Setup call to timeout but volume will finish mounting. + TimeoutOnSetupVolumeName = "timeout-setup-volume" + // TimeoutOnMountDeviceVolumeName will cause MountDevice call to timeout but Setup will finish. + TimeoutOnMountDeviceVolumeName = "timeout-mount-device-volume" ) // fakeVolumeHost is useful for testing volume plugins. @@ -835,6 +840,9 @@ func (fv *FakeVolume) CanMount() error { func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) error { fv.Lock() defer fv.Unlock() + if fv.VolName == TimeoutOnSetupVolumeName { + return volumetypes.NewOperationTimedOutError("time out on setup") + } fv.SetUpCallCount++ return fv.SetUpAt(fv.getPath(), mounterArgs) } @@ -1039,6 +1047,9 @@ func (fv *FakeVolume) GetDeviceMountPath(spec *Spec) (string, error) { func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath string) error { fv.Lock() defer fv.Unlock() + if spec.Name() == TimeoutOnMountDeviceVolumeName { + return volumetypes.NewOperationTimedOutError("error mounting device") + } fv.MountDeviceCallCount++ return nil } @@ -1049,6 +1060,12 @@ func (fv *FakeVolume) GetMountDeviceCallCount() int { return fv.MountDeviceCallCount } +func (fv *FakeVolume) GetUnmountDeviceCallCount() int { + fv.RLock() + defer fv.RUnlock() + return fv.UnmountDeviceCallCount +} + func (fv *FakeVolume) Detach(volumeName string, nodeName types.NodeName) error { fv.Lock() defer fv.Unlock() @@ -1304,6 +1321,19 @@ func VerifyMountDeviceCallCount( expectedMountDeviceCallCount) } +func VerifyUnmountDeviceCallCount(expectedCallCount int, fakeVolumePlugin *FakeVolumePlugin) error { + for _, attacher := range fakeVolumePlugin.GetAttachers() { + actualCallCount := attacher.GetUnmountDeviceCallCount() + if actualCallCount >= expectedCallCount { + return nil + } + } + + return fmt.Errorf( + "No Attachers have expected MountunDeviceCallCount. Expected: <%v>.", + expectedCallCount) +} + // VerifyZeroMountDeviceCallCount ensures that all Attachers for this plugin // have a zero MountDeviceCallCount. Otherwise it returns an error. func VerifyZeroMountDeviceCallCount(fakeVolumePlugin *FakeVolumePlugin) error { diff --git a/pkg/volume/util/operationexecutor/operation_executor.go b/pkg/volume/util/operationexecutor/operation_executor.go index 92a4e4305a3..010299cee41 100644 --- a/pkg/volume/util/operationexecutor/operation_executor.go +++ b/pkg/volume/util/operationexecutor/operation_executor.go @@ -160,6 +160,7 @@ func NewOperationExecutor( } } +// MarkVolumeMountedOpts is an struct to pass arguments to MountVolume functions type MarkVolumeMountedOpts struct { PodName volumetypes.UniquePodName PodUID types.UID @@ -181,9 +182,13 @@ type ActualStateOfWorldMounterUpdater interface { // Marks the specified volume as unmounted from the specified pod MarkVolumeAsUnmounted(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error + // MarkVolumeMountAsUncertain marks state of volume mount for the pod uncertain + MarkVolumeMountAsUncertain(markVolumeOpts MarkVolumeMountedOpts) error + // Marks the specified volume as having been globally mounted. MarkDeviceAsMounted(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error + // MarkDeviceAsUncertain marks device state in global mount path as uncertain MarkDeviceAsUncertain(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error // Marks the specified volume as having its global mount unmounted. @@ -372,10 +377,10 @@ type VolumeToMount struct { type DeviceMountState string const ( - // DeviceGloballymounted means device has been globally mounted successfully + // DeviceGloballyMounted means device has been globally mounted successfully DeviceGloballyMounted DeviceMountState = "DeviceGloballyMounted" - // Uncertain means device may not be mounted but a mount operation may be + // DeviceMountUncertain means device may not be mounted but a mount operation may be // in-progress which can cause device mount to succeed. DeviceMountUncertain DeviceMountState = "DeviceMountUncertain" @@ -387,10 +392,13 @@ const ( type VolumeMountState string const ( + // VolumeMounted means volume has been mounted in pod's local path VolumeMounted VolumeMountState = "VolumeMounted" + // VolumeMountUncertain means volume may or may not be mounted in pods' local path VolumeMountUncertain VolumeMountState = "VolumeMountUncertain" + // VolumeNotMounted means volume has not been mounted in pod's local path VolumeNotMounted VolumeMountState = "VolumeNotMounted" ) diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 425a5b6f79a..2956ada9e66 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -580,6 +580,12 @@ func (og *operationGenerator) GenerateMountVolumeFunc( devicePath, deviceMountPath) if err != nil { + if volumetypes.IsOperationTimeOutError(err) { + markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) + if markDeviceUncertainError != nil { + klog.Infof("MountVolume.MarkDeviceAsUncertain failed with %v", markDeviceUncertainError) + } + } // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.MountDevice failed", err) } @@ -621,7 +627,25 @@ func (og *operationGenerator) GenerateMountVolumeFunc( FsGroup: fsGroup, DesiredSize: volumeToMount.DesiredSizeLimit, }) + // Update actual state of world + markOpts := MarkVolumeMountedOpts{ + PodName: volumeToMount.PodName, + PodUID: volumeToMount.Pod.UID, + VolumeName: volumeToMount.VolumeName, + Mounter: volumeMounter, + OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, + VolumeGidVolume: volumeToMount.VolumeGidValue, + VolumeSpec: originalSpec, + VolumeMountState: VolumeMounted, + } if mountErr != nil { + if volumetypes.IsOperationTimeOutError(mountErr) { + markOpts.VolumeMountState = VolumeMountUncertain + t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) + if t != nil { + klog.Errorf("MountVolume.MarkVolumeMountAsUncertain failed: %v", t) + } + } // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.SetUp failed", mountErr) } diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 2811cd1dc6c..425e5b47f6d 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -51,6 +51,31 @@ func (o *GeneratedOperations) Run() (eventErr, detailedErr error) { return o.OperationFunc() } +// OperationTimedOutError indicates a particular volume operation has timed out. +type OperationTimedOutError struct { + msg string +} + +func (err *OperationTimedOutError) Error() string { + return err.msg +} + +// NewOperationTimedOutError returns a new instance of OperationTimedOutError +func NewOperationTimedOutError(msg string) *OperationTimedOutError { + return &OperationTimedOutError{ + msg: msg, + } +} + +// IsOperationTimeOutError returns true if volume operation could have timed out for client but possibly +// still running or being processed by the volume plugin. +func IsOperationTimeOutError(err error) bool { + if _, ok := err.(*OperationTimedOutError); ok { + return true + } + return false +} + const ( // VolumeResizerKey is key that will be used to store resizer used // for resizing PVC. The generated key/value pair will be added From 50dbcb3e005b08136d8b4c3b1c062856b5ad4a02 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 10 Sep 2019 11:58:13 -0400 Subject: [PATCH 03/15] Make sure PodExistsInVolume does not uses uncertain volumes --- pkg/kubelet/volumemanager/cache/actual_state_of_world.go | 6 +++++- .../volumemanager/cache/actual_state_of_world_test.go | 7 ++++++- pkg/volume/csi/csi_client.go | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 182657e1c11..e68b3380480 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -127,7 +127,7 @@ type ActualStateOfWorld interface { // actual state of the world. GetMountedVolumes() []MountedVolume - // GetAllMountedVolumes returns list of all mounted volumes including + // GetAllMountedVolumes returns list of all possibly mounted volumes including // those that are in VolumeMounted state and VolumeMountUncertain state. GetAllMountedVolumes() []MountedVolume @@ -635,6 +635,10 @@ func (asw *actualStateOfWorld) PodExistsInVolume( podObj, podExists := volumeObj.mountedPods[podName] if podExists { + // if volume mount was uncertain we should keep trying to mount the volume + if podObj.volumeMountStateForPod == operationexecutor.VolumeMountUncertain { + return false, volumeObj.devicePath, nil + } if podObj.remountRequired { return true, volumeObj.devicePath, newRemountRequiredError(volumeObj.volumeName, podObj.podName) } diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go index 88ae2e283e8..684c02afe0d 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go @@ -592,7 +592,7 @@ func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) { verifyVolumeExistsInGloballyMountedVolumes(t, generatedVolumeName, asw) } -func TestGetMountedVolumesForPod(t *testing.T) { +func TestUncertainVolumeMounts(t *testing.T) { // Arrange volumePluginMgr, plugin := volumetesting.GetTestVolumePluginMgr(t) asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr) @@ -655,6 +655,11 @@ func TestGetMountedVolumesForPod(t *testing.T) { if volumeFound { t.Fatalf("expected volume %s to be not found in asw", volumeSpec1.Name()) } + + volExists, _, _ := asw.PodExistsInVolume(podName1, generatedVolumeName1) + if volExists { + t.Fatalf("expected volume %s to not exist in asw", generatedVolumeName1) + } } func verifyVolumeExistsInGloballyMountedVolumes( diff --git a/pkg/volume/csi/csi_client.go b/pkg/volume/csi/csi_client.go index 6f54f871e8f..aa00d85e859 100644 --- a/pkg/volume/csi/csi_client.go +++ b/pkg/volume/csi/csi_client.go @@ -639,7 +639,7 @@ func isFinalError(err error) bool { case codes.Canceled, // gRPC: Client Application cancelled the request codes.DeadlineExceeded, // gRPC: Timeout codes.Unavailable, // gRPC: Server shutting down, TCP connection broken - previous CreateVolume() may be still in progress. - codes.ResourceExhausted, // gRPC: Server temporarily out of resources - previous CreateVolume() may be still in progress. + codes.ResourceExhausted, // gRPC: Server temporarily out of resources - previous Publish operation may be still in progress. codes.Aborted: // CSI: Operation pending for volume return false } From dc9e64c31e47abdfff90c81b0dad7e62b388e1bb Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 24 Sep 2019 18:25:33 -0400 Subject: [PATCH 04/15] Implement return status codes --- .../attachdetach/testing/testvolumespec.go | 6 ++++++ pkg/volume/awsebs/attacher.go | 6 ++++++ pkg/volume/azure_dd/attacher.go | 6 ++++++ pkg/volume/cinder/attacher.go | 6 ++++++ pkg/volume/csi/csi_attacher.go | 5 +++++ pkg/volume/fc/attacher.go | 6 ++++++ pkg/volume/flexvolume/attacher.go | 6 ++++++ pkg/volume/gcepd/attacher.go | 6 ++++++ pkg/volume/iscsi/attacher.go | 7 +++++++ pkg/volume/local/local.go | 6 ++++++ pkg/volume/rbd/attacher.go | 6 ++++++ pkg/volume/testing/testing.go | 5 +++++ .../operationexecutor/operation_generator.go | 4 ++-- pkg/volume/util/types/types.go | 17 +++++++++++++++++ pkg/volume/volume.go | 4 ++++ pkg/volume/vsphere_volume/attacher.go | 6 ++++++ 16 files changed, 100 insertions(+), 2 deletions(-) diff --git a/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/pkg/controller/volume/attachdetach/testing/testvolumespec.go index 86b66f8f244..183d7dd7e14 100644 --- a/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -32,6 +32,7 @@ import ( "k8s.io/klog" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) const TestPluginName = "kubernetes.io/testPlugin" @@ -445,6 +446,11 @@ func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath st return nil } +func (attacher *testPluginAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + // Detacher type testPluginDetacher struct { detachedVolumeMap map[string][]string diff --git a/pkg/volume/awsebs/attacher.go b/pkg/volume/awsebs/attacher.go index 35bf55df8fe..aa22034e091 100644 --- a/pkg/volume/awsebs/attacher.go +++ b/pkg/volume/awsebs/attacher.go @@ -34,6 +34,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/aws" ) @@ -250,6 +251,11 @@ func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, dev return nil } +func (attacher *awsElasticBlockStoreAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type awsElasticBlockStoreDetacher struct { mounter mount.Interface awsVolumes aws.Volumes diff --git a/pkg/volume/azure_dd/attacher.go b/pkg/volume/azure_dd/attacher.go index 42296172f0d..c5c4705ca18 100644 --- a/pkg/volume/azure_dd/attacher.go +++ b/pkg/volume/azure_dd/attacher.go @@ -37,6 +37,7 @@ import ( cloudprovider "k8s.io/cloud-provider" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/azure" ) @@ -259,6 +260,11 @@ func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath str return nil } +func (d *azureDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := d.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + // Detach detaches disk from Azure VM. func (d *azureDiskDetacher) Detach(diskURI string, nodeName types.NodeName) error { if diskURI == "" { diff --git a/pkg/volume/cinder/attacher.go b/pkg/volume/cinder/attacher.go index ebf84d31d0f..3340d2d53c2 100644 --- a/pkg/volume/cinder/attacher.go +++ b/pkg/volume/cinder/attacher.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type cinderDiskAttacher struct { @@ -303,6 +304,11 @@ func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath st return nil } +func (attacher *cinderDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type cinderDiskDetacher struct { mounter mount.Interface cinderProvider BlockStorageProvider diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index b25aba98068..bd7b7a3e4f0 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -341,6 +341,11 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo return nil } +func (c *csiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := c.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + var _ volume.Detacher = &csiAttacher{} var _ volume.DeviceUnmounter = &csiAttacher{} diff --git a/pkg/volume/fc/attacher.go b/pkg/volume/fc/attacher.go index 4a431fd9928..385a916eca1 100644 --- a/pkg/volume/fc/attacher.go +++ b/pkg/volume/fc/attacher.go @@ -32,6 +32,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type fcAttacher struct { @@ -131,6 +132,11 @@ func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, de return nil } +func (attacher *fcAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type fcDetacher struct { mounter mount.Interface manager diskManager diff --git a/pkg/volume/flexvolume/attacher.go b/pkg/volume/flexvolume/attacher.go index 3b98eefa079..e83da3ff2d3 100644 --- a/pkg/volume/flexvolume/attacher.go +++ b/pkg/volume/flexvolume/attacher.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/klog" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type flexVolumeAttacher struct { @@ -97,6 +98,11 @@ func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, d return err } +func (attacher *flexVolumeAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + func (a *flexVolumeAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { volumesAttachedCheck := make(map[*volume.Spec]bool) for _, spec := range specs { diff --git a/pkg/volume/gcepd/attacher.go b/pkg/volume/gcepd/attacher.go index 43c03564c59..e9aa83e980d 100644 --- a/pkg/volume/gcepd/attacher.go +++ b/pkg/volume/gcepd/attacher.go @@ -38,6 +38,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/gce" ) @@ -328,6 +329,11 @@ func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, device return nil } +func (attacher *gcePersistentDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type gcePersistentDiskDetacher struct { host volume.VolumeHost gceDisks gce.Disks diff --git a/pkg/volume/iscsi/attacher.go b/pkg/volume/iscsi/attacher.go index 7b3d439077e..00d64cf21e4 100644 --- a/pkg/volume/iscsi/attacher.go +++ b/pkg/volume/iscsi/attacher.go @@ -31,6 +31,8 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" + "k8s.io/utils/keymutex" ) type iscsiAttacher struct { @@ -134,6 +136,11 @@ func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, return nil } +func (attacher *iscsiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type iscsiDetacher struct { host volume.VolumeHost mounter mount.Interface diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index b79180a6c87..53de686dacf 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/validation" "k8s.io/utils/keymutex" "k8s.io/utils/mount" @@ -370,6 +371,11 @@ func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, devic } } +func (dm *deviceMounter) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := dm.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + func getVolumeSourceFSType(spec *volume.Spec) (string, error) { if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Local != nil { diff --git a/pkg/volume/rbd/attacher.go b/pkg/volume/rbd/attacher.go index 12c2e77c935..7bfa3fa3a8a 100644 --- a/pkg/volume/rbd/attacher.go +++ b/pkg/volume/rbd/attacher.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // NewAttacher implements AttachableVolumePlugin.NewAttacher. @@ -184,6 +185,11 @@ func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, d return nil } +func (attacher *rbdAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + // rbdDetacher implements volume.Detacher interface. type rbdDetacher struct { plugin *rbdPlugin diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index e74750cb067..0810d83c231 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -1054,6 +1054,11 @@ func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath return nil } +func (fv *FakeVolume) MountDeviceWithStatusTracking(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := fv.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + func (fv *FakeVolume) GetMountDeviceCallCount() int { fv.RLock() defer fv.RUnlock() diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 2956ada9e66..5d530d4472f 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -575,12 +575,12 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Mount device to global mount path - err = volumeDeviceMounter.MountDevice( + operationState, err := volumeDeviceMounter.MountDeviceWithStatusTracking( volumeToMount.VolumeSpec, devicePath, deviceMountPath) if err != nil { - if volumetypes.IsOperationTimeOutError(err) { + if operationState == volumetypes.OperationInProgress { markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) if markDeviceUncertainError != nil { klog.Infof("MountVolume.MarkDeviceAsUncertain failed with %v", markDeviceUncertainError) diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 425e5b47f6d..baaa488137d 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -51,6 +51,23 @@ func (o *GeneratedOperations) Run() (eventErr, detailedErr error) { return o.OperationFunc() } +type OperationStatus string + +const ( + // OperationFinished means volume operation has been finished + OperationFinished OperationStatus = "Finished" + + // OperationInProgress means volume operation has been started and + // is in-progress. This state does not indicate if operation will succeed or fail but + // merely it has been started and in in-progress. + OperationInProgress OperationStatus = "InProgress" + + // OperationStateNoChange indicates it is unchanged from previous state. + // This can be used to indicate transient failures for an operation which + // was in-progress previously. + OperationStateNoChange OperationStatus = "NoChange" +) + // OperationTimedOutError indicates a particular volume operation has timed out. type OperationTimedOutError struct { msg string diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index 31fa8216e3e..83a79623694 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // Volume represents a directory used by pods or hosts on a node. All method @@ -248,6 +249,9 @@ type DeviceMounter interface { // individual pods can then bind mount // Note that devicePath can be empty if the volume plugin does not implement any of Attach and WaitForAttach methods. MountDevice(spec *Spec, devicePath string, deviceMountPath string) error + + // MountDeviceWithStatusTracking is same as MountDevice except status of mount operation is also returned + MountDeviceWithStatusTracking(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) } type BulkVolumeVerifier interface { diff --git a/pkg/volume/vsphere_volume/attacher.go b/pkg/volume/vsphere_volume/attacher.go index 8c247167858..947fc57d2cf 100644 --- a/pkg/volume/vsphere_volume/attacher.go +++ b/pkg/volume/vsphere_volume/attacher.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/vsphere" ) @@ -248,6 +249,11 @@ func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath s return nil } +func (attacher *vsphereVMDKAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.MountDevice(spec, devicePath, deviceMountPath) + return volumetypes.OperationFinished, err +} + type vsphereVMDKDetacher struct { mounter mount.Interface vsphereVolumes vsphere.Volumes From 321e99367af3437db4b2df871c3c84f2f603b6d3 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 25 Sep 2019 16:00:11 -0400 Subject: [PATCH 05/15] Add code to handle Setup With Status tracking --- pkg/volume/awsebs/aws_ebs.go | 7 ++ pkg/volume/azure_dd/azure_mounter.go | 6 ++ pkg/volume/azure_file/azure_file.go | 7 ++ pkg/volume/cephfs/cephfs.go | 7 ++ pkg/volume/cinder/cinder.go | 6 ++ pkg/volume/configmap/configmap.go | 6 ++ pkg/volume/csi/csi_attacher.go | 50 ++++++++------ pkg/volume/csi/csi_mounter.go | 67 +++++++++++-------- pkg/volume/downwardapi/downwardapi.go | 6 ++ pkg/volume/emptydir/empty_dir.go | 6 ++ pkg/volume/fc/fc.go | 6 ++ pkg/volume/flexvolume/mounter.go | 7 ++ pkg/volume/flocker/flocker.go | 6 ++ pkg/volume/gcepd/gce_pd.go | 7 ++ pkg/volume/git_repo/git_repo.go | 7 ++ pkg/volume/glusterfs/glusterfs.go | 7 ++ pkg/volume/hostpath/host_path.go | 7 ++ pkg/volume/iscsi/iscsi.go | 6 ++ pkg/volume/local/local.go | 6 ++ pkg/volume/nfs/nfs.go | 6 ++ pkg/volume/portworx/portworx.go | 6 ++ pkg/volume/projected/projected.go | 6 ++ pkg/volume/quobyte/quobyte.go | 7 ++ pkg/volume/rbd/rbd.go | 6 ++ pkg/volume/scaleio/sio_volume.go | 6 ++ pkg/volume/secret/secret.go | 6 ++ pkg/volume/storageos/storageos.go | 6 ++ pkg/volume/testing/testing.go | 5 ++ .../operationexecutor/operation_generator.go | 23 +++++-- pkg/volume/volume.go | 5 ++ pkg/volume/vsphere_volume/vsphere_volume.go | 8 ++- 31 files changed, 263 insertions(+), 54 deletions(-) diff --git a/pkg/volume/awsebs/aws_ebs.go b/pkg/volume/awsebs/aws_ebs.go index 7bae0358e34..23e81f0ebcc 100644 --- a/pkg/volume/awsebs/aws_ebs.go +++ b/pkg/volume/awsebs/aws_ebs.go @@ -39,6 +39,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/aws" utilstrings "k8s.io/utils/strings" ) @@ -369,6 +370,12 @@ func (b *awsElasticBlockStoreMounter) SetUp(mounterArgs volume.MounterArgs) erro return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetupWithStatusTracking attaches the disk and bind mounts to the volume path. +func (b *awsElasticBlockStoreMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt attaches the disk and bind mounts to the volume path. func (b *awsElasticBlockStoreMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // TODO: handle failed mounts here. diff --git a/pkg/volume/azure_dd/azure_mounter.go b/pkg/volume/azure_dd/azure_mounter.go index 2f8d38bd0aa..c7d5f23441a 100644 --- a/pkg/volume/azure_dd/azure_mounter.go +++ b/pkg/volume/azure_dd/azure_mounter.go @@ -29,6 +29,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type azureDiskMounter struct { @@ -69,6 +70,11 @@ func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { return m.SetUpAt(m.GetPath(), mounterArgs) } +func (m *azureDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := m.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (m *azureDiskMounter) GetPath() string { return getPath(m.dataDisk.podUID, m.dataDisk.volumeName, m.plugin.host) } diff --git a/pkg/volume/azure_file/azure_file.go b/pkg/volume/azure_file/azure_file.go index cd1a13ba369..56b88600751 100644 --- a/pkg/volume/azure_file/azure_file.go +++ b/pkg/volume/azure_file/azure_file.go @@ -36,6 +36,7 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/azure" ) @@ -239,6 +240,12 @@ func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetUp attaches the disk and bind mounts to the volume path. +func (b *azureFileMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *azureFileMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) klog.V(4).Infof("AzureFile mount set up: %s %v %v", dir, !notMnt, err) diff --git a/pkg/volume/cephfs/cephfs.go b/pkg/volume/cephfs/cephfs.go index 4ba29214fd9..bfa86d8c6a1 100644 --- a/pkg/volume/cephfs/cephfs.go +++ b/pkg/volume/cephfs/cephfs.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -223,6 +224,12 @@ func (cephfsVolume *cephfsMounter) SetUp(mounterArgs volume.MounterArgs) error { return cephfsVolume.SetUpAt(cephfsVolume.GetPath(), mounterArgs) } +// SetUp attaches the disk and bind mounts to the volume path. +func (cephfsVolume *cephfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := cephfsVolume.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt attaches the disk and bind mounts to the volume path. func (cephfsVolume *cephfsMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := cephfsVolume.mounter.IsLikelyNotMountPoint(dir) diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go index d09baeb0caa..8a60ac8a8a8 100644 --- a/pkg/volume/cinder/cinder.go +++ b/pkg/volume/cinder/cinder.go @@ -39,6 +39,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/openstack" ) @@ -393,6 +394,11 @@ func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *cinderVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUp bind mounts to the volume path. func (b *cinderVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { klog.V(5).Infof("Cinder SetUp %s to %s", b.pdName, dir) diff --git a/pkg/volume/configmap/configmap.go b/pkg/volume/configmap/configmap.go index 7b0d900f16e..0c80c34f6b9 100644 --- a/pkg/volume/configmap/configmap.go +++ b/pkg/volume/configmap/configmap.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the entry point for plugin detection in a package. @@ -184,6 +185,11 @@ func (b *configMapVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *configMapVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *configMapVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { klog.V(3).Infof("Setting up volume %v for pod %v at %v", b.volName, b.pod.UID, dir) diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index bd7b7a3e4f0..6428bf9e35c 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -220,37 +220,44 @@ func (c *csiAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) { return deviceMountPath, nil } -func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (err error) { +func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { + _, err := c.MountDeviceWithStatusTracking(spec, devicePath, deviceMountPath) + return err +} + +func (c *csiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { klog.V(4).Infof(log("attacher.MountDevice(%s, %s)", devicePath, deviceMountPath)) + // lets default to operation as finished state + opExitStatus := volumetypes.OperationFinished if deviceMountPath == "" { - return errors.New(log("attacher.MountDevice failed, deviceMountPath is empty")) + return opExitStatus, errors.New(log("attacher.MountDevice failed, deviceMountPath is empty")) } mounted, err := isDirMounted(c.plugin, deviceMountPath) if err != nil { klog.Error(log("attacher.MountDevice failed while checking mount status for dir [%s]", deviceMountPath)) - return err + return opExitStatus, err } if mounted { klog.V(4).Info(log("attacher.MountDevice skipping mount, dir already mounted [%s]", deviceMountPath)) - return nil + return opExitStatus, nil } // Setup if spec == nil { - return errors.New(log("attacher.MountDevice failed, spec is nil")) + return opExitStatus, errors.New(log("attacher.MountDevice failed, spec is nil")) } csiSource, err := getPVSourceFromSpec(spec) if err != nil { - return errors.New(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err)) + return opExitStatus, errors.New(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err)) } // Store volume metadata for UnmountDevice. Keep it around even if the // driver does not support NodeStage, UnmountDevice still needs it. if err = os.MkdirAll(deviceMountPath, 0750); err != nil { - return errors.New(log("attacher.MountDevice failed to create dir %#v: %v", deviceMountPath, err)) + return opExitStatus, errors.New(log("attacher.MountDevice failed to create dir %#v: %v", deviceMountPath, err)) } klog.V(4).Info(log("created target path successfully [%s]", deviceMountPath)) dataDir := filepath.Dir(deviceMountPath) @@ -263,11 +270,12 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo if cleanErr := os.RemoveAll(dataDir); cleanErr != nil { klog.Error(log("failed to remove dir after error [%s]: %v", dataDir, cleanErr)) } - return err + return opExitStatus, err } defer func() { - // Only for non-timedout errors remove the mount directory - if err != nil && !volumetypes.IsOperationTimeOutError(err) { + // Only if there was an error and volume operation was considered + // finished, we should remove the directory. + if err != nil && opExitStatus == volumetypes.OperationFinished { // clean up metadata klog.Errorf(log("attacher.MountDevice failed: %v", err)) if err := removeMountDir(c.plugin, deviceMountPath); err != nil { @@ -279,7 +287,7 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo if c.csiClient == nil { c.csiClient, err = newCsiDriverClient(csiDriverName(csiSource.Driver)) if err != nil { - return errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) + return opExitStatus, errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) } } csi := c.csiClient @@ -289,12 +297,12 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo // Check whether "STAGE_UNSTAGE_VOLUME" is set stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) if err != nil { - return err + return opExitStatus, err } if !stageUnstageSet { klog.Infof(log("attacher.MountDevice STAGE_UNSTAGE_VOLUME capability not set. Skipping MountDevice...")) // defer does *not* remove the metadata file and it's correct - UnmountDevice needs it there. - return nil + return opExitStatus, nil } // Start MountDevice @@ -307,7 +315,9 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo if err != nil { err = fmt.Errorf("fetching NodeStageSecretRef %s/%s failed: %v", csiSource.NodeStageSecretRef.Namespace, csiSource.NodeStageSecretRef.Name, err) - return err + // if we failed to fetch secret then that could be a transient error + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, err } } @@ -334,16 +344,14 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo mountOptions) if err != nil { - return err + if volumetypes.IsOperationTimeOutError(err) { + opExitStatus = volumetypes.OperationInProgress + } + return opExitStatus, err } klog.V(4).Infof(log("attacher.MountDevice successfully requested NodeStageVolume [%s]", deviceMountPath)) - return nil -} - -func (c *csiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := c.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + return opExitStatus, err } var _ volume.Detacher = &csiAttacher{} diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 7fb73725da3..6e0fb98aad8 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -103,29 +103,41 @@ func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) error { return c.SetUpAt(c.GetPath(), mounterArgs) } +func (c *csiMountMgr) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := c.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { + _, err := c.setupUtil(dir, mounterArgs) + return err +} + +func (c *csiMountMgr) setupUtil(dir string, mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { klog.V(4).Infof(log("Mounter.SetUpAt(%s)", dir)) + // default to finished operation status + opExitStatus := volumetypes.OperationFinished mounted, err := isDirMounted(c.plugin, dir) if err != nil { - return errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err)) + return opExitStatus, errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err)) } if mounted { klog.V(4).Info(log("mounter.SetUpAt skipping mount, dir already mounted [%s]", dir)) - return nil + return opExitStatus, nil } csi, err := c.csiClientGetter.Get() if err != nil { - return errors.New(log("mounter.SetUpAt failed to get CSI client: %v", err)) + return opExitStatus, errors.New(log("mounter.SetUpAt failed to get CSI client: %v", err)) } ctx, cancel := context.WithTimeout(context.Background(), csiTimeout) defer cancel() volSrc, pvSrc, err := getSourceFromSpec(c.spec) if err != nil { - return errors.New(log("mounter.SetupAt failed to get CSI persistent source: %v", err)) + return opExitStatus, errors.New(log("mounter.SetupAt failed to get CSI persistent source: %v", err)) } driverName := c.driverName @@ -146,10 +158,10 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error switch { case volSrc != nil: if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) { - return fmt.Errorf("CSIInlineVolume feature required") + return opExitStatus, fmt.Errorf("CSIInlineVolume feature required") } if c.volumeLifecycleMode != storage.VolumeLifecycleEphemeral { - return fmt.Errorf("unexpected volume mode: %s", c.volumeLifecycleMode) + return opExitStatus, fmt.Errorf("unexpected volume mode: %s", c.volumeLifecycleMode) } if volSrc.FSType != nil { fsType = *volSrc.FSType @@ -164,7 +176,7 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error } case pvSrc != nil: if c.volumeLifecycleMode != storage.VolumeLifecyclePersistent { - return fmt.Errorf("unexpected driver mode: %s", c.volumeLifecycleMode) + return opExitStatus, fmt.Errorf("unexpected driver mode: %s", c.volumeLifecycleMode) } fsType = pvSrc.FSType @@ -185,13 +197,13 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error // Check for STAGE_UNSTAGE_VOLUME set and populate deviceMountPath if so stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) if err != nil { - return errors.New(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capability: %v", err)) + return opExitStatus, errors.New(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capability: %v", err)) } if stageUnstageSet { deviceMountPath, err = makeDeviceMountPath(c.plugin, c.spec) if err != nil { - return errors.New(log("mounter.SetUpAt failed to make device mount path: %v", err)) + return opExitStatus, errors.New(log("mounter.SetUpAt failed to make device mount path: %v", err)) } } @@ -200,18 +212,20 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error nodeName := string(c.plugin.host.GetNodeName()) c.publishContext, err = c.plugin.getPublishContext(c.k8s, volumeHandle, string(driverName), nodeName) if err != nil { - return err + // we could have a transient error associated with fetching publish context + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, err } publishContext = c.publishContext } default: - return fmt.Errorf("volume source not found in volume.Spec") + return opExitStatus, fmt.Errorf("volume source not found in volume.Spec") } // create target_dir before call to NodePublish if err := os.MkdirAll(dir, 0750); err != nil { - return errors.New(log("mounter.SetUpAt failed to create dir %#v: %v", dir, err)) + return opExitStatus, errors.New(log("mounter.SetUpAt failed to create dir %#v: %v", dir, err)) } klog.V(4).Info(log("created target path successfully [%s]", dir)) @@ -219,7 +233,8 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error if secretRef != nil { nodePublishSecrets, err = getCredentialsFromSecret(c.k8s, secretRef) if err != nil { - return fmt.Errorf("fetching NodePublishSecretRef %s/%s failed: %v", + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, fmt.Errorf("fetching NodePublishSecretRef %s/%s failed: %v", secretRef.Namespace, secretRef.Name, err) } @@ -228,7 +243,8 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error // Inject pod information into volume_attributes podAttrs, err := c.podAttributes() if err != nil { - return errors.New(log("mounter.SetUpAt failed to assemble volume attributes: %v", err)) + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, errors.New(log("mounter.SetUpAt failed to assemble volume attributes: %v", err)) } if podAttrs != nil { if volAttribs == nil { @@ -255,13 +271,16 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error ) if err != nil { - // If error is not of type time out then we can remove the mount directory if volumetypes.IsOperationTimeOutError(err) { + opExitStatus = volumetypes.OperationInProgress + } + // If operation finished with error then we can remove the mount directory. + if opExitStatus == volumetypes.OperationFinished { if removeMountDirErr := removeMountDir(c.plugin, dir); removeMountDirErr != nil { klog.Error(log("mounter.SetupAt failed to remove mount dir after a NodePublish() error [%s]: %v", dir, removeMountDirErr)) } } - return errors.New(log("mounter.SetupAt failed: %v", err)) + return opExitStatus, errors.New(log("mounter.SetupAt failed: %v", err)) } c.supportsSELinux, err = c.kubeVolHost.GetHostUtil().GetSELinuxSupport(dir) @@ -276,22 +295,16 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error err = c.applyFSGroup(fsType, mounterArgs.FsGroup) if err != nil { + // If we are here that means volume was mounted correctly and it must at least be unmounted + // before it can be used by someone else. + opExitStatus = volumetypes.OperationInProgress // attempt to rollback mount. fsGrpErr := fmt.Errorf("applyFSGroup failed for vol %s: %v", c.volumeID, err) - if unpubErr := csi.NodeUnpublishVolume(ctx, c.volumeID, dir); unpubErr != nil { - klog.Error(log("NodeUnpublishVolume failed for [%s]: %v", c.volumeID, unpubErr)) - return fsGrpErr - } - - if unmountErr := removeMountDir(c.plugin, dir); unmountErr != nil { - klog.Error(log("removeMountDir failed for [%s]: %v", dir, unmountErr)) - return fsGrpErr - } - return fsGrpErr + return opExitStatus, fsGrpErr } klog.V(4).Infof(log("mounter.SetUp successfully requested NodePublish [%s]", dir)) - return nil + return opExitStatus, nil } func (c *csiMountMgr) podAttributes() (map[string]string, error) { diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index 12746696888..caee1fd4027 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/fieldpath" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" utilstrings "k8s.io/utils/strings" ) @@ -174,6 +175,11 @@ func (b *downwardAPIVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *downwardAPIVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *downwardAPIVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { klog.V(3).Infof("Setting up a downwardAPI volume %v for pod %v/%v at %v", b.volName, b.pod.Namespace, b.pod.Name, dir) // Wrap EmptyDir. Here we rely on the idempotency of the wrapped plugin to avoid repeatedly mounting diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index 607705aea9f..b5cc0803627 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/fsquota" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // TODO: in the near future, this will be changed to be more restrictive @@ -196,6 +197,11 @@ func (ed *emptyDir) SetUp(mounterArgs volume.MounterArgs) error { return ed.SetUpAt(ed.GetPath(), mounterArgs) } +func (ed *emptyDir) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := ed.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt creates new directory. func (ed *emptyDir) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := ed.mounter.IsLikelyNotMountPoint(dir) diff --git a/pkg/volume/fc/fc.go b/pkg/volume/fc/fc.go index dfc2aa9d062..b5940251460 100644 --- a/pkg/volume/fc/fc.go +++ b/pkg/volume/fc/fc.go @@ -35,6 +35,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -373,6 +374,11 @@ func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *fcDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *fcDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // diskSetUp checks mountpoints and prevent repeated calls err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup) diff --git a/pkg/volume/flexvolume/mounter.go b/pkg/volume/flexvolume/mounter.go index 94229d0d833..47def08da8e 100644 --- a/pkg/volume/flexvolume/mounter.go +++ b/pkg/volume/flexvolume/mounter.go @@ -21,6 +21,7 @@ import ( "strconv" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/utils/exec" ) @@ -43,6 +44,12 @@ func (f *flexVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return f.SetUpAt(f.GetPath(), mounterArgs) } +// SetUp creates new directory. +func (f *flexVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := f.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt creates new directory. func (f *flexVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // Mount only once. diff --git a/pkg/volume/flocker/flocker.go b/pkg/volume/flocker/flocker.go index 723b28de4db..8adb9186ce5 100644 --- a/pkg/volume/flocker/flocker.go +++ b/pkg/volume/flocker/flocker.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/util/env" "k8s.io/kubernetes/pkg/volume" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -235,6 +236,11 @@ func (b *flockerVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *flockerVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // newFlockerClient uses environment variables and pod attributes to return a // flocker client capable of talking with the Flocker control service. func (p *flockerPlugin) newFlockerClient(hostIP string) (*flockerapi.Client, error) { diff --git a/pkg/volume/gcepd/gce_pd.go b/pkg/volume/gcepd/gce_pd.go index a1f4eff61b1..1d8409706e4 100644 --- a/pkg/volume/gcepd/gce_pd.go +++ b/pkg/volume/gcepd/gce_pd.go @@ -40,6 +40,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" gcecloud "k8s.io/legacy-cloud-providers/gce" ) @@ -372,6 +373,12 @@ func (b *gcePersistentDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetUp bind mounts the disk global mount to the volume path. +func (b *gcePersistentDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUp bind mounts the disk global mount to the give volume path. func (b *gcePersistentDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // TODO: handle failed mounts here. diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index aee38f5bbf9..d982cae4d9b 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/utils/exec" utilstrings "k8s.io/utils/strings" ) @@ -179,6 +180,12 @@ func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetUp creates new directory and clones a git repo. +func (b *gitRepoVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt creates new directory and clones a git repo. func (b *gitRepoVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { if volumeutil.IsReady(b.getMetaDir()) { diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go index 8067ba83344..c9164d08b93 100644 --- a/pkg/volume/glusterfs/glusterfs.go +++ b/pkg/volume/glusterfs/glusterfs.go @@ -47,6 +47,7 @@ import ( v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -273,6 +274,12 @@ func (b *glusterfsMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetUp attaches the disk and bind mounts to the volume path. +func (b *glusterfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *glusterfsMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) klog.V(4).Infof("mount setup: %s %v %v", dir, !notMnt, err) diff --git a/pkg/volume/hostpath/host_path.go b/pkg/volume/hostpath/host_path.go index af10f49ed54..47c8601f542 100644 --- a/pkg/volume/hostpath/host_path.go +++ b/pkg/volume/hostpath/host_path.go @@ -31,6 +31,7 @@ import ( "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/validation" ) @@ -238,6 +239,12 @@ func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) error { return checkType(b.GetPath(), b.pathType, b.hu) } +// SetUpWithStatusTracking calls setup and returns additional information about operation state +func (b *hostPathMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt does not make sense for host paths - probably programmer error. func (b *hostPathMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { return fmt.Errorf("SetUpAt() does not make sense for host paths") diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 957a90a331a..51fbdb20121 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -34,6 +34,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" ioutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -342,6 +343,11 @@ func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *iscsiDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // diskSetUp checks mountpoints and prevent repeated calls err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup) diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index 53de686dacf..58f5cf7153e 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -479,6 +479,12 @@ func (m *localVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return m.SetUpAt(m.GetPath(), mounterArgs) } +// SetUp bind mounts the directory to the volume path +func (m *localVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := m.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt bind mounts the directory to the volume path and sets up volume ownership func (m *localVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { m.plugin.volumeLocks.LockKey(m.globalPath) diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index 41b2e1dd9bb..5077f91a4d2 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -31,6 +31,7 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) func getPath(uid types.UID, volName string, host volume.VolumeHost) string { @@ -241,6 +242,11 @@ func (nfsMounter *nfsMounter) SetUp(mounterArgs volume.MounterArgs) error { return nfsMounter.SetUpAt(nfsMounter.GetPath(), mounterArgs) } +func (nfsMounter *nfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := nfsMounter.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (nfsMounter *nfsMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := mount.IsNotMountPoint(nfsMounter.mounter, dir) klog.V(4).Infof("NFS mount set up: %s %v %v", dir, !notMnt, err) diff --git a/pkg/volume/portworx/portworx.go b/pkg/volume/portworx/portworx.go index da6cfbe7088..31e253340a4 100644 --- a/pkg/volume/portworx/portworx.go +++ b/pkg/volume/portworx/portworx.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) const ( @@ -299,6 +300,11 @@ func (b *portworxVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *portworxVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUpAt attaches the disk and bind mounts to the volume path. func (b *portworxVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) diff --git a/pkg/volume/projected/projected.go b/pkg/volume/projected/projected.go index 65e1ac5e2f1..31b30eb0050 100644 --- a/pkg/volume/projected/projected.go +++ b/pkg/volume/projected/projected.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/volume/downwardapi" "k8s.io/kubernetes/pkg/volume/secret" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" utilstrings "k8s.io/utils/strings" ) @@ -188,6 +189,11 @@ func (s *projectedVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return s.SetUpAt(s.GetPath(), mounterArgs) } +func (s *projectedVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := s.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (s *projectedVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { klog.V(3).Infof("Setting up volume %v for pod %v at %v", s.volName, s.pod.UID, dir) diff --git a/pkg/volume/quobyte/quobyte.go b/pkg/volume/quobyte/quobyte.go index 33d730da522..d488d238bac 100644 --- a/pkg/volume/quobyte/quobyte.go +++ b/pkg/volume/quobyte/quobyte.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -239,6 +240,12 @@ func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) error { return mounter.SetUpAt(pluginDir, mounterArgs) } +// SetUpWithStatusTracking attaches the disk and bind mounts to the volume path. +func (mounter *quobyteMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := mounter.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (mounter *quobyteMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // Check if Quobyte is already mounted on the host in the Plugin Dir // if so we can use this mountpoint instead of creating a new one diff --git a/pkg/volume/rbd/rbd.go b/pkg/volume/rbd/rbd.go index a07fe8bf06d..57fdf0021e6 100644 --- a/pkg/volume/rbd/rbd.go +++ b/pkg/volume/rbd/rbd.go @@ -40,6 +40,7 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" volutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -840,6 +841,11 @@ func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *rbdMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { // diskSetUp checks mountpoints and prevent repeated calls klog.V(4).Infof("rbd: attempting to setup at %s", dir) diff --git a/pkg/volume/scaleio/sio_volume.go b/pkg/volume/scaleio/sio_volume.go index 9904147be53..368dec3dd23 100644 --- a/pkg/volume/scaleio/sio_volume.go +++ b/pkg/volume/scaleio/sio_volume.go @@ -35,6 +35,7 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type sioVolume struct { @@ -82,6 +83,11 @@ func (v *sioVolume) SetUp(mounterArgs volume.MounterArgs) error { return v.SetUpAt(v.GetPath(), mounterArgs) } +func (v *sioVolume) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := v.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUp bind mounts the disk global mount to the volume path. func (v *sioVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { v.plugin.volumeMtx.LockKey(v.volSpecName) diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index 3eee6d91827..31662addbf3 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the entry point for plugin detection in a package. @@ -179,6 +180,11 @@ func (b *secretVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *secretVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (b *secretVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { klog.V(3).Infof("Setting up volume %v for pod %v at %v", b.volName, b.pod.UID, dir) diff --git a/pkg/volume/storageos/storageos.go b/pkg/volume/storageos/storageos.go index a90e384e9a6..3def2c36eed 100644 --- a/pkg/volume/storageos/storageos.go +++ b/pkg/volume/storageos/storageos.go @@ -36,6 +36,7 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -376,6 +377,11 @@ func (b *storageosMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +func (b *storageosMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // SetUp bind mounts the disk global mount to the give volume path. func (b *storageosMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { notMnt, err := b.mounter.IsLikelyNotMountPoint(dir) diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 0810d83c231..263ad6b0034 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -847,6 +847,11 @@ func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) error { return fv.SetUpAt(fv.getPath(), mounterArgs) } +func (fv *FakeVolume) SetUpWithStatusTracking(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { + err := fv.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + func (fv *FakeVolume) GetSetUpCallCount() int { fv.RLock() defer fv.RUnlock() diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 5d530d4472f..692356e3565 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -580,10 +580,16 @@ func (og *operationGenerator) GenerateMountVolumeFunc( devicePath, deviceMountPath) if err != nil { - if operationState == volumetypes.OperationInProgress { + switch operationState { + case volumetypes.OperationInProgress: markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) if markDeviceUncertainError != nil { - klog.Infof("MountVolume.MarkDeviceAsUncertain failed with %v", markDeviceUncertainError) + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error()) + } + case volumetypes.OperationFinished: + markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName) + if markDeviceUnmountError != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error()) } } // On failure, return error. Caller will log and retry. @@ -623,7 +629,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Execute mount - mountErr := volumeMounter.SetUp(volume.MounterArgs{ + opExitStatus, mountErr := volumeMounter.SetUpWithStatusTracking(volume.MounterArgs{ FsGroup: fsGroup, DesiredSize: volumeToMount.DesiredSizeLimit, }) @@ -639,11 +645,18 @@ func (og *operationGenerator) GenerateMountVolumeFunc( VolumeMountState: VolumeMounted, } if mountErr != nil { - if volumetypes.IsOperationTimeOutError(mountErr) { + switch opExitStatus { + case volumetypes.OperationInProgress: markOpts.VolumeMountState = VolumeMountUncertain t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) if t != nil { - klog.Errorf("MountVolume.MarkVolumeMountAsUncertain failed: %v", t) + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) + } + case volumetypes.OperationFinished: + markOpts.VolumeMountState = VolumeNotMounted + t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) + if t != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) } } // On failure, return error. Caller will log and retry. diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index 83a79623694..d18f42c1700 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -130,6 +130,11 @@ type Mounter interface { // accessed by the pod. This may be called more than once, so // implementations must be idempotent. SetUp(mounterArgs MounterArgs) error + + // SetupWithStatusTracking is similar to SetUp function except it + // also return operation status as a return value + SetUpWithStatusTracking(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) + // SetUpAt prepares and mounts/unpacks the volume to the // specified directory path, which may or may not exist yet. // The mount point and its content should be owned by diff --git a/pkg/volume/vsphere_volume/vsphere_volume.go b/pkg/volume/vsphere_volume/vsphere_volume.go index 2d023da3b1f..a521f1d7bf5 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume.go +++ b/pkg/volume/vsphere_volume/vsphere_volume.go @@ -38,7 +38,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" -) + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" // This is the primary entrypoint for volume plugins. func ProbeVolumePlugins() []volume.VolumePlugin { @@ -217,6 +217,12 @@ func (b *vsphereVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { return b.SetUpAt(b.GetPath(), mounterArgs) } +// SetUp attaches the disk and bind mounts to the volume path. +func (b *vsphereVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUp(mounterArgs) + return volumetypes.OperationFinished, err +} + // Checks prior to mount operations to verify that the required components (binaries, etc.) // to mount the volume are available on the underlying node. // If not, it returns an error From 27a70a9260c6c0388193b50b1646c9e204d32d0f Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 25 Sep 2019 16:24:29 -0400 Subject: [PATCH 06/15] Update generated files --- pkg/controller/volume/attachdetach/testing/BUILD | 1 + pkg/kubelet/kubelet_volumes_test.go | 5 +++++ pkg/volume/BUILD | 1 + pkg/volume/awsebs/BUILD | 1 + pkg/volume/azure_dd/BUILD | 1 + pkg/volume/azure_file/BUILD | 1 + pkg/volume/cephfs/BUILD | 1 + pkg/volume/cinder/BUILD | 1 + pkg/volume/configmap/BUILD | 1 + pkg/volume/downwardapi/BUILD | 1 + pkg/volume/emptydir/BUILD | 1 + pkg/volume/fc/BUILD | 1 + pkg/volume/flexvolume/BUILD | 1 + pkg/volume/flocker/BUILD | 1 + pkg/volume/gcepd/BUILD | 1 + pkg/volume/git_repo/BUILD | 1 + pkg/volume/glusterfs/BUILD | 1 + pkg/volume/hostpath/BUILD | 1 + pkg/volume/iscsi/BUILD | 1 + pkg/volume/local/BUILD | 1 + pkg/volume/nfs/BUILD | 1 + pkg/volume/portworx/BUILD | 1 + pkg/volume/projected/BUILD | 1 + pkg/volume/quobyte/BUILD | 1 + pkg/volume/rbd/BUILD | 1 + pkg/volume/scaleio/BUILD | 1 + pkg/volume/secret/BUILD | 1 + pkg/volume/storageos/BUILD | 1 + pkg/volume/testing/testing.go | 6 ++++++ pkg/volume/vsphere_volume/BUILD | 1 + 30 files changed, 39 insertions(+) diff --git a/pkg/controller/volume/attachdetach/testing/BUILD b/pkg/controller/volume/attachdetach/testing/BUILD index e063b6b5fe2..03a639344d3 100644 --- a/pkg/controller/volume/attachdetach/testing/BUILD +++ b/pkg/controller/volume/attachdetach/testing/BUILD @@ -12,6 +12,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/kubelet/kubelet_volumes_test.go b/pkg/kubelet/kubelet_volumes_test.go index bfc5c8b7c22..b5d2c168e55 100644 --- a/pkg/kubelet/kubelet_volumes_test.go +++ b/pkg/kubelet/kubelet_volumes_test.go @@ -29,6 +29,7 @@ import ( "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) func TestListVolumesForPod(t *testing.T) { @@ -538,6 +539,10 @@ func (f *stubVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { return nil } +func (f *stubVolume) SetUpWithStatusTracking(mountArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + return volumetypes.OperationFinished, nil +} + type stubBlockVolume struct { dirPath string volName string diff --git a/pkg/volume/BUILD b/pkg/volume/BUILD index 8e608ecc467..88919d029a4 100644 --- a/pkg/volume/BUILD +++ b/pkg/volume/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", "//pkg/volume/util/subpath:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/awsebs/BUILD b/pkg/volume/awsebs/BUILD index 0a64e9943ea..a9dfc8b4361 100644 --- a/pkg/volume/awsebs/BUILD +++ b/pkg/volume/awsebs/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/azure_dd/BUILD b/pkg/volume/azure_dd/BUILD index 9e607d94ef0..b2839f87927 100644 --- a/pkg/volume/azure_dd/BUILD +++ b/pkg/volume/azure_dd/BUILD @@ -27,6 +27,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/azure_file/BUILD b/pkg/volume/azure_file/BUILD index 1c4640f78a0..f425722d0b9 100644 --- a/pkg/volume/azure_file/BUILD +++ b/pkg/volume/azure_file/BUILD @@ -13,6 +13,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/cephfs/BUILD b/pkg/volume/cephfs/BUILD index b521e4b48c9..f3ed56c1c85 100644 --- a/pkg/volume/cephfs/BUILD +++ b/pkg/volume/cephfs/BUILD @@ -16,6 +16,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/cinder/BUILD b/pkg/volume/cinder/BUILD index 6d8674c91d3..06278d9ddeb 100644 --- a/pkg/volume/cinder/BUILD +++ b/pkg/volume/cinder/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/configmap/BUILD b/pkg/volume/configmap/BUILD index ab7d2571142..3300373c646 100644 --- a/pkg/volume/configmap/BUILD +++ b/pkg/volume/configmap/BUILD @@ -16,6 +16,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/downwardapi/BUILD b/pkg/volume/downwardapi/BUILD index cece3c521e2..081164f60a4 100644 --- a/pkg/volume/downwardapi/BUILD +++ b/pkg/volume/downwardapi/BUILD @@ -15,6 +15,7 @@ go_library( "//pkg/fieldpath:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library", diff --git a/pkg/volume/emptydir/BUILD b/pkg/volume/emptydir/BUILD index c4a58fda540..13ba66ba972 100644 --- a/pkg/volume/emptydir/BUILD +++ b/pkg/volume/emptydir/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/fsquota:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/fc/BUILD b/pkg/volume/fc/BUILD index dd16c9f27b3..158fc17f212 100644 --- a/pkg/volume/fc/BUILD +++ b/pkg/volume/fc/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/flexvolume/BUILD b/pkg/volume/flexvolume/BUILD index 9cb8aceaa93..777ede4375d 100644 --- a/pkg/volume/flexvolume/BUILD +++ b/pkg/volume/flexvolume/BUILD @@ -32,6 +32,7 @@ go_library( "//pkg/util/filesystem:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/flocker/BUILD b/pkg/volume/flocker/BUILD index 276ada39eed..e67799ee70e 100644 --- a/pkg/volume/flocker/BUILD +++ b/pkg/volume/flocker/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/util/env:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/gcepd/BUILD b/pkg/volume/gcepd/BUILD index cff495a05d4..2ef8af55718 100644 --- a/pkg/volume/gcepd/BUILD +++ b/pkg/volume/gcepd/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/git_repo/BUILD b/pkg/volume/git_repo/BUILD index 57a9e29bdf2..467410ea49b 100644 --- a/pkg/volume/git_repo/BUILD +++ b/pkg/volume/git_repo/BUILD @@ -16,6 +16,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", diff --git a/pkg/volume/glusterfs/BUILD b/pkg/volume/glusterfs/BUILD index a7b6e671934..a8a73afe7d5 100644 --- a/pkg/volume/glusterfs/BUILD +++ b/pkg/volume/glusterfs/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/apis/core/v1/helper:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/hostpath/BUILD b/pkg/volume/hostpath/BUILD index 0c2bd65bf3a..5aae5056809 100644 --- a/pkg/volume/hostpath/BUILD +++ b/pkg/volume/hostpath/BUILD @@ -18,6 +18,7 @@ go_library( "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/validation:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/iscsi/BUILD b/pkg/volume/iscsi/BUILD index c7ac6a79bf9..68c19fa25f4 100644 --- a/pkg/volume/iscsi/BUILD +++ b/pkg/volume/iscsi/BUILD @@ -21,6 +21,7 @@ go_library( "//pkg/kubelet/config:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/local/BUILD b/pkg/volume/local/BUILD index 1fcbe6c957f..1115ac9314b 100644 --- a/pkg/volume/local/BUILD +++ b/pkg/volume/local/BUILD @@ -13,6 +13,7 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/validation:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/nfs/BUILD b/pkg/volume/nfs/BUILD index 624a7898a2e..268871a739a 100644 --- a/pkg/volume/nfs/BUILD +++ b/pkg/volume/nfs/BUILD @@ -17,6 +17,7 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/portworx/BUILD b/pkg/volume/portworx/BUILD index 06f8c232f02..41e6240d7ee 100644 --- a/pkg/volume/portworx/BUILD +++ b/pkg/volume/portworx/BUILD @@ -33,6 +33,7 @@ go_library( "//pkg/apis/core:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/projected/BUILD b/pkg/volume/projected/BUILD index d3685747bf5..3dfe5afe15a 100644 --- a/pkg/volume/projected/BUILD +++ b/pkg/volume/projected/BUILD @@ -41,6 +41,7 @@ go_library( "//pkg/volume/downwardapi:go_default_library", "//pkg/volume/secret:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/pkg/volume/quobyte/BUILD b/pkg/volume/quobyte/BUILD index 60bc5a55ab1..e8f05722228 100644 --- a/pkg/volume/quobyte/BUILD +++ b/pkg/volume/quobyte/BUILD @@ -17,6 +17,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/rbd/BUILD b/pkg/volume/rbd/BUILD index 09226ab256b..f26fdbb9895 100644 --- a/pkg/volume/rbd/BUILD +++ b/pkg/volume/rbd/BUILD @@ -21,6 +21,7 @@ go_library( "//pkg/util/node:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/scaleio/BUILD b/pkg/volume/scaleio/BUILD index f1410f50657..5af6e3ecf91 100644 --- a/pkg/volume/scaleio/BUILD +++ b/pkg/volume/scaleio/BUILD @@ -42,6 +42,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/secret/BUILD b/pkg/volume/secret/BUILD index cb168c9532d..a34ad5fd998 100644 --- a/pkg/volume/secret/BUILD +++ b/pkg/volume/secret/BUILD @@ -16,6 +16,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/storageos/BUILD b/pkg/volume/storageos/BUILD index 8d1b5730cbe..eea84684a13 100644 --- a/pkg/volume/storageos/BUILD +++ b/pkg/volume/storageos/BUILD @@ -17,6 +17,7 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 263ad6b0034..7544859913b 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -849,6 +849,9 @@ func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) error { func (fv *FakeVolume) SetUpWithStatusTracking(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { err := fv.SetUp(mounterArgs) + if volumetypes.IsOperationTimeOutError(err) { + return volumetypes.OperationInProgress, err + } return volumetypes.OperationFinished, err } @@ -1061,6 +1064,9 @@ func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath func (fv *FakeVolume) MountDeviceWithStatusTracking(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { err := fv.MountDevice(spec, devicePath, deviceMountPath) + if volumetypes.IsOperationTimeOutError(err) { + return volumetypes.OperationInProgress, err + } return volumetypes.OperationFinished, err } diff --git a/pkg/volume/vsphere_volume/BUILD b/pkg/volume/vsphere_volume/BUILD index b4bab5c5ef9..a2f466175d9 100644 --- a/pkg/volume/vsphere_volume/BUILD +++ b/pkg/volume/vsphere_volume/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", From 57019e0628adcbfe0c218feebbdb94544274be3c Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 27 Sep 2019 15:20:36 -0400 Subject: [PATCH 07/15] Add tests for verifying in-progress state --- pkg/volume/csi/csi_attacher.go | 5 + pkg/volume/csi/csi_attacher_test.go | 168 ++++++++++++++++++---------- pkg/volume/csi/csi_client_test.go | 13 +++ pkg/volume/csi/csi_mounter.go | 4 +- pkg/volume/csi/csi_mounter_test.go | 109 ++++++++++++++++++ pkg/volume/csi/fake/fake_client.go | 23 +++- 6 files changed, 257 insertions(+), 65 deletions(-) diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index 6428bf9e35c..7814a9f860d 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -309,6 +309,11 @@ func (c *csiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePat nodeName := string(c.plugin.host.GetNodeName()) publishContext, err := c.plugin.getPublishContext(c.k8s, csiSource.VolumeHandle, csiSource.Driver, nodeName) + if err != nil { + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, err + } + nodeStageSecrets := map[string]string{} if csiSource.NodeStageSecretRef != nil { nodeStageSecrets, err = getCredentialsFromSecret(c.k8s, csiSource.NodeStageSecretRef) diff --git a/pkg/volume/csi/csi_attacher_test.go b/pkg/volume/csi/csi_attacher_test.go index 075601ad9ca..ae215e93b28 100644 --- a/pkg/volume/csi/csi_attacher_test.go +++ b/pkg/volume/csi/csi_attacher_test.go @@ -44,7 +44,9 @@ import ( featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" + fakecsi "k8s.io/kubernetes/pkg/volume/csi/fake" volumetest "k8s.io/kubernetes/pkg/volume/testing" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) var ( @@ -1055,72 +1057,110 @@ func TestAttacherGetDeviceMountPath(t *testing.T) { func TestAttacherMountDevice(t *testing.T) { pvName := "test-pv" testCases := []struct { - testName string - volName string - devicePath string - deviceMountPath string - stageUnstageSet bool - shouldFail bool - spec *volume.Spec + testName string + volName string + devicePath string + deviceMountPath string + stageUnstageSet bool + shouldFail bool + createAttachment bool + exitStatus volumetypes.OperationStatus + spec *volume.Spec }{ { - testName: "normal PV", - volName: "test-vol1", - devicePath: "path1", - deviceMountPath: "path2", - stageUnstageSet: true, - spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + testName: "normal PV", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: true, + createAttachment: true, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + exitStatus: volumetypes.OperationFinished, }, { - testName: "normal PV with mount options", - volName: "test-vol1", - devicePath: "path1", - deviceMountPath: "path2", - stageUnstageSet: true, - spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false), + testName: "normal PV with mount options", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: true, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false), }, { - testName: "no vol name", - volName: "", - devicePath: "path1", - deviceMountPath: "path2", - stageUnstageSet: true, - shouldFail: true, - spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false), + testName: "normal PV but with missing attachment should result in no-change", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: true, + createAttachment: false, + shouldFail: true, + exitStatus: volumetypes.OperationStateNoChange, + spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false), }, { - testName: "no device path", - volName: "test-vol1", - devicePath: "", - deviceMountPath: "path2", - stageUnstageSet: true, - shouldFail: false, - spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + testName: "no vol name", + volName: "", + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: true, + shouldFail: true, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false), }, { - testName: "no device mount path", - volName: "test-vol1", - devicePath: "path1", - deviceMountPath: "", - stageUnstageSet: true, - shouldFail: true, - spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + testName: "no device path", + volName: "test-vol1", + devicePath: "", + deviceMountPath: "path2", + stageUnstageSet: true, + shouldFail: false, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), }, { - testName: "stage_unstage cap not set", - volName: "test-vol1", - devicePath: "path1", - deviceMountPath: "path2", - stageUnstageSet: false, - spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + testName: "no device mount path", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "", + stageUnstageSet: true, + shouldFail: true, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), }, { - testName: "failure with volume source", - volName: "test-vol1", - devicePath: "path1", - deviceMountPath: "path2", - shouldFail: true, - spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)), + testName: "stage_unstage cap not set", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: false, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), + }, + { + testName: "failure with volume source", + volName: "test-vol1", + devicePath: "path1", + deviceMountPath: "path2", + shouldFail: true, + createAttachment: true, + exitStatus: volumetypes.OperationFinished, + spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)), + }, + { + testName: "pv with nodestage timeout should result in in-progress device", + volName: fakecsi.NodeStageTimeOut_VolumeID, + devicePath: "path1", + deviceMountPath: "path2", + stageUnstageSet: true, + createAttachment: true, + spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, fakecsi.NodeStageTimeOut_VolumeID), false), + exitStatus: volumetypes.OperationInProgress, + shouldFail: true, }, } @@ -1146,18 +1186,20 @@ func TestAttacherMountDevice(t *testing.T) { nodeName := string(csiAttacher.plugin.host.GetNodeName()) attachID := getAttachmentName(tc.volName, testDriver, nodeName) - // Set up volume attachment - attachment := makeTestAttachment(attachID, nodeName, pvName) - _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment) - if err != nil { - t.Fatalf("failed to attach: %v", err) + if tc.createAttachment { + // Set up volume attachment + attachment := makeTestAttachment(attachID, nodeName, pvName) + _, err := csiAttacher.k8s.StorageV1().VolumeAttachments().Create(attachment) + if err != nil { + t.Fatalf("failed to attach: %v", err) + } + go func() { + fakeWatcher.Delete(attachment) + }() } - go func() { - fakeWatcher.Delete(attachment) - }() // Run - err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) + exitStatus, err := csiAttacher.MountDeviceWithStatusTracking(tc.spec, tc.devicePath, tc.deviceMountPath) // Verify if err != nil { @@ -1170,6 +1212,10 @@ func TestAttacherMountDevice(t *testing.T) { t.Errorf("test should fail, but no error occurred") } + if exitStatus != tc.exitStatus { + t.Fatalf("expected exitStatus: %v got: %v", tc.exitStatus, exitStatus) + } + // Verify call goes through all the way numStaged := 1 if !tc.stageUnstageSet { diff --git a/pkg/volume/csi/csi_client_test.go b/pkg/volume/csi/csi_client_test.go index cef0e814fc6..3724b2cb574 100644 --- a/pkg/volume/csi/csi_client_test.go +++ b/pkg/volume/csi/csi_client_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/csi/fake" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type fakeCsiDriverClient struct { @@ -156,6 +157,12 @@ func (c *fakeCsiDriverClient) NodePublishVolume( } _, err := c.nodeClient.NodePublishVolume(ctx, req) + if err != nil { + if isFinalError(err) { + return err + } + return volumetypes.NewOperationTimedOutError(err.Error()) + } return err } @@ -201,6 +208,12 @@ func (c *fakeCsiDriverClient) NodeStageVolume(ctx context.Context, } _, err := c.nodeClient.NodeStageVolume(ctx, req) + if err != nil { + if isFinalError(err) { + return err + } + return volumetypes.NewOperationTimedOutError(err.Error()) + } return err } diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 6e0fb98aad8..22a5085bd03 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -104,8 +104,8 @@ func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) error { } func (c *csiMountMgr) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := c.SetUp(mounterArgs) - return volumetypes.OperationFinished, err + opExitStatus, err := c.setupUtil(c.GetPath(), mounterArgs) + return opExitStatus, err } func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index 985e208faa0..fcde71c0c13 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -36,7 +36,9 @@ import ( featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" + fakecsi "k8s.io/kubernetes/pkg/volume/csi/fake" "k8s.io/kubernetes/pkg/volume/util" + volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) var ( @@ -396,6 +398,113 @@ func TestMounterSetUpSimple(t *testing.T) { } } +func TestMounterSetupWithStatusTracking(t *testing.T) { + fakeClient := fakeclient.NewSimpleClientset() + plug, tmpDir := newTestPlugin(t, fakeClient) + defer os.RemoveAll(tmpDir) + + testCases := []struct { + name string + podUID types.UID + spec func(string, []string) *volume.Spec + shouldFail bool + exitStatus volumetypes.OperationStatus + createAttachment bool + }{ + { + name: "setup with correct persistent volume source should result in finish exit status", + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + spec: func(fsType string, options []string) *volume.Spec { + pvSrc := makeTestPV("pv1", 20, testDriver, "vol1") + pvSrc.Spec.CSI.FSType = fsType + pvSrc.Spec.MountOptions = options + return volume.NewSpecFromPersistentVolume(pvSrc, false) + }, + exitStatus: volumetypes.OperationFinished, + createAttachment: true, + }, + { + name: "setup with missing attachment should result in nochange", + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + spec: func(fsType string, options []string) *volume.Spec { + return volume.NewSpecFromPersistentVolume(makeTestPV("pv3", 20, testDriver, "vol4"), false) + }, + exitStatus: volumetypes.OperationStateNoChange, + createAttachment: false, + shouldFail: true, + }, + { + name: "setup with timeout errors on NodePublish", + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + spec: func(fsType string, options []string) *volume.Spec { + return volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, fakecsi.NodePublishTimeOut_VolumeID), false) + }, + createAttachment: true, + exitStatus: volumetypes.OperationInProgress, + shouldFail: true, + }, + { + name: "setup with missing secrets should result in nochange exit", + podUID: types.UID(fmt.Sprintf("%08X", rand.Uint64())), + spec: func(fsType string, options []string) *volume.Spec { + pv := makeTestPV("pv5", 20, testDriver, "vol6") + pv.Spec.PersistentVolumeSource.CSI.NodePublishSecretRef = &api.SecretReference{ + Name: "foo", + Namespace: "default", + } + return volume.NewSpecFromPersistentVolume(pv, false) + }, + exitStatus: volumetypes.OperationStateNoChange, + createAttachment: true, + shouldFail: true, + }, + } + + for _, tc := range testCases { + registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) + t.Run(tc.name, func(t *testing.T) { + mounter, err := plug.NewMounter( + tc.spec("ext4", []string{}), + &api.Pod{ObjectMeta: meta.ObjectMeta{UID: tc.podUID, Namespace: testns}}, + volume.VolumeOptions{}, + ) + if mounter == nil { + t.Fatal("failed to create CSI mounter") + } + + csiMounter := mounter.(*csiMountMgr) + csiMounter.csiClient = setupClient(t, true) + + if csiMounter.volumeLifecycleMode != storagev1beta1.VolumeLifecyclePersistent { + t.Fatal("unexpected volume mode: ", csiMounter.volumeLifecycleMode) + } + + if tc.createAttachment { + attachID := getAttachmentName(csiMounter.volumeID, string(csiMounter.driverName), string(plug.host.GetNodeName())) + attachment := makeTestAttachment(attachID, "test-node", csiMounter.spec.Name()) + _, err = csiMounter.k8s.StorageV1().VolumeAttachments().Create(attachment) + if err != nil { + t.Fatalf("failed to setup VolumeAttachment: %v", err) + } + } + + opExistStatus, err := csiMounter.SetUpWithStatusTracking(volume.MounterArgs{}) + + if opExistStatus != tc.exitStatus { + t.Fatalf("expected exitStatus: %v but got %v", tc.exitStatus, opExistStatus) + } + + if tc.shouldFail && err == nil { + t.Fatalf("expected failure but Setup succeeded") + } + + if !tc.shouldFail && err != nil { + t.Fatalf("expected successs got mounter.Setup failed with: %v", err) + } + }) + } +} + func TestMounterSetUpWithInline(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIInlineVolume, true)() diff --git a/pkg/volume/csi/fake/fake_client.go b/pkg/volume/csi/fake/fake_client.go index 19072963da0..0ce54f50ad8 100644 --- a/pkg/volume/csi/fake/fake_client.go +++ b/pkg/volume/csi/fake/fake_client.go @@ -21,9 +21,17 @@ import ( "errors" "strings" - "google.golang.org/grpc" - csipb "github.com/container-storage-interface/spec/lib/go/csi" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + // NodePublishTimeout_VolumeID is volume id that will result in NodePublish operation to timeout + NodePublishTimeOut_VolumeID = "node-publish-timeout" + // NodeStageTimeOut_VolumeID is a volume id that will result in NodeStage operation to timeout + NodeStageTimeOut_VolumeID = "node-stage-timeout" ) // IdentityClient is a CSI identity client used for testing @@ -158,6 +166,12 @@ func (f *NodeClient) NodePublishVolume(ctx context.Context, req *csipb.NodePubli if !strings.Contains(fsTypes, fsType) { return nil, errors.New("invalid fstype") } + + if req.GetVolumeId() == NodePublishTimeOut_VolumeID { + timeoutErr := status.Errorf(codes.DeadlineExceeded, "timeout exceeded") + return nil, timeoutErr + } + f.nodePublishedVolumes[req.GetVolumeId()] = CSIVolume{ VolumeHandle: req.GetVolumeId(), Path: req.GetTargetPath(), @@ -214,6 +228,11 @@ func (f *NodeClient) NodeStageVolume(ctx context.Context, req *csipb.NodeStageVo return nil, errors.New("invalid fstype") } + if req.GetVolumeId() == NodeStageTimeOut_VolumeID { + timeoutErr := status.Errorf(codes.DeadlineExceeded, "timeout exceeded") + return nil, timeoutErr + } + f.nodeStagedVolumes[req.GetVolumeId()] = csiVol return &csipb.NodeStageVolumeResponse{}, nil } From 0c52b6606e6f779ddd0cd22a4ca372b1abf8da60 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 27 Sep 2019 15:25:19 -0400 Subject: [PATCH 08/15] Refactor NodeStage function Timeout operations should result in Fix unit tests for uncertainDeviceGlobalMounts --- pkg/kubelet/BUILD | 1 + .../reconciler/reconciler_test.go | 221 ++++++++++-------- pkg/volume/csi/BUILD | 1 + pkg/volume/csi/csi_mounter_test.go | 2 +- pkg/volume/csi/fake/BUILD | 2 + pkg/volume/flexvolume/attacher.go | 4 +- pkg/volume/testing/testing.go | 26 ++- pkg/volume/util/types/types.go | 1 + 8 files changed, 161 insertions(+), 97 deletions(-) diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index f942cf4c2aa..f6681956119 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -224,6 +224,7 @@ go_test( "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/subpath:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go index dfafd8985a1..ae8071145cf 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go @@ -51,9 +51,10 @@ const ( reconcilerLoopSleepDuration time.Duration = 1 * time.Nanosecond // waitForAttachTimeout is the maximum amount of time a // operationexecutor.Mount call will wait for a volume to be attached. - waitForAttachTimeout time.Duration = 1 * time.Second - nodeName k8stypes.NodeName = k8stypes.NodeName("mynodename") - kubeletPodsDir string = "fake-dir" + waitForAttachTimeout time.Duration = 1 * time.Second + nodeName k8stypes.NodeName = k8stypes.NodeName("mynodename") + kubeletPodsDir string = "fake-dir" + testOperationBackOffDuration time.Duration = 100 * time.Millisecond ) func hasAddedPods() bool { return true } @@ -1134,7 +1135,7 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) { // resize operation and clear the fsResizeRequired flag for volume. go reconciler.Run(wait.NeverStop) - waitErr := retryWithExponentialBackOff(500*time.Millisecond, func() (done bool, err error) { + waitErr := retryWithExponentialBackOff(testOperationBackOffDuration, func() (done bool, err error) { mounted, _, err := asw.PodExistsInVolume(podName, volumeName) return mounted && err == nil, nil }) @@ -1147,97 +1148,131 @@ func Test_Run_Positive_VolumeFSResizeControllerAttachEnabled(t *testing.T) { func Test_UncertainDeviceGlobalMounts(t *testing.T) { fsMode := v1.PersistentVolumeFilesystem - pv := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: volumetesting.TimeoutOnMountDeviceVolumeName, - UID: "pvuid", + var tests = []struct { + name string + deviceState operationexecutor.DeviceMountState + unmountDeviceCallCount int + volumeName string + }{ + { + name: "timed out operations should result in device marked as uncertain", + deviceState: operationexecutor.DeviceMountUncertain, + unmountDeviceCallCount: 1, + volumeName: volumetesting.TimeoutOnMountDeviceVolumeName, }, - Spec: v1.PersistentVolumeSpec{ - ClaimRef: &v1.ObjectReference{Name: "pvc"}, - VolumeMode: &fsMode, + { + name: "failed operation should result in not-mounted device", + deviceState: operationexecutor.DeviceNotMounted, + unmountDeviceCallCount: 0, + volumeName: volumetesting.FailMountDeviceVolumeName, + }, + { + name: "timeout followed by failed operation should result in non-mounted device", + deviceState: operationexecutor.DeviceNotMounted, + unmountDeviceCallCount: 0, + volumeName: volumetesting.TimeoutAndFailOnMountDeviceVolumeName, }, } - pvc := &v1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pvc", - UID: "pvcuid", - }, - Spec: v1.PersistentVolumeClaimSpec{ - VolumeName: volumetesting.TimeoutOnMountDeviceVolumeName, - }, - } - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod1", - UID: "pod1uid", - }, - Spec: v1.PodSpec{ - Volumes: []v1.Volume{ - { - Name: "volume-name", - VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: pvc.Name, + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.volumeName, + UID: "pvuid", + }, + Spec: v1.PersistentVolumeSpec{ + ClaimRef: &v1.ObjectReference{Name: "pvc"}, + VolumeMode: &fsMode, + }, + } + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc", + UID: "pvcuid", + }, + Spec: v1.PersistentVolumeClaimSpec{ + VolumeName: tc.volumeName, + }, + } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "volume-name", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvc.Name, + }, + }, }, }, }, - }, - }, + } + + volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) + dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) + asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) + kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ + Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", tc.volumeName)), + DevicePath: "fake/path", + }) + fakeRecorder := &record.FakeRecorder{} + fakeHandler := volumetesting.NewBlockVolumePathHandler() + oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( + kubeClient, + volumePluginMgr, + fakeRecorder, + false, /* checkNodeCapabilitiesBeforeMount */ + fakeHandler)) + + reconciler := NewReconciler( + kubeClient, + true, /* controllerAttachDetachEnabled */ + reconcilerLoopSleepDuration, + waitForAttachTimeout, + nodeName, + dsw, + asw, + hasAddedPods, + oex, + &mount.FakeMounter{}, + hostutil.NewFakeHostUtil(nil), + volumePluginMgr, + kubeletPodsDir) + volumeSpec := &volume.Spec{PersistentVolume: pv} + podName := util.GetUniquePodName(pod) + volumeName, err := dsw.AddPodToVolume( + podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) + // Assert + if err != nil { + t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) + } + dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) + + // Start the reconciler to fill ASW. + stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) + go func() { + reconciler.Run(stopChan) + close(stoppedChan) + }() + waitForVolumeToExistInASW(t, volumeName, asw) + if tc.deviceState == operationexecutor.DeviceMountUncertain { + waitForUncertainGlobalMount(t, volumeName, asw) + } + + dsw.DeletePodFromVolume(podName, volumeName) + waitForDetach(t, volumeName, asw) + + volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) + + }) } - - volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) - dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) - asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) - kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ - Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", volumetesting.TimeoutOnMountDeviceVolumeName)), - DevicePath: "fake/path", - }) - fakeRecorder := &record.FakeRecorder{} - fakeHandler := volumetesting.NewBlockVolumePathHandler() - oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( - kubeClient, - volumePluginMgr, - fakeRecorder, - false, /* checkNodeCapabilitiesBeforeMount */ - fakeHandler)) - - reconciler := NewReconciler( - kubeClient, - true, /* controllerAttachDetachEnabled */ - reconcilerLoopSleepDuration, - waitForAttachTimeout, - nodeName, - dsw, - asw, - hasAddedPods, - oex, - &mount.FakeMounter{}, - hostutil.NewFakeHostUtil(nil), - volumePluginMgr, - kubeletPodsDir) - volumeSpec := &volume.Spec{PersistentVolume: pv} - podName := util.GetUniquePodName(pod) - volumeName, err := dsw.AddPodToVolume( - podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) - // Assert - if err != nil { - t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) - } - dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) - - // Start the reconciler to fill ASW. - stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) - go func() { - reconciler.Run(stopChan) - close(stoppedChan) - }() - waitForVolumeToExistInASW(t, volumeName, asw) - waitForUncertainGlobalMount(t, volumeName, asw) - - dsw.DeletePodFromVolume(podName, volumeName) - waitForDetach(t, volumeName, asw) - - volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) } func Test_UncertainVolumeMountState(t *testing.T) { @@ -1339,7 +1374,7 @@ func Test_UncertainVolumeMountState(t *testing.T) { func waitForUncertainGlobalMount(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { // check if volume is globally mounted in uncertain state err := retryWithExponentialBackOff( - time.Duration(500*time.Millisecond), + testOperationBackOffDuration, func() (bool, error) { unmountedVolumes := asw.GetUnmountedVolumes() for _, v := range unmountedVolumes { @@ -1359,7 +1394,7 @@ func waitForUncertainGlobalMount(t *testing.T, volumeName v1.UniqueVolumeName, a func waitForUncertainPodMount(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { // check if volume is locally pod mounted in uncertain state err := retryWithExponentialBackOff( - time.Duration(500*time.Millisecond), + testOperationBackOffDuration, func() (bool, error) { allMountedVolumes := asw.GetAllMountedVolumes() for _, v := range allMountedVolumes { @@ -1382,7 +1417,7 @@ func waitForMount( volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { err := retryWithExponentialBackOff( - time.Duration(500*time.Millisecond), + testOperationBackOffDuration, func() (bool, error) { mountedVolumes := asw.GetMountedVolumes() for _, mountedVolume := range mountedVolumes { @@ -1402,7 +1437,7 @@ func waitForMount( func waitForVolumeToExistInASW(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { err := retryWithExponentialBackOff( - time.Duration(500*time.Millisecond), + testOperationBackOffDuration, func() (bool, error) { if asw.VolumeExists(volumeName) { return true, nil @@ -1420,7 +1455,7 @@ func waitForDetach( volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { err := retryWithExponentialBackOff( - time.Duration(500*time.Millisecond), + testOperationBackOffDuration, func() (bool, error) { if asw.VolumeExists(volumeName) { return false, nil diff --git a/pkg/volume/csi/BUILD b/pkg/volume/csi/BUILD index db1aa80e0d7..f81314c7565 100644 --- a/pkg/volume/csi/BUILD +++ b/pkg/volume/csi/BUILD @@ -66,6 +66,7 @@ go_test( "//pkg/volume/csi/fake:go_default_library", "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", + "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index fcde71c0c13..c397ddf2bae 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -499,7 +499,7 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { } if !tc.shouldFail && err != nil { - t.Fatalf("expected successs got mounter.Setup failed with: %v", err) + t.Fatalf("expected success got mounter.Setup failed with: %v", err) } }) } diff --git a/pkg/volume/csi/fake/BUILD b/pkg/volume/csi/fake/BUILD index c2c6b44d4f5..0d50b64946d 100644 --- a/pkg/volume/csi/fake/BUILD +++ b/pkg/volume/csi/fake/BUILD @@ -11,6 +11,8 @@ go_library( deps = [ "//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", ], ) diff --git a/pkg/volume/flexvolume/attacher.go b/pkg/volume/flexvolume/attacher.go index e83da3ff2d3..07e9582a134 100644 --- a/pkg/volume/flexvolume/attacher.go +++ b/pkg/volume/flexvolume/attacher.go @@ -98,8 +98,8 @@ func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, d return err } -func (attacher *flexVolumeAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +func (a *flexVolumeAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := a.MountDevice(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 7544859913b..083c7a6fab6 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -71,6 +71,10 @@ const ( TimeoutOnSetupVolumeName = "timeout-setup-volume" // TimeoutOnMountDeviceVolumeName will cause MountDevice call to timeout but Setup will finish. TimeoutOnMountDeviceVolumeName = "timeout-mount-device-volume" + // TimeoutAndFailOnMountDeviceVolumeName will cause first MountDevice call to timeout but second call will fail + TimeoutAndFailOnMountDeviceVolumeName = "timeout-and-fail-mount-device-name" + // FailMountDeviceVolumeName will cause MountDevice operation on volume to fail + FailMountDeviceVolumeName = "fail-mount-device-volume-name" ) // fakeVolumeHost is useful for testing volume plugins. @@ -388,6 +392,7 @@ func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume { UnmountDeviceHook: plugin.UnmountDeviceHook, } volume.VolumesAttached = make(map[string]types.NodeName) + volume.DeviceMountState = make(map[string]volumetypes.OperationStatus) *list = append(*list, volume) return volume } @@ -789,7 +794,8 @@ type FakeVolume struct { VolName string Plugin *FakeVolumePlugin MetricsNil - VolumesAttached map[string]types.NodeName + VolumesAttached map[string]types.NodeName + DeviceMountState map[string]volumetypes.OperationStatus // Add callbacks as needed WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) @@ -1056,8 +1062,26 @@ func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath fv.Lock() defer fv.Unlock() if spec.Name() == TimeoutOnMountDeviceVolumeName { + fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress return volumetypes.NewOperationTimedOutError("error mounting device") } + + if spec.Name() == FailMountDeviceVolumeName { + fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + return fmt.Errorf("error mounting disk: %s", devicePath) + } + + if spec.Name() == TimeoutAndFailOnMountDeviceVolumeName { + oldState, ok := fv.DeviceMountState[spec.Name()] + if !ok { + fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress + return volumetypes.NewOperationTimedOutError("error mounting state") + } + if oldState == volumetypes.OperationInProgress { + fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + return fmt.Errorf("error mounting disk: %s", devicePath) + } + } fv.MountDeviceCallCount++ return nil } diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index baaa488137d..284427fcabb 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -51,6 +51,7 @@ func (o *GeneratedOperations) Run() (eventErr, detailedErr error) { return o.OperationFunc() } +// OperationStatus is used to store status of a volume operation type OperationStatus string const ( From db9ac38592d9ef51dfe7f348659a9315b13546ce Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 6 Nov 2019 16:29:54 -0500 Subject: [PATCH 09/15] Change signature of MountDevice function and remove MountDeviceWithStatusTracking --- .../attachdetach/testing/testvolumespec.go | 9 +-- pkg/volume/awsebs/attacher.go | 17 ++---- pkg/volume/azure_dd/attacher.go | 11 ++-- pkg/volume/cinder/attacher.go | 6 +- pkg/volume/csi/csi_attacher.go | 7 +-- pkg/volume/csi/csi_attacher_test.go | 2 +- pkg/volume/csi/csi_test.go | 2 +- pkg/volume/fc/attacher.go | 58 +++++++++---------- pkg/volume/flexvolume/attacher.go | 54 +++++++++-------- pkg/volume/gcepd/attacher.go | 6 +- pkg/volume/iscsi/attacher.go | 6 +- pkg/volume/local/local.go | 44 +++++++------- pkg/volume/local/local_test.go | 4 +- pkg/volume/rbd/attacher.go | 12 ++-- pkg/volume/rbd/rbd_test.go | 2 +- pkg/volume/testing/testing.go | 6 +- .../operationexecutor/operation_generator.go | 2 +- pkg/volume/volume.go | 5 +- pkg/volume/vsphere_volume/attacher.go | 8 +-- 19 files changed, 118 insertions(+), 143 deletions(-) diff --git a/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/pkg/controller/volume/attachdetach/testing/testvolumespec.go index 183d7dd7e14..22d689f2803 100644 --- a/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -441,14 +441,9 @@ func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath st if spec == nil { *attacher.ErrorEncountered = true klog.Errorf("MountDevice called with nil volume spec") - return fmt.Errorf("MountDevice called with nil volume spec") + return volumetypes.OperationFinished, fmt.Errorf("MountDevice called with nil volume spec") } - return nil -} - -func (attacher *testPluginAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + return volumetypes.OperationFinished, nil } // Detacher diff --git a/pkg/volume/awsebs/attacher.go b/pkg/volume/awsebs/attacher.go index aa22034e091..a13e5738faa 100644 --- a/pkg/volume/awsebs/attacher.go +++ b/pkg/volume/awsebs/attacher.go @@ -207,7 +207,7 @@ func (attacher *awsElasticBlockStoreAttacher) GetDeviceMountPath( } // FIXME: this method can be further pruned. -func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { mounter := attacher.host.GetMounter(awsElasticBlockStorePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -222,17 +222,17 @@ func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, dev dir = filepath.Dir(deviceMountPath) } if err := os.MkdirAll(dir, 0750); err != nil { - return fmt.Errorf("making dir %s failed with %s", dir, err) + return volumetypes.OperationFinished, fmt.Errorf("making dir %s failed with %s", dir, err) } notMnt = true } else { - return err + return volumetypes.OperationFinished, err } } volumeSource, readOnly, err := getVolumeSource(spec) if err != nil { - return err + return volumetypes.OperationFinished, err } options := []string{} @@ -245,15 +245,10 @@ func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, dev err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) if err != nil { os.Remove(deviceMountPath) - return err + return volumetypes.OperationFinished, err } } - return nil -} - -func (attacher *awsElasticBlockStoreAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + return volumetypes.OperationFinished, nil } type awsElasticBlockStoreDetacher struct { diff --git a/pkg/volume/azure_dd/attacher.go b/pkg/volume/azure_dd/attacher.go index c5c4705ca18..290ca67e122 100644 --- a/pkg/volume/azure_dd/attacher.go +++ b/pkg/volume/azure_dd/attacher.go @@ -199,7 +199,11 @@ func (a *azureDiskAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error return makeGlobalPDPath(a.plugin.host, volumeSource.DataDiskURI, isManagedDisk) } -func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + return volumetypes.OperationFinished, attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) +} + +func (attacher *azureDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.plugin.host.GetMounter(azureDataDiskPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) @@ -260,11 +264,6 @@ func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath str return nil } -func (d *azureDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := d.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - // Detach detaches disk from Azure VM. func (d *azureDiskDetacher) Detach(diskURI string, nodeName types.NodeName) error { if diskURI == "" { diff --git a/pkg/volume/cinder/attacher.go b/pkg/volume/cinder/attacher.go index 3340d2d53c2..21af74720b0 100644 --- a/pkg/volume/cinder/attacher.go +++ b/pkg/volume/cinder/attacher.go @@ -269,7 +269,7 @@ func (attacher *cinderDiskAttacher) GetDeviceMountPath( } // FIXME: this method can be further pruned. -func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *cinderDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.host.GetMounter(cinderVolumePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -304,8 +304,8 @@ func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath st return nil } -func (attacher *cinderDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index 7814a9f860d..5f9006352f6 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -220,12 +220,7 @@ func (c *csiAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) { return deviceMountPath, nil } -func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { - _, err := c.MountDeviceWithStatusTracking(spec, devicePath, deviceMountPath) - return err -} - -func (c *csiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { +func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { klog.V(4).Infof(log("attacher.MountDevice(%s, %s)", devicePath, deviceMountPath)) // lets default to operation as finished state opExitStatus := volumetypes.OperationFinished diff --git a/pkg/volume/csi/csi_attacher_test.go b/pkg/volume/csi/csi_attacher_test.go index ae215e93b28..6e4bcc258fa 100644 --- a/pkg/volume/csi/csi_attacher_test.go +++ b/pkg/volume/csi/csi_attacher_test.go @@ -1348,7 +1348,7 @@ func TestAttacherMountDeviceWithInline(t *testing.T) { }() // Run - err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) + _, err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) // Verify if err != nil { diff --git a/pkg/volume/csi/csi_test.go b/pkg/volume/csi/csi_test.go index 3ec20217760..5d310c81308 100644 --- a/pkg/volume/csi/csi_test.go +++ b/pkg/volume/csi/csi_test.go @@ -360,7 +360,7 @@ func TestCSI_VolumeAll(t *testing.T) { if err != nil { t.Fatalf("csiTest.VolumeAll deviceMounter.GetdeviceMountPath failed %s", err) } - if err := csiDevMounter.MountDevice(volSpec, devicePath, devMountPath); err != nil { + if _, err := csiDevMounter.MountDevice(volSpec, devicePath, devMountPath); err != nil { t.Fatalf("csiTest.VolumeAll deviceMounter.MountDevice failed: %v", err) } t.Log("csiTest.VolumeAll device mounted at path:", devMountPath) diff --git a/pkg/volume/fc/attacher.go b/pkg/volume/fc/attacher.go index 385a916eca1..09b663b6866 100644 --- a/pkg/volume/fc/attacher.go +++ b/pkg/volume/fc/attacher.go @@ -97,44 +97,42 @@ func (attacher *fcAttacher) GetDeviceMountPath( return attacher.manager.MakeGlobalPDName(*mounter.fcDisk), nil } -func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { - mounter := attacher.host.GetMounter(fcPluginName) - notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(deviceMountPath, 0750); err != nil { +func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + mountInternal := func() error { + mounter := attacher.host.GetMounter(fcPluginName) + notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) + if err != nil { + if os.IsNotExist(err) { + if err := os.MkdirAll(deviceMountPath, 0750); err != nil { + return err + } + notMnt = true + } else { return err } - notMnt = true - } else { - return err } - } - volumeSource, readOnly, err := getVolumeSource(spec) - if err != nil { - return err - } - - options := []string{} - if readOnly { - options = append(options, "ro") - } - if notMnt { - diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(fcPluginName)} - mountOptions := volumeutil.MountOptionFromSpec(spec, options...) - err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) + volumeSource, readOnly, err := getVolumeSource(spec) if err != nil { - os.Remove(deviceMountPath) return err } - } - return nil -} -func (attacher *fcAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + options := []string{} + if readOnly { + options = append(options, "ro") + } + if notMnt { + diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(fcPluginName)} + mountOptions := volumeutil.MountOptionFromSpec(spec, options...) + err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) + if err != nil { + os.Remove(deviceMountPath) + return err + } + } + return nil + } + return volumetypes.OperationFinished, mountInternal() } type fcDetacher struct { diff --git a/pkg/volume/flexvolume/attacher.go b/pkg/volume/flexvolume/attacher.go index 07e9582a134..d526ed23c1b 100644 --- a/pkg/volume/flexvolume/attacher.go +++ b/pkg/volume/flexvolume/attacher.go @@ -71,36 +71,34 @@ func (a *flexVolumeAttacher) GetDeviceMountPath(spec *volume.Spec) (string, erro } // MountDevice is part of the volume.Attacher interface -func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { - // Mount only once. - alreadyMounted, err := prepareForMount(a.plugin.host.GetMounter(a.plugin.GetPluginName()), deviceMountPath) - if err != nil { +func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + mountInternal := func() error { + // Mount only once. + alreadyMounted, err := prepareForMount(a.plugin.host.GetMounter(a.plugin.GetPluginName()), deviceMountPath) + if err != nil { + return err + } + if alreadyMounted { + return nil + } + + call := a.plugin.NewDriverCall(mountDeviceCmd) + call.Append(deviceMountPath) + call.Append(devicePath) + call.AppendSpec(spec, a.plugin.host, nil) + + _, err = call.Run() + if isCmdNotSupportedErr(err) { + // Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the + // plugin does not implement attach interface. + if devicePath != "" { + return (*attacherDefaults)(a).MountDevice(spec, devicePath, deviceMountPath, a.plugin.host.GetMounter(a.plugin.GetPluginName())) + } + return nil + } return err } - if alreadyMounted { - return nil - } - - call := a.plugin.NewDriverCall(mountDeviceCmd) - call.Append(deviceMountPath) - call.Append(devicePath) - call.AppendSpec(spec, a.plugin.host, nil) - - _, err = call.Run() - if isCmdNotSupportedErr(err) { - // Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the - // plugin does not implement attach interface. - if devicePath != "" { - return (*attacherDefaults)(a).MountDevice(spec, devicePath, deviceMountPath, a.plugin.host.GetMounter(a.plugin.GetPluginName())) - } - return nil - } - return err -} - -func (a *flexVolumeAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := a.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + return volumetypes.OperationFinished, mountInternal() } func (a *flexVolumeAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { diff --git a/pkg/volume/gcepd/attacher.go b/pkg/volume/gcepd/attacher.go index e9aa83e980d..4b492edabec 100644 --- a/pkg/volume/gcepd/attacher.go +++ b/pkg/volume/gcepd/attacher.go @@ -287,7 +287,7 @@ func (attacher *gcePersistentDiskAttacher) GetDeviceMountPath( return makeGlobalPDName(attacher.host, volumeSource.PDName), nil } -func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *gcePersistentDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { // Only mount the PD globally once. mounter := attacher.host.GetMounter(gcePersistentDiskPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) @@ -329,8 +329,8 @@ func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, device return nil } -func (attacher *gcePersistentDiskAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/iscsi/attacher.go b/pkg/volume/iscsi/attacher.go index 00d64cf21e4..20c801126ee 100644 --- a/pkg/volume/iscsi/attacher.go +++ b/pkg/volume/iscsi/attacher.go @@ -102,7 +102,7 @@ func (attacher *iscsiAttacher) GetDeviceMountPath( return attacher.manager.MakeGlobalPDName(*mounter.iscsiDisk), nil } -func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *iscsiAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.host.GetMounter(iscsiPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -136,8 +136,8 @@ func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, return nil } -func (attacher *iscsiAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index 58f5cf7153e..1aa6b78fde2 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -349,31 +349,29 @@ func (dm *deviceMounter) mountLocalBlockDevice(spec *volume.Spec, devicePath str return nil } -func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { - if spec.PersistentVolume.Spec.Local == nil || len(spec.PersistentVolume.Spec.Local.Path) == 0 { - return fmt.Errorf("local volume source is nil or local path is not set") - } - fileType, err := dm.hostUtil.GetFileType(spec.PersistentVolume.Spec.Local.Path) - if err != nil { - return err - } +func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + mountInternal := func() error { + if spec.PersistentVolume.Spec.Local == nil || len(spec.PersistentVolume.Spec.Local.Path) == 0 { + return fmt.Errorf("local volume source is nil or local path is not set") + } + fileType, err := dm.hostUtil.GetFileType(spec.PersistentVolume.Spec.Local.Path) + if err != nil { + return err + } - switch fileType { - case hostutil.FileTypeBlockDev: - // local volume plugin does not implement AttachableVolumePlugin interface, so set devicePath to Path in PV spec directly - devicePath = spec.PersistentVolume.Spec.Local.Path - return dm.mountLocalBlockDevice(spec, devicePath, deviceMountPath) - case hostutil.FileTypeDirectory: - // if the given local volume path is of already filesystem directory, return directly - return nil - default: - return fmt.Errorf("only directory and block device are supported") + switch fileType { + case hostutil.FileTypeBlockDev: + // local volume plugin does not implement AttachableVolumePlugin interface, so set devicePath to Path in PV spec directly + devicePath = spec.PersistentVolume.Spec.Local.Path + return dm.mountLocalBlockDevice(spec, devicePath, deviceMountPath) + case hostutil.FileTypeDirectory: + // if the given local volume path is of already filesystem directory, return directly + return nil + default: + return fmt.Errorf("only directory and block device are supported") + } } -} - -func (dm *deviceMounter) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := dm.MountDevice(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err + return volumetypes.OperationFinished, mountInternal() } func getVolumeSourceFSType(spec *volume.Spec) (string, error) { diff --git a/pkg/volume/local/local_test.go b/pkg/volume/local/local_test.go index 301cff5f1dd..bb96a4fac31 100644 --- a/pkg/volume/local/local_test.go +++ b/pkg/volume/local/local_test.go @@ -231,7 +231,7 @@ func TestBlockDeviceGlobalPathAndMountDevice(t *testing.T) { fmt.Println("expected global path is:", expectedGlobalPath) - err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath) + _, err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath) if err != nil { t.Fatal(err) } @@ -276,7 +276,7 @@ func TestFSGlobalPathAndMountDevice(t *testing.T) { } // Actually, we will do nothing if the local path is FS type - err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath) + _, err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath) if err != nil { t.Fatal(err) } diff --git a/pkg/volume/rbd/attacher.go b/pkg/volume/rbd/attacher.go index 7bfa3fa3a8a..354100c1b39 100644 --- a/pkg/volume/rbd/attacher.go +++ b/pkg/volume/rbd/attacher.go @@ -144,10 +144,7 @@ func (attacher *rbdAttacher) GetDeviceMountPath(spec *volume.Spec) (string, erro return makePDNameInternal(attacher.plugin.host, pool, img), nil } -// MountDevice implements Attacher.MountDevice. It is called by the kubelet to -// mount device at the given mount path. -// This method is idempotent, callers are responsible for retrying on failure. -func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *rbdAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { klog.V(4).Infof("rbd: mouting device %s to %s", devicePath, deviceMountPath) notMnt, err := attacher.mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -185,8 +182,11 @@ func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, d return nil } -func (attacher *rbdAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +// MountDevice implements Attacher.MountDevice. It is called by the kubelet to +// mount device at the given mount path. +// This method is idempotent, callers are responsible for retrying on failure. +func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/rbd/rbd_test.go b/pkg/volume/rbd/rbd_test.go index e58020ddadb..311b854b6b1 100644 --- a/pkg/volume/rbd/rbd_test.go +++ b/pkg/volume/rbd/rbd_test.go @@ -281,7 +281,7 @@ func doTestPlugin(t *testing.T, c *testcase) { if deviceMountPath != c.expectedDeviceMountPath { t.Errorf("Unexpected mount path, expected %q, not: %q", c.expectedDeviceMountPath, deviceMountPath) } - err = attacher.MountDevice(c.spec, devicePath, deviceMountPath) + _, err = attacher.MountDevice(c.spec, devicePath, deviceMountPath) if err != nil { t.Fatal(err) } diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 083c7a6fab6..ffc68b154a9 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -1058,7 +1058,7 @@ func (fv *FakeVolume) GetDeviceMountPath(spec *Spec) (string, error) { return "", nil } -func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath string) error { +func (fv *FakeVolume) mountDeviceInternal(spec *Spec, devicePath string, deviceMountPath string) error { fv.Lock() defer fv.Unlock() if spec.Name() == TimeoutOnMountDeviceVolumeName { @@ -1086,8 +1086,8 @@ func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath return nil } -func (fv *FakeVolume) MountDeviceWithStatusTracking(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := fv.MountDevice(spec, devicePath, deviceMountPath) +func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := fv.mountDeviceInternal(spec, devicePath, deviceMountPath) if volumetypes.IsOperationTimeOutError(err) { return volumetypes.OperationInProgress, err } diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 692356e3565..932d2ba5104 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -575,7 +575,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Mount device to global mount path - operationState, err := volumeDeviceMounter.MountDeviceWithStatusTracking( + operationState, err := volumeDeviceMounter.MountDevice( volumeToMount.VolumeSpec, devicePath, deviceMountPath) diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index d18f42c1700..d6ffe91df2e 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -253,10 +253,7 @@ type DeviceMounter interface { // MountDevice mounts the disk to a global path which // individual pods can then bind mount // Note that devicePath can be empty if the volume plugin does not implement any of Attach and WaitForAttach methods. - MountDevice(spec *Spec, devicePath string, deviceMountPath string) error - - // MountDeviceWithStatusTracking is same as MountDevice except status of mount operation is also returned - MountDeviceWithStatusTracking(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) + MountDevice(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) } type BulkVolumeVerifier interface { diff --git a/pkg/volume/vsphere_volume/attacher.go b/pkg/volume/vsphere_volume/attacher.go index 947fc57d2cf..3f5e56142b7 100644 --- a/pkg/volume/vsphere_volume/attacher.go +++ b/pkg/volume/vsphere_volume/attacher.go @@ -208,8 +208,7 @@ func (plugin *vsphereVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([ return mounter.GetMountRefs(deviceMountPath) } -// MountDevice mounts device to global mount point. -func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *vsphereVMDKAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { klog.Info("vsphere MountDevice", devicePath, deviceMountPath) mounter := attacher.host.GetMounter(vsphereVolumePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) @@ -249,8 +248,9 @@ func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath s return nil } -func (attacher *vsphereVMDKAttacher) MountDeviceWithStatusTracking(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.MountDevice(spec, devicePath, deviceMountPath) +// MountDevice mounts device to global mount point. +func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { + err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) return volumetypes.OperationFinished, err } From cdbd3ba5c2966c4ffe407a9ea4b747ecb3d51fef Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 7 Nov 2019 08:02:14 -0500 Subject: [PATCH 10/15] Change interface of SetUp function --- hack/.staticcheck_failures | 1 - .../attachdetach/testing/testvolumespec.go | 2 +- pkg/kubelet/kubelet_volumes_test.go | 8 +-- .../cache/actual_state_of_world.go | 3 +- pkg/volume/awsebs/aws_ebs.go | 9 +-- pkg/volume/awsebs/aws_ebs_test.go | 4 +- pkg/volume/azure_dd/azure_mounter.go | 8 +-- pkg/volume/azure_file/azure_file.go | 9 +-- pkg/volume/azure_file/azure_file_test.go | 2 +- pkg/volume/cephfs/cephfs.go | 9 +-- pkg/volume/cephfs/cephfs_test.go | 2 +- pkg/volume/cinder/cinder.go | 8 +-- pkg/volume/cinder/cinder_test.go | 2 +- pkg/volume/configmap/configmap.go | 8 +-- pkg/volume/configmap/configmap_test.go | 10 +-- pkg/volume/csi/csi_attacher_test.go | 2 +- pkg/volume/csi/csi_client.go | 8 +-- pkg/volume/csi/csi_mounter.go | 6 +- pkg/volume/csi/csi_mounter_test.go | 10 +-- pkg/volume/csi/csi_test.go | 2 +- pkg/volume/downwardapi/downwardapi.go | 8 +-- pkg/volume/downwardapi/downwardapi_test.go | 4 +- pkg/volume/emptydir/empty_dir.go | 8 +-- pkg/volume/emptydir/empty_dir_test.go | 2 +- pkg/volume/fc/fc.go | 8 +-- pkg/volume/fc/fc_test.go | 2 +- pkg/volume/flexvolume/mounter.go | 9 +-- pkg/volume/flocker/flocker.go | 8 +-- pkg/volume/gcepd/gce_pd.go | 9 +-- pkg/volume/gcepd/gce_pd_test.go | 4 +- pkg/volume/git_repo/git_repo.go | 9 +-- pkg/volume/glusterfs/glusterfs.go | 9 +-- pkg/volume/glusterfs/glusterfs_test.go | 2 +- pkg/volume/hostpath/host_path.go | 24 +++---- pkg/volume/hostpath/host_path_test.go | 4 +- pkg/volume/iscsi/iscsi.go | 8 +-- pkg/volume/iscsi/iscsi_test.go | 2 +- pkg/volume/local/local.go | 9 +-- pkg/volume/local/local_test.go | 8 +-- pkg/volume/nfs/nfs.go | 8 +-- pkg/volume/nfs/nfs_test.go | 2 +- pkg/volume/portworx/portworx.go | 8 +-- pkg/volume/portworx/portworx_test.go | 2 +- pkg/volume/projected/projected.go | 8 +-- pkg/volume/projected/projected_test.go | 10 +-- pkg/volume/quobyte/quobyte.go | 9 +-- pkg/volume/quobyte/quobyte_test.go | 2 +- pkg/volume/rbd/rbd.go | 8 +-- pkg/volume/rbd/rbd_test.go | 2 +- pkg/volume/scaleio/sio_volume.go | 8 +-- pkg/volume/scaleio/sio_volume_test.go | 4 +- pkg/volume/secret/secret.go | 8 +-- pkg/volume/secret/secret_test.go | 10 +-- pkg/volume/storageos/storageos.go | 68 +++++++++---------- pkg/volume/storageos/storageos_test.go | 2 +- pkg/volume/testing/testing.go | 21 +++--- .../operationexecutor/operation_generator.go | 2 +- pkg/volume/volume.go | 6 +- pkg/volume/vsphere_volume/vsphere_volume.go | 9 +-- .../vsphere_volume/vsphere_volume_test.go | 2 +- 60 files changed, 163 insertions(+), 286 deletions(-) diff --git a/hack/.staticcheck_failures b/hack/.staticcheck_failures index a90443e253d..7931c65fae6 100644 --- a/hack/.staticcheck_failures +++ b/hack/.staticcheck_failures @@ -53,7 +53,6 @@ pkg/volume/flexvolume pkg/volume/flocker pkg/volume/hostpath pkg/volume/iscsi -pkg/volume/local pkg/volume/portworx pkg/volume/quobyte pkg/volume/rbd diff --git a/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/pkg/controller/volume/attachdetach/testing/testvolumespec.go index 22d689f2803..eac942b0895 100644 --- a/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -435,7 +435,7 @@ func (attacher *testPluginAttacher) GetDeviceMountPath(spec *volume.Spec) (strin return "", nil } -func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { attacher.pluginLock.Lock() defer attacher.pluginLock.Unlock() if spec == nil { diff --git a/pkg/kubelet/kubelet_volumes_test.go b/pkg/kubelet/kubelet_volumes_test.go index b5d2c168e55..85e86ca55c6 100644 --- a/pkg/kubelet/kubelet_volumes_test.go +++ b/pkg/kubelet/kubelet_volumes_test.go @@ -531,18 +531,14 @@ func (f *stubVolume) CanMount() error { return nil } -func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) error { - return nil +func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + return volumetypes.OperationFinished, nil } func (f *stubVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { return nil } -func (f *stubVolume) SetUpWithStatusTracking(mountArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - return volumetypes.OperationFinished, nil -} - type stubBlockVolume struct { dirPath string volName string diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index e68b3380480..1aedc92af8d 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -173,7 +173,8 @@ type AttachedVolume struct { DeviceMountState operationexecutor.DeviceMountState } -// DeviceMayBeMounted returns true if device may be mounted in global path. +// DeviceMayBeMounted returns true if device is mounted in global path or is in +// uncertain state. func (av AttachedVolume) DeviceMayBeMounted() bool { return av.DeviceMountState == operationexecutor.DeviceGloballyMounted || av.DeviceMountState == operationexecutor.DeviceMountUncertain diff --git a/pkg/volume/awsebs/aws_ebs.go b/pkg/volume/awsebs/aws_ebs.go index 23e81f0ebcc..11bbd2d17f0 100644 --- a/pkg/volume/awsebs/aws_ebs.go +++ b/pkg/volume/awsebs/aws_ebs.go @@ -366,13 +366,8 @@ func (b *awsElasticBlockStoreMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *awsElasticBlockStoreMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetupWithStatusTracking attaches the disk and bind mounts to the volume path. -func (b *awsElasticBlockStoreMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *awsElasticBlockStoreMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/awsebs/aws_ebs_test.go b/pkg/volume/awsebs/aws_ebs_test.go index 021ecc46dc5..db0fcca91cb 100644 --- a/pkg/volume/awsebs/aws_ebs_test.go +++ b/pkg/volume/awsebs/aws_ebs_test.go @@ -141,7 +141,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -372,7 +372,7 @@ func TestMountOptions(t *testing.T) { t.Errorf("Got a nil Mounter") } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/azure_dd/azure_mounter.go b/pkg/volume/azure_dd/azure_mounter.go index c7d5f23441a..f641e78e789 100644 --- a/pkg/volume/azure_dd/azure_mounter.go +++ b/pkg/volume/azure_dd/azure_mounter.go @@ -66,12 +66,8 @@ func (m *azureDiskMounter) CanMount() error { return nil } -func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { - return m.SetUpAt(m.GetPath(), mounterArgs) -} - -func (m *azureDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := m.SetUp(mounterArgs) +func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := m.SetUpAt(m.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/azure_file/azure_file.go b/pkg/volume/azure_file/azure_file.go index 56b88600751..427e88e1043 100644 --- a/pkg/volume/azure_file/azure_file.go +++ b/pkg/volume/azure_file/azure_file.go @@ -236,13 +236,8 @@ func (b *azureFileMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp attaches the disk and bind mounts to the volume path. -func (b *azureFileMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/azure_file/azure_file_test.go b/pkg/volume/azure_file/azure_file_test.go index 6d42eb9ad8c..d3407b8959a 100644 --- a/pkg/volume/azure_file/azure_file_test.go +++ b/pkg/volume/azure_file/azure_file_test.go @@ -154,7 +154,7 @@ func testPlugin(t *testing.T, tmpDir string, volumeHost volume.VolumeHost) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/cephfs/cephfs.go b/pkg/volume/cephfs/cephfs.go index bfa86d8c6a1..f9cd9be0d49 100644 --- a/pkg/volume/cephfs/cephfs.go +++ b/pkg/volume/cephfs/cephfs.go @@ -220,13 +220,8 @@ func (cephfsVolume *cephfsMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (cephfsVolume *cephfsMounter) SetUp(mounterArgs volume.MounterArgs) error { - return cephfsVolume.SetUpAt(cephfsVolume.GetPath(), mounterArgs) -} - -// SetUp attaches the disk and bind mounts to the volume path. -func (cephfsVolume *cephfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := cephfsVolume.SetUp(mounterArgs) +func (cephfsVolume *cephfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := cephfsVolume.SetUpAt(cephfsVolume.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/cephfs/cephfs_test.go b/pkg/volume/cephfs/cephfs_test.go index abe498c5f10..ea674d80ff8 100644 --- a/pkg/volume/cephfs/cephfs_test.go +++ b/pkg/volume/cephfs/cephfs_test.go @@ -88,7 +88,7 @@ func TestPlugin(t *testing.T) { if volumePath != volpath { t.Errorf("Got unexpected path: %s", volumePath) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go index 8a60ac8a8a8..d694775f35a 100644 --- a/pkg/volume/cinder/cinder.go +++ b/pkg/volume/cinder/cinder.go @@ -390,12 +390,8 @@ func (b *cinderVolumeMounter) CanMount() error { return nil } -func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *cinderVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/cinder/cinder_test.go b/pkg/volume/cinder/cinder_test.go index bd0d0c6b929..5a151f5fc33 100644 --- a/pkg/volume/cinder/cinder_test.go +++ b/pkg/volume/cinder/cinder_test.go @@ -169,7 +169,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/configmap/configmap.go b/pkg/volume/configmap/configmap.go index 0c80c34f6b9..4347b4b2dad 100644 --- a/pkg/volume/configmap/configmap.go +++ b/pkg/volume/configmap/configmap.go @@ -181,12 +181,8 @@ func (b *configMapVolumeMounter) CanMount() error { return nil } -func (b *configMapVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *configMapVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *configMapVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/configmap/configmap_test.go b/pkg/volume/configmap/configmap_test.go index e03d39d1a25..0e7b2172ba7 100644 --- a/pkg/volume/configmap/configmap_test.go +++ b/pkg/volume/configmap/configmap_test.go @@ -368,7 +368,7 @@ func TestPlugin(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -428,7 +428,7 @@ func TestPluginReboot(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -492,7 +492,7 @@ func TestPluginOptional(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -591,7 +591,7 @@ func TestPluginKeysOptional(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -671,7 +671,7 @@ func TestInvalidConfigMapSetup(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected setup to fail") } diff --git a/pkg/volume/csi/csi_attacher_test.go b/pkg/volume/csi/csi_attacher_test.go index 6e4bcc258fa..22b4de03eea 100644 --- a/pkg/volume/csi/csi_attacher_test.go +++ b/pkg/volume/csi/csi_attacher_test.go @@ -1199,7 +1199,7 @@ func TestAttacherMountDevice(t *testing.T) { } // Run - exitStatus, err := csiAttacher.MountDeviceWithStatusTracking(tc.spec, tc.devicePath, tc.deviceMountPath) + exitStatus, err := csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) // Verify if err != nil { diff --git a/pkg/volume/csi/csi_client.go b/pkg/volume/csi/csi_client.go index aa00d85e859..939e4d3a42b 100644 --- a/pkg/volume/csi/csi_client.go +++ b/pkg/volume/csi/csi_client.go @@ -632,18 +632,18 @@ func isFinalError(err error) bool { if !ok { // This is not gRPC error. The operation must have failed before gRPC // method was called, otherwise we would get gRPC error. - // We don't know if any previous CreateVolume is in progress, be on the safe side. + // We don't know if any previous volume operation is in progress, be on the safe side. return false } switch st.Code() { case codes.Canceled, // gRPC: Client Application cancelled the request codes.DeadlineExceeded, // gRPC: Timeout - codes.Unavailable, // gRPC: Server shutting down, TCP connection broken - previous CreateVolume() may be still in progress. - codes.ResourceExhausted, // gRPC: Server temporarily out of resources - previous Publish operation may be still in progress. + codes.Unavailable, // gRPC: Server shutting down, TCP connection broken - previous volume operation may be still in progress. + codes.ResourceExhausted, // gRPC: Server temporarily out of resources - previous volume operation may be still in progress. codes.Aborted: // CSI: Operation pending for volume return false } - // All other errors mean that provisioning either did not + // All other errors mean that operation either did not // even start or failed. It is for sure not in progress. return true } diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 22a5085bd03..1915adcac5d 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -99,11 +99,7 @@ func (c *csiMountMgr) CanMount() error { return nil } -func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) error { - return c.SetUpAt(c.GetPath(), mounterArgs) -} - -func (c *csiMountMgr) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { +func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { opExitStatus, err := c.setupUtil(c.GetPath(), mounterArgs) return opExitStatus, err } diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index c397ddf2bae..a8e9d544671 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -221,7 +221,7 @@ func MounterSetUpTests(t *testing.T, podInfoEnabled bool) { var mounterArgs volume.MounterArgs fsGroup := int64(2000) mounterArgs.FsGroup = &fsGroup - if err := csiMounter.SetUp(mounterArgs); err != nil { + if _, err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -361,7 +361,7 @@ func TestMounterSetUpSimple(t *testing.T) { } // Mounter.SetUp() - if err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -488,7 +488,7 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { } } - opExistStatus, err := csiMounter.SetUpWithStatusTracking(volume.MounterArgs{}) + opExistStatus, err := csiMounter.SetUp(volume.MounterArgs{}) if opExistStatus != tc.exitStatus { t.Fatalf("expected exitStatus: %v but got %v", tc.exitStatus, opExistStatus) @@ -604,7 +604,7 @@ func TestMounterSetUpWithInline(t *testing.T) { } // Mounter.SetUp() - if err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -757,7 +757,7 @@ func TestMounterSetUpWithFSGroup(t *testing.T) { fsGroupPtr = &fsGroup } mounterArgs.FsGroup = fsGroupPtr - if err := csiMounter.SetUp(mounterArgs); err != nil { + if _, err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } diff --git a/pkg/volume/csi/csi_test.go b/pkg/volume/csi/csi_test.go index 5d310c81308..0ee4858f955 100644 --- a/pkg/volume/csi/csi_test.go +++ b/pkg/volume/csi/csi_test.go @@ -417,7 +417,7 @@ func TestCSI_VolumeAll(t *testing.T) { csiMounter.csiClient = csiClient var mounterArgs volume.MounterArgs mounterArgs.FsGroup = fsGroup - if err := csiMounter.SetUp(mounterArgs); err != nil { + if _, err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("csiTest.VolumeAll mounter.Setup(fsGroup) failed: %s", err) } t.Log("csiTest.VolumeAll mounter.Setup(fsGroup) done OK") diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index caee1fd4027..83c8b11fc3d 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -171,12 +171,8 @@ func (b *downwardAPIVolumeMounter) CanMount() error { // This function is not idempotent by design. We want the data to be refreshed periodically. // The internal sync interval of kubelet will drive the refresh of data. // TODO: Add volume specific ticker and refresh loop -func (b *downwardAPIVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *downwardAPIVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *downwardAPIVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/downwardapi/downwardapi_test.go b/pkg/volume/downwardapi/downwardapi_test.go index 647ebe3ff56..8584e812d5c 100644 --- a/pkg/volume/downwardapi/downwardapi_test.go +++ b/pkg/volume/downwardapi/downwardapi_test.go @@ -253,7 +253,7 @@ func newDownwardAPITest(t *testing.T, name string, volumeFiles, podLabels, podAn volumePath := mounter.GetPath() - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -380,7 +380,7 @@ func (step reSetUp) run(test *downwardAPITest) { } // now re-run Setup - if err = test.mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err = test.mounter.SetUp(volume.MounterArgs{}); err != nil { test.t.Errorf("Failed to re-setup volume: %v", err) } diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index b5cc0803627..2e64bff6c4d 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -193,12 +193,8 @@ func (ed *emptyDir) CanMount() error { } // SetUp creates new directory. -func (ed *emptyDir) SetUp(mounterArgs volume.MounterArgs) error { - return ed.SetUpAt(ed.GetPath(), mounterArgs) -} - -func (ed *emptyDir) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := ed.SetUp(mounterArgs) +func (ed *emptyDir) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := ed.SetUpAt(ed.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/emptydir/empty_dir_test.go b/pkg/volume/emptydir/empty_dir_test.go index 892ec1ec342..4c4bcac53af 100644 --- a/pkg/volume/emptydir/empty_dir_test.go +++ b/pkg/volume/emptydir/empty_dir_test.go @@ -164,7 +164,7 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) { t.Errorf("Got unexpected path: %s", volPath) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } diff --git a/pkg/volume/fc/fc.go b/pkg/volume/fc/fc.go index b5940251460..259d1b8bbbe 100644 --- a/pkg/volume/fc/fc.go +++ b/pkg/volume/fc/fc.go @@ -370,12 +370,8 @@ func (b *fcDiskMounter) CanMount() error { return nil } -func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *fcDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/fc/fc_test.go b/pkg/volume/fc/fc_test.go index 63d5a08e09a..32dc1b51d9e 100644 --- a/pkg/volume/fc/fc_test.go +++ b/pkg/volume/fc/fc_test.go @@ -181,7 +181,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/flexvolume/mounter.go b/pkg/volume/flexvolume/mounter.go index 47def08da8e..084e7ff7701 100644 --- a/pkg/volume/flexvolume/mounter.go +++ b/pkg/volume/flexvolume/mounter.go @@ -40,13 +40,8 @@ var _ volume.Mounter = &flexVolumeMounter{} // Mounter interface // SetUp creates new directory. -func (f *flexVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return f.SetUpAt(f.GetPath(), mounterArgs) -} - -// SetUp creates new directory. -func (f *flexVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := f.SetUp(mounterArgs) +func (f *flexVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := f.SetUpAt(f.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/flocker/flocker.go b/pkg/volume/flocker/flocker.go index 8adb9186ce5..2c951e68709 100644 --- a/pkg/volume/flocker/flocker.go +++ b/pkg/volume/flocker/flocker.go @@ -232,12 +232,8 @@ func (b *flockerVolumeMounter) GetPath() string { } // SetUp bind mounts the disk global mount to the volume path. -func (b *flockerVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *flockerVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *flockerVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/gcepd/gce_pd.go b/pkg/volume/gcepd/gce_pd.go index 1d8409706e4..a43ca3868fa 100644 --- a/pkg/volume/gcepd/gce_pd.go +++ b/pkg/volume/gcepd/gce_pd.go @@ -369,13 +369,8 @@ func (b *gcePersistentDiskMounter) CanMount() error { } // SetUp bind mounts the disk global mount to the volume path. -func (b *gcePersistentDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp bind mounts the disk global mount to the volume path. -func (b *gcePersistentDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *gcePersistentDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/gcepd/gce_pd_test.go b/pkg/volume/gcepd/gce_pd_test.go index d45de1be877..6102930b1c5 100644 --- a/pkg/volume/gcepd/gce_pd_test.go +++ b/pkg/volume/gcepd/gce_pd_test.go @@ -144,7 +144,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -282,7 +282,7 @@ func TestMountOptions(t *testing.T) { t.Errorf("Got a nil Mounter") } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index d982cae4d9b..aacc389194d 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -176,13 +176,8 @@ func (b *gitRepoVolumeMounter) CanMount() error { } // SetUp creates new directory and clones a git repo. -func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp creates new directory and clones a git repo. -func (b *gitRepoVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go index c9164d08b93..c42edb94197 100644 --- a/pkg/volume/glusterfs/glusterfs.go +++ b/pkg/volume/glusterfs/glusterfs.go @@ -270,13 +270,8 @@ func (b *glusterfsMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *glusterfsMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp attaches the disk and bind mounts to the volume path. -func (b *glusterfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *glusterfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/glusterfs/glusterfs_test.go b/pkg/volume/glusterfs/glusterfs_test.go index 25e199d2ad9..1eba9fbc9a8 100644 --- a/pkg/volume/glusterfs/glusterfs_test.go +++ b/pkg/volume/glusterfs/glusterfs_test.go @@ -119,7 +119,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != expectedPath { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, volumePath) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/hostpath/host_path.go b/pkg/volume/hostpath/host_path.go index 47c8601f542..649a0f07836 100644 --- a/pkg/volume/hostpath/host_path.go +++ b/pkg/volume/hostpath/host_path.go @@ -227,22 +227,20 @@ func (b *hostPathMounter) CanMount() error { } // SetUp does nothing. -func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) error { - err := validation.ValidatePathNoBacksteps(b.GetPath()) - if err != nil { - return fmt.Errorf("invalid HostPath `%s`: %v", b.GetPath(), err) - } +func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + internalSetup := func() error { + err := validation.ValidatePathNoBacksteps(b.GetPath()) + if err != nil { + return fmt.Errorf("invalid HostPath `%s`: %v", b.GetPath(), err) + } - if *b.pathType == v1.HostPathUnset { - return nil + if *b.pathType == v1.HostPathUnset { + return nil + } + return checkType(b.GetPath(), b.pathType, b.hu) } - return checkType(b.GetPath(), b.pathType, b.hu) -} + return volumetypes.OperationFinished, internalSetup() -// SetUpWithStatusTracking calls setup and returns additional information about operation state -func (b *hostPathMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) - return volumetypes.OperationFinished, err } // SetUpAt does not make sense for host paths - probably programmer error. diff --git a/pkg/volume/hostpath/host_path_test.go b/pkg/volume/hostpath/host_path_test.go index fa94755b1bc..2191d0d6148 100644 --- a/pkg/volume/hostpath/host_path_test.go +++ b/pkg/volume/hostpath/host_path_test.go @@ -219,7 +219,7 @@ func TestInvalidHostPath(t *testing.T) { t.Fatal(err) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) expectedMsg := "invalid HostPath `/no/backsteps/allowed/..`: must not contain '..'" if err.Error() != expectedMsg { t.Fatalf("expected error `%s` but got `%s`", expectedMsg, err) @@ -255,7 +255,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 51fbdb20121..1e46cbba7b0 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -339,12 +339,8 @@ func (b *iscsiDiskMounter) CanMount() error { return nil } -func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *iscsiDiskMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/iscsi/iscsi_test.go b/pkg/volume/iscsi/iscsi_test.go index a062067e123..924855f55c3 100644 --- a/pkg/volume/iscsi/iscsi_test.go +++ b/pkg/volume/iscsi/iscsi_test.go @@ -177,7 +177,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index 1aa6b78fde2..7f0a8e41f32 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -473,13 +473,8 @@ func (m *localVolumeMounter) CanMount() error { } // SetUp bind mounts the directory to the volume path -func (m *localVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return m.SetUpAt(m.GetPath(), mounterArgs) -} - -// SetUp bind mounts the directory to the volume path -func (m *localVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := m.SetUp(mounterArgs) +func (m *localVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := m.SetUpAt(m.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/local/local_test.go b/pkg/volume/local/local_test.go index bb96a4fac31..c48e3bbffe9 100644 --- a/pkg/volume/local/local_test.go +++ b/pkg/volume/local/local_test.go @@ -201,7 +201,7 @@ func TestInvalidLocalPath(t *testing.T) { t.Fatal(err) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) expectedMsg := "invalid path: /no/backsteps/allowed/.. must not contain '..'" if err.Error() != expectedMsg { t.Fatalf("expected error `%s` but got `%s`", expectedMsg, err) @@ -308,7 +308,7 @@ func TestMountUnmount(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } @@ -429,7 +429,7 @@ func testFSGroupMount(plug volume.VolumePlugin, pod *v1.Pod, tmpDir string, fsGr var mounterArgs volume.MounterArgs mounterArgs.FsGroup = &fsGroup - if err := mounter.SetUp(mounterArgs); err != nil { + if _, err := mounter.SetUp(mounterArgs); err != nil { return err } return nil @@ -587,7 +587,7 @@ func TestMountOptions(t *testing.T) { fakeMounter := mount.NewFakeMounter(nil) mounter.(*localVolumeMounter).mounter = fakeMounter - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index 5077f91a4d2..c02b256dd23 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -238,12 +238,8 @@ func (nfsMounter *nfsMounter) GetAttributes() volume.Attributes { } // SetUp attaches the disk and bind mounts to the volume path. -func (nfsMounter *nfsMounter) SetUp(mounterArgs volume.MounterArgs) error { - return nfsMounter.SetUpAt(nfsMounter.GetPath(), mounterArgs) -} - -func (nfsMounter *nfsMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := nfsMounter.SetUp(mounterArgs) +func (nfsMounter *nfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := nfsMounter.SetUpAt(nfsMounter.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/nfs/nfs_test.go b/pkg/volume/nfs/nfs_test.go index f2b0e519060..298c1ff5d1d 100644 --- a/pkg/volume/nfs/nfs_test.go +++ b/pkg/volume/nfs/nfs_test.go @@ -123,7 +123,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != expectedPath { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, volumePath) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/portworx/portworx.go b/pkg/volume/portworx/portworx.go index 31e253340a4..87d34363faa 100644 --- a/pkg/volume/portworx/portworx.go +++ b/pkg/volume/portworx/portworx.go @@ -296,12 +296,8 @@ func (b *portworxVolumeMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *portworxVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *portworxVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *portworxVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/portworx/portworx_test.go b/pkg/volume/portworx/portworx_test.go index 02492f6d99d..d70c036e3c5 100644 --- a/pkg/volume/portworx/portworx_test.go +++ b/pkg/volume/portworx/portworx_test.go @@ -164,7 +164,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/projected/projected.go b/pkg/volume/projected/projected.go index 31b30eb0050..dcbc0f478bd 100644 --- a/pkg/volume/projected/projected.go +++ b/pkg/volume/projected/projected.go @@ -185,12 +185,8 @@ func (s *projectedVolumeMounter) CanMount() error { return nil } -func (s *projectedVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return s.SetUpAt(s.GetPath(), mounterArgs) -} - -func (s *projectedVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := s.SetUp(mounterArgs) +func (s *projectedVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := s.SetUpAt(s.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/projected/projected_test.go b/pkg/volume/projected/projected_test.go index ecf9b694073..bd882305df0 100644 --- a/pkg/volume/projected/projected_test.go +++ b/pkg/volume/projected/projected_test.go @@ -887,7 +887,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -953,7 +953,7 @@ func TestInvalidPathProjected(t *testing.T) { } var mounterArgs volume.MounterArgs - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected error while setting up secret") } @@ -1004,7 +1004,7 @@ func TestPluginReboot(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -1056,7 +1056,7 @@ func TestPluginOptional(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -1154,7 +1154,7 @@ func TestPluginOptionalKeys(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } diff --git a/pkg/volume/quobyte/quobyte.go b/pkg/volume/quobyte/quobyte.go index d488d238bac..19e6f2924c0 100644 --- a/pkg/volume/quobyte/quobyte.go +++ b/pkg/volume/quobyte/quobyte.go @@ -235,14 +235,9 @@ func (mounter *quobyteMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) error { +func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { pluginDir := mounter.plugin.host.GetPluginDir(utilstrings.EscapeQualifiedName(quobytePluginName)) - return mounter.SetUpAt(pluginDir, mounterArgs) -} - -// SetUpWithStatusTracking attaches the disk and bind mounts to the volume path. -func (mounter *quobyteMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := mounter.SetUp(mounterArgs) + err := mounter.SetUpAt(pluginDir, mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/quobyte/quobyte_test.go b/pkg/volume/quobyte/quobyte_test.go index eb3ef2bbba8..d24ca69a265 100644 --- a/pkg/volume/quobyte/quobyte_test.go +++ b/pkg/volume/quobyte/quobyte_test.go @@ -102,7 +102,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir) { t.Errorf("Got unexpected path: %s expected: %s", volumePath, fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir)) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } unmounter, err := plug.(*quobytePlugin).newUnmounterInternal("vol", types.UID("poduid"), mount.NewFakeMounter(nil)) diff --git a/pkg/volume/rbd/rbd.go b/pkg/volume/rbd/rbd.go index 57fdf0021e6..751909b69fe 100644 --- a/pkg/volume/rbd/rbd.go +++ b/pkg/volume/rbd/rbd.go @@ -837,12 +837,8 @@ func (b *rbdMounter) CanMount() error { return nil } -func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *rbdMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/rbd/rbd_test.go b/pkg/volume/rbd/rbd_test.go index 311b854b6b1..fa07b6b5ba1 100644 --- a/pkg/volume/rbd/rbd_test.go +++ b/pkg/volume/rbd/rbd_test.go @@ -307,7 +307,7 @@ func doTestPlugin(t *testing.T, c *testcase) { t.Errorf("Unexpected path, expected %q, got: %q", c.expectedPodMountPath, path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/scaleio/sio_volume.go b/pkg/volume/scaleio/sio_volume.go index 368dec3dd23..72c20aefa1d 100644 --- a/pkg/volume/scaleio/sio_volume.go +++ b/pkg/volume/scaleio/sio_volume.go @@ -79,12 +79,8 @@ func (v *sioVolume) CanMount() error { return nil } -func (v *sioVolume) SetUp(mounterArgs volume.MounterArgs) error { - return v.SetUpAt(v.GetPath(), mounterArgs) -} - -func (v *sioVolume) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := v.SetUp(mounterArgs) +func (v *sioVolume) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := v.SetUpAt(v.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/scaleio/sio_volume_test.go b/pkg/volume/scaleio/sio_volume_test.go index ca871817589..e3ac12440d5 100644 --- a/pkg/volume/scaleio/sio_volume_test.go +++ b/pkg/volume/scaleio/sio_volume_test.go @@ -190,7 +190,7 @@ func TestVolumeMounterUnmounter(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -344,7 +344,7 @@ func TestVolumeProvisioner(t *testing.T) { t.Fatalf("failed to create sio mgr: %v", err) } sioVol.sioMgr.client = sio - if err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("Expected success, got: %v", err) } diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index 31662addbf3..dbaab27995d 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -176,12 +176,8 @@ func (b *secretVolumeMounter) CanMount() error { return nil } -func (b *secretVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *secretVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *secretVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/secret/secret_test.go b/pkg/volume/secret/secret_test.go index 7d60d7b7d6c..fa7e74fc5ee 100644 --- a/pkg/volume/secret/secret_test.go +++ b/pkg/volume/secret/secret_test.go @@ -327,7 +327,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -402,7 +402,7 @@ func TestInvalidPathSecret(t *testing.T) { } var mounterArgs volume.MounterArgs - err = mounter.SetUp(mounterArgs) + _, err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected error while setting up secret") } @@ -453,7 +453,7 @@ func TestPluginReboot(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -505,7 +505,7 @@ func TestPluginOptional(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -603,7 +603,7 @@ func TestPluginOptionalKeys(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - err = mounter.SetUp(volume.MounterArgs{}) + _, err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } diff --git a/pkg/volume/storageos/storageos.go b/pkg/volume/storageos/storageos.go index 3def2c36eed..27ac988868f 100644 --- a/pkg/volume/storageos/storageos.go +++ b/pkg/volume/storageos/storageos.go @@ -344,42 +344,40 @@ func (b *storageosMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *storageosMounter) SetUp(mounterArgs volume.MounterArgs) error { - // Need a namespace to find the volume, try pod's namespace if not set. - if b.volNamespace == "" { - klog.V(2).Infof("Setting StorageOS volume namespace to pod namespace: %s", b.podNamespace) - b.volNamespace = b.podNamespace +func (b *storageosMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + internalSetup := func() error { + // Need a namespace to find the volume, try pod's namespace if not set. + if b.volNamespace == "" { + klog.V(2).Infof("Setting StorageOS volume namespace to pod namespace: %s", b.podNamespace) + b.volNamespace = b.podNamespace + } + + targetPath := makeGlobalPDName(b.plugin.host, b.pvName, b.volNamespace, b.volName) + + // Attach the device to the host. + if err := b.manager.AttachDevice(b, targetPath); err != nil { + klog.Errorf("Failed to attach device at %s: %s", targetPath, err.Error()) + return err + } + + // Attach the StorageOS volume as a block device + devicePath, err := b.manager.AttachVolume(b) + if err != nil { + klog.Errorf("Failed to attach StorageOS volume %s: %s", b.volName, err.Error()) + return err + } + + // Mount the loop device into the plugin's disk global mount dir. + err = b.manager.MountVolume(b, devicePath, targetPath) + if err != nil { + return err + } + klog.V(4).Infof("Successfully mounted StorageOS volume %s into global mount directory", b.volName) + + // Bind mount the volume into the pod + return b.SetUpAt(b.GetPath(), mounterArgs) } - - targetPath := makeGlobalPDName(b.plugin.host, b.pvName, b.volNamespace, b.volName) - - // Attach the device to the host. - if err := b.manager.AttachDevice(b, targetPath); err != nil { - klog.Errorf("Failed to attach device at %s: %s", targetPath, err.Error()) - return err - } - - // Attach the StorageOS volume as a block device - devicePath, err := b.manager.AttachVolume(b) - if err != nil { - klog.Errorf("Failed to attach StorageOS volume %s: %s", b.volName, err.Error()) - return err - } - - // Mount the loop device into the plugin's disk global mount dir. - err = b.manager.MountVolume(b, devicePath, targetPath) - if err != nil { - return err - } - klog.V(4).Infof("Successfully mounted StorageOS volume %s into global mount directory", b.volName) - - // Bind mount the volume into the pod - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -func (b *storageosMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) - return volumetypes.OperationFinished, err + return volumetypes.OperationFinished, internalSetup() } // SetUp bind mounts the disk global mount to the give volume path. diff --git a/pkg/volume/storageos/storageos_test.go b/pkg/volume/storageos/storageos_test.go index d26f24af7c5..3758c9debcc 100644 --- a/pkg/volume/storageos/storageos_test.go +++ b/pkg/volume/storageos/storageos_test.go @@ -210,7 +210,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Expected path: '%s' got: '%s'", expectedPath, volPath) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volPath); err != nil { diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index ffc68b154a9..69c21256e65 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -843,18 +843,17 @@ func (fv *FakeVolume) CanMount() error { return nil } -func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) error { - fv.Lock() - defer fv.Unlock() - if fv.VolName == TimeoutOnSetupVolumeName { - return volumetypes.NewOperationTimedOutError("time out on setup") +func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { + internalSetup := func() error { + fv.Lock() + defer fv.Unlock() + if fv.VolName == TimeoutOnSetupVolumeName { + return volumetypes.NewOperationTimedOutError("time out on setup") + } + fv.SetUpCallCount++ + return fv.SetUpAt(fv.getPath(), mounterArgs) } - fv.SetUpCallCount++ - return fv.SetUpAt(fv.getPath(), mounterArgs) -} - -func (fv *FakeVolume) SetUpWithStatusTracking(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { - err := fv.SetUp(mounterArgs) + err := internalSetup() if volumetypes.IsOperationTimeOutError(err) { return volumetypes.OperationInProgress, err } diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 932d2ba5104..8b080560127 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -629,7 +629,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Execute mount - opExitStatus, mountErr := volumeMounter.SetUpWithStatusTracking(volume.MounterArgs{ + opExitStatus, mountErr := volumeMounter.SetUp(volume.MounterArgs{ FsGroup: fsGroup, DesiredSize: volumeToMount.DesiredSizeLimit, }) diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index d6ffe91df2e..c751f9c959b 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -129,11 +129,7 @@ type Mounter interface { // content should be owned by 'fsGroup' so that it can be // accessed by the pod. This may be called more than once, so // implementations must be idempotent. - SetUp(mounterArgs MounterArgs) error - - // SetupWithStatusTracking is similar to SetUp function except it - // also return operation status as a return value - SetUpWithStatusTracking(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) + SetUp(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) // SetUpAt prepares and mounts/unpacks the volume to the // specified directory path, which may or may not exist yet. diff --git a/pkg/volume/vsphere_volume/vsphere_volume.go b/pkg/volume/vsphere_volume/vsphere_volume.go index a521f1d7bf5..2d68ee6136f 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume.go +++ b/pkg/volume/vsphere_volume/vsphere_volume.go @@ -213,13 +213,8 @@ func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *vsphereVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { - return b.SetUpAt(b.GetPath(), mounterArgs) -} - -// SetUp attaches the disk and bind mounts to the volume path. -func (b *vsphereVolumeMounter) SetUpWithStatusTracking(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUp(mounterArgs) +func (b *vsphereVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { + err := b.SetUpAt(b.GetPath(), mounterArgs) return volumetypes.OperationFinished, err } diff --git a/pkg/volume/vsphere_volume/vsphere_volume_test.go b/pkg/volume/vsphere_volume/vsphere_volume_test.go index ae59c319813..ac282ea3cf6 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume_test.go +++ b/pkg/volume/vsphere_volume/vsphere_volume_test.go @@ -126,7 +126,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } From 5feea93163b5f1a3cf80f76fa0109e46e9aa9a0b Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 11 Nov 2019 18:27:54 -0500 Subject: [PATCH 11/15] Rename MarkVolumeMountedOpts to MarkVolumeOpts Also remove VolumeNotMounted state --- .../volumemanager/cache/actual_state_of_world.go | 9 ++++----- .../cache/actual_state_of_world_test.go | 12 ++++++------ pkg/kubelet/volumemanager/metrics/metrics_test.go | 2 +- .../desired_state_of_world_populator_test.go | 2 +- pkg/kubelet/volumemanager/reconciler/reconciler.go | 2 +- pkg/volume/csi/csi_mounter.go | 1 + .../util/operationexecutor/operation_executor.go | 11 ++++------- .../util/operationexecutor/operation_generator.go | 5 ++--- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 1aedc92af8d..c6172af508f 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -59,7 +59,7 @@ type ActualStateOfWorld interface { // volume, reset the pod's remountRequired value. // If a volume with the name volumeName does not exist in the list of // attached volumes, an error is returned. - AddPodToVolume(operationexecutor.MarkVolumeMountedOpts) error + AddPodToVolume(operationexecutor.MarkVolumeOpts) error // MarkRemountRequired marks each volume that is successfully attached and // mounted for the specified pod as requiring remount (if the plugin for the @@ -313,7 +313,6 @@ type mountedPod struct { // volumeMountStateForPod stores state of volume mount for the pod. if it is: // - VolumeMounted: means volume for pod has been successfully mounted // - VolumeMountUncertain: means volume for pod may not be mounted, but it must be unmounted - // - VolumeNotMounted: means volume for pod has not been mounted volumeMountStateForPod operationexecutor.VolumeMountState } @@ -332,7 +331,7 @@ func (asw *actualStateOfWorld) MarkVolumeAsDetached( asw.DeleteVolume(volumeName) } -func (asw *actualStateOfWorld) MarkVolumeAsMounted(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { +func (asw *actualStateOfWorld) MarkVolumeAsMounted(markVolumeOpts operationexecutor.MarkVolumeOpts) error { return asw.AddPodToVolume(markVolumeOpts) } @@ -360,7 +359,7 @@ func (asw *actualStateOfWorld) MarkDeviceAsUncertain( return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceMountUncertain, devicePath, deviceMountPath) } -func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { +func (asw *actualStateOfWorld) MarkVolumeMountAsUncertain(markVolumeOpts operationexecutor.MarkVolumeOpts) error { markVolumeOpts.VolumeMountState = operationexecutor.VolumeMountUncertain return asw.AddPodToVolume(markVolumeOpts) } @@ -428,7 +427,7 @@ func (asw *actualStateOfWorld) addVolume( return nil } -func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.MarkVolumeMountedOpts) error { +func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.MarkVolumeOpts) error { podName := markVolumeOpts.PodName podUID := markVolumeOpts.PodUID volumeName := markVolumeOpts.VolumeName diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go index 684c02afe0d..e44f958a4ad 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go @@ -221,7 +221,7 @@ func Test_AddPodToVolume_Positive_ExistingVolumeNewNode(t *testing.T) { } // Act - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: podName, PodUID: pod.UID, VolumeName: generatedVolumeName, @@ -295,7 +295,7 @@ func Test_AddPodToVolume_Positive_ExistingVolumeExistingNode(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: podName, PodUID: pod.UID, VolumeName: generatedVolumeName, @@ -402,7 +402,7 @@ func Test_AddTwoPodsToVolume_Positive(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - markVolumeOpts1 := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts1 := operationexecutor.MarkVolumeOpts{ PodName: podName1, PodUID: pod1.UID, VolumeName: generatedVolumeName1, @@ -428,7 +428,7 @@ func Test_AddTwoPodsToVolume_Positive(t *testing.T) { t.Fatalf("NewBlockVolumeMapper failed. Expected: Actual: <%v>", err) } - markVolumeOpts2 := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts2 := operationexecutor.MarkVolumeOpts{ PodName: podName2, PodUID: pod2.UID, VolumeName: generatedVolumeName1, @@ -513,7 +513,7 @@ func Test_AddPodToVolume_Negative_VolumeDoesntExist(t *testing.T) { } // Act - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: podName, PodUID: pod.UID, VolumeName: volumeName, @@ -632,7 +632,7 @@ func TestUncertainVolumeMounts(t *testing.T) { t.Fatalf("NewMounter failed. Expected: Actual: <%v>", err) } - markVolumeOpts1 := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts1 := operationexecutor.MarkVolumeOpts{ PodName: podName1, PodUID: pod1.UID, VolumeName: generatedVolumeName1, diff --git a/pkg/kubelet/volumemanager/metrics/metrics_test.go b/pkg/kubelet/volumemanager/metrics/metrics_test.go index 2af2c17cdf5..33f4d27eb01 100644 --- a/pkg/kubelet/volumemanager/metrics/metrics_test.go +++ b/pkg/kubelet/volumemanager/metrics/metrics_test.go @@ -78,7 +78,7 @@ func TestMetricCollection(t *testing.T) { t.Fatalf("MarkVolumeAsAttached failed. Expected: Actual: <%v>", err) } - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: podName, PodUID: pod.UID, VolumeName: generatedVolumeName, diff --git a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go index 423ac509cae..9f887a18305 100644 --- a/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go +++ b/pkg/kubelet/volumemanager/populator/desired_state_of_world_populator_test.go @@ -855,7 +855,7 @@ func reconcileASW(asw cache.ActualStateOfWorld, dsw cache.DesiredStateOfWorld, t if err != nil { t.Fatalf("Unexpected error when MarkVolumeAsAttached: %v", err) } - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: volumeToMount.PodName, PodUID: volumeToMount.Pod.UID, VolumeName: volumeToMount.VolumeName, diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler.go b/pkg/kubelet/volumemanager/reconciler/reconciler.go index ec46ea492ac..adb2e2038cd 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler.go @@ -640,7 +640,7 @@ func (rc *reconciler) updateStates(volumesNeedUpdate map[v1.UniqueVolumeName]*re klog.Errorf("Could not add volume information to actual state of world: %v", err) continue } - markVolumeOpts := operationexecutor.MarkVolumeMountedOpts{ + markVolumeOpts := operationexecutor.MarkVolumeOpts{ PodName: volume.podName, PodUID: types.UID(volume.podName), VolumeName: volume.volumeName, diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 1915adcac5d..9b9c4e76342 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -126,6 +126,7 @@ func (c *csiMountMgr) setupUtil(dir string, mounterArgs volume.MounterArgs) (vol csi, err := c.csiClientGetter.Get() if err != nil { + opExitStatus = volumetypes.OperationStateNoChange return opExitStatus, errors.New(log("mounter.SetUpAt failed to get CSI client: %v", err)) } ctx, cancel := context.WithTimeout(context.Background(), csiTimeout) diff --git a/pkg/volume/util/operationexecutor/operation_executor.go b/pkg/volume/util/operationexecutor/operation_executor.go index 010299cee41..8c0bdf0fca4 100644 --- a/pkg/volume/util/operationexecutor/operation_executor.go +++ b/pkg/volume/util/operationexecutor/operation_executor.go @@ -160,8 +160,8 @@ func NewOperationExecutor( } } -// MarkVolumeMountedOpts is an struct to pass arguments to MountVolume functions -type MarkVolumeMountedOpts struct { +// MarkVolumeOpts is an struct to pass arguments to MountVolume functions +type MarkVolumeOpts struct { PodName volumetypes.UniquePodName PodUID types.UID VolumeName v1.UniqueVolumeName @@ -177,13 +177,13 @@ type MarkVolumeMountedOpts struct { // state of the world cache after successful mount/unmount. type ActualStateOfWorldMounterUpdater interface { // Marks the specified volume as mounted to the specified pod - MarkVolumeAsMounted(markVolumeOpts MarkVolumeMountedOpts) error + MarkVolumeAsMounted(markVolumeOpts MarkVolumeOpts) error // Marks the specified volume as unmounted from the specified pod MarkVolumeAsUnmounted(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error // MarkVolumeMountAsUncertain marks state of volume mount for the pod uncertain - MarkVolumeMountAsUncertain(markVolumeOpts MarkVolumeMountedOpts) error + MarkVolumeMountAsUncertain(markVolumeOpts MarkVolumeOpts) error // Marks the specified volume as having been globally mounted. MarkDeviceAsMounted(volumeName v1.UniqueVolumeName, devicePath, deviceMountPath string) error @@ -397,9 +397,6 @@ const ( // VolumeMountUncertain means volume may or may not be mounted in pods' local path VolumeMountUncertain VolumeMountState = "VolumeMountUncertain" - - // VolumeNotMounted means volume has not been mounted in pod's local path - VolumeNotMounted VolumeMountState = "VolumeNotMounted" ) // GenerateMsgDetailed returns detailed msgs for volumes to mount diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 8b080560127..1da44f42b04 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -634,7 +634,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( DesiredSize: volumeToMount.DesiredSizeLimit, }) // Update actual state of world - markOpts := MarkVolumeMountedOpts{ + markOpts := MarkVolumeOpts{ PodName: volumeToMount.PodName, PodUID: volumeToMount.Pod.UID, VolumeName: volumeToMount.VolumeName, @@ -653,7 +653,6 @@ func (og *operationGenerator) GenerateMountVolumeFunc( klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) } case volumetypes.OperationFinished: - markOpts.VolumeMountState = VolumeNotMounted t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) if t != nil { klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) @@ -1021,7 +1020,7 @@ func (og *operationGenerator) GenerateMapVolumeFunc( return volumeToMount.GenerateError("MapVolume.MarkVolumeAsMounted failed while expanding volume", resizeError) } - markVolumeOpts := MarkVolumeMountedOpts{ + markVolumeOpts := MarkVolumeOpts{ PodName: volumeToMount.PodName, PodUID: volumeToMount.Pod.UID, VolumeName: volumeToMount.VolumeName, From 309c6f863a1ec15c49370983999da0c5c8008d41 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 13 Nov 2019 12:44:38 -0500 Subject: [PATCH 12/15] Handle the case of remounts correctly --- .../cache/actual_state_of_world.go | 28 ++ .../reconciler/reconciler_test.go | 282 ++++++++++++------ pkg/volume/csi/csi_mounter.go | 6 +- pkg/volume/testing/testing.go | 126 ++++++-- .../operationexecutor/operation_executor.go | 9 + .../operationexecutor/operation_generator.go | 68 +++-- pkg/volume/util/types/types.go | 2 +- 7 files changed, 384 insertions(+), 137 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index c6172af508f..6ebd6b78e2d 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -369,6 +369,34 @@ func (asw *actualStateOfWorld) MarkDeviceAsUnmounted( return asw.SetDeviceMountState(volumeName, operationexecutor.DeviceNotMounted, "", "") } +func (asw *actualStateOfWorld) GetDeviceMountState(volumeName v1.UniqueVolumeName) operationexecutor.DeviceMountState { + asw.RLock() + defer asw.RUnlock() + + volumeObj, volumeExists := asw.attachedVolumes[volumeName] + if !volumeExists { + return operationexecutor.DeviceNotMounted + } + + return volumeObj.deviceMountState +} + +func (asw *actualStateOfWorld) GetVolumeMountState(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) operationexecutor.VolumeMountState { + asw.RLock() + defer asw.RUnlock() + + volumeObj, volumeExists := asw.attachedVolumes[volumeName] + if !volumeExists { + return operationexecutor.VolumeNotMounted + } + + podObj, podExists := volumeObj.mountedPods[podName] + if !podExists { + return operationexecutor.VolumeNotMounted + } + return podObj.volumeMountStateForPod +} + // addVolume adds the given volume to the cache indicating the specified // volume is attached to this node. If no volume name is supplied, a unique // volume name is generated from the volumeSpec and returned on success. If a diff --git a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go index ae8071145cf..9fde0713d92 100644 --- a/pkg/kubelet/volumemanager/reconciler/reconciler_test.go +++ b/pkg/kubelet/volumemanager/reconciler/reconciler_test.go @@ -55,6 +55,7 @@ const ( nodeName k8stypes.NodeName = k8stypes.NodeName("mynodename") kubeletPodsDir string = "fake-dir" testOperationBackOffDuration time.Duration = 100 * time.Millisecond + reconcilerSyncWaitDuration time.Duration = 10 * time.Second ) func hasAddedPods() bool { return true } @@ -1153,6 +1154,7 @@ func Test_UncertainDeviceGlobalMounts(t *testing.T) { deviceState operationexecutor.DeviceMountState unmountDeviceCallCount int volumeName string + supportRemount bool }{ { name: "timed out operations should result in device marked as uncertain", @@ -1172,6 +1174,20 @@ func Test_UncertainDeviceGlobalMounts(t *testing.T) { unmountDeviceCallCount: 0, volumeName: volumetesting.TimeoutAndFailOnMountDeviceVolumeName, }, + { + name: "success followed by timeout operation should result in mounted device", + deviceState: operationexecutor.DeviceGloballyMounted, + unmountDeviceCallCount: 1, + volumeName: volumetesting.SuccessAndTimeoutDeviceName, + supportRemount: true, + }, + { + name: "success followed by failed operation should result in mounted device", + deviceState: operationexecutor.DeviceGloballyMounted, + unmountDeviceCallCount: 1, + volumeName: volumetesting.SuccessAndFailOnMountDeviceName, + supportRemount: true, + }, } for _, tc := range tests { @@ -1216,6 +1232,8 @@ func Test_UncertainDeviceGlobalMounts(t *testing.T) { } volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) + fakePlugin.SupportsRemount = tc.supportRemount + dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ @@ -1262,113 +1280,203 @@ func Test_UncertainDeviceGlobalMounts(t *testing.T) { close(stoppedChan) }() waitForVolumeToExistInASW(t, volumeName, asw) + if tc.volumeName == volumetesting.TimeoutAndFailOnMountDeviceVolumeName { + // Wait upto 10s for reconciler to catchup + time.Sleep(reconcilerSyncWaitDuration) + } + + if tc.volumeName == volumetesting.SuccessAndFailOnMountDeviceName || + tc.volumeName == volumetesting.SuccessAndTimeoutDeviceName { + // wait for mount and then break it via remount + waitForMount(t, fakePlugin, volumeName, asw) + asw.MarkRemountRequired(podName) + time.Sleep(reconcilerSyncWaitDuration) + } + if tc.deviceState == operationexecutor.DeviceMountUncertain { waitForUncertainGlobalMount(t, volumeName, asw) } + if tc.deviceState == operationexecutor.DeviceGloballyMounted { + waitForMount(t, fakePlugin, volumeName, asw) + } + dsw.DeletePodFromVolume(podName, volumeName) waitForDetach(t, volumeName, asw) - - volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) - + err = volumetesting.VerifyUnmountDeviceCallCount(tc.unmountDeviceCallCount, fakePlugin) + if err != nil { + t.Errorf("Error verifying UnMountDeviceCallCount: %v", err) + } }) } } func Test_UncertainVolumeMountState(t *testing.T) { fsMode := v1.PersistentVolumeFilesystem - pv := &v1.PersistentVolume{ - ObjectMeta: metav1.ObjectMeta{ - Name: volumetesting.TimeoutOnSetupVolumeName, - UID: "pvuid", + var tests = []struct { + name string + volumeState operationexecutor.VolumeMountState + unmountDeviceCallCount int + unmountVolumeCount int + volumeName string + supportRemount bool + }{ + { + name: "timed out operations should result in volume marked as uncertain", + volumeState: operationexecutor.VolumeMountUncertain, + unmountDeviceCallCount: 1, + unmountVolumeCount: 1, + volumeName: volumetesting.TimeoutOnSetupVolumeName, }, - Spec: v1.PersistentVolumeSpec{ - ClaimRef: &v1.ObjectReference{Name: "pvc"}, - VolumeMode: &fsMode, + { + name: "failed operation should result in not-mounted volume", + volumeState: operationexecutor.VolumeNotMounted, + unmountDeviceCallCount: 0, + unmountVolumeCount: 0, + volumeName: volumetesting.FailOnSetupVolumeName, + }, + { + name: "timeout followed by failed operation should result in non-mounted volume", + volumeState: operationexecutor.VolumeNotMounted, + unmountDeviceCallCount: 0, + unmountVolumeCount: 0, + volumeName: volumetesting.TimeoutAndFailOnSetupVolumeName, + }, + { + name: "success followed by timeout operation should result in mounted volume", + volumeState: operationexecutor.VolumeMounted, + unmountDeviceCallCount: 1, + unmountVolumeCount: 1, + volumeName: volumetesting.SuccessAndTimeoutSetupVolumeName, + supportRemount: true, + }, + { + name: "success followed by failed operation should result in mounted volume", + volumeState: operationexecutor.VolumeMounted, + unmountDeviceCallCount: 1, + unmountVolumeCount: 1, + volumeName: volumetesting.SuccessAndFailOnSetupVolumeName, + supportRemount: true, }, } - pvc := &v1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pvc", - UID: "pvcuid", - }, - Spec: v1.PersistentVolumeClaimSpec{ - VolumeName: volumetesting.TimeoutOnSetupVolumeName, - }, - } - pod := &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "pod1", - UID: "pod1uid", - }, - Spec: v1.PodSpec{ - Volumes: []v1.Volume{ - { - Name: "volume-name", - VolumeSource: v1.VolumeSource{ - PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ - ClaimName: pvc.Name, + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.volumeName, + UID: "pvuid", + }, + Spec: v1.PersistentVolumeSpec{ + ClaimRef: &v1.ObjectReference{Name: "pvc"}, + VolumeMode: &fsMode, + }, + } + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pvc", + UID: "pvcuid", + }, + Spec: v1.PersistentVolumeClaimSpec{ + VolumeName: tc.volumeName, + }, + } + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "volume-name", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: pvc.Name, + }, + }, }, }, }, - }, - }, + } + + volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) + fakePlugin.SupportsRemount = tc.supportRemount + dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) + asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) + kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ + Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", tc.volumeName)), + DevicePath: "fake/path", + }) + fakeRecorder := &record.FakeRecorder{} + fakeHandler := volumetesting.NewBlockVolumePathHandler() + oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( + kubeClient, + volumePluginMgr, + fakeRecorder, + false, /* checkNodeCapabilitiesBeforeMount */ + fakeHandler)) + + reconciler := NewReconciler( + kubeClient, + true, /* controllerAttachDetachEnabled */ + reconcilerLoopSleepDuration, + waitForAttachTimeout, + nodeName, + dsw, + asw, + hasAddedPods, + oex, + &mount.FakeMounter{}, + hostutil.NewFakeHostUtil(nil), + volumePluginMgr, + kubeletPodsDir) + volumeSpec := &volume.Spec{PersistentVolume: pv} + podName := util.GetUniquePodName(pod) + volumeName, err := dsw.AddPodToVolume( + podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) + // Assert + if err != nil { + t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) + } + dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) + + // Start the reconciler to fill ASW. + stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) + go func() { + reconciler.Run(stopChan) + close(stoppedChan) + }() + waitForVolumeToExistInASW(t, volumeName, asw) + if tc.volumeName == volumetesting.TimeoutAndFailOnSetupVolumeName { + // Wait upto 10s for reconciler to catchup + time.Sleep(reconcilerSyncWaitDuration) + } + + if tc.volumeName == volumetesting.SuccessAndFailOnSetupVolumeName || + tc.volumeName == volumetesting.SuccessAndTimeoutSetupVolumeName { + // wait for mount and then break it via remount + waitForMount(t, fakePlugin, volumeName, asw) + asw.MarkRemountRequired(podName) + time.Sleep(reconcilerSyncWaitDuration) + } + + if tc.volumeState == operationexecutor.VolumeMountUncertain { + waitForUncertainPodMount(t, volumeName, asw) + } + + if tc.volumeState == operationexecutor.VolumeMounted { + waitForMount(t, fakePlugin, volumeName, asw) + } + + dsw.DeletePodFromVolume(podName, volumeName) + waitForDetach(t, volumeName, asw) + + volumetesting.VerifyUnmountDeviceCallCount(tc.unmountDeviceCallCount, fakePlugin) + volumetesting.VerifyTearDownCallCount(tc.unmountVolumeCount, fakePlugin) + }) } - volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t) - dsw := cache.NewDesiredStateOfWorld(volumePluginMgr) - asw := cache.NewActualStateOfWorld(nodeName, volumePluginMgr) - kubeClient := createtestClientWithPVPVC(pv, pvc, v1.AttachedVolume{ - Name: v1.UniqueVolumeName(fmt.Sprintf("fake-plugin/%s", volumetesting.TimeoutOnSetupVolumeName)), - DevicePath: "fake/path", - }) - fakeRecorder := &record.FakeRecorder{} - fakeHandler := volumetesting.NewBlockVolumePathHandler() - oex := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator( - kubeClient, - volumePluginMgr, - fakeRecorder, - false, /* checkNodeCapabilitiesBeforeMount */ - fakeHandler)) - - reconciler := NewReconciler( - kubeClient, - true, /* controllerAttachDetachEnabled */ - reconcilerLoopSleepDuration, - waitForAttachTimeout, - nodeName, - dsw, - asw, - hasAddedPods, - oex, - &mount.FakeMounter{}, - hostutil.NewFakeHostUtil(nil), - volumePluginMgr, - kubeletPodsDir) - volumeSpec := &volume.Spec{PersistentVolume: pv} - podName := util.GetUniquePodName(pod) - volumeName, err := dsw.AddPodToVolume( - podName, pod, volumeSpec, volumeSpec.Name(), "" /* volumeGidValue */) - // Assert - if err != nil { - t.Fatalf("AddPodToVolume failed. Expected: Actual: <%v>", err) - } - dsw.MarkVolumesReportedInUse([]v1.UniqueVolumeName{volumeName}) - - // Start the reconciler to fill ASW. - stopChan, stoppedChan := make(chan struct{}), make(chan struct{}) - go func() { - reconciler.Run(stopChan) - close(stoppedChan) - }() - waitForVolumeToExistInASW(t, volumeName, asw) - waitForUncertainPodMount(t, volumeName, asw) - - dsw.DeletePodFromVolume(podName, volumeName) - waitForDetach(t, volumeName, asw) - - volumetesting.VerifyUnmountDeviceCallCount(1, fakePlugin) - volumetesting.VerifyTearDownCallCount(1, fakePlugin) } func waitForUncertainGlobalMount(t *testing.T, volumeName v1.UniqueVolumeName, asw cache.ActualStateOfWorld) { diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 9b9c4e76342..35bc07328f3 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -100,16 +100,16 @@ func (c *csiMountMgr) CanMount() error { } func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - opExitStatus, err := c.setupUtil(c.GetPath(), mounterArgs) + opExitStatus, err := c.setupInternal(c.GetPath(), mounterArgs) return opExitStatus, err } func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { - _, err := c.setupUtil(dir, mounterArgs) + _, err := c.setupInternal(dir, mounterArgs) return err } -func (c *csiMountMgr) setupUtil(dir string, mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { +func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { klog.V(4).Infof(log("Mounter.SetUpAt(%s)", dir)) // default to finished operation status opExitStatus := volumetypes.OperationFinished diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 69c21256e65..b027fa673d0 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -69,12 +69,25 @@ const ( MultiAttachNode = "multi-attach-node" // TimeoutOnSetupVolumeName will cause Setup call to timeout but volume will finish mounting. TimeoutOnSetupVolumeName = "timeout-setup-volume" + // FailOnSetupVolumeName will cause setup call to fail + FailOnSetupVolumeName = "fail-setup-volume" + //TimeoutAndFailOnSetupVolumeName will first timeout and then fail the setup + TimeoutAndFailOnSetupVolumeName = "timeout-and-fail-setup-volume" + // SuccessAndTimeoutSetupVolumeName will cause first mount operation to succeed but subsequent attempts to timeout + SuccessAndTimeoutSetupVolumeName = "success-and-timeout-setup-volume-name" + // SuccessAndFailOnSetupVolumeName will cause first mount operation to succeed but subsequent attempts to fail + SuccessAndFailOnSetupVolumeName = "success-and-failed-setup-device-name" + // TimeoutOnMountDeviceVolumeName will cause MountDevice call to timeout but Setup will finish. TimeoutOnMountDeviceVolumeName = "timeout-mount-device-volume" // TimeoutAndFailOnMountDeviceVolumeName will cause first MountDevice call to timeout but second call will fail TimeoutAndFailOnMountDeviceVolumeName = "timeout-and-fail-mount-device-name" // FailMountDeviceVolumeName will cause MountDevice operation on volume to fail FailMountDeviceVolumeName = "fail-mount-device-volume-name" + // SuccessAndTimeoutDeviceName will cause first mount operation to succeed but subsequent attempts to timeout + SuccessAndTimeoutDeviceName = "success-and-timeout-device-name" + // SuccessAndFailOnMountDeviceName will cause first mount operation to succeed but subsequent attempts to fail + SuccessAndFailOnMountDeviceName = "success-and-failed-mount-device-name" ) // fakeVolumeHost is useful for testing volume plugins. @@ -354,6 +367,7 @@ type FakeVolumePlugin struct { VolumeLimitsError error LimitKey string ProvisionDelaySeconds int + SupportsRemount bool // Add callbacks as needed WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) @@ -393,6 +407,7 @@ func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume { } volume.VolumesAttached = make(map[string]types.NodeName) volume.DeviceMountState = make(map[string]volumetypes.OperationStatus) + volume.VolumeMountState = make(map[string]volumetypes.OperationStatus) *list = append(*list, volume) return volume } @@ -430,7 +445,7 @@ func (plugin *FakeVolumePlugin) CanSupport(spec *Spec) bool { } func (plugin *FakeVolumePlugin) RequiresRemount() bool { - return false + return plugin.SupportsRemount } func (plugin *FakeVolumePlugin) SupportsMountOption() bool { @@ -796,6 +811,7 @@ type FakeVolume struct { MetricsNil VolumesAttached map[string]types.NodeName DeviceMountState map[string]volumetypes.OperationStatus + VolumeMountState map[string]volumetypes.OperationStatus // Add callbacks as needed WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) @@ -844,22 +860,58 @@ func (fv *FakeVolume) CanMount() error { } func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { - internalSetup := func() error { - fv.Lock() - defer fv.Unlock() - if fv.VolName == TimeoutOnSetupVolumeName { - return volumetypes.NewOperationTimedOutError("time out on setup") - } - fv.SetUpCallCount++ - return fv.SetUpAt(fv.getPath(), mounterArgs) - } - err := internalSetup() + fv.Lock() + defer fv.Unlock() + err := fv.setupInternal(mounterArgs) + fv.SetUpCallCount++ if volumetypes.IsOperationTimeOutError(err) { return volumetypes.OperationInProgress, err } return volumetypes.OperationFinished, err } +func (fv *FakeVolume) setupInternal(mounterArgs MounterArgs) error { + if fv.VolName == TimeoutOnSetupVolumeName { + fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress + return volumetypes.NewOperationTimedOutError("time out on setup") + } + + if fv.VolName == FailOnSetupVolumeName { + return fmt.Errorf("mounting volume failed") + } + + if fv.VolName == TimeoutAndFailOnSetupVolumeName { + _, ok := fv.VolumeMountState[fv.VolName] + if !ok { + fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress + return volumetypes.NewOperationTimedOutError("time out on setup") + } + fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished + return fmt.Errorf("mounting volume failed") + + } + + if fv.VolName == SuccessAndFailOnSetupVolumeName { + _, ok := fv.VolumeMountState[fv.VolName] + if ok { + fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished + return fmt.Errorf("mounting volume failed") + } + } + + if fv.VolName == SuccessAndTimeoutSetupVolumeName { + _, ok := fv.VolumeMountState[fv.VolName] + if ok { + fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress + return volumetypes.NewOperationTimedOutError("time out on setup") + } + } + + fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished + + return fv.SetUpAt(fv.getPath(), mounterArgs) +} + func (fv *FakeVolume) GetSetUpCallCount() int { fv.RLock() defer fv.RUnlock() @@ -1071,16 +1123,30 @@ func (fv *FakeVolume) mountDeviceInternal(spec *Spec, devicePath string, deviceM } if spec.Name() == TimeoutAndFailOnMountDeviceVolumeName { - oldState, ok := fv.DeviceMountState[spec.Name()] + _, ok := fv.DeviceMountState[spec.Name()] if !ok { + fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress + return volumetypes.NewOperationTimedOutError("timed out mounting error") + } + fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + return fmt.Errorf("error mounting disk: %s", devicePath) + } + + if spec.Name() == SuccessAndTimeoutDeviceName { + _, ok := fv.DeviceMountState[spec.Name()] + if ok { fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress return volumetypes.NewOperationTimedOutError("error mounting state") } - if oldState == volumetypes.OperationInProgress { - fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + } + + if spec.Name() == SuccessAndFailOnMountDeviceName { + _, ok := fv.DeviceMountState[spec.Name()] + if ok { return fmt.Errorf("error mounting disk: %s", devicePath) } } + fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished fv.MountDeviceCallCount++ return nil } @@ -1361,16 +1427,25 @@ func VerifyMountDeviceCallCount( } func VerifyUnmountDeviceCallCount(expectedCallCount int, fakeVolumePlugin *FakeVolumePlugin) error { - for _, attacher := range fakeVolumePlugin.GetAttachers() { - actualCallCount := attacher.GetUnmountDeviceCallCount() - if actualCallCount >= expectedCallCount { + detachers := fakeVolumePlugin.GetDetachers() + if len(detachers) == 0 && (expectedCallCount == 0) { + return nil + } + actualCallCount := 0 + for _, detacher := range detachers { + actualCallCount = detacher.GetUnmountDeviceCallCount() + if expectedCallCount == 0 && actualCallCount == expectedCallCount { + return nil + } + + if (expectedCallCount > 0) && (actualCallCount >= expectedCallCount) { return nil } } return fmt.Errorf( - "No Attachers have expected MountunDeviceCallCount. Expected: <%v>.", - expectedCallCount) + "Expected DeviceUnmount Call %d, got %d", + expectedCallCount, actualCallCount) } // VerifyZeroMountDeviceCallCount ensures that all Attachers for this plugin @@ -1427,9 +1502,18 @@ func VerifyZeroSetUpCallCount(fakeVolumePlugin *FakeVolumePlugin) error { func VerifyTearDownCallCount( expectedTearDownCallCount int, fakeVolumePlugin *FakeVolumePlugin) error { - for _, unmounter := range fakeVolumePlugin.GetUnmounters() { + unmounters := fakeVolumePlugin.GetUnmounters() + if len(unmounters) == 0 && (expectedTearDownCallCount == 0) { + return nil + } + + for _, unmounter := range unmounters { actualCallCount := unmounter.GetTearDownCallCount() - if actualCallCount >= expectedTearDownCallCount { + if expectedTearDownCallCount == 0 && actualCallCount == expectedTearDownCallCount { + return nil + } + + if (expectedTearDownCallCount > 0) && (actualCallCount >= expectedTearDownCallCount) { return nil } } diff --git a/pkg/volume/util/operationexecutor/operation_executor.go b/pkg/volume/util/operationexecutor/operation_executor.go index 8c0bdf0fca4..463770f1730 100644 --- a/pkg/volume/util/operationexecutor/operation_executor.go +++ b/pkg/volume/util/operationexecutor/operation_executor.go @@ -196,6 +196,12 @@ type ActualStateOfWorldMounterUpdater interface { // Marks the specified volume's file system resize request is finished. MarkVolumeAsResized(podName volumetypes.UniquePodName, volumeName v1.UniqueVolumeName) error + + // GetDeviceMountState returns mount state of the device in global path + GetDeviceMountState(volumeName v1.UniqueVolumeName) DeviceMountState + + // GetVolumeMountState returns mount state of the volume for the Pod + GetVolumeMountState(volumName v1.UniqueVolumeName, podName volumetypes.UniquePodName) VolumeMountState } // ActualStateOfWorldAttacherUpdater defines a set of operations updating the @@ -397,6 +403,9 @@ const ( // VolumeMountUncertain means volume may or may not be mounted in pods' local path VolumeMountUncertain VolumeMountState = "VolumeMountUncertain" + + // VolumeNotMounted means volume has not be mounted in pod's local path + VolumeNotMounted VolumeMountState = "VolumeNotMounted" ) // GenerateMsgDetailed returns detailed msgs for volumes to mount diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 1da44f42b04..7be76b9e34d 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -580,18 +580,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( devicePath, deviceMountPath) if err != nil { - switch operationState { - case volumetypes.OperationInProgress: - markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) - if markDeviceUncertainError != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error()) - } - case volumetypes.OperationFinished: - markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName) - if markDeviceUnmountError != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error()) - } - } + og.markDeviceErrorState(volumeToMount, devicePath, deviceMountPath, operationState, actualStateOfWorld) // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.MountDevice failed", err) } @@ -645,19 +634,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( VolumeMountState: VolumeMounted, } if mountErr != nil { - switch opExitStatus { - case volumetypes.OperationInProgress: - markOpts.VolumeMountState = VolumeMountUncertain - t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) - if t != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) - } - case volumetypes.OperationFinished: - t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) - if t != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) - } - } + og.markVolumeErrorState(volumeToMount, markOpts, opExitStatus, actualStateOfWorld) // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.SetUp failed", mountErr) } @@ -717,6 +694,47 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } } +func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount, devicePath, deviceMountPath string, operationState volumetypes.OperationStatus, actualStateOfWorld ActualStateOfWorldMounterUpdater) { + switch operationState { + case volumetypes.OperationInProgress: + // only devices which are not mounted can be marked as uncertain. We do not want to mark a device + // which was previously marked as mounted here as uncertain. + if actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted { + markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) + if markDeviceUncertainError != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error()) + } + } + case volumetypes.OperationFinished: + // Similarly only devices which were uncertain can be marked as unmounted + if actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceMountUncertain { + markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName) + if markDeviceUnmountError != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error()) + } + } + } +} + +func (og *operationGenerator) markVolumeErrorState(volumeToMount VolumeToMount, markOpts MarkVolumeOpts, operationState volumetypes.OperationStatus, actualStateOfWorld ActualStateOfWorldMounterUpdater) { + switch operationState { + case volumetypes.OperationInProgress: + if actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeNotMounted { + t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) + if t != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) + } + } + case volumetypes.OperationFinished: + if actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeMountUncertain { + t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) + if t != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) + } + } + } +} + func (og *operationGenerator) GenerateUnmountVolumeFunc( volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 284427fcabb..4cbcd2c22f3 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -60,7 +60,7 @@ const ( // OperationInProgress means volume operation has been started and // is in-progress. This state does not indicate if operation will succeed or fail but - // merely it has been started and in in-progress. + // merely it has been started and is in-progress. OperationInProgress OperationStatus = "InProgress" // OperationStateNoChange indicates it is unchanged from previous state. From 0741f6fa2958449298ab660649ef3d623d2b7ef6 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 14 Nov 2019 16:31:40 -0500 Subject: [PATCH 13/15] Ensure that metadata directory is not created if secret is not found To ensure that metadata directory is not created if secret is not found, we will move fetching secrets bit more earlier in the code. --- pkg/volume/csi/csi_attacher.go | 75 ++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index 5f9006352f6..c1fc1ec385e 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -249,6 +249,45 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo return opExitStatus, errors.New(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err)) } + // lets check if node/unstage is supported + if c.csiClient == nil { + c.csiClient, err = newCsiDriverClient(csiDriverName(csiSource.Driver)) + if err != nil { + return opExitStatus, errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) + } + } + csi := c.csiClient + + ctx, cancel := context.WithTimeout(context.Background(), csiTimeout) + defer cancel() + // Check whether "STAGE_UNSTAGE_VOLUME" is set + stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) + if err != nil { + return opExitStatus, err + } + + // Get secrets and publish context required for mountDevice + nodeName := string(c.plugin.host.GetNodeName()) + publishContext, err := c.plugin.getPublishContext(c.k8s, csiSource.VolumeHandle, csiSource.Driver, nodeName) + + if err != nil { + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, err + } + + nodeStageSecrets := map[string]string{} + // we only require secrets if csiSource has them and volume has NodeStage capability + if csiSource.NodeStageSecretRef != nil && stageUnstageSet { + nodeStageSecrets, err = getCredentialsFromSecret(c.k8s, csiSource.NodeStageSecretRef) + if err != nil { + err = fmt.Errorf("fetching NodeStageSecretRef %s/%s failed: %v", + csiSource.NodeStageSecretRef.Namespace, csiSource.NodeStageSecretRef.Name, err) + // if we failed to fetch secret then that could be a transient error + opExitStatus = volumetypes.OperationStateNoChange + return opExitStatus, err + } + } + // Store volume metadata for UnmountDevice. Keep it around even if the // driver does not support NodeStage, UnmountDevice still needs it. if err = os.MkdirAll(deviceMountPath, 0750); err != nil { @@ -279,48 +318,12 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo } }() - if c.csiClient == nil { - c.csiClient, err = newCsiDriverClient(csiDriverName(csiSource.Driver)) - if err != nil { - return opExitStatus, errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) - } - } - csi := c.csiClient - - ctx, cancel := context.WithTimeout(context.Background(), csiTimeout) - defer cancel() - // Check whether "STAGE_UNSTAGE_VOLUME" is set - stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) - if err != nil { - return opExitStatus, err - } if !stageUnstageSet { klog.Infof(log("attacher.MountDevice STAGE_UNSTAGE_VOLUME capability not set. Skipping MountDevice...")) // defer does *not* remove the metadata file and it's correct - UnmountDevice needs it there. return opExitStatus, nil } - // Start MountDevice - nodeName := string(c.plugin.host.GetNodeName()) - publishContext, err := c.plugin.getPublishContext(c.k8s, csiSource.VolumeHandle, csiSource.Driver, nodeName) - - if err != nil { - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, err - } - - nodeStageSecrets := map[string]string{} - if csiSource.NodeStageSecretRef != nil { - nodeStageSecrets, err = getCredentialsFromSecret(c.k8s, csiSource.NodeStageSecretRef) - if err != nil { - err = fmt.Errorf("fetching NodeStageSecretRef %s/%s failed: %v", - csiSource.NodeStageSecretRef.Namespace, csiSource.NodeStageSecretRef.Name, err) - // if we failed to fetch secret then that could be a transient error - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, err - } - } - //TODO (vladimirvivien) implement better AccessModes mapping between k8s and CSI accessMode := v1.ReadWriteOnce if spec.PersistentVolume.Spec.AccessModes != nil { From 4b8e552a8882b205c5365b7ea0b042f969579a4e Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 14 Nov 2019 18:55:46 -0500 Subject: [PATCH 14/15] Use typed errors for special casing volume progress Use typed errors rather than operation status for indicating operation progress --- hack/.staticcheck_failures | 1 + .../volume/attachdetach/testing/BUILD | 1 - .../attachdetach/testing/testvolumespec.go | 7 +- pkg/kubelet/BUILD | 1 - pkg/kubelet/kubelet_volumes_test.go | 5 +- pkg/volume/BUILD | 1 - pkg/volume/awsebs/BUILD | 1 - pkg/volume/awsebs/attacher.go | 13 ++- pkg/volume/awsebs/aws_ebs.go | 6 +- pkg/volume/awsebs/aws_ebs_test.go | 4 +- pkg/volume/azure_dd/BUILD | 1 - pkg/volume/azure_dd/attacher.go | 7 +- pkg/volume/azure_dd/azure_mounter.go | 6 +- pkg/volume/azure_file/BUILD | 1 - pkg/volume/azure_file/azure_file.go | 6 +- pkg/volume/azure_file/azure_file_test.go | 2 +- pkg/volume/cephfs/BUILD | 1 - pkg/volume/cephfs/cephfs.go | 6 +- pkg/volume/cephfs/cephfs_test.go | 2 +- pkg/volume/cinder/BUILD | 1 - pkg/volume/cinder/attacher.go | 8 +- pkg/volume/cinder/cinder.go | 6 +- pkg/volume/cinder/cinder_test.go | 2 +- pkg/volume/configmap/BUILD | 1 - pkg/volume/configmap/configmap.go | 6 +- pkg/volume/configmap/configmap_test.go | 10 +-- pkg/volume/csi/csi_attacher.go | 39 ++++----- pkg/volume/csi/csi_attacher_test.go | 24 +++--- pkg/volume/csi/csi_client.go | 4 +- pkg/volume/csi/csi_client_test.go | 14 +--- pkg/volume/csi/csi_mounter.go | 68 ++++++--------- pkg/volume/csi/csi_mounter_test.go | 26 +++--- pkg/volume/csi/csi_test.go | 4 +- pkg/volume/downwardapi/BUILD | 1 - pkg/volume/downwardapi/downwardapi.go | 6 +- pkg/volume/downwardapi/downwardapi_test.go | 4 +- pkg/volume/emptydir/BUILD | 1 - pkg/volume/emptydir/empty_dir.go | 6 +- pkg/volume/emptydir/empty_dir_test.go | 2 +- pkg/volume/fc/BUILD | 1 - pkg/volume/fc/attacher.go | 60 +++++++------- pkg/volume/fc/fc.go | 6 +- pkg/volume/fc/fc_test.go | 2 +- pkg/volume/flexvolume/BUILD | 1 - pkg/volume/flexvolume/attacher.go | 50 +++++------ pkg/volume/flexvolume/mounter.go | 6 +- pkg/volume/flocker/BUILD | 1 - pkg/volume/flocker/flocker.go | 6 +- pkg/volume/gcepd/BUILD | 1 - pkg/volume/gcepd/attacher.go | 8 +- pkg/volume/gcepd/gce_pd.go | 6 +- pkg/volume/gcepd/gce_pd_test.go | 4 +- pkg/volume/git_repo/BUILD | 1 - pkg/volume/git_repo/git_repo.go | 6 +- pkg/volume/glusterfs/BUILD | 1 - pkg/volume/glusterfs/glusterfs.go | 6 +- pkg/volume/glusterfs/glusterfs_test.go | 2 +- pkg/volume/hostpath/BUILD | 1 - pkg/volume/hostpath/host_path.go | 21 ++--- pkg/volume/hostpath/host_path_test.go | 4 +- pkg/volume/iscsi/BUILD | 1 - pkg/volume/iscsi/attacher.go | 9 +- pkg/volume/iscsi/iscsi.go | 6 +- pkg/volume/iscsi/iscsi_test.go | 2 +- pkg/volume/local/BUILD | 1 - pkg/volume/local/local.go | 47 +++++------ pkg/volume/local/local_test.go | 12 +-- pkg/volume/nfs/BUILD | 1 - pkg/volume/nfs/nfs.go | 6 +- pkg/volume/nfs/nfs_test.go | 2 +- pkg/volume/portworx/BUILD | 1 - pkg/volume/portworx/portworx.go | 6 +- pkg/volume/portworx/portworx_test.go | 2 +- pkg/volume/projected/BUILD | 1 - pkg/volume/projected/projected.go | 6 +- pkg/volume/projected/projected_test.go | 10 +-- pkg/volume/quobyte/BUILD | 1 - pkg/volume/quobyte/quobyte.go | 6 +- pkg/volume/quobyte/quobyte_test.go | 2 +- pkg/volume/rbd/BUILD | 1 - pkg/volume/rbd/attacher.go | 14 +--- pkg/volume/rbd/rbd.go | 6 +- pkg/volume/rbd/rbd_test.go | 4 +- pkg/volume/scaleio/BUILD | 1 - pkg/volume/scaleio/sio_volume.go | 6 +- pkg/volume/scaleio/sio_volume_test.go | 4 +- pkg/volume/secret/BUILD | 1 - pkg/volume/secret/secret.go | 6 +- pkg/volume/secret/secret_test.go | 10 +-- pkg/volume/storageos/BUILD | 1 - pkg/volume/storageos/storageos.go | 64 +++++++------- pkg/volume/storageos/storageos_test.go | 2 +- pkg/volume/testing/testing.go | 69 +++++++-------- .../operationexecutor/operation_generator.go | 83 +++++++++---------- pkg/volume/util/types/types.go | 68 ++++++++------- pkg/volume/volume.go | 15 +++- pkg/volume/vsphere_volume/BUILD | 1 - pkg/volume/vsphere_volume/attacher.go | 10 +-- pkg/volume/vsphere_volume/vsphere_volume.go | 7 +- .../vsphere_volume/vsphere_volume_test.go | 2 +- 100 files changed, 418 insertions(+), 578 deletions(-) diff --git a/hack/.staticcheck_failures b/hack/.staticcheck_failures index 7931c65fae6..a90443e253d 100644 --- a/hack/.staticcheck_failures +++ b/hack/.staticcheck_failures @@ -53,6 +53,7 @@ pkg/volume/flexvolume pkg/volume/flocker pkg/volume/hostpath pkg/volume/iscsi +pkg/volume/local pkg/volume/portworx pkg/volume/quobyte pkg/volume/rbd diff --git a/pkg/controller/volume/attachdetach/testing/BUILD b/pkg/controller/volume/attachdetach/testing/BUILD index 03a639344d3..e063b6b5fe2 100644 --- a/pkg/controller/volume/attachdetach/testing/BUILD +++ b/pkg/controller/volume/attachdetach/testing/BUILD @@ -12,7 +12,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/controller/volume/attachdetach/testing/testvolumespec.go b/pkg/controller/volume/attachdetach/testing/testvolumespec.go index eac942b0895..86b66f8f244 100644 --- a/pkg/controller/volume/attachdetach/testing/testvolumespec.go +++ b/pkg/controller/volume/attachdetach/testing/testvolumespec.go @@ -32,7 +32,6 @@ import ( "k8s.io/klog" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) const TestPluginName = "kubernetes.io/testPlugin" @@ -435,15 +434,15 @@ func (attacher *testPluginAttacher) GetDeviceMountPath(spec *volume.Spec) (strin return "", nil } -func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { +func (attacher *testPluginAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { attacher.pluginLock.Lock() defer attacher.pluginLock.Unlock() if spec == nil { *attacher.ErrorEncountered = true klog.Errorf("MountDevice called with nil volume spec") - return volumetypes.OperationFinished, fmt.Errorf("MountDevice called with nil volume spec") + return fmt.Errorf("MountDevice called with nil volume spec") } - return volumetypes.OperationFinished, nil + return nil } // Detacher diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index f6681956119..f942cf4c2aa 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -224,7 +224,6 @@ go_test( "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/subpath:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/pkg/kubelet/kubelet_volumes_test.go b/pkg/kubelet/kubelet_volumes_test.go index 85e86ca55c6..bfc5c8b7c22 100644 --- a/pkg/kubelet/kubelet_volumes_test.go +++ b/pkg/kubelet/kubelet_volumes_test.go @@ -29,7 +29,6 @@ import ( "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) func TestListVolumesForPod(t *testing.T) { @@ -531,8 +530,8 @@ func (f *stubVolume) CanMount() error { return nil } -func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - return volumetypes.OperationFinished, nil +func (f *stubVolume) SetUp(mounterArgs volume.MounterArgs) error { + return nil } func (f *stubVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/BUILD b/pkg/volume/BUILD index 88919d029a4..8e608ecc467 100644 --- a/pkg/volume/BUILD +++ b/pkg/volume/BUILD @@ -23,7 +23,6 @@ go_library( "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", "//pkg/volume/util/subpath:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/awsebs/BUILD b/pkg/volume/awsebs/BUILD index a9dfc8b4361..0a64e9943ea 100644 --- a/pkg/volume/awsebs/BUILD +++ b/pkg/volume/awsebs/BUILD @@ -23,7 +23,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/awsebs/attacher.go b/pkg/volume/awsebs/attacher.go index a13e5738faa..35bf55df8fe 100644 --- a/pkg/volume/awsebs/attacher.go +++ b/pkg/volume/awsebs/attacher.go @@ -34,7 +34,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/aws" ) @@ -207,7 +206,7 @@ func (attacher *awsElasticBlockStoreAttacher) GetDeviceMountPath( } // FIXME: this method can be further pruned. -func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { +func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.host.GetMounter(awsElasticBlockStorePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -222,17 +221,17 @@ func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, dev dir = filepath.Dir(deviceMountPath) } if err := os.MkdirAll(dir, 0750); err != nil { - return volumetypes.OperationFinished, fmt.Errorf("making dir %s failed with %s", dir, err) + return fmt.Errorf("making dir %s failed with %s", dir, err) } notMnt = true } else { - return volumetypes.OperationFinished, err + return err } } volumeSource, readOnly, err := getVolumeSource(spec) if err != nil { - return volumetypes.OperationFinished, err + return err } options := []string{} @@ -245,10 +244,10 @@ func (attacher *awsElasticBlockStoreAttacher) MountDevice(spec *volume.Spec, dev err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) if err != nil { os.Remove(deviceMountPath) - return volumetypes.OperationFinished, err + return err } } - return volumetypes.OperationFinished, nil + return nil } type awsElasticBlockStoreDetacher struct { diff --git a/pkg/volume/awsebs/aws_ebs.go b/pkg/volume/awsebs/aws_ebs.go index 11bbd2d17f0..7bae0358e34 100644 --- a/pkg/volume/awsebs/aws_ebs.go +++ b/pkg/volume/awsebs/aws_ebs.go @@ -39,7 +39,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/aws" utilstrings "k8s.io/utils/strings" ) @@ -366,9 +365,8 @@ func (b *awsElasticBlockStoreMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *awsElasticBlockStoreMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *awsElasticBlockStoreMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUpAt attaches the disk and bind mounts to the volume path. diff --git a/pkg/volume/awsebs/aws_ebs_test.go b/pkg/volume/awsebs/aws_ebs_test.go index db0fcca91cb..021ecc46dc5 100644 --- a/pkg/volume/awsebs/aws_ebs_test.go +++ b/pkg/volume/awsebs/aws_ebs_test.go @@ -141,7 +141,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -372,7 +372,7 @@ func TestMountOptions(t *testing.T) { t.Errorf("Got a nil Mounter") } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/azure_dd/BUILD b/pkg/volume/azure_dd/BUILD index b2839f87927..9e607d94ef0 100644 --- a/pkg/volume/azure_dd/BUILD +++ b/pkg/volume/azure_dd/BUILD @@ -27,7 +27,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/azure_dd/attacher.go b/pkg/volume/azure_dd/attacher.go index 290ca67e122..42296172f0d 100644 --- a/pkg/volume/azure_dd/attacher.go +++ b/pkg/volume/azure_dd/attacher.go @@ -37,7 +37,6 @@ import ( cloudprovider "k8s.io/cloud-provider" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/azure" ) @@ -199,11 +198,7 @@ func (a *azureDiskAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error return makeGlobalPDPath(a.plugin.host, volumeSource.DataDiskURI, isManagedDisk) } -func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - return volumetypes.OperationFinished, attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) -} - -func (attacher *azureDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.plugin.host.GetMounter(azureDataDiskPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) diff --git a/pkg/volume/azure_dd/azure_mounter.go b/pkg/volume/azure_dd/azure_mounter.go index f641e78e789..2f8d38bd0aa 100644 --- a/pkg/volume/azure_dd/azure_mounter.go +++ b/pkg/volume/azure_dd/azure_mounter.go @@ -29,7 +29,6 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type azureDiskMounter struct { @@ -66,9 +65,8 @@ func (m *azureDiskMounter) CanMount() error { return nil } -func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := m.SetUpAt(m.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (m *azureDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { + return m.SetUpAt(m.GetPath(), mounterArgs) } func (m *azureDiskMounter) GetPath() string { diff --git a/pkg/volume/azure_file/BUILD b/pkg/volume/azure_file/BUILD index f425722d0b9..1c4640f78a0 100644 --- a/pkg/volume/azure_file/BUILD +++ b/pkg/volume/azure_file/BUILD @@ -13,7 +13,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/azure_file/azure_file.go b/pkg/volume/azure_file/azure_file.go index 427e88e1043..cd1a13ba369 100644 --- a/pkg/volume/azure_file/azure_file.go +++ b/pkg/volume/azure_file/azure_file.go @@ -36,7 +36,6 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/azure" ) @@ -236,9 +235,8 @@ func (b *azureFileMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *azureFileMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *azureFileMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/azure_file/azure_file_test.go b/pkg/volume/azure_file/azure_file_test.go index d3407b8959a..6d42eb9ad8c 100644 --- a/pkg/volume/azure_file/azure_file_test.go +++ b/pkg/volume/azure_file/azure_file_test.go @@ -154,7 +154,7 @@ func testPlugin(t *testing.T, tmpDir string, volumeHost volume.VolumeHost) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/cephfs/BUILD b/pkg/volume/cephfs/BUILD index f3ed56c1c85..b521e4b48c9 100644 --- a/pkg/volume/cephfs/BUILD +++ b/pkg/volume/cephfs/BUILD @@ -16,7 +16,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/cephfs/cephfs.go b/pkg/volume/cephfs/cephfs.go index f9cd9be0d49..4ba29214fd9 100644 --- a/pkg/volume/cephfs/cephfs.go +++ b/pkg/volume/cephfs/cephfs.go @@ -33,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -220,9 +219,8 @@ func (cephfsVolume *cephfsMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (cephfsVolume *cephfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := cephfsVolume.SetUpAt(cephfsVolume.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (cephfsVolume *cephfsMounter) SetUp(mounterArgs volume.MounterArgs) error { + return cephfsVolume.SetUpAt(cephfsVolume.GetPath(), mounterArgs) } // SetUpAt attaches the disk and bind mounts to the volume path. diff --git a/pkg/volume/cephfs/cephfs_test.go b/pkg/volume/cephfs/cephfs_test.go index ea674d80ff8..abe498c5f10 100644 --- a/pkg/volume/cephfs/cephfs_test.go +++ b/pkg/volume/cephfs/cephfs_test.go @@ -88,7 +88,7 @@ func TestPlugin(t *testing.T) { if volumePath != volpath { t.Errorf("Got unexpected path: %s", volumePath) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/cinder/BUILD b/pkg/volume/cinder/BUILD index 06278d9ddeb..6d8674c91d3 100644 --- a/pkg/volume/cinder/BUILD +++ b/pkg/volume/cinder/BUILD @@ -20,7 +20,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/cinder/attacher.go b/pkg/volume/cinder/attacher.go index 21af74720b0..ebf84d31d0f 100644 --- a/pkg/volume/cinder/attacher.go +++ b/pkg/volume/cinder/attacher.go @@ -34,7 +34,6 @@ import ( "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type cinderDiskAttacher struct { @@ -269,7 +268,7 @@ func (attacher *cinderDiskAttacher) GetDeviceMountPath( } // FIXME: this method can be further pruned. -func (attacher *cinderDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.host.GetMounter(cinderVolumePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -304,11 +303,6 @@ func (attacher *cinderDiskAttacher) mountDeviceInternal(spec *volume.Spec, devic return nil } -func (attacher *cinderDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - type cinderDiskDetacher struct { mounter mount.Interface cinderProvider BlockStorageProvider diff --git a/pkg/volume/cinder/cinder.go b/pkg/volume/cinder/cinder.go index d694775f35a..d09baeb0caa 100644 --- a/pkg/volume/cinder/cinder.go +++ b/pkg/volume/cinder/cinder.go @@ -39,7 +39,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/openstack" ) @@ -390,9 +389,8 @@ func (b *cinderVolumeMounter) CanMount() error { return nil } -func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *cinderVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUp bind mounts to the volume path. diff --git a/pkg/volume/cinder/cinder_test.go b/pkg/volume/cinder/cinder_test.go index 5a151f5fc33..bd0d0c6b929 100644 --- a/pkg/volume/cinder/cinder_test.go +++ b/pkg/volume/cinder/cinder_test.go @@ -169,7 +169,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/configmap/BUILD b/pkg/volume/configmap/BUILD index 3300373c646..ab7d2571142 100644 --- a/pkg/volume/configmap/BUILD +++ b/pkg/volume/configmap/BUILD @@ -16,7 +16,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/configmap/configmap.go b/pkg/volume/configmap/configmap.go index 4347b4b2dad..7b0d900f16e 100644 --- a/pkg/volume/configmap/configmap.go +++ b/pkg/volume/configmap/configmap.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the entry point for plugin detection in a package. @@ -181,9 +180,8 @@ func (b *configMapVolumeMounter) CanMount() error { return nil } -func (b *configMapVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *configMapVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *configMapVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/configmap/configmap_test.go b/pkg/volume/configmap/configmap_test.go index 0e7b2172ba7..e03d39d1a25 100644 --- a/pkg/volume/configmap/configmap_test.go +++ b/pkg/volume/configmap/configmap_test.go @@ -368,7 +368,7 @@ func TestPlugin(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -428,7 +428,7 @@ func TestPluginReboot(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -492,7 +492,7 @@ func TestPluginOptional(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -591,7 +591,7 @@ func TestPluginKeysOptional(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -671,7 +671,7 @@ func TestInvalidConfigMapSetup(t *testing.T) { var mounterArgs volume.MounterArgs group := int64(1001) mounterArgs.FsGroup = &group - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected setup to fail") } diff --git a/pkg/volume/csi/csi_attacher.go b/pkg/volume/csi/csi_attacher.go index c1fc1ec385e..fbe710fbfb5 100644 --- a/pkg/volume/csi/csi_attacher.go +++ b/pkg/volume/csi/csi_attacher.go @@ -220,40 +220,38 @@ func (c *csiAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) { return deviceMountPath, nil } -func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { +func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { klog.V(4).Infof(log("attacher.MountDevice(%s, %s)", devicePath, deviceMountPath)) - // lets default to operation as finished state - opExitStatus := volumetypes.OperationFinished if deviceMountPath == "" { - return opExitStatus, errors.New(log("attacher.MountDevice failed, deviceMountPath is empty")) + return errors.New(log("attacher.MountDevice failed, deviceMountPath is empty")) } mounted, err := isDirMounted(c.plugin, deviceMountPath) if err != nil { klog.Error(log("attacher.MountDevice failed while checking mount status for dir [%s]", deviceMountPath)) - return opExitStatus, err + return err } if mounted { klog.V(4).Info(log("attacher.MountDevice skipping mount, dir already mounted [%s]", deviceMountPath)) - return opExitStatus, nil + return nil } // Setup if spec == nil { - return opExitStatus, errors.New(log("attacher.MountDevice failed, spec is nil")) + return errors.New(log("attacher.MountDevice failed, spec is nil")) } csiSource, err := getPVSourceFromSpec(spec) if err != nil { - return opExitStatus, errors.New(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err)) + return errors.New(log("attacher.MountDevice failed to get CSIPersistentVolumeSource: %v", err)) } // lets check if node/unstage is supported if c.csiClient == nil { c.csiClient, err = newCsiDriverClient(csiDriverName(csiSource.Driver)) if err != nil { - return opExitStatus, errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) + return errors.New(log("attacher.MountDevice failed to create newCsiDriverClient: %v", err)) } } csi := c.csiClient @@ -263,7 +261,7 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo // Check whether "STAGE_UNSTAGE_VOLUME" is set stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) if err != nil { - return opExitStatus, err + return err } // Get secrets and publish context required for mountDevice @@ -271,8 +269,7 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo publishContext, err := c.plugin.getPublishContext(c.k8s, csiSource.VolumeHandle, csiSource.Driver, nodeName) if err != nil { - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, err + return volumetypes.NewTransientOperationFailure(err.Error()) } nodeStageSecrets := map[string]string{} @@ -283,15 +280,14 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo err = fmt.Errorf("fetching NodeStageSecretRef %s/%s failed: %v", csiSource.NodeStageSecretRef.Namespace, csiSource.NodeStageSecretRef.Name, err) // if we failed to fetch secret then that could be a transient error - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, err + return volumetypes.NewTransientOperationFailure(err.Error()) } } // Store volume metadata for UnmountDevice. Keep it around even if the // driver does not support NodeStage, UnmountDevice still needs it. if err = os.MkdirAll(deviceMountPath, 0750); err != nil { - return opExitStatus, errors.New(log("attacher.MountDevice failed to create dir %#v: %v", deviceMountPath, err)) + return errors.New(log("attacher.MountDevice failed to create dir %#v: %v", deviceMountPath, err)) } klog.V(4).Info(log("created target path successfully [%s]", deviceMountPath)) dataDir := filepath.Dir(deviceMountPath) @@ -304,12 +300,12 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo if cleanErr := os.RemoveAll(dataDir); cleanErr != nil { klog.Error(log("failed to remove dir after error [%s]: %v", dataDir, cleanErr)) } - return opExitStatus, err + return err } defer func() { // Only if there was an error and volume operation was considered // finished, we should remove the directory. - if err != nil && opExitStatus == volumetypes.OperationFinished { + if err != nil && volumetypes.IsOperationFinishedError(err) { // clean up metadata klog.Errorf(log("attacher.MountDevice failed: %v", err)) if err := removeMountDir(c.plugin, deviceMountPath); err != nil { @@ -321,7 +317,7 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo if !stageUnstageSet { klog.Infof(log("attacher.MountDevice STAGE_UNSTAGE_VOLUME capability not set. Skipping MountDevice...")) // defer does *not* remove the metadata file and it's correct - UnmountDevice needs it there. - return opExitStatus, nil + return nil } //TODO (vladimirvivien) implement better AccessModes mapping between k8s and CSI @@ -347,14 +343,11 @@ func (c *csiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMo mountOptions) if err != nil { - if volumetypes.IsOperationTimeOutError(err) { - opExitStatus = volumetypes.OperationInProgress - } - return opExitStatus, err + return err } klog.V(4).Infof(log("attacher.MountDevice successfully requested NodeStageVolume [%s]", deviceMountPath)) - return opExitStatus, err + return err } var _ volume.Detacher = &csiAttacher{} diff --git a/pkg/volume/csi/csi_attacher_test.go b/pkg/volume/csi/csi_attacher_test.go index 22b4de03eea..41c646cf839 100644 --- a/pkg/volume/csi/csi_attacher_test.go +++ b/pkg/volume/csi/csi_attacher_test.go @@ -1056,6 +1056,9 @@ func TestAttacherGetDeviceMountPath(t *testing.T) { func TestAttacherMountDevice(t *testing.T) { pvName := "test-pv" + nonFinalError := volumetypes.NewUncertainProgressError("") + transientError := volumetypes.NewTransientOperationFailure("") + testCases := []struct { testName string volName string @@ -1064,7 +1067,7 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet bool shouldFail bool createAttachment bool - exitStatus volumetypes.OperationStatus + exitError error spec *volume.Spec }{ { @@ -1075,7 +1078,6 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, createAttachment: true, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), - exitStatus: volumetypes.OperationFinished, }, { testName: "normal PV with mount options", @@ -1084,7 +1086,6 @@ func TestAttacherMountDevice(t *testing.T) { deviceMountPath: "path2", stageUnstageSet: true, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false), }, { @@ -1095,7 +1096,7 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, createAttachment: false, shouldFail: true, - exitStatus: volumetypes.OperationStateNoChange, + exitError: transientError, spec: volume.NewSpecFromPersistentVolume(makeTestPVWithMountOptions(pvName, 10, testDriver, "test-vol1", []string{"test-op"}), false), }, { @@ -1106,7 +1107,6 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, shouldFail: true, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, ""), false), }, { @@ -1117,7 +1117,6 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, shouldFail: false, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), }, { @@ -1128,7 +1127,6 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, shouldFail: true, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), }, { @@ -1138,7 +1136,6 @@ func TestAttacherMountDevice(t *testing.T) { deviceMountPath: "path2", stageUnstageSet: false, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, "test-vol1"), false), }, { @@ -1148,7 +1145,6 @@ func TestAttacherMountDevice(t *testing.T) { deviceMountPath: "path2", shouldFail: true, createAttachment: true, - exitStatus: volumetypes.OperationFinished, spec: volume.NewSpecFromVolume(makeTestVol(pvName, testDriver)), }, { @@ -1159,7 +1155,7 @@ func TestAttacherMountDevice(t *testing.T) { stageUnstageSet: true, createAttachment: true, spec: volume.NewSpecFromPersistentVolume(makeTestPV(pvName, 10, testDriver, fakecsi.NodeStageTimeOut_VolumeID), false), - exitStatus: volumetypes.OperationInProgress, + exitError: nonFinalError, shouldFail: true, }, } @@ -1199,7 +1195,7 @@ func TestAttacherMountDevice(t *testing.T) { } // Run - exitStatus, err := csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) + err := csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) // Verify if err != nil { @@ -1212,8 +1208,8 @@ func TestAttacherMountDevice(t *testing.T) { t.Errorf("test should fail, but no error occurred") } - if exitStatus != tc.exitStatus { - t.Fatalf("expected exitStatus: %v got: %v", tc.exitStatus, exitStatus) + if tc.exitError != nil && reflect.TypeOf(tc.exitError) != reflect.TypeOf(err) { + t.Fatalf("expected exitError: %v got: %v", tc.exitError, err) } // Verify call goes through all the way @@ -1348,7 +1344,7 @@ func TestAttacherMountDeviceWithInline(t *testing.T) { }() // Run - _, err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) + err = csiAttacher.MountDevice(tc.spec, tc.devicePath, tc.deviceMountPath) // Verify if err != nil { diff --git a/pkg/volume/csi/csi_client.go b/pkg/volume/csi/csi_client.go index 939e4d3a42b..9da810cd3c0 100644 --- a/pkg/volume/csi/csi_client.go +++ b/pkg/volume/csi/csi_client.go @@ -260,7 +260,7 @@ func (c *csiDriverClient) NodePublishVolume( _, err = nodeClient.NodePublishVolume(ctx, req) if err != nil && !isFinalError(err) { - return volumetypes.NewOperationTimedOutError(err.Error()) + return volumetypes.NewUncertainProgressError(err.Error()) } return nil } @@ -382,7 +382,7 @@ func (c *csiDriverClient) NodeStageVolume(ctx context.Context, _, err = nodeClient.NodeStageVolume(ctx, req) if err != nil && !isFinalError(err) { - return volumetypes.NewOperationTimedOutError(err.Error()) + return volumetypes.NewUncertainProgressError(err.Error()) } return err } diff --git a/pkg/volume/csi/csi_client_test.go b/pkg/volume/csi/csi_client_test.go index 3724b2cb574..83080da2575 100644 --- a/pkg/volume/csi/csi_client_test.go +++ b/pkg/volume/csi/csi_client_test.go @@ -157,11 +157,8 @@ func (c *fakeCsiDriverClient) NodePublishVolume( } _, err := c.nodeClient.NodePublishVolume(ctx, req) - if err != nil { - if isFinalError(err) { - return err - } - return volumetypes.NewOperationTimedOutError(err.Error()) + if err != nil && !isFinalError(err) { + return volumetypes.NewUncertainProgressError(err.Error()) } return err } @@ -208,11 +205,8 @@ func (c *fakeCsiDriverClient) NodeStageVolume(ctx context.Context, } _, err := c.nodeClient.NodeStageVolume(ctx, req) - if err != nil { - if isFinalError(err) { - return err - } - return volumetypes.NewOperationTimedOutError(err.Error()) + if err != nil && !isFinalError(err) { + return volumetypes.NewUncertainProgressError(err.Error()) } return err } diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 35bc07328f3..ad53d124b78 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -99,42 +99,34 @@ func (c *csiMountMgr) CanMount() error { return nil } -func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - opExitStatus, err := c.setupInternal(c.GetPath(), mounterArgs) - return opExitStatus, err +func (c *csiMountMgr) SetUp(mounterArgs volume.MounterArgs) error { + return c.SetUpAt(c.GetPath(), mounterArgs) } func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { - _, err := c.setupInternal(dir, mounterArgs) - return err -} - -func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { klog.V(4).Infof(log("Mounter.SetUpAt(%s)", dir)) - // default to finished operation status - opExitStatus := volumetypes.OperationFinished mounted, err := isDirMounted(c.plugin, dir) if err != nil { - return opExitStatus, errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err)) + return errors.New(log("mounter.SetUpAt failed while checking mount status for dir [%s]: %v", dir, err)) } if mounted { klog.V(4).Info(log("mounter.SetUpAt skipping mount, dir already mounted [%s]", dir)) - return opExitStatus, nil + return nil } csi, err := c.csiClientGetter.Get() if err != nil { - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, errors.New(log("mounter.SetUpAt failed to get CSI client: %v", err)) + return volumetypes.NewTransientOperationFailure(log("mounter.SetUpAt failed to get CSI client: %v", err)) + } ctx, cancel := context.WithTimeout(context.Background(), csiTimeout) defer cancel() volSrc, pvSrc, err := getSourceFromSpec(c.spec) if err != nil { - return opExitStatus, errors.New(log("mounter.SetupAt failed to get CSI persistent source: %v", err)) + return errors.New(log("mounter.SetupAt failed to get CSI persistent source: %v", err)) } driverName := c.driverName @@ -155,10 +147,10 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) switch { case volSrc != nil: if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) { - return opExitStatus, fmt.Errorf("CSIInlineVolume feature required") + return fmt.Errorf("CSIInlineVolume feature required") } if c.volumeLifecycleMode != storage.VolumeLifecycleEphemeral { - return opExitStatus, fmt.Errorf("unexpected volume mode: %s", c.volumeLifecycleMode) + return fmt.Errorf("unexpected volume mode: %s", c.volumeLifecycleMode) } if volSrc.FSType != nil { fsType = *volSrc.FSType @@ -173,7 +165,7 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) } case pvSrc != nil: if c.volumeLifecycleMode != storage.VolumeLifecyclePersistent { - return opExitStatus, fmt.Errorf("unexpected driver mode: %s", c.volumeLifecycleMode) + return fmt.Errorf("unexpected driver mode: %s", c.volumeLifecycleMode) } fsType = pvSrc.FSType @@ -194,13 +186,13 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) // Check for STAGE_UNSTAGE_VOLUME set and populate deviceMountPath if so stageUnstageSet, err := csi.NodeSupportsStageUnstage(ctx) if err != nil { - return opExitStatus, errors.New(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capability: %v", err)) + return errors.New(log("mounter.SetUpAt failed to check for STAGE_UNSTAGE_VOLUME capability: %v", err)) } if stageUnstageSet { deviceMountPath, err = makeDeviceMountPath(c.plugin, c.spec) if err != nil { - return opExitStatus, errors.New(log("mounter.SetUpAt failed to make device mount path: %v", err)) + return errors.New(log("mounter.SetUpAt failed to make device mount path: %v", err)) } } @@ -210,19 +202,18 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) c.publishContext, err = c.plugin.getPublishContext(c.k8s, volumeHandle, string(driverName), nodeName) if err != nil { // we could have a transient error associated with fetching publish context - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, err + return volumetypes.NewTransientOperationFailure(log("mounter.SetUpAt failed to fetch publishContext: %v", err)) } publishContext = c.publishContext } default: - return opExitStatus, fmt.Errorf("volume source not found in volume.Spec") + return fmt.Errorf("volume source not found in volume.Spec") } // create target_dir before call to NodePublish if err := os.MkdirAll(dir, 0750); err != nil { - return opExitStatus, errors.New(log("mounter.SetUpAt failed to create dir %#v: %v", dir, err)) + return errors.New(log("mounter.SetUpAt failed to create dir %#v: %v", dir, err)) } klog.V(4).Info(log("created target path successfully [%s]", dir)) @@ -230,9 +221,8 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) if secretRef != nil { nodePublishSecrets, err = getCredentialsFromSecret(c.k8s, secretRef) if err != nil { - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, fmt.Errorf("fetching NodePublishSecretRef %s/%s failed: %v", - secretRef.Namespace, secretRef.Name, err) + return volumetypes.NewTransientOperationFailure(fmt.Sprintf("fetching NodePublishSecretRef %s/%s failed: %v", + secretRef.Namespace, secretRef.Name, err)) } } @@ -240,8 +230,7 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) // Inject pod information into volume_attributes podAttrs, err := c.podAttributes() if err != nil { - opExitStatus = volumetypes.OperationStateNoChange - return opExitStatus, errors.New(log("mounter.SetUpAt failed to assemble volume attributes: %v", err)) + return volumetypes.NewTransientOperationFailure(log("mounter.SetUpAt failed to assemble volume attributes: %v", err)) } if podAttrs != nil { if volAttribs == nil { @@ -268,16 +257,13 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) ) if err != nil { - if volumetypes.IsOperationTimeOutError(err) { - opExitStatus = volumetypes.OperationInProgress - } // If operation finished with error then we can remove the mount directory. - if opExitStatus == volumetypes.OperationFinished { + if volumetypes.IsOperationFinishedError(err) { if removeMountDirErr := removeMountDir(c.plugin, dir); removeMountDirErr != nil { klog.Error(log("mounter.SetupAt failed to remove mount dir after a NodePublish() error [%s]: %v", dir, removeMountDirErr)) } } - return opExitStatus, errors.New(log("mounter.SetupAt failed: %v", err)) + return err } c.supportsSELinux, err = c.kubeVolHost.GetHostUtil().GetSELinuxSupport(dir) @@ -289,19 +275,17 @@ func (c *csiMountMgr) setupInternal(dir string, mounterArgs volume.MounterArgs) // The following logic is derived from https://github.com/kubernetes/kubernetes/issues/66323 // if fstype is "", then skip fsgroup (could be indication of non-block filesystem) // if fstype is provided and pv.AccessMode == ReadWriteOnly, then apply fsgroup - err = c.applyFSGroup(fsType, mounterArgs.FsGroup) if err != nil { - // If we are here that means volume was mounted correctly and it must at least be unmounted - // before it can be used by someone else. - opExitStatus = volumetypes.OperationInProgress - // attempt to rollback mount. - fsGrpErr := fmt.Errorf("applyFSGroup failed for vol %s: %v", c.volumeID, err) - return opExitStatus, fsGrpErr + // At this point mount operation is successful: + // 1. Since volume can not be used by the pod because of invalid permissions, we must return error + // 2. Since mount is successful, we must record volume as mounted in uncertain state, so it can be + // cleaned up. + return volumetypes.NewUncertainProgressError(fmt.Sprintf("applyFSGroup failed for vol %s: %v", c.volumeID, err)) } klog.V(4).Infof(log("mounter.SetUp successfully requested NodePublish [%s]", dir)) - return opExitStatus, nil + return nil } func (c *csiMountMgr) podAttributes() (map[string]string, error) { diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index a8e9d544671..ef73b31ad97 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -221,7 +221,7 @@ func MounterSetUpTests(t *testing.T, podInfoEnabled bool) { var mounterArgs volume.MounterArgs fsGroup := int64(2000) mounterArgs.FsGroup = &fsGroup - if _, err := csiMounter.SetUp(mounterArgs); err != nil { + if err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -361,7 +361,7 @@ func TestMounterSetUpSimple(t *testing.T) { } // Mounter.SetUp() - if _, err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { + if err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -402,13 +402,15 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { fakeClient := fakeclient.NewSimpleClientset() plug, tmpDir := newTestPlugin(t, fakeClient) defer os.RemoveAll(tmpDir) + nonFinalError := volumetypes.NewUncertainProgressError("non-final-error") + transientError := volumetypes.NewTransientOperationFailure("transient-error") testCases := []struct { name string podUID types.UID spec func(string, []string) *volume.Spec shouldFail bool - exitStatus volumetypes.OperationStatus + exitError error createAttachment bool }{ { @@ -420,7 +422,6 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { pvSrc.Spec.MountOptions = options return volume.NewSpecFromPersistentVolume(pvSrc, false) }, - exitStatus: volumetypes.OperationFinished, createAttachment: true, }, { @@ -429,7 +430,7 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { spec: func(fsType string, options []string) *volume.Spec { return volume.NewSpecFromPersistentVolume(makeTestPV("pv3", 20, testDriver, "vol4"), false) }, - exitStatus: volumetypes.OperationStateNoChange, + exitError: transientError, createAttachment: false, shouldFail: true, }, @@ -440,7 +441,7 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { return volume.NewSpecFromPersistentVolume(makeTestPV("pv4", 20, testDriver, fakecsi.NodePublishTimeOut_VolumeID), false) }, createAttachment: true, - exitStatus: volumetypes.OperationInProgress, + exitError: nonFinalError, shouldFail: true, }, { @@ -454,7 +455,7 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { } return volume.NewSpecFromPersistentVolume(pv, false) }, - exitStatus: volumetypes.OperationStateNoChange, + exitError: transientError, createAttachment: true, shouldFail: true, }, @@ -487,11 +488,10 @@ func TestMounterSetupWithStatusTracking(t *testing.T) { t.Fatalf("failed to setup VolumeAttachment: %v", err) } } + err = csiMounter.SetUp(volume.MounterArgs{}) - opExistStatus, err := csiMounter.SetUp(volume.MounterArgs{}) - - if opExistStatus != tc.exitStatus { - t.Fatalf("expected exitStatus: %v but got %v", tc.exitStatus, opExistStatus) + if tc.exitError != nil && reflect.TypeOf(tc.exitError) != reflect.TypeOf(err) { + t.Fatalf("expected exitError: %+v got: %+v", tc.exitError, err) } if tc.shouldFail && err == nil { @@ -604,7 +604,7 @@ func TestMounterSetUpWithInline(t *testing.T) { } // Mounter.SetUp() - if _, err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { + if err := csiMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } @@ -757,7 +757,7 @@ func TestMounterSetUpWithFSGroup(t *testing.T) { fsGroupPtr = &fsGroup } mounterArgs.FsGroup = fsGroupPtr - if _, err := csiMounter.SetUp(mounterArgs); err != nil { + if err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("mounter.Setup failed: %v", err) } diff --git a/pkg/volume/csi/csi_test.go b/pkg/volume/csi/csi_test.go index 0ee4858f955..3ec20217760 100644 --- a/pkg/volume/csi/csi_test.go +++ b/pkg/volume/csi/csi_test.go @@ -360,7 +360,7 @@ func TestCSI_VolumeAll(t *testing.T) { if err != nil { t.Fatalf("csiTest.VolumeAll deviceMounter.GetdeviceMountPath failed %s", err) } - if _, err := csiDevMounter.MountDevice(volSpec, devicePath, devMountPath); err != nil { + if err := csiDevMounter.MountDevice(volSpec, devicePath, devMountPath); err != nil { t.Fatalf("csiTest.VolumeAll deviceMounter.MountDevice failed: %v", err) } t.Log("csiTest.VolumeAll device mounted at path:", devMountPath) @@ -417,7 +417,7 @@ func TestCSI_VolumeAll(t *testing.T) { csiMounter.csiClient = csiClient var mounterArgs volume.MounterArgs mounterArgs.FsGroup = fsGroup - if _, err := csiMounter.SetUp(mounterArgs); err != nil { + if err := csiMounter.SetUp(mounterArgs); err != nil { t.Fatalf("csiTest.VolumeAll mounter.Setup(fsGroup) failed: %s", err) } t.Log("csiTest.VolumeAll mounter.Setup(fsGroup) done OK") diff --git a/pkg/volume/downwardapi/BUILD b/pkg/volume/downwardapi/BUILD index 081164f60a4..cece3c521e2 100644 --- a/pkg/volume/downwardapi/BUILD +++ b/pkg/volume/downwardapi/BUILD @@ -15,7 +15,6 @@ go_library( "//pkg/fieldpath:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library", diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index 83c8b11fc3d..12746696888 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -28,7 +28,6 @@ import ( "k8s.io/kubernetes/pkg/fieldpath" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" utilstrings "k8s.io/utils/strings" ) @@ -171,9 +170,8 @@ func (b *downwardAPIVolumeMounter) CanMount() error { // This function is not idempotent by design. We want the data to be refreshed periodically. // The internal sync interval of kubelet will drive the refresh of data. // TODO: Add volume specific ticker and refresh loop -func (b *downwardAPIVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *downwardAPIVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *downwardAPIVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/downwardapi/downwardapi_test.go b/pkg/volume/downwardapi/downwardapi_test.go index 8584e812d5c..647ebe3ff56 100644 --- a/pkg/volume/downwardapi/downwardapi_test.go +++ b/pkg/volume/downwardapi/downwardapi_test.go @@ -253,7 +253,7 @@ func newDownwardAPITest(t *testing.T, name string, volumeFiles, podLabels, podAn volumePath := mounter.GetPath() - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -380,7 +380,7 @@ func (step reSetUp) run(test *downwardAPITest) { } // now re-run Setup - if _, err = test.mounter.SetUp(volume.MounterArgs{}); err != nil { + if err = test.mounter.SetUp(volume.MounterArgs{}); err != nil { test.t.Errorf("Failed to re-setup volume: %v", err) } diff --git a/pkg/volume/emptydir/BUILD b/pkg/volume/emptydir/BUILD index 13ba66ba972..c4a58fda540 100644 --- a/pkg/volume/emptydir/BUILD +++ b/pkg/volume/emptydir/BUILD @@ -20,7 +20,6 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/fsquota:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index 2e64bff6c4d..607705aea9f 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -33,7 +33,6 @@ import ( "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/fsquota" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // TODO: in the near future, this will be changed to be more restrictive @@ -193,9 +192,8 @@ func (ed *emptyDir) CanMount() error { } // SetUp creates new directory. -func (ed *emptyDir) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := ed.SetUpAt(ed.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (ed *emptyDir) SetUp(mounterArgs volume.MounterArgs) error { + return ed.SetUpAt(ed.GetPath(), mounterArgs) } // SetUpAt creates new directory. diff --git a/pkg/volume/emptydir/empty_dir_test.go b/pkg/volume/emptydir/empty_dir_test.go index 4c4bcac53af..892ec1ec342 100644 --- a/pkg/volume/emptydir/empty_dir_test.go +++ b/pkg/volume/emptydir/empty_dir_test.go @@ -164,7 +164,7 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) { t.Errorf("Got unexpected path: %s", volPath) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } diff --git a/pkg/volume/fc/BUILD b/pkg/volume/fc/BUILD index 158fc17f212..dd16c9f27b3 100644 --- a/pkg/volume/fc/BUILD +++ b/pkg/volume/fc/BUILD @@ -20,7 +20,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/fc/attacher.go b/pkg/volume/fc/attacher.go index 09b663b6866..4a431fd9928 100644 --- a/pkg/volume/fc/attacher.go +++ b/pkg/volume/fc/attacher.go @@ -32,7 +32,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type fcAttacher struct { @@ -97,42 +96,39 @@ func (attacher *fcAttacher) GetDeviceMountPath( return attacher.manager.MakeGlobalPDName(*mounter.fcDisk), nil } -func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - mountInternal := func() error { - mounter := attacher.host.GetMounter(fcPluginName) - notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) - if err != nil { - if os.IsNotExist(err) { - if err := os.MkdirAll(deviceMountPath, 0750); err != nil { - return err - } - notMnt = true - } else { +func (attacher *fcAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { + mounter := attacher.host.GetMounter(fcPluginName) + notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) + if err != nil { + if os.IsNotExist(err) { + if err := os.MkdirAll(deviceMountPath, 0750); err != nil { return err } - } - - volumeSource, readOnly, err := getVolumeSource(spec) - if err != nil { + notMnt = true + } else { return err } - - options := []string{} - if readOnly { - options = append(options, "ro") - } - if notMnt { - diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(fcPluginName)} - mountOptions := volumeutil.MountOptionFromSpec(spec, options...) - err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) - if err != nil { - os.Remove(deviceMountPath) - return err - } - } - return nil } - return volumetypes.OperationFinished, mountInternal() + + volumeSource, readOnly, err := getVolumeSource(spec) + if err != nil { + return err + } + + options := []string{} + if readOnly { + options = append(options, "ro") + } + if notMnt { + diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Exec: attacher.host.GetExec(fcPluginName)} + mountOptions := volumeutil.MountOptionFromSpec(spec, options...) + err = diskMounter.FormatAndMount(devicePath, deviceMountPath, volumeSource.FSType, mountOptions) + if err != nil { + os.Remove(deviceMountPath) + return err + } + } + return nil } type fcDetacher struct { diff --git a/pkg/volume/fc/fc.go b/pkg/volume/fc/fc.go index 259d1b8bbbe..dfc2aa9d062 100644 --- a/pkg/volume/fc/fc.go +++ b/pkg/volume/fc/fc.go @@ -35,7 +35,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -370,9 +369,8 @@ func (b *fcDiskMounter) CanMount() error { return nil } -func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *fcDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/fc/fc_test.go b/pkg/volume/fc/fc_test.go index 32dc1b51d9e..63d5a08e09a 100644 --- a/pkg/volume/fc/fc_test.go +++ b/pkg/volume/fc/fc_test.go @@ -181,7 +181,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/flexvolume/BUILD b/pkg/volume/flexvolume/BUILD index 777ede4375d..9cb8aceaa93 100644 --- a/pkg/volume/flexvolume/BUILD +++ b/pkg/volume/flexvolume/BUILD @@ -32,7 +32,6 @@ go_library( "//pkg/util/filesystem:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/flexvolume/attacher.go b/pkg/volume/flexvolume/attacher.go index d526ed23c1b..3b98eefa079 100644 --- a/pkg/volume/flexvolume/attacher.go +++ b/pkg/volume/flexvolume/attacher.go @@ -23,7 +23,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/klog" "k8s.io/kubernetes/pkg/volume" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type flexVolumeAttacher struct { @@ -71,34 +70,31 @@ func (a *flexVolumeAttacher) GetDeviceMountPath(spec *volume.Spec) (string, erro } // MountDevice is part of the volume.Attacher interface -func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - mountInternal := func() error { - // Mount only once. - alreadyMounted, err := prepareForMount(a.plugin.host.GetMounter(a.plugin.GetPluginName()), deviceMountPath) - if err != nil { - return err - } - if alreadyMounted { - return nil - } - - call := a.plugin.NewDriverCall(mountDeviceCmd) - call.Append(deviceMountPath) - call.Append(devicePath) - call.AppendSpec(spec, a.plugin.host, nil) - - _, err = call.Run() - if isCmdNotSupportedErr(err) { - // Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the - // plugin does not implement attach interface. - if devicePath != "" { - return (*attacherDefaults)(a).MountDevice(spec, devicePath, deviceMountPath, a.plugin.host.GetMounter(a.plugin.GetPluginName())) - } - return nil - } +func (a *flexVolumeAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { + // Mount only once. + alreadyMounted, err := prepareForMount(a.plugin.host.GetMounter(a.plugin.GetPluginName()), deviceMountPath) + if err != nil { return err } - return volumetypes.OperationFinished, mountInternal() + if alreadyMounted { + return nil + } + + call := a.plugin.NewDriverCall(mountDeviceCmd) + call.Append(deviceMountPath) + call.Append(devicePath) + call.AppendSpec(spec, a.plugin.host, nil) + + _, err = call.Run() + if isCmdNotSupportedErr(err) { + // Devicepath is empty if the plugin does not support attach calls. Ignore mountDevice calls if the + // plugin does not implement attach interface. + if devicePath != "" { + return (*attacherDefaults)(a).MountDevice(spec, devicePath, deviceMountPath, a.plugin.host.GetMounter(a.plugin.GetPluginName())) + } + return nil + } + return err } func (a *flexVolumeAttacher) VolumesAreAttached(specs []*volume.Spec, nodeName types.NodeName) (map[*volume.Spec]bool, error) { diff --git a/pkg/volume/flexvolume/mounter.go b/pkg/volume/flexvolume/mounter.go index 084e7ff7701..94229d0d833 100644 --- a/pkg/volume/flexvolume/mounter.go +++ b/pkg/volume/flexvolume/mounter.go @@ -21,7 +21,6 @@ import ( "strconv" "k8s.io/kubernetes/pkg/volume" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/utils/exec" ) @@ -40,9 +39,8 @@ var _ volume.Mounter = &flexVolumeMounter{} // Mounter interface // SetUp creates new directory. -func (f *flexVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := f.SetUpAt(f.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (f *flexVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return f.SetUpAt(f.GetPath(), mounterArgs) } // SetUpAt creates new directory. diff --git a/pkg/volume/flocker/BUILD b/pkg/volume/flocker/BUILD index e67799ee70e..276ada39eed 100644 --- a/pkg/volume/flocker/BUILD +++ b/pkg/volume/flocker/BUILD @@ -19,7 +19,6 @@ go_library( "//pkg/util/env:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/flocker/flocker.go b/pkg/volume/flocker/flocker.go index 2c951e68709..723b28de4db 100644 --- a/pkg/volume/flocker/flocker.go +++ b/pkg/volume/flocker/flocker.go @@ -31,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/util/env" "k8s.io/kubernetes/pkg/volume" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -232,9 +231,8 @@ func (b *flockerVolumeMounter) GetPath() string { } // SetUp bind mounts the disk global mount to the volume path. -func (b *flockerVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *flockerVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // newFlockerClient uses environment variables and pod attributes to return a diff --git a/pkg/volume/gcepd/BUILD b/pkg/volume/gcepd/BUILD index 2ef8af55718..cff495a05d4 100644 --- a/pkg/volume/gcepd/BUILD +++ b/pkg/volume/gcepd/BUILD @@ -20,7 +20,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/gcepd/attacher.go b/pkg/volume/gcepd/attacher.go index 4b492edabec..43c03564c59 100644 --- a/pkg/volume/gcepd/attacher.go +++ b/pkg/volume/gcepd/attacher.go @@ -38,7 +38,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/gce" ) @@ -287,7 +286,7 @@ func (attacher *gcePersistentDiskAttacher) GetDeviceMountPath( return makeGlobalPDName(attacher.host, volumeSource.PDName), nil } -func (attacher *gcePersistentDiskAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { // Only mount the PD globally once. mounter := attacher.host.GetMounter(gcePersistentDiskPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) @@ -329,11 +328,6 @@ func (attacher *gcePersistentDiskAttacher) mountDeviceInternal(spec *volume.Spec return nil } -func (attacher *gcePersistentDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - type gcePersistentDiskDetacher struct { host volume.VolumeHost gceDisks gce.Disks diff --git a/pkg/volume/gcepd/gce_pd.go b/pkg/volume/gcepd/gce_pd.go index a43ca3868fa..a1f4eff61b1 100644 --- a/pkg/volume/gcepd/gce_pd.go +++ b/pkg/volume/gcepd/gce_pd.go @@ -40,7 +40,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" gcecloud "k8s.io/legacy-cloud-providers/gce" ) @@ -369,9 +368,8 @@ func (b *gcePersistentDiskMounter) CanMount() error { } // SetUp bind mounts the disk global mount to the volume path. -func (b *gcePersistentDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *gcePersistentDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUp bind mounts the disk global mount to the give volume path. diff --git a/pkg/volume/gcepd/gce_pd_test.go b/pkg/volume/gcepd/gce_pd_test.go index 6102930b1c5..d45de1be877 100644 --- a/pkg/volume/gcepd/gce_pd_test.go +++ b/pkg/volume/gcepd/gce_pd_test.go @@ -144,7 +144,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -282,7 +282,7 @@ func TestMountOptions(t *testing.T) { t.Errorf("Got a nil Mounter") } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/git_repo/BUILD b/pkg/volume/git_repo/BUILD index 467410ea49b..57a9e29bdf2 100644 --- a/pkg/volume/git_repo/BUILD +++ b/pkg/volume/git_repo/BUILD @@ -16,7 +16,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index aacc389194d..aee38f5bbf9 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -26,7 +26,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/utils/exec" utilstrings "k8s.io/utils/strings" ) @@ -176,9 +175,8 @@ func (b *gitRepoVolumeMounter) CanMount() error { } // SetUp creates new directory and clones a git repo. -func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUpAt creates new directory and clones a git repo. diff --git a/pkg/volume/glusterfs/BUILD b/pkg/volume/glusterfs/BUILD index a8a73afe7d5..a7b6e671934 100644 --- a/pkg/volume/glusterfs/BUILD +++ b/pkg/volume/glusterfs/BUILD @@ -19,7 +19,6 @@ go_library( "//pkg/apis/core/v1/helper:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go index c42edb94197..8067ba83344 100644 --- a/pkg/volume/glusterfs/glusterfs.go +++ b/pkg/volume/glusterfs/glusterfs.go @@ -47,7 +47,6 @@ import ( v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -270,9 +269,8 @@ func (b *glusterfsMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *glusterfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *glusterfsMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *glusterfsMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/glusterfs/glusterfs_test.go b/pkg/volume/glusterfs/glusterfs_test.go index 1eba9fbc9a8..25e199d2ad9 100644 --- a/pkg/volume/glusterfs/glusterfs_test.go +++ b/pkg/volume/glusterfs/glusterfs_test.go @@ -119,7 +119,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != expectedPath { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, volumePath) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/hostpath/BUILD b/pkg/volume/hostpath/BUILD index 5aae5056809..0c2bd65bf3a 100644 --- a/pkg/volume/hostpath/BUILD +++ b/pkg/volume/hostpath/BUILD @@ -18,7 +18,6 @@ go_library( "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/validation:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/hostpath/host_path.go b/pkg/volume/hostpath/host_path.go index 649a0f07836..af10f49ed54 100644 --- a/pkg/volume/hostpath/host_path.go +++ b/pkg/volume/hostpath/host_path.go @@ -31,7 +31,6 @@ import ( "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/validation" ) @@ -227,20 +226,16 @@ func (b *hostPathMounter) CanMount() error { } // SetUp does nothing. -func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - internalSetup := func() error { - err := validation.ValidatePathNoBacksteps(b.GetPath()) - if err != nil { - return fmt.Errorf("invalid HostPath `%s`: %v", b.GetPath(), err) - } - - if *b.pathType == v1.HostPathUnset { - return nil - } - return checkType(b.GetPath(), b.pathType, b.hu) +func (b *hostPathMounter) SetUp(mounterArgs volume.MounterArgs) error { + err := validation.ValidatePathNoBacksteps(b.GetPath()) + if err != nil { + return fmt.Errorf("invalid HostPath `%s`: %v", b.GetPath(), err) } - return volumetypes.OperationFinished, internalSetup() + if *b.pathType == v1.HostPathUnset { + return nil + } + return checkType(b.GetPath(), b.pathType, b.hu) } // SetUpAt does not make sense for host paths - probably programmer error. diff --git a/pkg/volume/hostpath/host_path_test.go b/pkg/volume/hostpath/host_path_test.go index 2191d0d6148..fa94755b1bc 100644 --- a/pkg/volume/hostpath/host_path_test.go +++ b/pkg/volume/hostpath/host_path_test.go @@ -219,7 +219,7 @@ func TestInvalidHostPath(t *testing.T) { t.Fatal(err) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) expectedMsg := "invalid HostPath `/no/backsteps/allowed/..`: must not contain '..'" if err.Error() != expectedMsg { t.Fatalf("expected error `%s` but got `%s`", expectedMsg, err) @@ -255,7 +255,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } diff --git a/pkg/volume/iscsi/BUILD b/pkg/volume/iscsi/BUILD index 68c19fa25f4..c7ac6a79bf9 100644 --- a/pkg/volume/iscsi/BUILD +++ b/pkg/volume/iscsi/BUILD @@ -21,7 +21,6 @@ go_library( "//pkg/kubelet/config:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/iscsi/attacher.go b/pkg/volume/iscsi/attacher.go index 20c801126ee..7b3d439077e 100644 --- a/pkg/volume/iscsi/attacher.go +++ b/pkg/volume/iscsi/attacher.go @@ -31,8 +31,6 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" - "k8s.io/utils/keymutex" ) type iscsiAttacher struct { @@ -102,7 +100,7 @@ func (attacher *iscsiAttacher) GetDeviceMountPath( return attacher.manager.MakeGlobalPDName(*mounter.iscsiDisk), nil } -func (attacher *iscsiAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { mounter := attacher.host.GetMounter(iscsiPluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -136,11 +134,6 @@ func (attacher *iscsiAttacher) mountDeviceInternal(spec *volume.Spec, devicePath return nil } -func (attacher *iscsiAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - type iscsiDetacher struct { host volume.VolumeHost mounter mount.Interface diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 1e46cbba7b0..957a90a331a 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -34,7 +34,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" ioutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -339,9 +338,8 @@ func (b *iscsiDiskMounter) CanMount() error { return nil } -func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/iscsi/iscsi_test.go b/pkg/volume/iscsi/iscsi_test.go index 924855f55c3..a062067e123 100644 --- a/pkg/volume/iscsi/iscsi_test.go +++ b/pkg/volume/iscsi/iscsi_test.go @@ -177,7 +177,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/local/BUILD b/pkg/volume/local/BUILD index 1115ac9314b..1fcbe6c957f 100644 --- a/pkg/volume/local/BUILD +++ b/pkg/volume/local/BUILD @@ -13,7 +13,6 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/hostutil:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/validation:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/local/local.go b/pkg/volume/local/local.go index 7f0a8e41f32..b79180a6c87 100644 --- a/pkg/volume/local/local.go +++ b/pkg/volume/local/local.go @@ -33,7 +33,6 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/hostutil" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/validation" "k8s.io/utils/keymutex" "k8s.io/utils/mount" @@ -349,29 +348,26 @@ func (dm *deviceMounter) mountLocalBlockDevice(spec *volume.Spec, devicePath str return nil } -func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - mountInternal := func() error { - if spec.PersistentVolume.Spec.Local == nil || len(spec.PersistentVolume.Spec.Local.Path) == 0 { - return fmt.Errorf("local volume source is nil or local path is not set") - } - fileType, err := dm.hostUtil.GetFileType(spec.PersistentVolume.Spec.Local.Path) - if err != nil { - return err - } - - switch fileType { - case hostutil.FileTypeBlockDev: - // local volume plugin does not implement AttachableVolumePlugin interface, so set devicePath to Path in PV spec directly - devicePath = spec.PersistentVolume.Spec.Local.Path - return dm.mountLocalBlockDevice(spec, devicePath, deviceMountPath) - case hostutil.FileTypeDirectory: - // if the given local volume path is of already filesystem directory, return directly - return nil - default: - return fmt.Errorf("only directory and block device are supported") - } +func (dm *deviceMounter) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { + if spec.PersistentVolume.Spec.Local == nil || len(spec.PersistentVolume.Spec.Local.Path) == 0 { + return fmt.Errorf("local volume source is nil or local path is not set") + } + fileType, err := dm.hostUtil.GetFileType(spec.PersistentVolume.Spec.Local.Path) + if err != nil { + return err + } + + switch fileType { + case hostutil.FileTypeBlockDev: + // local volume plugin does not implement AttachableVolumePlugin interface, so set devicePath to Path in PV spec directly + devicePath = spec.PersistentVolume.Spec.Local.Path + return dm.mountLocalBlockDevice(spec, devicePath, deviceMountPath) + case hostutil.FileTypeDirectory: + // if the given local volume path is of already filesystem directory, return directly + return nil + default: + return fmt.Errorf("only directory and block device are supported") } - return volumetypes.OperationFinished, mountInternal() } func getVolumeSourceFSType(spec *volume.Spec) (string, error) { @@ -473,9 +469,8 @@ func (m *localVolumeMounter) CanMount() error { } // SetUp bind mounts the directory to the volume path -func (m *localVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := m.SetUpAt(m.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (m *localVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return m.SetUpAt(m.GetPath(), mounterArgs) } // SetUpAt bind mounts the directory to the volume path and sets up volume ownership diff --git a/pkg/volume/local/local_test.go b/pkg/volume/local/local_test.go index c48e3bbffe9..301cff5f1dd 100644 --- a/pkg/volume/local/local_test.go +++ b/pkg/volume/local/local_test.go @@ -201,7 +201,7 @@ func TestInvalidLocalPath(t *testing.T) { t.Fatal(err) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) expectedMsg := "invalid path: /no/backsteps/allowed/.. must not contain '..'" if err.Error() != expectedMsg { t.Fatalf("expected error `%s` but got `%s`", expectedMsg, err) @@ -231,7 +231,7 @@ func TestBlockDeviceGlobalPathAndMountDevice(t *testing.T) { fmt.Println("expected global path is:", expectedGlobalPath) - _, err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath) + err = dm.MountDevice(pvSpec, tmpBlockDir, expectedGlobalPath) if err != nil { t.Fatal(err) } @@ -276,7 +276,7 @@ func TestFSGlobalPathAndMountDevice(t *testing.T) { } // Actually, we will do nothing if the local path is FS type - _, err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath) + err = dm.MountDevice(pvSpec, tmpFSDir, expectedGlobalPath) if err != nil { t.Fatal(err) } @@ -308,7 +308,7 @@ func TestMountUnmount(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } @@ -429,7 +429,7 @@ func testFSGroupMount(plug volume.VolumePlugin, pod *v1.Pod, tmpDir string, fsGr var mounterArgs volume.MounterArgs mounterArgs.FsGroup = &fsGroup - if _, err := mounter.SetUp(mounterArgs); err != nil { + if err := mounter.SetUp(mounterArgs); err != nil { return err } return nil @@ -587,7 +587,7 @@ func TestMountOptions(t *testing.T) { fakeMounter := mount.NewFakeMounter(nil) mounter.(*localVolumeMounter).mounter = fakeMounter - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } mountOptions := fakeMounter.MountPoints[0].Opts diff --git a/pkg/volume/nfs/BUILD b/pkg/volume/nfs/BUILD index 268871a739a..624a7898a2e 100644 --- a/pkg/volume/nfs/BUILD +++ b/pkg/volume/nfs/BUILD @@ -17,7 +17,6 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//pkg/volume/util/recyclerclient:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index c02b256dd23..41b2e1dd9bb 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -31,7 +31,6 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) func getPath(uid types.UID, volName string, host volume.VolumeHost) string { @@ -238,9 +237,8 @@ func (nfsMounter *nfsMounter) GetAttributes() volume.Attributes { } // SetUp attaches the disk and bind mounts to the volume path. -func (nfsMounter *nfsMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := nfsMounter.SetUpAt(nfsMounter.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (nfsMounter *nfsMounter) SetUp(mounterArgs volume.MounterArgs) error { + return nfsMounter.SetUpAt(nfsMounter.GetPath(), mounterArgs) } func (nfsMounter *nfsMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/nfs/nfs_test.go b/pkg/volume/nfs/nfs_test.go index 298c1ff5d1d..f2b0e519060 100644 --- a/pkg/volume/nfs/nfs_test.go +++ b/pkg/volume/nfs/nfs_test.go @@ -123,7 +123,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != expectedPath { t.Errorf("Unexpected path, expected %q, got: %q", expectedPath, volumePath) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volumePath); err != nil { diff --git a/pkg/volume/portworx/BUILD b/pkg/volume/portworx/BUILD index 41e6240d7ee..06f8c232f02 100644 --- a/pkg/volume/portworx/BUILD +++ b/pkg/volume/portworx/BUILD @@ -33,7 +33,6 @@ go_library( "//pkg/apis/core:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/portworx/portworx.go b/pkg/volume/portworx/portworx.go index 87d34363faa..da6cfbe7088 100644 --- a/pkg/volume/portworx/portworx.go +++ b/pkg/volume/portworx/portworx.go @@ -31,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) const ( @@ -296,9 +295,8 @@ func (b *portworxVolumeMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *portworxVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *portworxVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUpAt attaches the disk and bind mounts to the volume path. diff --git a/pkg/volume/portworx/portworx_test.go b/pkg/volume/portworx/portworx_test.go index d70c036e3c5..02492f6d99d 100644 --- a/pkg/volume/portworx/portworx_test.go +++ b/pkg/volume/portworx/portworx_test.go @@ -164,7 +164,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/projected/BUILD b/pkg/volume/projected/BUILD index 3dfe5afe15a..d3685747bf5 100644 --- a/pkg/volume/projected/BUILD +++ b/pkg/volume/projected/BUILD @@ -41,7 +41,6 @@ go_library( "//pkg/volume/downwardapi:go_default_library", "//pkg/volume/secret:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/authentication/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", diff --git a/pkg/volume/projected/projected.go b/pkg/volume/projected/projected.go index dcbc0f478bd..65e1ac5e2f1 100644 --- a/pkg/volume/projected/projected.go +++ b/pkg/volume/projected/projected.go @@ -33,7 +33,6 @@ import ( "k8s.io/kubernetes/pkg/volume/downwardapi" "k8s.io/kubernetes/pkg/volume/secret" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" utilstrings "k8s.io/utils/strings" ) @@ -185,9 +184,8 @@ func (s *projectedVolumeMounter) CanMount() error { return nil } -func (s *projectedVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := s.SetUpAt(s.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (s *projectedVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return s.SetUpAt(s.GetPath(), mounterArgs) } func (s *projectedVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/projected/projected_test.go b/pkg/volume/projected/projected_test.go index bd882305df0..ecf9b694073 100644 --- a/pkg/volume/projected/projected_test.go +++ b/pkg/volume/projected/projected_test.go @@ -887,7 +887,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -953,7 +953,7 @@ func TestInvalidPathProjected(t *testing.T) { } var mounterArgs volume.MounterArgs - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected error while setting up secret") } @@ -1004,7 +1004,7 @@ func TestPluginReboot(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -1056,7 +1056,7 @@ func TestPluginOptional(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -1154,7 +1154,7 @@ func TestPluginOptionalKeys(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } diff --git a/pkg/volume/quobyte/BUILD b/pkg/volume/quobyte/BUILD index e8f05722228..60bc5a55ab1 100644 --- a/pkg/volume/quobyte/BUILD +++ b/pkg/volume/quobyte/BUILD @@ -17,7 +17,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/quobyte/quobyte.go b/pkg/volume/quobyte/quobyte.go index 19e6f2924c0..33d730da522 100644 --- a/pkg/volume/quobyte/quobyte.go +++ b/pkg/volume/quobyte/quobyte.go @@ -33,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -235,10 +234,9 @@ func (mounter *quobyteMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { +func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) error { pluginDir := mounter.plugin.host.GetPluginDir(utilstrings.EscapeQualifiedName(quobytePluginName)) - err := mounter.SetUpAt(pluginDir, mounterArgs) - return volumetypes.OperationFinished, err + return mounter.SetUpAt(pluginDir, mounterArgs) } func (mounter *quobyteMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/quobyte/quobyte_test.go b/pkg/volume/quobyte/quobyte_test.go index d24ca69a265..eb3ef2bbba8 100644 --- a/pkg/volume/quobyte/quobyte_test.go +++ b/pkg/volume/quobyte/quobyte_test.go @@ -102,7 +102,7 @@ func doTestPlugin(t *testing.T, spec *volume.Spec) { if volumePath != fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir) { t.Errorf("Got unexpected path: %s expected: %s", volumePath, fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir)) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } unmounter, err := plug.(*quobytePlugin).newUnmounterInternal("vol", types.UID("poduid"), mount.NewFakeMounter(nil)) diff --git a/pkg/volume/rbd/BUILD b/pkg/volume/rbd/BUILD index f26fdbb9895..09226ab256b 100644 --- a/pkg/volume/rbd/BUILD +++ b/pkg/volume/rbd/BUILD @@ -21,7 +21,6 @@ go_library( "//pkg/util/node:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/rbd/attacher.go b/pkg/volume/rbd/attacher.go index 354100c1b39..12c2e77c935 100644 --- a/pkg/volume/rbd/attacher.go +++ b/pkg/volume/rbd/attacher.go @@ -28,7 +28,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // NewAttacher implements AttachableVolumePlugin.NewAttacher. @@ -144,7 +143,10 @@ func (attacher *rbdAttacher) GetDeviceMountPath(spec *volume.Spec) (string, erro return makePDNameInternal(attacher.plugin.host, pool, img), nil } -func (attacher *rbdAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +// MountDevice implements Attacher.MountDevice. It is called by the kubelet to +// mount device at the given mount path. +// This method is idempotent, callers are responsible for retrying on failure. +func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { klog.V(4).Infof("rbd: mouting device %s to %s", devicePath, deviceMountPath) notMnt, err := attacher.mounter.IsLikelyNotMountPoint(deviceMountPath) if err != nil { @@ -182,14 +184,6 @@ func (attacher *rbdAttacher) mountDeviceInternal(spec *volume.Spec, devicePath s return nil } -// MountDevice implements Attacher.MountDevice. It is called by the kubelet to -// mount device at the given mount path. -// This method is idempotent, callers are responsible for retrying on failure. -func (attacher *rbdAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - // rbdDetacher implements volume.Detacher interface. type rbdDetacher struct { plugin *rbdPlugin diff --git a/pkg/volume/rbd/rbd.go b/pkg/volume/rbd/rbd.go index 751909b69fe..a07fe8bf06d 100644 --- a/pkg/volume/rbd/rbd.go +++ b/pkg/volume/rbd/rbd.go @@ -40,7 +40,6 @@ import ( "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" volutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/kubernetes/pkg/volume/util/volumepathhandler" ) @@ -837,9 +836,8 @@ func (b *rbdMounter) CanMount() error { return nil } -func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/rbd/rbd_test.go b/pkg/volume/rbd/rbd_test.go index fa07b6b5ba1..e58020ddadb 100644 --- a/pkg/volume/rbd/rbd_test.go +++ b/pkg/volume/rbd/rbd_test.go @@ -281,7 +281,7 @@ func doTestPlugin(t *testing.T, c *testcase) { if deviceMountPath != c.expectedDeviceMountPath { t.Errorf("Unexpected mount path, expected %q, not: %q", c.expectedDeviceMountPath, deviceMountPath) } - _, err = attacher.MountDevice(c.spec, devicePath, deviceMountPath) + err = attacher.MountDevice(c.spec, devicePath, deviceMountPath) if err != nil { t.Fatal(err) } @@ -307,7 +307,7 @@ func doTestPlugin(t *testing.T, c *testcase) { t.Errorf("Unexpected path, expected %q, got: %q", c.expectedPodMountPath, path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { diff --git a/pkg/volume/scaleio/BUILD b/pkg/volume/scaleio/BUILD index 5af6e3ecf91..f1410f50657 100644 --- a/pkg/volume/scaleio/BUILD +++ b/pkg/volume/scaleio/BUILD @@ -42,7 +42,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/scaleio/sio_volume.go b/pkg/volume/scaleio/sio_volume.go index 72c20aefa1d..9904147be53 100644 --- a/pkg/volume/scaleio/sio_volume.go +++ b/pkg/volume/scaleio/sio_volume.go @@ -35,7 +35,6 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) type sioVolume struct { @@ -79,9 +78,8 @@ func (v *sioVolume) CanMount() error { return nil } -func (v *sioVolume) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := v.SetUpAt(v.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (v *sioVolume) SetUp(mounterArgs volume.MounterArgs) error { + return v.SetUpAt(v.GetPath(), mounterArgs) } // SetUp bind mounts the disk global mount to the volume path. diff --git a/pkg/volume/scaleio/sio_volume_test.go b/pkg/volume/scaleio/sio_volume_test.go index e3ac12440d5..ca871817589 100644 --- a/pkg/volume/scaleio/sio_volume_test.go +++ b/pkg/volume/scaleio/sio_volume_test.go @@ -190,7 +190,7 @@ func TestVolumeMounterUnmounter(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { + if err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(path); err != nil { @@ -344,7 +344,7 @@ func TestVolumeProvisioner(t *testing.T) { t.Fatalf("failed to create sio mgr: %v", err) } sioVol.sioMgr.client = sio - if _, err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { + if err := sioMounter.SetUp(volume.MounterArgs{}); err != nil { t.Fatalf("Expected success, got: %v", err) } diff --git a/pkg/volume/secret/BUILD b/pkg/volume/secret/BUILD index a34ad5fd998..cb168c9532d 100644 --- a/pkg/volume/secret/BUILD +++ b/pkg/volume/secret/BUILD @@ -16,7 +16,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index dbaab27995d..3eee6d91827 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -29,7 +29,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the entry point for plugin detection in a package. @@ -176,9 +175,8 @@ func (b *secretVolumeMounter) CanMount() error { return nil } -func (b *secretVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *secretVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } func (b *secretVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { diff --git a/pkg/volume/secret/secret_test.go b/pkg/volume/secret/secret_test.go index fa7e74fc5ee..7d60d7b7d6c 100644 --- a/pkg/volume/secret/secret_test.go +++ b/pkg/volume/secret/secret_test.go @@ -327,7 +327,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -402,7 +402,7 @@ func TestInvalidPathSecret(t *testing.T) { } var mounterArgs volume.MounterArgs - _, err = mounter.SetUp(mounterArgs) + err = mounter.SetUp(mounterArgs) if err == nil { t.Errorf("Expected error while setting up secret") } @@ -453,7 +453,7 @@ func TestPluginReboot(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -505,7 +505,7 @@ func TestPluginOptional(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } @@ -603,7 +603,7 @@ func TestPluginOptionalKeys(t *testing.T) { t.Errorf("Got unexpected path: %s", volumePath) } - _, err = mounter.SetUp(volume.MounterArgs{}) + err = mounter.SetUp(volume.MounterArgs{}) if err != nil { t.Errorf("Failed to setup volume: %v", err) } diff --git a/pkg/volume/storageos/BUILD b/pkg/volume/storageos/BUILD index eea84684a13..8d1b5730cbe 100644 --- a/pkg/volume/storageos/BUILD +++ b/pkg/volume/storageos/BUILD @@ -17,7 +17,6 @@ go_library( deps = [ "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/volume/storageos/storageos.go b/pkg/volume/storageos/storageos.go index 27ac988868f..a90e384e9a6 100644 --- a/pkg/volume/storageos/storageos.go +++ b/pkg/volume/storageos/storageos.go @@ -36,7 +36,6 @@ import ( volumehelpers "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // ProbeVolumePlugins is the primary entrypoint for volume plugins. @@ -344,40 +343,37 @@ func (b *storageosMounter) CanMount() error { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *storageosMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - internalSetup := func() error { - // Need a namespace to find the volume, try pod's namespace if not set. - if b.volNamespace == "" { - klog.V(2).Infof("Setting StorageOS volume namespace to pod namespace: %s", b.podNamespace) - b.volNamespace = b.podNamespace - } - - targetPath := makeGlobalPDName(b.plugin.host, b.pvName, b.volNamespace, b.volName) - - // Attach the device to the host. - if err := b.manager.AttachDevice(b, targetPath); err != nil { - klog.Errorf("Failed to attach device at %s: %s", targetPath, err.Error()) - return err - } - - // Attach the StorageOS volume as a block device - devicePath, err := b.manager.AttachVolume(b) - if err != nil { - klog.Errorf("Failed to attach StorageOS volume %s: %s", b.volName, err.Error()) - return err - } - - // Mount the loop device into the plugin's disk global mount dir. - err = b.manager.MountVolume(b, devicePath, targetPath) - if err != nil { - return err - } - klog.V(4).Infof("Successfully mounted StorageOS volume %s into global mount directory", b.volName) - - // Bind mount the volume into the pod - return b.SetUpAt(b.GetPath(), mounterArgs) +func (b *storageosMounter) SetUp(mounterArgs volume.MounterArgs) error { + // Need a namespace to find the volume, try pod's namespace if not set. + if b.volNamespace == "" { + klog.V(2).Infof("Setting StorageOS volume namespace to pod namespace: %s", b.podNamespace) + b.volNamespace = b.podNamespace } - return volumetypes.OperationFinished, internalSetup() + + targetPath := makeGlobalPDName(b.plugin.host, b.pvName, b.volNamespace, b.volName) + + // Attach the device to the host. + if err := b.manager.AttachDevice(b, targetPath); err != nil { + klog.Errorf("Failed to attach device at %s: %s", targetPath, err.Error()) + return err + } + + // Attach the StorageOS volume as a block device + devicePath, err := b.manager.AttachVolume(b) + if err != nil { + klog.Errorf("Failed to attach StorageOS volume %s: %s", b.volName, err.Error()) + return err + } + + // Mount the loop device into the plugin's disk global mount dir. + err = b.manager.MountVolume(b, devicePath, targetPath) + if err != nil { + return err + } + klog.V(4).Infof("Successfully mounted StorageOS volume %s into global mount directory", b.volName) + + // Bind mount the volume into the pod + return b.SetUpAt(b.GetPath(), mounterArgs) } // SetUp bind mounts the disk global mount to the give volume path. diff --git a/pkg/volume/storageos/storageos_test.go b/pkg/volume/storageos/storageos_test.go index 3758c9debcc..d26f24af7c5 100644 --- a/pkg/volume/storageos/storageos_test.go +++ b/pkg/volume/storageos/storageos_test.go @@ -210,7 +210,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Expected path: '%s' got: '%s'", expectedPath, volPath) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } if _, err := os.Stat(volPath); err != nil { diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index b027fa673d0..0bdad8924ba 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -88,6 +88,14 @@ const ( SuccessAndTimeoutDeviceName = "success-and-timeout-device-name" // SuccessAndFailOnMountDeviceName will cause first mount operation to succeed but subsequent attempts to fail SuccessAndFailOnMountDeviceName = "success-and-failed-mount-device-name" + + deviceNotMounted = "deviceNotMounted" + deviceMountUncertain = "deviceMountUncertain" + deviceMounted = "deviceMounted" + + volumeNotMounted = "volumeNotMounted" + volumeMountUncertain = "volumeMountUncertain" + volumeMounted = "volumeMounted" ) // fakeVolumeHost is useful for testing volume plugins. @@ -406,8 +414,8 @@ func (plugin *FakeVolumePlugin) getFakeVolume(list *[]*FakeVolume) *FakeVolume { UnmountDeviceHook: plugin.UnmountDeviceHook, } volume.VolumesAttached = make(map[string]types.NodeName) - volume.DeviceMountState = make(map[string]volumetypes.OperationStatus) - volume.VolumeMountState = make(map[string]volumetypes.OperationStatus) + volume.DeviceMountState = make(map[string]string) + volume.VolumeMountState = make(map[string]string) *list = append(*list, volume) return volume } @@ -810,8 +818,8 @@ type FakeVolume struct { Plugin *FakeVolumePlugin MetricsNil VolumesAttached map[string]types.NodeName - DeviceMountState map[string]volumetypes.OperationStatus - VolumeMountState map[string]volumetypes.OperationStatus + DeviceMountState map[string]string + VolumeMountState map[string]string // Add callbacks as needed WaitForAttachHook func(spec *Spec, devicePath string, pod *v1.Pod, spectimeout time.Duration) (string, error) @@ -859,34 +867,32 @@ func (fv *FakeVolume) CanMount() error { return nil } -func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) { +func (fv *FakeVolume) SetUp(mounterArgs MounterArgs) error { fv.Lock() defer fv.Unlock() err := fv.setupInternal(mounterArgs) fv.SetUpCallCount++ - if volumetypes.IsOperationTimeOutError(err) { - return volumetypes.OperationInProgress, err - } - return volumetypes.OperationFinished, err + return err } func (fv *FakeVolume) setupInternal(mounterArgs MounterArgs) error { if fv.VolName == TimeoutOnSetupVolumeName { - fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("time out on setup") + fv.VolumeMountState[fv.VolName] = volumeMountUncertain + return volumetypes.NewUncertainProgressError("time out on setup") } if fv.VolName == FailOnSetupVolumeName { + fv.VolumeMountState[fv.VolName] = volumeNotMounted return fmt.Errorf("mounting volume failed") } if fv.VolName == TimeoutAndFailOnSetupVolumeName { _, ok := fv.VolumeMountState[fv.VolName] if !ok { - fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("time out on setup") + fv.VolumeMountState[fv.VolName] = volumeMountUncertain + return volumetypes.NewUncertainProgressError("time out on setup") } - fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished + fv.VolumeMountState[fv.VolName] = volumeNotMounted return fmt.Errorf("mounting volume failed") } @@ -894,7 +900,7 @@ func (fv *FakeVolume) setupInternal(mounterArgs MounterArgs) error { if fv.VolName == SuccessAndFailOnSetupVolumeName { _, ok := fv.VolumeMountState[fv.VolName] if ok { - fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished + fv.VolumeMountState[fv.VolName] = volumeNotMounted return fmt.Errorf("mounting volume failed") } } @@ -902,13 +908,12 @@ func (fv *FakeVolume) setupInternal(mounterArgs MounterArgs) error { if fv.VolName == SuccessAndTimeoutSetupVolumeName { _, ok := fv.VolumeMountState[fv.VolName] if ok { - fv.VolumeMountState[fv.VolName] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("time out on setup") + fv.VolumeMountState[fv.VolName] = volumeMountUncertain + return volumetypes.NewUncertainProgressError("time out on setup") } } - fv.VolumeMountState[fv.VolName] = volumetypes.OperationFinished - + fv.VolumeMountState[fv.VolName] = volumeNotMounted return fv.SetUpAt(fv.getPath(), mounterArgs) } @@ -1113,30 +1118,30 @@ func (fv *FakeVolume) mountDeviceInternal(spec *Spec, devicePath string, deviceM fv.Lock() defer fv.Unlock() if spec.Name() == TimeoutOnMountDeviceVolumeName { - fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("error mounting device") + fv.DeviceMountState[spec.Name()] = deviceMountUncertain + return volumetypes.NewUncertainProgressError("mount failed") } if spec.Name() == FailMountDeviceVolumeName { - fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + fv.DeviceMountState[spec.Name()] = deviceNotMounted return fmt.Errorf("error mounting disk: %s", devicePath) } if spec.Name() == TimeoutAndFailOnMountDeviceVolumeName { _, ok := fv.DeviceMountState[spec.Name()] if !ok { - fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("timed out mounting error") + fv.DeviceMountState[spec.Name()] = deviceMountUncertain + return volumetypes.NewUncertainProgressError("timed out mounting error") } - fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + fv.DeviceMountState[spec.Name()] = deviceNotMounted return fmt.Errorf("error mounting disk: %s", devicePath) } if spec.Name() == SuccessAndTimeoutDeviceName { _, ok := fv.DeviceMountState[spec.Name()] if ok { - fv.DeviceMountState[spec.Name()] = volumetypes.OperationInProgress - return volumetypes.NewOperationTimedOutError("error mounting state") + fv.DeviceMountState[spec.Name()] = deviceMountUncertain + return volumetypes.NewUncertainProgressError("error mounting state") } } @@ -1146,17 +1151,13 @@ func (fv *FakeVolume) mountDeviceInternal(spec *Spec, devicePath string, deviceM return fmt.Errorf("error mounting disk: %s", devicePath) } } - fv.DeviceMountState[spec.Name()] = volumetypes.OperationFinished + fv.DeviceMountState[spec.Name()] = deviceMounted fv.MountDeviceCallCount++ return nil } -func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := fv.mountDeviceInternal(spec, devicePath, deviceMountPath) - if volumetypes.IsOperationTimeOutError(err) { - return volumetypes.OperationInProgress, err - } - return volumetypes.OperationFinished, err +func (fv *FakeVolume) MountDevice(spec *Spec, devicePath string, deviceMountPath string) error { + return fv.mountDeviceInternal(spec, devicePath, deviceMountPath) } func (fv *FakeVolume) GetMountDeviceCallCount() int { diff --git a/pkg/volume/util/operationexecutor/operation_generator.go b/pkg/volume/util/operationexecutor/operation_generator.go index 7be76b9e34d..d453c049608 100644 --- a/pkg/volume/util/operationexecutor/operation_generator.go +++ b/pkg/volume/util/operationexecutor/operation_generator.go @@ -575,12 +575,12 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Mount device to global mount path - operationState, err := volumeDeviceMounter.MountDevice( + err = volumeDeviceMounter.MountDevice( volumeToMount.VolumeSpec, devicePath, deviceMountPath) if err != nil { - og.markDeviceErrorState(volumeToMount, devicePath, deviceMountPath, operationState, actualStateOfWorld) + og.markDeviceErrorState(volumeToMount, devicePath, deviceMountPath, err, actualStateOfWorld) // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.MountDevice failed", err) } @@ -618,7 +618,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } // Execute mount - opExitStatus, mountErr := volumeMounter.SetUp(volume.MounterArgs{ + mountErr := volumeMounter.SetUp(volume.MounterArgs{ FsGroup: fsGroup, DesiredSize: volumeToMount.DesiredSizeLimit, }) @@ -630,11 +630,11 @@ func (og *operationGenerator) GenerateMountVolumeFunc( Mounter: volumeMounter, OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, VolumeGidVolume: volumeToMount.VolumeGidValue, - VolumeSpec: originalSpec, + VolumeSpec: volumeToMount.VolumeSpec, VolumeMountState: VolumeMounted, } if mountErr != nil { - og.markVolumeErrorState(volumeToMount, markOpts, opExitStatus, actualStateOfWorld) + og.markVolumeErrorState(volumeToMount, markOpts, mountErr, actualStateOfWorld) // On failure, return error. Caller will log and retry. return volumeToMount.GenerateError("MountVolume.SetUp failed", mountErr) } @@ -660,17 +660,6 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } } - // Update actual state of world - markOpts := MarkVolumeMountedOpts{ - PodName: volumeToMount.PodName, - PodUID: volumeToMount.Pod.UID, - VolumeName: volumeToMount.VolumeName, - Mounter: volumeMounter, - OuterVolumeSpecName: volumeToMount.OuterVolumeSpecName, - VolumeGidVolume: volumeToMount.VolumeGidValue, - VolumeSpec: volumeToMount.VolumeSpec, - VolumeMountState: VolumeMounted, - } markVolMountedErr := actualStateOfWorld.MarkVolumeAsMounted(markOpts) if markVolMountedErr != nil { // On failure, return error. Caller will log and retry. @@ -694,45 +683,47 @@ func (og *operationGenerator) GenerateMountVolumeFunc( } } -func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount, devicePath, deviceMountPath string, operationState volumetypes.OperationStatus, actualStateOfWorld ActualStateOfWorldMounterUpdater) { - switch operationState { - case volumetypes.OperationInProgress: +func (og *operationGenerator) markDeviceErrorState(volumeToMount VolumeToMount, devicePath, deviceMountPath string, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) { + if volumetypes.IsOperationFinishedError(mountError) && + actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceMountUncertain { + // Only devices which were uncertain can be marked as unmounted + markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName) + if markDeviceUnmountError != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error()) + } + return + } + + if volumetypes.IsUncertainProgressError(mountError) && + actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted { // only devices which are not mounted can be marked as uncertain. We do not want to mark a device // which was previously marked as mounted here as uncertain. - if actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceNotMounted { - markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) - if markDeviceUncertainError != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error()) - } - } - case volumetypes.OperationFinished: - // Similarly only devices which were uncertain can be marked as unmounted - if actualStateOfWorld.GetDeviceMountState(volumeToMount.VolumeName) == DeviceMountUncertain { - markDeviceUnmountError := actualStateOfWorld.MarkDeviceAsUnmounted(volumeToMount.VolumeName) - if markDeviceUnmountError != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUnmounted failed", markDeviceUnmountError).Error()) - } + markDeviceUncertainError := actualStateOfWorld.MarkDeviceAsUncertain(volumeToMount.VolumeName, devicePath, deviceMountPath) + if markDeviceUncertainError != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountDevice.MarkDeviceAsUncertain failed", markDeviceUncertainError).Error()) } } + } -func (og *operationGenerator) markVolumeErrorState(volumeToMount VolumeToMount, markOpts MarkVolumeOpts, operationState volumetypes.OperationStatus, actualStateOfWorld ActualStateOfWorldMounterUpdater) { - switch operationState { - case volumetypes.OperationInProgress: - if actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeNotMounted { - t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) - if t != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) - } +func (og *operationGenerator) markVolumeErrorState(volumeToMount VolumeToMount, markOpts MarkVolumeOpts, mountError error, actualStateOfWorld ActualStateOfWorldMounterUpdater) { + if volumetypes.IsOperationFinishedError(mountError) && + actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeMountUncertain { + t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) + if t != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) } - case volumetypes.OperationFinished: - if actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeMountUncertain { - t := actualStateOfWorld.MarkVolumeAsUnmounted(volumeToMount.PodName, volumeToMount.VolumeName) - if t != nil { - klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeAsUnmounted failed", t).Error()) - } + return + } + + if volumetypes.IsUncertainProgressError(mountError) && + actualStateOfWorld.GetVolumeMountState(volumeToMount.VolumeName, markOpts.PodName) == VolumeNotMounted { + t := actualStateOfWorld.MarkVolumeMountAsUncertain(markOpts) + if t != nil { + klog.Errorf(volumeToMount.GenerateErrorDetailed("MountVolume.MarkVolumeMountAsUncertain failed", t).Error()) } } + } func (og *operationGenerator) GenerateUnmountVolumeFunc( diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 4cbcd2c22f3..199365c3520 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -51,44 +51,52 @@ func (o *GeneratedOperations) Run() (eventErr, detailedErr error) { return o.OperationFunc() } -// OperationStatus is used to store status of a volume operation -type OperationStatus string - -const ( - // OperationFinished means volume operation has been finished - OperationFinished OperationStatus = "Finished" - - // OperationInProgress means volume operation has been started and - // is in-progress. This state does not indicate if operation will succeed or fail but - // merely it has been started and is in-progress. - OperationInProgress OperationStatus = "InProgress" - - // OperationStateNoChange indicates it is unchanged from previous state. - // This can be used to indicate transient failures for an operation which - // was in-progress previously. - OperationStateNoChange OperationStatus = "NoChange" -) - -// OperationTimedOutError indicates a particular volume operation has timed out. -type OperationTimedOutError struct { +// TransientOperationFailure indicates operation failed with a transient error +// and may fix itself when retried. +type TransientOperationFailure struct { msg string } -func (err *OperationTimedOutError) Error() string { +func (err *TransientOperationFailure) Error() string { return err.msg } -// NewOperationTimedOutError returns a new instance of OperationTimedOutError -func NewOperationTimedOutError(msg string) *OperationTimedOutError { - return &OperationTimedOutError{ - msg: msg, - } +// NewTransientOperationFailure creates an instance of TransientOperationFailure error +func NewTransientOperationFailure(msg string) *TransientOperationFailure { + return &TransientOperationFailure{msg: msg} } -// IsOperationTimeOutError returns true if volume operation could have timed out for client but possibly -// still running or being processed by the volume plugin. -func IsOperationTimeOutError(err error) bool { - if _, ok := err.(*OperationTimedOutError); ok { +// UncertainProgressError indicates operation failed with a non-final error +// and operation may be in-progress in background. +type UncertainProgressError struct { + msg string +} + +func (err *UncertainProgressError) Error() string { + return err.msg +} + +// NewUncertainProgressError creates an instance of UncertainProgressError type +func NewUncertainProgressError(msg string) *UncertainProgressError { + return &UncertainProgressError{msg: msg} +} + +// IsOperationFinishedError checks if given error is of type that indicates +// operation is finished with an error. +func IsOperationFinishedError(err error) bool { + if _, ok := err.(*UncertainProgressError); ok { + return false + } + if _, ok := err.(*TransientOperationFailure); ok { + return false + } + return true +} + +// IsUncertainProgressError checks if given error is of type that indicates +// operation might be in-progress in background. +func IsUncertainProgressError(err error) bool { + if _, ok := err.(*UncertainProgressError); ok { return true } return false diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index c751f9c959b..0efabf92508 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -19,11 +19,10 @@ package volume import ( "time" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" ) // Volume represents a directory used by pods or hosts on a node. All method @@ -129,7 +128,11 @@ type Mounter interface { // content should be owned by 'fsGroup' so that it can be // accessed by the pod. This may be called more than once, so // implementations must be idempotent. - SetUp(mounterArgs MounterArgs) (volumetypes.OperationStatus, error) + // It could return following types of errors: + // - TransientOperationFailure + // - UncertainProgressError + // - Error of any other type should be considered a final error + SetUp(mounterArgs MounterArgs) error // SetUpAt prepares and mounts/unpacks the volume to the // specified directory path, which may or may not exist yet. @@ -249,7 +252,11 @@ type DeviceMounter interface { // MountDevice mounts the disk to a global path which // individual pods can then bind mount // Note that devicePath can be empty if the volume plugin does not implement any of Attach and WaitForAttach methods. - MountDevice(spec *Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) + // It could return following types of errors: + // - TransientOperationFailure + // - UncertainProgressError + // - Error of any other type should be considered a final error + MountDevice(spec *Spec, devicePath string, deviceMountPath string) error } type BulkVolumeVerifier interface { diff --git a/pkg/volume/vsphere_volume/BUILD b/pkg/volume/vsphere_volume/BUILD index a2f466175d9..b4bab5c5ef9 100644 --- a/pkg/volume/vsphere_volume/BUILD +++ b/pkg/volume/vsphere_volume/BUILD @@ -23,7 +23,6 @@ go_library( "//pkg/features:go_default_library", "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", - "//pkg/volume/util/types:go_default_library", "//pkg/volume/util/volumepathhandler:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", diff --git a/pkg/volume/vsphere_volume/attacher.go b/pkg/volume/vsphere_volume/attacher.go index 3f5e56142b7..8c247167858 100644 --- a/pkg/volume/vsphere_volume/attacher.go +++ b/pkg/volume/vsphere_volume/attacher.go @@ -33,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/volume" volumeutil "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" "k8s.io/legacy-cloud-providers/vsphere" ) @@ -208,7 +207,8 @@ func (plugin *vsphereVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([ return mounter.GetMountRefs(deviceMountPath) } -func (attacher *vsphereVMDKAttacher) mountDeviceInternal(spec *volume.Spec, devicePath string, deviceMountPath string) error { +// MountDevice mounts device to global mount point. +func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error { klog.Info("vsphere MountDevice", devicePath, deviceMountPath) mounter := attacher.host.GetMounter(vsphereVolumePluginName) notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath) @@ -248,12 +248,6 @@ func (attacher *vsphereVMDKAttacher) mountDeviceInternal(spec *volume.Spec, devi return nil } -// MountDevice mounts device to global mount point. -func (attacher *vsphereVMDKAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) (volumetypes.OperationStatus, error) { - err := attacher.mountDeviceInternal(spec, devicePath, deviceMountPath) - return volumetypes.OperationFinished, err -} - type vsphereVMDKDetacher struct { mounter mount.Interface vsphereVolumes vsphere.Volumes diff --git a/pkg/volume/vsphere_volume/vsphere_volume.go b/pkg/volume/vsphere_volume/vsphere_volume.go index 2d68ee6136f..2d023da3b1f 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume.go +++ b/pkg/volume/vsphere_volume/vsphere_volume.go @@ -38,7 +38,7 @@ import ( "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" - volumetypes "k8s.io/kubernetes/pkg/volume/util/types" +) // This is the primary entrypoint for volume plugins. func ProbeVolumePlugins() []volume.VolumePlugin { @@ -213,9 +213,8 @@ func (b *vsphereVolumeMounter) GetAttributes() volume.Attributes { } // SetUp attaches the disk and bind mounts to the volume path. -func (b *vsphereVolumeMounter) SetUp(mounterArgs volume.MounterArgs) (volumetypes.OperationStatus, error) { - err := b.SetUpAt(b.GetPath(), mounterArgs) - return volumetypes.OperationFinished, err +func (b *vsphereVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error { + return b.SetUpAt(b.GetPath(), mounterArgs) } // Checks prior to mount operations to verify that the required components (binaries, etc.) diff --git a/pkg/volume/vsphere_volume/vsphere_volume_test.go b/pkg/volume/vsphere_volume/vsphere_volume_test.go index ac282ea3cf6..ae59c319813 100644 --- a/pkg/volume/vsphere_volume/vsphere_volume_test.go +++ b/pkg/volume/vsphere_volume/vsphere_volume_test.go @@ -126,7 +126,7 @@ func TestPlugin(t *testing.T) { t.Errorf("Got unexpected path: %s", path) } - if _, err := mounter.SetUp(volume.MounterArgs{}); err != nil { + if err := mounter.SetUp(volume.MounterArgs{}); err != nil { t.Errorf("Expected success, got: %v", err) } From ca532c6fb2c08f859eca13e0557f3b2aec9a18e0 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 11 Dec 2019 21:51:03 -0500 Subject: [PATCH 15/15] Ensure that error is returned on NodePublish --- pkg/kubelet/volumemanager/cache/actual_state_of_world.go | 3 ++- pkg/volume/csi/csi_client.go | 2 +- pkg/volume/util/types/types.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 6ebd6b78e2d..c5d84ee3cde 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -24,7 +24,7 @@ import ( "fmt" "sync" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/klog" @@ -490,6 +490,7 @@ func (asw *actualStateOfWorld) AddPodToVolume(markVolumeOpts operationexecutor.M // If pod exists, reset remountRequired value podObj.remountRequired = false + podObj.volumeMountStateForPod = markVolumeOpts.VolumeMountState asw.attachedVolumes[volumeName].mountedPods[podName] = podObj return nil } diff --git a/pkg/volume/csi/csi_client.go b/pkg/volume/csi/csi_client.go index 9da810cd3c0..1dce2eccc4c 100644 --- a/pkg/volume/csi/csi_client.go +++ b/pkg/volume/csi/csi_client.go @@ -262,7 +262,7 @@ func (c *csiDriverClient) NodePublishVolume( if err != nil && !isFinalError(err) { return volumetypes.NewUncertainProgressError(err.Error()) } - return nil + return err } func (c *csiDriverClient) NodeExpandVolume(ctx context.Context, volumeID, volumePath string, newSize resource.Quantity) (resource.Quantity, error) { diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 199365c3520..1a34a7d3153 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -82,7 +82,7 @@ func NewUncertainProgressError(msg string) *UncertainProgressError { } // IsOperationFinishedError checks if given error is of type that indicates -// operation is finished with an error. +// operation is finished with a FINAL error. func IsOperationFinishedError(err error) bool { if _, ok := err.(*UncertainProgressError); ok { return false