k8s.io/kubernetes@v1.29.3/pkg/controller/volume/attachdetach/reconciler/reconciler_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package reconciler
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	k8stypes "k8s.io/apimachinery/pkg/types"
    29  	"k8s.io/apimachinery/pkg/util/wait"
    30  	"k8s.io/client-go/informers"
    31  	"k8s.io/client-go/tools/record"
    32  	"k8s.io/component-base/metrics/legacyregistry"
    33  	metricstestutil "k8s.io/component-base/metrics/testutil"
    34  	"k8s.io/klog/v2"
    35  	"k8s.io/klog/v2/ktesting"
    36  	"k8s.io/kubernetes/pkg/controller"
    37  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
    38  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics"
    39  	"k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater"
    40  	controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing"
    41  	volumetesting "k8s.io/kubernetes/pkg/volume/testing"
    42  	"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
    43  	"k8s.io/kubernetes/pkg/volume/util/types"
    44  	utilstrings "k8s.io/utils/strings"
    45  )
    46  
    47  const (
    48  	reconcilerLoopPeriod          = 10 * time.Millisecond
    49  	syncLoopPeriod                = 100 * time.Minute
    50  	maxWaitForUnmountDuration     = 50 * time.Millisecond
    51  	maxLongWaitForUnmountDuration = 4200 * time.Second
    52  	volumeAttachedCheckTimeout    = 5 * time.Second
    53  )
    54  
    55  var registerMetrics sync.Once
    56  
    57  // Calls Run()
    58  // Verifies there are no calls to attach or detach.
    59  func Test_Run_Positive_DoNothing(t *testing.T) {
    60  	// Arrange
    61  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
    62  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
    63  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
    64  
    65  	fakeKubeClient := controllervolumetesting.CreateTestClient()
    66  	fakeRecorder := &record.FakeRecorder{}
    67  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
    68  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
    69  		fakeKubeClient,
    70  		volumePluginMgr,
    71  		fakeRecorder,
    72  		fakeHandler))
    73  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
    74  	nsu := statusupdater.NewNodeStatusUpdater(
    75  		fakeKubeClient, informerFactory.Core().V1().Nodes().Lister(), asw)
    76  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
    77  	reconciler := NewReconciler(
    78  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
    79  
    80  	// Act
    81  	_, ctx := ktesting.NewTestContext(t)
    82  	ctx, cancel := context.WithCancel(ctx)
    83  	defer cancel()
    84  	go reconciler.Run(ctx)
    85  
    86  	// Assert
    87  	waitForNewAttacherCallCount(t, 0 /* expectedCallCount */, fakePlugin)
    88  	verifyNewAttacherCallCount(t, true /* expectZeroNewAttacherCallCount */, fakePlugin)
    89  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
    90  	waitForAttachCallCount(t, 0 /* expectedAttachCallCount */, fakePlugin)
    91  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
    92  }
    93  
    94  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
    95  // Calls Run()
    96  // Verifies there is one attach call and no detach calls.
    97  func Test_Run_Positive_OneDesiredVolumeAttach(t *testing.T) {
    98  	// Arrange
    99  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   100  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   101  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   102  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   103  	fakeRecorder := &record.FakeRecorder{}
   104  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   105  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   106  		fakeKubeClient,
   107  		volumePluginMgr,
   108  		fakeRecorder,
   109  		fakeHandler))
   110  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   111  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   112  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   113  	reconciler := NewReconciler(
   114  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   115  	podName := "pod-uid"
   116  	volumeName := v1.UniqueVolumeName("volume-name")
   117  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   118  	nodeName := k8stypes.NodeName("node-name")
   119  	dsw.AddNode(nodeName, false /*keepTerminatedPodVolumes*/)
   120  	volumeExists := dsw.VolumeExists(volumeName, nodeName)
   121  	if volumeExists {
   122  		t.Fatalf(
   123  			"Volume %q/node %q should not exist, but it does.",
   124  			volumeName,
   125  			nodeName)
   126  	}
   127  
   128  	_, podErr := dsw.AddPod(types.UniquePodName(podName), controllervolumetesting.NewPod(podName, podName), volumeSpec, nodeName)
   129  	if podErr != nil {
   130  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podErr)
   131  	}
   132  
   133  	// Act
   134  	_, ctx := ktesting.NewTestContext(t)
   135  	ctx, cancel := context.WithCancel(ctx)
   136  	defer cancel()
   137  	go reconciler.Run(ctx)
   138  
   139  	// Assert
   140  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   141  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   142  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   143  }
   144  
   145  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
   146  // Calls Run()
   147  // Verifies there is one attach call and no detach calls.
   148  // Marks the node/volume as unmounted.
   149  // Deletes the node/volume/pod tuple from desiredStateOfWorld cache.
   150  // Verifies there is one detach call and no (new) attach calls.
   151  func Test_Run_Positive_OneDesiredVolumeAttachThenDetachWithUnmountedVolume(t *testing.T) {
   152  	// Arrange
   153  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   154  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   155  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   156  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   157  	fakeRecorder := &record.FakeRecorder{}
   158  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   159  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   160  		fakeKubeClient,
   161  		volumePluginMgr,
   162  		fakeRecorder,
   163  		fakeHandler))
   164  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   165  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   166  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   167  	reconciler := NewReconciler(
   168  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   169  	podName := "pod-uid"
   170  	volumeName := v1.UniqueVolumeName("volume-name")
   171  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   172  	nodeName := k8stypes.NodeName("node-name")
   173  	dsw.AddNode(nodeName, false /*keepTerminatedPodVolumes*/)
   174  	volumeExists := dsw.VolumeExists(volumeName, nodeName)
   175  	if volumeExists {
   176  		t.Fatalf(
   177  			"Volume %q/node %q should not exist, but it does.",
   178  			volumeName,
   179  			nodeName)
   180  	}
   181  
   182  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName), controllervolumetesting.NewPod(podName, podName), volumeSpec, nodeName)
   183  	if podAddErr != nil {
   184  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   185  	}
   186  
   187  	// Act
   188  	logger, ctx := ktesting.NewTestContext(t)
   189  	ctx, cancel := context.WithCancel(ctx)
   190  	defer cancel()
   191  	go reconciler.Run(ctx)
   192  
   193  	// Assert
   194  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   195  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   196  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   197  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   198  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   199  
   200  	// Act
   201  	dsw.DeletePod(types.UniquePodName(podName), generatedVolumeName, nodeName)
   202  	volumeExists = dsw.VolumeExists(generatedVolumeName, nodeName)
   203  	if volumeExists {
   204  		t.Fatalf(
   205  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   206  			podName,
   207  			generatedVolumeName,
   208  			nodeName)
   209  	}
   210  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName, true /* mounted */)
   211  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName, false /* mounted */)
   212  
   213  	// Assert
   214  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   215  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   216  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   217  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   218  	waitForDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
   219  }
   220  
   221  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
   222  // Calls Run()
   223  // Verifies there is one attach call and no detach calls.
   224  // Deletes the node/volume/pod tuple from desiredStateOfWorld cache without first marking the node/volume as unmounted.
   225  // Verifies there is one detach call and no (new) attach calls.
   226  func Test_Run_Positive_OneDesiredVolumeAttachThenDetachWithMountedVolume(t *testing.T) {
   227  	registerMetrics.Do(func() {
   228  		legacyregistry.MustRegister(metrics.ForceDetachMetricCounter)
   229  	})
   230  	// Arrange
   231  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   232  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   233  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   234  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   235  	fakeRecorder := &record.FakeRecorder{}
   236  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   237  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   238  		fakeKubeClient,
   239  		volumePluginMgr,
   240  		fakeRecorder,
   241  		fakeHandler))
   242  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   243  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   244  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   245  	reconciler := NewReconciler(
   246  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   247  	podName := "pod-uid"
   248  	volumeName := v1.UniqueVolumeName("volume-name")
   249  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   250  	nodeName := k8stypes.NodeName("node-name")
   251  	dsw.AddNode(nodeName, false /*keepTerminatedPodVolumes*/)
   252  
   253  	volumeExists := dsw.VolumeExists(volumeName, nodeName)
   254  	if volumeExists {
   255  		t.Fatalf(
   256  			"Volume %q/node %q should not exist, but it does.",
   257  			volumeName,
   258  			nodeName)
   259  	}
   260  
   261  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName), controllervolumetesting.NewPod(podName, podName), volumeSpec, nodeName)
   262  	if podAddErr != nil {
   263  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   264  	}
   265  
   266  	// Act
   267  	_, ctx := ktesting.NewTestContext(t)
   268  	ctx, cancel := context.WithCancel(ctx)
   269  	defer cancel()
   270  	go reconciler.Run(ctx)
   271  
   272  	// Assert
   273  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   274  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   275  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   276  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   277  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   278  
   279  	// Act
   280  	dsw.DeletePod(types.UniquePodName(podName), generatedVolumeName, nodeName)
   281  	volumeExists = dsw.VolumeExists(generatedVolumeName, nodeName)
   282  	if volumeExists {
   283  		t.Fatalf(
   284  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   285  			podName,
   286  			generatedVolumeName,
   287  			nodeName)
   288  	}
   289  
   290  	// Assert -- Timer will trigger detach
   291  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   292  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   293  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   294  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   295  	waitForDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
   296  
   297  	// Force detach metric due to timeout
   298  	testForceDetachMetric(t, 1, metrics.ForceDetachReasonTimeout)
   299  }
   300  
   301  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
   302  // Has node update fail
   303  // Calls Run()
   304  // Verifies there is one attach call and no detach calls.
   305  // Marks the node/volume as unmounted.
   306  // Deletes the node/volume/pod tuple from desiredStateOfWorld cache.
   307  // Verifies there are NO detach call and no (new) attach calls.
   308  func Test_Run_Negative_OneDesiredVolumeAttachThenDetachWithUnmountedVolumeUpdateStatusFail(t *testing.T) {
   309  	// Arrange
   310  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   311  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   312  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   313  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   314  	fakeRecorder := &record.FakeRecorder{}
   315  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   316  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   317  		fakeKubeClient,
   318  		volumePluginMgr,
   319  		fakeRecorder,
   320  		fakeHandler))
   321  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   322  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   323  	nsu := statusupdater.NewFakeNodeStatusUpdater(true /* returnError */)
   324  	reconciler := NewReconciler(
   325  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   326  	podName := "pod-uid"
   327  	volumeName := v1.UniqueVolumeName("volume-name")
   328  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   329  	nodeName := k8stypes.NodeName("node-name")
   330  	dsw.AddNode(nodeName, false /*keepTerminatedPodVolumes*/)
   331  	volumeExists := dsw.VolumeExists(volumeName, nodeName)
   332  	if volumeExists {
   333  		t.Fatalf(
   334  			"Volume %q/node %q should not exist, but it does.",
   335  			volumeName,
   336  			nodeName)
   337  	}
   338  
   339  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName), controllervolumetesting.NewPod(podName, podName), volumeSpec, nodeName)
   340  	if podAddErr != nil {
   341  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   342  	}
   343  
   344  	// Act
   345  	logger, ctx := ktesting.NewTestContext(t)
   346  	ctx, cancel := context.WithCancel(ctx)
   347  	defer cancel()
   348  	go reconciler.Run(ctx)
   349  
   350  	// Assert
   351  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   352  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   353  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   354  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   355  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   356  
   357  	// Act
   358  	dsw.DeletePod(types.UniquePodName(podName), generatedVolumeName, nodeName)
   359  	volumeExists = dsw.VolumeExists(generatedVolumeName, nodeName)
   360  	if volumeExists {
   361  		t.Fatalf(
   362  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   363  			podName,
   364  			generatedVolumeName,
   365  			nodeName)
   366  	}
   367  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName, true /* mounted */)
   368  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName, false /* mounted */)
   369  
   370  	// Assert
   371  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   372  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   373  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   374  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   375  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   376  }
   377  
   378  // Creates a volume with accessMode ReadWriteMany
   379  // Populates desiredStateOfWorld cache with two node/volume/pod tuples pointing to the created volume
   380  // Calls Run()
   381  // Verifies there are two attach calls and no detach calls.
   382  // Deletes the first node/volume/pod tuple from desiredStateOfWorld cache without first marking the node/volume as unmounted.
   383  // Verifies there is one detach call and no (new) attach calls.
   384  // Deletes the second node/volume/pod tuple from desiredStateOfWorld cache without first marking the node/volume as unmounted.
   385  // Verifies there are two detach calls and no (new) attach calls.
   386  func Test_Run_OneVolumeAttachAndDetachMultipleNodesWithReadWriteMany(t *testing.T) {
   387  	// Arrange
   388  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   389  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   390  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   391  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   392  	fakeRecorder := &record.FakeRecorder{}
   393  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   394  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   395  		fakeKubeClient,
   396  		volumePluginMgr,
   397  		fakeRecorder,
   398  		fakeHandler))
   399  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   400  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   401  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   402  	reconciler := NewReconciler(
   403  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   404  	podName1 := "pod-uid1"
   405  	podName2 := "pod-uid2"
   406  	volumeName := v1.UniqueVolumeName("volume-name")
   407  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   408  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}
   409  	nodeName1 := k8stypes.NodeName("node-name1")
   410  	nodeName2 := k8stypes.NodeName(volumetesting.MultiAttachNode)
   411  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   412  	dsw.AddNode(nodeName2, false /*keepTerminatedPodVolumes*/)
   413  
   414  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   415  	if podAddErr != nil {
   416  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   417  	}
   418  
   419  	_, podAddErr = dsw.AddPod(types.UniquePodName(podName2), controllervolumetesting.NewPod(podName2, podName2), volumeSpec, nodeName2)
   420  	if podAddErr != nil {
   421  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   422  	}
   423  
   424  	// Act
   425  	_, ctx := ktesting.NewTestContext(t)
   426  	ctx, cancel := context.WithCancel(ctx)
   427  	defer cancel()
   428  	go reconciler.Run(ctx)
   429  
   430  	// Assert
   431  	waitForNewAttacherCallCount(t, 2 /* expectedCallCount */, fakePlugin)
   432  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   433  	waitForTotalAttachCallCount(t, 2 /* expectedAttachCallCount */, fakePlugin)
   434  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   435  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   436  	waitForAttachedToNodesCount(t, 2 /* expectedNodeCount */, generatedVolumeName, asw)
   437  
   438  	// Act
   439  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   440  	volumeExists := dsw.VolumeExists(generatedVolumeName, nodeName1)
   441  	if volumeExists {
   442  		t.Fatalf(
   443  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   444  			podName1,
   445  			generatedVolumeName,
   446  			nodeName1)
   447  	}
   448  
   449  	// Assert -- Timer will trigger detach
   450  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   451  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   452  	waitForTotalAttachCallCount(t, 2 /* expectedAttachCallCount */, fakePlugin)
   453  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   454  	waitForTotalDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
   455  
   456  	// Act
   457  	dsw.DeletePod(types.UniquePodName(podName2), generatedVolumeName, nodeName2)
   458  	volumeExists = dsw.VolumeExists(generatedVolumeName, nodeName2)
   459  	if volumeExists {
   460  		t.Fatalf(
   461  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   462  			podName2,
   463  			generatedVolumeName,
   464  			nodeName2)
   465  	}
   466  
   467  	// Assert -- Timer will trigger detach
   468  	waitForNewDetacherCallCount(t, 2 /* expectedCallCount */, fakePlugin)
   469  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   470  	waitForTotalAttachCallCount(t, 2 /* expectedAttachCallCount */, fakePlugin)
   471  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   472  	waitForTotalDetachCallCount(t, 2 /* expectedDetachCallCount */, fakePlugin)
   473  }
   474  
   475  // Creates a volume with accessMode ReadWriteOnce
   476  // Populates desiredStateOfWorld cache with two ode/volume/pod tuples pointing to the created volume
   477  // Calls Run()
   478  // Verifies there is one attach call and no detach calls.
   479  // Deletes the node/volume/pod tuple from desiredStateOfWorld which succeeded in attaching
   480  // Verifies there are two attach call and one detach call.
   481  func Test_Run_OneVolumeAttachAndDetachMultipleNodesWithReadWriteOnce(t *testing.T) {
   482  	// Arrange
   483  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   484  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   485  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   486  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   487  	fakeRecorder := &record.FakeRecorder{}
   488  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   489  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   490  		fakeKubeClient,
   491  		volumePluginMgr,
   492  		fakeRecorder,
   493  		fakeHandler))
   494  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   495  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   496  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   497  	reconciler := NewReconciler(
   498  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   499  	podName1 := "pod-uid1"
   500  	podName2 := "pod-uid2"
   501  	volumeName := v1.UniqueVolumeName("volume-name")
   502  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   503  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
   504  	nodeName1 := k8stypes.NodeName("node-name1")
   505  	nodeName2 := k8stypes.NodeName("node-name2")
   506  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   507  	dsw.AddNode(nodeName2, false /*keepTerminatedPodVolumes*/)
   508  
   509  	// Add both pods at the same time to provoke a potential race condition in the reconciler
   510  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   511  	if podAddErr != nil {
   512  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   513  	}
   514  	_, podAddErr = dsw.AddPod(types.UniquePodName(podName2), controllervolumetesting.NewPod(podName2, podName2), volumeSpec, nodeName2)
   515  	if podAddErr != nil {
   516  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   517  	}
   518  
   519  	// Act
   520  	_, ctx := ktesting.NewTestContext(t)
   521  	ctx, cancel := context.WithCancel(ctx)
   522  	defer cancel()
   523  	go reconciler.Run(ctx)
   524  
   525  	// Assert
   526  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   527  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   528  	waitForTotalAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   529  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   530  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   531  	waitForAttachedToNodesCount(t, 1 /* expectedNodeCount */, generatedVolumeName, asw)
   532  
   533  	nodesForVolume := asw.GetNodesForAttachedVolume(generatedVolumeName)
   534  
   535  	// check if multiattach is marked
   536  	// at least one volume+node should be marked with multiattach error
   537  	nodeAttachedTo := nodesForVolume[0]
   538  	waitForMultiAttachErrorOnNode(t, nodeAttachedTo, dsw)
   539  
   540  	// Act
   541  	podToDelete := ""
   542  	if nodesForVolume[0] == nodeName1 {
   543  		podToDelete = podName1
   544  	} else if nodesForVolume[0] == nodeName2 {
   545  		podToDelete = podName2
   546  	} else {
   547  		t.Fatal("Volume attached to unexpected node")
   548  	}
   549  
   550  	dsw.DeletePod(types.UniquePodName(podToDelete), generatedVolumeName, nodesForVolume[0])
   551  	volumeExists := dsw.VolumeExists(generatedVolumeName, nodesForVolume[0])
   552  	if volumeExists {
   553  		t.Fatalf(
   554  			"Deleted pod %q from volume %q/node %q. Volume should also be deleted but it still exists.",
   555  			podToDelete,
   556  			generatedVolumeName,
   557  			nodesForVolume[0])
   558  	}
   559  
   560  	// Assert
   561  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   562  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   563  	waitForTotalDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
   564  	waitForNewAttacherCallCount(t, 2 /* expectedCallCount */, fakePlugin)
   565  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   566  	waitForTotalAttachCallCount(t, 2 /* expectedAttachCallCount */, fakePlugin)
   567  }
   568  
   569  // Creates a volume with accessMode ReadWriteOnce
   570  // First create a pod which will try to attach the volume to the a node named "uncertain-node". The attach call for this node will
   571  // fail for timeout, but the volume will be actually attached to the node after the call.
   572  // Secondly, delete this pod.
   573  // Lastly, create a pod scheduled to a normal node which will trigger attach volume to the node. The attach should return successfully.
   574  func Test_Run_OneVolumeAttachAndDetachUncertainNodesWithReadWriteOnce(t *testing.T) {
   575  	// Arrange
   576  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   577  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   578  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   579  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   580  	fakeRecorder := &record.FakeRecorder{}
   581  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   582  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   583  		fakeKubeClient,
   584  		volumePluginMgr,
   585  		fakeRecorder,
   586  		fakeHandler))
   587  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   588  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   589  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   590  	reconciler := NewReconciler(
   591  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   592  	podName1 := "pod-uid1"
   593  	podName2 := "pod-uid2"
   594  	volumeName := v1.UniqueVolumeName("volume-name")
   595  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   596  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
   597  	nodeName1 := k8stypes.NodeName(volumetesting.UncertainAttachNode)
   598  	nodeName2 := k8stypes.NodeName("node-name2")
   599  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   600  	dsw.AddNode(nodeName2, false /*keepTerminatedPodVolumes*/)
   601  
   602  	// Act
   603  	logger, ctx := ktesting.NewTestContext(t)
   604  	ctx, cancel := context.WithCancel(ctx)
   605  	defer cancel()
   606  	go reconciler.Run(ctx)
   607  
   608  	// Add the pod in which the volume is attached to the uncertain node
   609  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   610  	if podAddErr != nil {
   611  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   612  	}
   613  
   614  	time.Sleep(1 * time.Second)
   615  	// Volume is added to asw. Because attach operation fails, volume should not be reported as attached to the node.
   616  	waitForVolumeAddedToNode(t, generatedVolumeName, nodeName1, asw)
   617  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   618  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, true, asw, volumeAttachedCheckTimeout)
   619  
   620  	// When volume is added to the node, it is set to mounted by default. Then the status will be updated by checking node status VolumeInUse.
   621  	// Without this, the delete operation will be delayed due to mounted status
   622  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName1, false /* mounted */)
   623  
   624  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   625  
   626  	waitForVolumeRemovedFromNode(t, generatedVolumeName, nodeName1, asw)
   627  
   628  	// Add a second pod which tries to attach the volume to a different node.
   629  	generatedVolumeName, podAddErr = dsw.AddPod(types.UniquePodName(podName2), controllervolumetesting.NewPod(podName2, podName2), volumeSpec, nodeName2)
   630  	if podAddErr != nil {
   631  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   632  	}
   633  	waitForVolumeAttachedToNode(t, generatedVolumeName, nodeName2, asw)
   634  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName2, cache.AttachStateAttached, asw)
   635  
   636  }
   637  
   638  func Test_Run_UpdateNodeStatusFailBeforeOneVolumeDetachNodeWithReadWriteOnce(t *testing.T) {
   639  	// Arrange
   640  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   641  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   642  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   643  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   644  	fakeRecorder := &record.FakeRecorder{}
   645  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   646  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   647  		fakeKubeClient,
   648  		volumePluginMgr,
   649  		fakeRecorder,
   650  		fakeHandler))
   651  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   652  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   653  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   654  	logger, ctx := ktesting.NewTestContext(t)
   655  	ctx, cancel := context.WithCancel(ctx)
   656  	defer cancel()
   657  	rc := NewReconciler(
   658  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   659  	reconciliationLoopFunc := rc.(*reconciler).reconciliationLoopFunc(ctx)
   660  	podName1 := "pod-uid1"
   661  	volumeName := v1.UniqueVolumeName("volume-name")
   662  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   663  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
   664  	nodeName1 := k8stypes.NodeName("node-name1")
   665  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   666  
   667  	// Add the pod in which the volume is attached to the FailDetachNode
   668  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   669  	if podAddErr != nil {
   670  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   671  	}
   672  
   673  	// Act
   674  	reconciliationLoopFunc(ctx)
   675  
   676  	// Volume is added to asw, volume should be reported as attached to the node.
   677  	waitForVolumeAddedToNode(t, generatedVolumeName, nodeName1, asw)
   678  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   679  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, true, asw, volumeAttachedCheckTimeout)
   680  
   681  	// Delete the pod
   682  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   683  
   684  	// Mock NodeStatusUpdate fail
   685  	rc.(*reconciler).nodeStatusUpdater = statusupdater.NewFakeNodeStatusUpdater(true /* returnError */)
   686  	reconciliationLoopFunc(ctx)
   687  	// The first detach will be triggered after at least 50ms (maxWaitForUnmountDuration in test).
   688  	time.Sleep(100 * time.Millisecond)
   689  	reconciliationLoopFunc(ctx)
   690  	// Right before detach operation is performed, the volume will be first removed from being reported
   691  	// as attached on node status (RemoveVolumeFromReportAsAttached). After UpdateNodeStatus operation which is expected to fail,
   692  	// controller then added the volume back as attached.
   693  	// verifyVolumeReportedAsAttachedToNode will check volume is in the list of volume attached that needs to be updated
   694  	// in node status. By calling this function (GetVolumesToReportAttached), node status should be updated, and the volume
   695  	// will not need to be updated until new changes are applied (detach is triggered again)
   696  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   697  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, true, asw, volumeAttachedCheckTimeout)
   698  
   699  }
   700  
   701  func Test_Run_OneVolumeDetachFailNodeWithReadWriteOnce(t *testing.T) {
   702  	// Arrange
   703  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   704  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   705  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   706  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   707  	fakeRecorder := &record.FakeRecorder{}
   708  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   709  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   710  		fakeKubeClient,
   711  		volumePluginMgr,
   712  		fakeRecorder,
   713  		fakeHandler))
   714  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   715  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   716  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   717  	reconciler := NewReconciler(
   718  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   719  	podName1 := "pod-uid1"
   720  	podName2 := "pod-uid2"
   721  	podName3 := "pod-uid3"
   722  	volumeName := v1.UniqueVolumeName("volume-name")
   723  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   724  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
   725  	nodeName1 := k8stypes.NodeName(volumetesting.FailDetachNode)
   726  	nodeName2 := k8stypes.NodeName("node-name2")
   727  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   728  	dsw.AddNode(nodeName2, false /*keepTerminatedPodVolumes*/)
   729  
   730  	// Act
   731  	logger, ctx := ktesting.NewTestContext(t)
   732  	ctx, cancel := context.WithCancel(ctx)
   733  	defer cancel()
   734  	go reconciler.Run(ctx)
   735  
   736  	// Add the pod in which the volume is attached to the FailDetachNode
   737  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   738  	if podAddErr != nil {
   739  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   740  	}
   741  
   742  	// Volume is added to asw, volume should be reported as attached to the node.
   743  	waitForVolumeAddedToNode(t, generatedVolumeName, nodeName1, asw)
   744  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   745  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, true, asw, volumeAttachedCheckTimeout)
   746  
   747  	// Delete the pod, but detach will fail
   748  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   749  
   750  	// The first detach will be triggered after at least 50ms (maxWaitForUnmountDuration in test).
   751  	// Right before detach operation is performed, the volume will be first removed from being reported
   752  	// as attached on node status (RemoveVolumeFromReportAsAttached). After detach operation which is expected to fail,
   753  	// controller then treats the attachment as Uncertain.
   754  	// Here it sleeps 100ms so that detach should be triggered already at this point.
   755  	time.Sleep(100 * time.Millisecond)
   756  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateUncertain, asw)
   757  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, false, asw, volumeAttachedCheckTimeout)
   758  
   759  	// Add a second pod which tries to attach the volume to the same node.
   760  	// After adding pod to the same node, detach will not be triggered any more,
   761  	// the volume gets attached and reported as attached to the node.
   762  	generatedVolumeName, podAddErr = dsw.AddPod(types.UniquePodName(podName2), controllervolumetesting.NewPod(podName2, podName2), volumeSpec, nodeName1)
   763  	if podAddErr != nil {
   764  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   765  	}
   766  	// Sleep 1s to verify no detach are triggered after second pod is added in the future.
   767  	time.Sleep(1000 * time.Millisecond)
   768  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   769  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, true, asw, volumeAttachedCheckTimeout)
   770  	// verifyVolumeNoStatusUpdateNeeded(t, logger, generatedVolumeName, nodeName1, asw)
   771  
   772  	// Add a third pod which tries to attach the volume to a different node.
   773  	// At this point, volume is still attached to first node. There are no status update for both nodes.
   774  	generatedVolumeName, podAddErr = dsw.AddPod(types.UniquePodName(podName3), controllervolumetesting.NewPod(podName3, podName3), volumeSpec, nodeName2)
   775  	if podAddErr != nil {
   776  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   777  	}
   778  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateAttached, asw)
   779  	verifyVolumeNoStatusUpdateNeeded(t, logger, generatedVolumeName, nodeName1, asw)
   780  	verifyVolumeNoStatusUpdateNeeded(t, logger, generatedVolumeName, nodeName2, asw)
   781  }
   782  
   783  // Creates a volume with accessMode ReadWriteOnce
   784  // First create a pod which will try to attach the volume to the a node named "timeout-node". The attach call for this node will
   785  // fail for timeout, but the volume will be actually attached to the node after the call.
   786  // Secondly, delete the this pod.
   787  // Lastly, create a pod scheduled to a normal node which will trigger attach volume to the node. The attach should return successfully.
   788  func Test_Run_OneVolumeAttachAndDetachTimeoutNodesWithReadWriteOnce(t *testing.T) {
   789  	// Arrange
   790  	volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
   791  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   792  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   793  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   794  	fakeRecorder := &record.FakeRecorder{}
   795  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   796  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   797  		fakeKubeClient,
   798  		volumePluginMgr,
   799  		fakeRecorder,
   800  		fakeHandler))
   801  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   802  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   803  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   804  	reconciler := NewReconciler(
   805  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
   806  	podName1 := "pod-uid1"
   807  	podName2 := "pod-uid2"
   808  	volumeName := v1.UniqueVolumeName("volume-name")
   809  	volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
   810  	volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
   811  	nodeName1 := k8stypes.NodeName(volumetesting.TimeoutAttachNode)
   812  	nodeName2 := k8stypes.NodeName("node-name2")
   813  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   814  	dsw.AddNode(nodeName2, false /*keepTerminatedPodVolumes*/)
   815  
   816  	// Act
   817  	logger, ctx := ktesting.NewTestContext(t)
   818  	ctx, cancel := context.WithCancel(ctx)
   819  	defer cancel()
   820  	go reconciler.Run(ctx)
   821  
   822  	// Add the pod in which the volume is attached to the timeout node
   823  	generatedVolumeName, podAddErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1, podName1), volumeSpec, nodeName1)
   824  	if podAddErr != nil {
   825  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   826  	}
   827  
   828  	// Volume is added to asw. Because attach operation fails, volume should not be reported as attached to the node.
   829  	waitForVolumeAddedToNode(t, generatedVolumeName, nodeName1, asw)
   830  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName1, cache.AttachStateUncertain, asw)
   831  	verifyVolumeReportedAsAttachedToNode(t, logger, generatedVolumeName, nodeName1, false, asw, volumeAttachedCheckTimeout)
   832  
   833  	// When volume is added to the node, it is set to mounted by default. Then the status will be updated by checking node status VolumeInUse.
   834  	// Without this, the delete operation will be delayed due to mounted status
   835  	asw.SetVolumeMountedByNode(logger, generatedVolumeName, nodeName1, false /* mounted */)
   836  
   837  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   838  
   839  	waitForVolumeRemovedFromNode(t, generatedVolumeName, nodeName1, asw)
   840  
   841  	// Add a second pod which tries to attach the volume to a different node.
   842  	generatedVolumeName, podAddErr = dsw.AddPod(types.UniquePodName(podName2), controllervolumetesting.NewPod(podName2, podName2), volumeSpec, nodeName2)
   843  	if podAddErr != nil {
   844  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podAddErr)
   845  	}
   846  	waitForVolumeAttachedToNode(t, generatedVolumeName, nodeName2, asw)
   847  	verifyVolumeAttachedToNode(t, generatedVolumeName, nodeName2, cache.AttachStateAttached, asw)
   848  
   849  }
   850  
   851  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
   852  // The node has node.kubernetes.io/out-of-service taint present.
   853  //
   854  // The maxWaitForUnmountDuration is longer (in this case it is 4200 * time.Second so that detach does not happen
   855  // immediately due to timeout.
   856  //
   857  // Calls Run()
   858  // Verifies there is one attach call and no detach calls.
   859  // Deletes the pod from desiredStateOfWorld cache without first marking the node/volume as unmounted.
   860  // Verifies there is one detach call and no (new) attach calls.
   861  func Test_Run_OneVolumeDetachOnOutOfServiceTaintedNode(t *testing.T) {
   862  	registerMetrics.Do(func() {
   863  		legacyregistry.MustRegister(metrics.ForceDetachMetricCounter)
   864  	})
   865  	// Arrange
   866  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   867  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   868  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   869  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   870  	fakeRecorder := &record.FakeRecorder{}
   871  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   872  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   873  		fakeKubeClient,
   874  		volumePluginMgr,
   875  		fakeRecorder,
   876  		fakeHandler))
   877  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   878  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   879  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   880  	reconciler := NewReconciler(
   881  		reconcilerLoopPeriod, maxLongWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad,
   882  		nsu, nodeLister, fakeRecorder)
   883  	podName1 := "pod-uid1"
   884  	volumeName1 := v1.UniqueVolumeName("volume-name1")
   885  	volumeSpec1 := controllervolumetesting.GetTestVolumeSpec(string(volumeName1), volumeName1)
   886  	nodeName1 := k8stypes.NodeName("worker-0")
   887  	node1 := &v1.Node{
   888  		ObjectMeta: metav1.ObjectMeta{Name: string(nodeName1)},
   889  		Spec: v1.NodeSpec{
   890  			Taints: []v1.Taint{{Key: v1.TaintNodeOutOfService, Effect: v1.TaintEffectNoExecute}},
   891  		},
   892  	}
   893  	informerFactory.Core().V1().Nodes().Informer().GetStore().Add(node1)
   894  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   895  	volumeExists := dsw.VolumeExists(volumeName1, nodeName1)
   896  	if volumeExists {
   897  		t.Fatalf(
   898  			"Volume %q/node %q should not exist, but it does.",
   899  			volumeName1,
   900  			nodeName1)
   901  	}
   902  
   903  	generatedVolumeName, podErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1,
   904  		podName1), volumeSpec1, nodeName1)
   905  	if podErr != nil {
   906  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podErr)
   907  	}
   908  
   909  	// Act
   910  	_, ctx := ktesting.NewTestContext(t)
   911  	ctx, cancel := context.WithCancel(ctx)
   912  	defer cancel()
   913  	go reconciler.Run(ctx)
   914  
   915  	// Assert
   916  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   917  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   918  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   919  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
   920  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
   921  
   922  	// Delete the pod and the volume will be detached only after the maxLongWaitForUnmountDuration expires as volume is
   923  	//not unmounted. Here maxLongWaitForUnmountDuration is used to mimic that node is out of service.
   924  	// But in this case the node has the node.kubernetes.io/out-of-service taint and hence it will not wait for
   925  	// maxLongWaitForUnmountDuration and will progress to detach immediately.
   926  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
   927  	// Assert -- Detach will be triggered if node has out of service taint
   928  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   929  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   930  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
   931  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
   932  	waitForDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
   933  
   934  	// Force detach metric due to out-of-service taint
   935  	testForceDetachMetric(t, 1, metrics.ForceDetachReasonOutOfService)
   936  }
   937  
   938  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
   939  // The node does not have the node.kubernetes.io/out-of-service taint present.
   940  //
   941  // The maxWaitForUnmountDuration is longer (in this case it is 4200 * time.Second so that detach does not happen
   942  // immediately due to timeout.
   943  //
   944  // Calls Run()
   945  // Verifies there is one attach call and no detach calls.
   946  // Deletes the pod from desiredStateOfWorld cache without first marking the node/volume as unmounted.
   947  // Verifies there is no detach call and no (new) attach calls.
   948  func Test_Run_OneVolumeDetachOnNoOutOfServiceTaintedNode(t *testing.T) {
   949  	// Arrange
   950  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
   951  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
   952  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
   953  	fakeKubeClient := controllervolumetesting.CreateTestClient()
   954  	fakeRecorder := &record.FakeRecorder{}
   955  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
   956  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
   957  		fakeKubeClient,
   958  		volumePluginMgr,
   959  		fakeRecorder,
   960  		fakeHandler))
   961  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
   962  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
   963  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
   964  	reconciler := NewReconciler(
   965  		reconcilerLoopPeriod, maxLongWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad,
   966  		nsu, nodeLister, fakeRecorder)
   967  	podName1 := "pod-uid1"
   968  	volumeName1 := v1.UniqueVolumeName("volume-name1")
   969  	volumeSpec1 := controllervolumetesting.GetTestVolumeSpec(string(volumeName1), volumeName1)
   970  	nodeName1 := k8stypes.NodeName("worker-0")
   971  	node1 := &v1.Node{
   972  		ObjectMeta: metav1.ObjectMeta{Name: string(nodeName1)},
   973  	}
   974  	informerFactory.Core().V1().Nodes().Informer().GetStore().Add(node1)
   975  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
   976  	volumeExists := dsw.VolumeExists(volumeName1, nodeName1)
   977  	if volumeExists {
   978  		t.Fatalf(
   979  			"Volume %q/node %q should not exist, but it does.",
   980  			volumeName1,
   981  			nodeName1)
   982  	}
   983  
   984  	generatedVolumeName, podErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1,
   985  		podName1), volumeSpec1, nodeName1)
   986  	if podErr != nil {
   987  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podErr)
   988  	}
   989  
   990  	// Act
   991  	_, ctx := ktesting.NewTestContext(t)
   992  	ctx, cancel := context.WithCancel(ctx)
   993  	defer cancel()
   994  	go reconciler.Run(ctx)
   995  
   996  	// Assert
   997  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
   998  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
   999  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
  1000  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
  1001  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
  1002  
  1003  	// Delete the pod and the volume will be detached only after the maxLongWaitForUnmountDuration expires as volume is
  1004  	// not unmounted. Here maxLongWaitForUnmountDuration is used to mimic that node is out of service.
  1005  	// But in this case the node does not have the node.kubernetes.io/out-of-service taint and hence it will wait for
  1006  	// maxLongWaitForUnmountDuration and will not be detached immediately.
  1007  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
  1008  	// Assert -- Detach will be triggered only after maxLongWaitForUnmountDuration expires
  1009  	waitForNewDetacherCallCount(t, 0 /* expectedCallCount */, fakePlugin)
  1010  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
  1011  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
  1012  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
  1013  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
  1014  }
  1015  
  1016  // Populates desiredStateOfWorld cache with one node/volume/pod tuple.
  1017  // The node starts as healthy.
  1018  //
  1019  // Calls Run()
  1020  // Verifies there is one attach call and no detach calls.
  1021  // Deletes the pod from desiredStateOfWorld cache without first marking the node/volume as unmounted.
  1022  // Verifies that the volume is NOT detached after maxWaitForUnmountDuration.
  1023  // Marks the node as unhealthy.
  1024  // Verifies that the volume is detached after maxWaitForUnmountDuration.
  1025  func Test_Run_OneVolumeDetachOnUnhealthyNode(t *testing.T) {
  1026  	// Arrange
  1027  	volumePluginMgr, fakePlugin := volumetesting.GetTestVolumePluginMgr(t)
  1028  	dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
  1029  	asw := cache.NewActualStateOfWorld(volumePluginMgr)
  1030  	fakeKubeClient := controllervolumetesting.CreateTestClient()
  1031  	fakeRecorder := &record.FakeRecorder{}
  1032  	fakeHandler := volumetesting.NewBlockVolumePathHandler()
  1033  	ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
  1034  		fakeKubeClient,
  1035  		volumePluginMgr,
  1036  		fakeRecorder,
  1037  		fakeHandler))
  1038  	informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
  1039  	nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
  1040  	nodeLister := informerFactory.Core().V1().Nodes().Lister()
  1041  	reconciler := NewReconciler(
  1042  		reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad,
  1043  		nsu, nodeLister, fakeRecorder)
  1044  	podName1 := "pod-uid1"
  1045  	volumeName1 := v1.UniqueVolumeName("volume-name1")
  1046  	volumeSpec1 := controllervolumetesting.GetTestVolumeSpec(string(volumeName1), volumeName1)
  1047  	nodeName1 := k8stypes.NodeName("worker-0")
  1048  	node1 := &v1.Node{
  1049  		ObjectMeta: metav1.ObjectMeta{Name: string(nodeName1)},
  1050  		Status: v1.NodeStatus{
  1051  			Conditions: []v1.NodeCondition{
  1052  				{
  1053  					Type:   v1.NodeReady,
  1054  					Status: v1.ConditionTrue,
  1055  				},
  1056  			},
  1057  		},
  1058  	}
  1059  	informerFactory.Core().V1().Nodes().Informer().GetStore().Add(node1)
  1060  	dsw.AddNode(nodeName1, false /*keepTerminatedPodVolumes*/)
  1061  	volumeExists := dsw.VolumeExists(volumeName1, nodeName1)
  1062  	if volumeExists {
  1063  		t.Fatalf(
  1064  			"Volume %q/node %q should not exist, but it does.",
  1065  			volumeName1,
  1066  			nodeName1)
  1067  	}
  1068  
  1069  	generatedVolumeName, podErr := dsw.AddPod(types.UniquePodName(podName1), controllervolumetesting.NewPod(podName1,
  1070  		podName1), volumeSpec1, nodeName1)
  1071  	if podErr != nil {
  1072  		t.Fatalf("AddPod failed. Expected: <no error> Actual: <%v>", podErr)
  1073  	}
  1074  
  1075  	// Act
  1076  	_, ctx := ktesting.NewTestContext(t)
  1077  	ctx, cancel := context.WithCancel(ctx)
  1078  	defer cancel()
  1079  	go reconciler.Run(ctx)
  1080  
  1081  	// Assert
  1082  	waitForNewAttacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
  1083  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
  1084  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
  1085  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
  1086  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
  1087  
  1088  	// Act
  1089  	// Delete the pod and the volume will be detached even after the maxWaitForUnmountDuration expires as volume is
  1090  	// not unmounted and the node is healthy.
  1091  	dsw.DeletePod(types.UniquePodName(podName1), generatedVolumeName, nodeName1)
  1092  	time.Sleep(maxWaitForUnmountDuration * 5)
  1093  	// Assert
  1094  	waitForNewDetacherCallCount(t, 0 /* expectedCallCount */, fakePlugin)
  1095  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
  1096  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
  1097  	verifyNewDetacherCallCount(t, true /* expectZeroNewDetacherCallCount */, fakePlugin)
  1098  	waitForDetachCallCount(t, 0 /* expectedDetachCallCount */, fakePlugin)
  1099  
  1100  	// Act
  1101  	// Mark the node unhealthy
  1102  	node2 := node1.DeepCopy()
  1103  	node2.Status.Conditions[0].Status = v1.ConditionFalse
  1104  	informerFactory.Core().V1().Nodes().Informer().GetStore().Update(node2)
  1105  	// Assert -- Detach was triggered after maxWaitForUnmountDuration
  1106  	waitForNewDetacherCallCount(t, 1 /* expectedCallCount */, fakePlugin)
  1107  	verifyNewAttacherCallCount(t, false /* expectZeroNewAttacherCallCount */, fakePlugin)
  1108  	waitForAttachCallCount(t, 1 /* expectedAttachCallCount */, fakePlugin)
  1109  	verifyNewDetacherCallCount(t, false /* expectZeroNewDetacherCallCount */, fakePlugin)
  1110  	waitForDetachCallCount(t, 1 /* expectedDetachCallCount */, fakePlugin)
  1111  }
  1112  
  1113  func Test_ReportMultiAttachError(t *testing.T) {
  1114  	type nodeWithPods struct {
  1115  		name     k8stypes.NodeName
  1116  		podNames []string
  1117  	}
  1118  	tests := []struct {
  1119  		name           string
  1120  		nodes          []nodeWithPods
  1121  		expectedEvents []string
  1122  	}{
  1123  		{
  1124  			"no pods use the volume",
  1125  			[]nodeWithPods{
  1126  				{"node1", []string{"ns1/pod1"}},
  1127  			},
  1128  			[]string{"Warning FailedAttachVolume Multi-Attach error for volume \"volume-name\" Volume is already exclusively attached to one node and can't be attached to another"},
  1129  		},
  1130  		{
  1131  			"pods in the same namespace use the volume",
  1132  			[]nodeWithPods{
  1133  				{"node1", []string{"ns1/pod1"}},
  1134  				{"node2", []string{"ns1/pod2"}},
  1135  			},
  1136  			[]string{"Warning FailedAttachVolume Multi-Attach error for volume \"volume-name\" Volume is already used by pod(s) pod2"},
  1137  		},
  1138  		{
  1139  			"pods in another namespace use the volume",
  1140  			[]nodeWithPods{
  1141  				{"node1", []string{"ns1/pod1"}},
  1142  				{"node2", []string{"ns2/pod2"}},
  1143  			},
  1144  			[]string{"Warning FailedAttachVolume Multi-Attach error for volume \"volume-name\" Volume is already used by 1 pod(s) in different namespaces"},
  1145  		},
  1146  		{
  1147  			"pods both in the same and another namespace use the volume",
  1148  			[]nodeWithPods{
  1149  				{"node1", []string{"ns1/pod1"}},
  1150  				{"node2", []string{"ns2/pod2"}},
  1151  				{"node3", []string{"ns1/pod3"}},
  1152  			},
  1153  			[]string{"Warning FailedAttachVolume Multi-Attach error for volume \"volume-name\" Volume is already used by pod(s) pod3 and 1 pod(s) in different namespaces"},
  1154  		},
  1155  	}
  1156  
  1157  	for _, test := range tests {
  1158  		// Arrange
  1159  		t.Logf("Test %q starting", test.name)
  1160  		volumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t)
  1161  		dsw := cache.NewDesiredStateOfWorld(volumePluginMgr)
  1162  		asw := cache.NewActualStateOfWorld(volumePluginMgr)
  1163  		fakeKubeClient := controllervolumetesting.CreateTestClient()
  1164  		fakeRecorder := record.NewFakeRecorder(100)
  1165  		fakeHandler := volumetesting.NewBlockVolumePathHandler()
  1166  		ad := operationexecutor.NewOperationExecutor(operationexecutor.NewOperationGenerator(
  1167  			fakeKubeClient,
  1168  			volumePluginMgr,
  1169  			fakeRecorder,
  1170  			fakeHandler))
  1171  		informerFactory := informers.NewSharedInformerFactory(fakeKubeClient, controller.NoResyncPeriodFunc())
  1172  		nodeLister := informerFactory.Core().V1().Nodes().Lister()
  1173  		nsu := statusupdater.NewFakeNodeStatusUpdater(false /* returnError */)
  1174  		rc := NewReconciler(
  1175  			reconcilerLoopPeriod, maxWaitForUnmountDuration, syncLoopPeriod, false, dsw, asw, ad, nsu, nodeLister, fakeRecorder)
  1176  
  1177  		nodes := []k8stypes.NodeName{}
  1178  		for _, n := range test.nodes {
  1179  			dsw.AddNode(n.name, false /*keepTerminatedPodVolumes*/)
  1180  			nodes = append(nodes, n.name)
  1181  			for _, podName := range n.podNames {
  1182  				volumeName := v1.UniqueVolumeName("volume-name")
  1183  				volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName)
  1184  				volumeSpec.PersistentVolume.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}
  1185  				uid := string(n.name) + "-" + podName // unique UID
  1186  				namespace, name := utilstrings.SplitQualifiedName(podName)
  1187  				pod := controllervolumetesting.NewPod(uid, name)
  1188  				pod.Namespace = namespace
  1189  				_, err := dsw.AddPod(types.UniquePodName(uid), pod, volumeSpec, n.name)
  1190  				if err != nil {
  1191  					t.Fatalf("Error adding pod %s to DSW: %s", podName, err)
  1192  				}
  1193  			}
  1194  		}
  1195  		// Act
  1196  		logger, _ := ktesting.NewTestContext(t)
  1197  		volumes := dsw.GetVolumesToAttach()
  1198  		for _, vol := range volumes {
  1199  			if vol.NodeName == "node1" {
  1200  				rc.(*reconciler).reportMultiAttachError(logger, vol, nodes)
  1201  			}
  1202  		}
  1203  
  1204  		// Assert
  1205  		close(fakeRecorder.Events)
  1206  		index := 0
  1207  		for event := range fakeRecorder.Events {
  1208  			if len(test.expectedEvents) < index {
  1209  				t.Errorf("Test %q: unexpected event received: %s", test.name, event)
  1210  			} else {
  1211  				expectedEvent := test.expectedEvents[index]
  1212  				if expectedEvent != event {
  1213  					t.Errorf("Test %q: event %d: expected %q, got %q", test.name, index, expectedEvent, event)
  1214  				}
  1215  			}
  1216  			index++
  1217  		}
  1218  		for i := index; i < len(test.expectedEvents); i++ {
  1219  			t.Errorf("Test %q: event %d: expected %q, got none", test.name, i, test.expectedEvents[i])
  1220  		}
  1221  	}
  1222  }
  1223  
  1224  func waitForMultiAttachErrorOnNode(
  1225  	t *testing.T,
  1226  	attachedNode k8stypes.NodeName,
  1227  	dsow cache.DesiredStateOfWorld) {
  1228  	multAttachCheckFunc := func() (bool, error) {
  1229  		for _, volumeToAttach := range dsow.GetVolumesToAttach() {
  1230  			if volumeToAttach.NodeName != attachedNode {
  1231  				if volumeToAttach.MultiAttachErrorReported {
  1232  					return true, nil
  1233  				}
  1234  			}
  1235  		}
  1236  		t.Logf("Warning: MultiAttach error not yet set on Node. Will retry.")
  1237  		return false, nil
  1238  	}
  1239  
  1240  	err := retryWithExponentialBackOff(100*time.Millisecond, multAttachCheckFunc)
  1241  	if err != nil {
  1242  		t.Fatalf("Timed out waiting for MultiAttach Error to be set on non-attached node")
  1243  	}
  1244  }
  1245  
  1246  func waitForNewAttacherCallCount(
  1247  	t *testing.T,
  1248  	expectedCallCount int,
  1249  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1250  	err := retryWithExponentialBackOff(
  1251  		time.Duration(5*time.Millisecond),
  1252  		func() (bool, error) {
  1253  			actualCallCount := fakePlugin.GetNewAttacherCallCount()
  1254  			if actualCallCount >= expectedCallCount {
  1255  				return true, nil
  1256  			}
  1257  			t.Logf(
  1258  				"Warning: Wrong NewAttacherCallCount. Expected: <%v> Actual: <%v>. Will retry.",
  1259  				expectedCallCount,
  1260  				actualCallCount)
  1261  			return false, nil
  1262  		},
  1263  	)
  1264  
  1265  	if err != nil {
  1266  		t.Fatalf(
  1267  			"Timed out waiting for NewAttacherCallCount. Expected: <%v> Actual: <%v>",
  1268  			expectedCallCount,
  1269  			fakePlugin.GetNewAttacherCallCount())
  1270  	}
  1271  }
  1272  
  1273  func waitForNewDetacherCallCount(
  1274  	t *testing.T,
  1275  	expectedCallCount int,
  1276  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1277  	err := retryWithExponentialBackOff(
  1278  		time.Duration(5*time.Millisecond),
  1279  		func() (bool, error) {
  1280  			actualCallCount := fakePlugin.GetNewDetacherCallCount()
  1281  			if actualCallCount >= expectedCallCount {
  1282  				return true, nil
  1283  			}
  1284  			t.Logf(
  1285  				"Warning: Wrong NewDetacherCallCount. Expected: <%v> Actual: <%v>. Will retry.",
  1286  				expectedCallCount,
  1287  				actualCallCount)
  1288  			return false, nil
  1289  		},
  1290  	)
  1291  
  1292  	if err != nil {
  1293  		t.Fatalf(
  1294  			"Timed out waiting for NewDetacherCallCount. Expected: <%v> Actual: <%v>",
  1295  			expectedCallCount,
  1296  			fakePlugin.GetNewDetacherCallCount())
  1297  	}
  1298  }
  1299  
  1300  func waitForAttachCallCount(
  1301  	t *testing.T,
  1302  	expectedAttachCallCount int,
  1303  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1304  	if len(fakePlugin.GetAttachers()) == 0 && expectedAttachCallCount == 0 {
  1305  		return
  1306  	}
  1307  
  1308  	err := retryWithExponentialBackOff(
  1309  		time.Duration(5*time.Millisecond),
  1310  		func() (bool, error) {
  1311  			for i, attacher := range fakePlugin.GetAttachers() {
  1312  				actualCallCount := attacher.GetAttachCallCount()
  1313  				if actualCallCount == expectedAttachCallCount {
  1314  					return true, nil
  1315  				}
  1316  				t.Logf(
  1317  					"Warning: Wrong attacher[%v].GetAttachCallCount(). Expected: <%v> Actual: <%v>. Will try next attacher.",
  1318  					i,
  1319  					expectedAttachCallCount,
  1320  					actualCallCount)
  1321  			}
  1322  
  1323  			t.Logf(
  1324  				"Warning: No attachers have expected AttachCallCount. Expected: <%v>. Will retry.",
  1325  				expectedAttachCallCount)
  1326  			return false, nil
  1327  		},
  1328  	)
  1329  
  1330  	if err != nil {
  1331  		t.Fatalf(
  1332  			"No attachers have expected AttachCallCount. Expected: <%v>",
  1333  			expectedAttachCallCount)
  1334  	}
  1335  }
  1336  
  1337  func waitForTotalAttachCallCount(
  1338  	t *testing.T,
  1339  	expectedAttachCallCount int,
  1340  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1341  	if len(fakePlugin.GetAttachers()) == 0 && expectedAttachCallCount == 0 {
  1342  		return
  1343  	}
  1344  
  1345  	err := retryWithExponentialBackOff(
  1346  		time.Duration(5*time.Millisecond),
  1347  		func() (bool, error) {
  1348  			totalCount := 0
  1349  			for _, attacher := range fakePlugin.GetAttachers() {
  1350  				totalCount += attacher.GetAttachCallCount()
  1351  			}
  1352  			if totalCount == expectedAttachCallCount {
  1353  				return true, nil
  1354  			}
  1355  			t.Logf(
  1356  				"Warning: Wrong total GetAttachCallCount(). Expected: <%v> Actual: <%v>. Will retry.",
  1357  				expectedAttachCallCount,
  1358  				totalCount)
  1359  
  1360  			return false, nil
  1361  		},
  1362  	)
  1363  
  1364  	if err != nil {
  1365  		t.Fatalf(
  1366  			"Total AttachCallCount does not match expected value. Expected: <%v>",
  1367  			expectedAttachCallCount)
  1368  	}
  1369  }
  1370  
  1371  func waitForDetachCallCount(
  1372  	t *testing.T,
  1373  	expectedDetachCallCount int,
  1374  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1375  	if len(fakePlugin.GetDetachers()) == 0 && expectedDetachCallCount == 0 {
  1376  		return
  1377  	}
  1378  
  1379  	err := retryWithExponentialBackOff(
  1380  		time.Duration(5*time.Millisecond),
  1381  		func() (bool, error) {
  1382  			for i, detacher := range fakePlugin.GetDetachers() {
  1383  				actualCallCount := detacher.GetDetachCallCount()
  1384  				if actualCallCount == expectedDetachCallCount {
  1385  					return true, nil
  1386  				}
  1387  				t.Logf(
  1388  					"Wrong detacher[%v].GetDetachCallCount(). Expected: <%v> Actual: <%v>. Will try next detacher.",
  1389  					i,
  1390  					expectedDetachCallCount,
  1391  					actualCallCount)
  1392  			}
  1393  
  1394  			t.Logf(
  1395  				"Warning: No detachers have expected DetachCallCount. Expected: <%v>. Will retry.",
  1396  				expectedDetachCallCount)
  1397  			return false, nil
  1398  		},
  1399  	)
  1400  
  1401  	if err != nil {
  1402  		t.Fatalf(
  1403  			"No detachers have expected DetachCallCount. Expected: <%v>",
  1404  			expectedDetachCallCount)
  1405  	}
  1406  }
  1407  
  1408  func waitForTotalDetachCallCount(
  1409  	t *testing.T,
  1410  	expectedDetachCallCount int,
  1411  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1412  	if len(fakePlugin.GetDetachers()) == 0 && expectedDetachCallCount == 0 {
  1413  		return
  1414  	}
  1415  
  1416  	err := retryWithExponentialBackOff(
  1417  		time.Duration(5*time.Millisecond),
  1418  		func() (bool, error) {
  1419  			totalCount := 0
  1420  			for _, detacher := range fakePlugin.GetDetachers() {
  1421  				totalCount += detacher.GetDetachCallCount()
  1422  			}
  1423  			if totalCount == expectedDetachCallCount {
  1424  				return true, nil
  1425  			}
  1426  			t.Logf(
  1427  				"Warning: Wrong total GetDetachCallCount(). Expected: <%v> Actual: <%v>. Will retry.",
  1428  				expectedDetachCallCount,
  1429  				totalCount)
  1430  
  1431  			return false, nil
  1432  		},
  1433  	)
  1434  
  1435  	if err != nil {
  1436  		t.Fatalf(
  1437  			"Total DetachCallCount does not match expected value. Expected: <%v>",
  1438  			expectedDetachCallCount)
  1439  	}
  1440  }
  1441  
  1442  func waitForAttachedToNodesCount(
  1443  	t *testing.T,
  1444  	expectedNodeCount int,
  1445  	volumeName v1.UniqueVolumeName,
  1446  	asw cache.ActualStateOfWorld) {
  1447  
  1448  	err := retryWithExponentialBackOff(
  1449  		time.Duration(5*time.Millisecond),
  1450  		func() (bool, error) {
  1451  			count := len(asw.GetNodesForAttachedVolume(volumeName))
  1452  			if count == expectedNodeCount {
  1453  				return true, nil
  1454  			}
  1455  			t.Logf(
  1456  				"Warning: Wrong number of nodes having <%v> attached. Expected: <%v> Actual: <%v>. Will retry.",
  1457  				volumeName,
  1458  				expectedNodeCount,
  1459  				count)
  1460  
  1461  			return false, nil
  1462  		},
  1463  	)
  1464  
  1465  	if err != nil {
  1466  		count := len(asw.GetNodesForAttachedVolume(volumeName))
  1467  		t.Fatalf(
  1468  			"Wrong number of nodes having <%v> attached. Expected: <%v> Actual: <%v>",
  1469  			volumeName,
  1470  			expectedNodeCount,
  1471  			count)
  1472  	}
  1473  }
  1474  
  1475  func verifyNewAttacherCallCount(
  1476  	t *testing.T,
  1477  	expectZeroNewAttacherCallCount bool,
  1478  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1479  
  1480  	if expectZeroNewAttacherCallCount &&
  1481  		fakePlugin.GetNewAttacherCallCount() != 0 {
  1482  		t.Fatalf(
  1483  			"Wrong NewAttacherCallCount. Expected: <0> Actual: <%v>",
  1484  			fakePlugin.GetNewAttacherCallCount())
  1485  	}
  1486  }
  1487  
  1488  func waitForVolumeAttachedToNode(
  1489  	t *testing.T,
  1490  	volumeName v1.UniqueVolumeName,
  1491  	nodeName k8stypes.NodeName,
  1492  	asw cache.ActualStateOfWorld) {
  1493  
  1494  	err := retryWithExponentialBackOff(
  1495  		time.Duration(500*time.Millisecond),
  1496  		func() (bool, error) {
  1497  			attachState := asw.GetAttachState(volumeName, nodeName)
  1498  			if attachState == cache.AttachStateAttached {
  1499  				return true, nil
  1500  			}
  1501  			t.Logf(
  1502  				"Warning: Volume <%v> is not attached to node  <%v> yet. Will retry.",
  1503  				volumeName,
  1504  				nodeName)
  1505  
  1506  			return false, nil
  1507  		},
  1508  	)
  1509  
  1510  	attachState := asw.GetAttachState(volumeName, nodeName)
  1511  	if err != nil && attachState != cache.AttachStateAttached {
  1512  		t.Fatalf(
  1513  			"Volume <%v> is not attached to node  <%v>.",
  1514  			volumeName,
  1515  			nodeName)
  1516  	}
  1517  }
  1518  
  1519  func waitForVolumeAddedToNode(
  1520  	t *testing.T,
  1521  	volumeName v1.UniqueVolumeName,
  1522  	nodeName k8stypes.NodeName,
  1523  	asw cache.ActualStateOfWorld) {
  1524  
  1525  	err := retryWithExponentialBackOff(
  1526  		time.Duration(500*time.Millisecond),
  1527  		func() (bool, error) {
  1528  			volumes := asw.GetAttachedVolumes()
  1529  			for _, volume := range volumes {
  1530  				if volume.VolumeName == volumeName && volume.NodeName == nodeName {
  1531  					return true, nil
  1532  				}
  1533  			}
  1534  			t.Logf(
  1535  				"Warning: Volume <%v> is not added to node  <%v> yet. Will retry.",
  1536  				volumeName,
  1537  				nodeName)
  1538  
  1539  			return false, nil
  1540  		},
  1541  	)
  1542  
  1543  	if err != nil {
  1544  		t.Fatalf(
  1545  			"Volume <%v> is not added to node  <%v>. %v",
  1546  			volumeName,
  1547  			nodeName, err)
  1548  	}
  1549  }
  1550  
  1551  func waitForVolumeRemovedFromNode(
  1552  	t *testing.T,
  1553  	volumeName v1.UniqueVolumeName,
  1554  	nodeName k8stypes.NodeName,
  1555  	asw cache.ActualStateOfWorld) {
  1556  
  1557  	err := retryWithExponentialBackOff(
  1558  		time.Duration(500*time.Millisecond),
  1559  		func() (bool, error) {
  1560  			volumes := asw.GetAttachedVolumes()
  1561  			exist := false
  1562  			for _, volume := range volumes {
  1563  				if volume.VolumeName == volumeName && volume.NodeName == nodeName {
  1564  					exist = true
  1565  				}
  1566  			}
  1567  			if exist {
  1568  				t.Logf(
  1569  					"Warning: Volume <%v> is not removed from the node  <%v> yet. Will retry.",
  1570  					volumeName,
  1571  					nodeName)
  1572  
  1573  				return false, nil
  1574  			}
  1575  			return true, nil
  1576  
  1577  		},
  1578  	)
  1579  
  1580  	if err != nil {
  1581  		t.Fatalf(
  1582  			"Volume <%v> is not removed from node  <%v>. %v",
  1583  			volumeName,
  1584  			nodeName, err)
  1585  	}
  1586  }
  1587  
  1588  func verifyVolumeAttachedToNode(
  1589  	t *testing.T,
  1590  	volumeName v1.UniqueVolumeName,
  1591  	nodeName k8stypes.NodeName,
  1592  	expectedAttachState cache.AttachState,
  1593  	asw cache.ActualStateOfWorld,
  1594  ) {
  1595  	attachState := asw.GetAttachState(volumeName, nodeName)
  1596  	if attachState != expectedAttachState {
  1597  		t.Fatalf("Check volume <%v> is attached to node <%v>, got %v, expected %v",
  1598  			volumeName,
  1599  			nodeName,
  1600  			attachState,
  1601  			expectedAttachState)
  1602  	}
  1603  	t.Logf("Volume <%v> is attached to node <%v>: %v", volumeName, nodeName, attachState)
  1604  }
  1605  
  1606  func verifyVolumeReportedAsAttachedToNode(
  1607  	t *testing.T,
  1608  	logger klog.Logger,
  1609  	volumeName v1.UniqueVolumeName,
  1610  	nodeName k8stypes.NodeName,
  1611  	isAttached bool,
  1612  	asw cache.ActualStateOfWorld,
  1613  	timeout time.Duration,
  1614  ) {
  1615  	var result bool
  1616  	var lastErr error
  1617  	err := wait.PollUntilContextTimeout(context.TODO(), 50*time.Millisecond, timeout, false, func(context.Context) (done bool, err error) {
  1618  		volumes := asw.GetVolumesToReportAttached(logger)
  1619  		for _, volume := range volumes[nodeName] {
  1620  			if volume.Name == volumeName {
  1621  				result = true
  1622  			}
  1623  		}
  1624  
  1625  		if result == isAttached {
  1626  			t.Logf("Volume <%v> is reported as attached to node <%v>: %v", volumeName, nodeName, result)
  1627  			return true, nil
  1628  		}
  1629  		lastErr = fmt.Errorf("Check volume <%v> is reported as attached to node <%v>, got %v, expected %v",
  1630  			volumeName,
  1631  			nodeName,
  1632  			result,
  1633  			isAttached)
  1634  		return false, nil
  1635  	})
  1636  	if err != nil {
  1637  		t.Fatalf("last error: %q, wait timeout: %q", lastErr, err.Error())
  1638  	}
  1639  
  1640  }
  1641  
  1642  func verifyVolumeNoStatusUpdateNeeded(
  1643  	t *testing.T,
  1644  	logger klog.Logger,
  1645  	volumeName v1.UniqueVolumeName,
  1646  	nodeName k8stypes.NodeName,
  1647  	asw cache.ActualStateOfWorld,
  1648  ) {
  1649  	volumes := asw.GetVolumesToReportAttached(logger)
  1650  	for _, volume := range volumes[nodeName] {
  1651  		if volume.Name == volumeName {
  1652  			t.Fatalf("Check volume <%v> is reported as need to update status on node <%v>, expected false",
  1653  				volumeName,
  1654  				nodeName)
  1655  		}
  1656  	}
  1657  	t.Logf("Volume <%v> is not reported as need to update status on node <%v>", volumeName, nodeName)
  1658  }
  1659  
  1660  func verifyNewDetacherCallCount(
  1661  	t *testing.T,
  1662  	expectZeroNewDetacherCallCount bool,
  1663  	fakePlugin *volumetesting.FakeVolumePlugin) {
  1664  
  1665  	if expectZeroNewDetacherCallCount &&
  1666  		fakePlugin.GetNewDetacherCallCount() != 0 {
  1667  		t.Fatalf("Wrong NewDetacherCallCount. Expected: <0> Actual: <%v>",
  1668  			fakePlugin.GetNewDetacherCallCount())
  1669  	}
  1670  }
  1671  
  1672  func retryWithExponentialBackOff(initialDuration time.Duration, fn wait.ConditionFunc) error {
  1673  	backoff := wait.Backoff{
  1674  		Duration: initialDuration,
  1675  		Factor:   3,
  1676  		Jitter:   0,
  1677  		Steps:    6,
  1678  	}
  1679  	return wait.ExponentialBackoff(backoff, fn)
  1680  }
  1681  
  1682  // verifies the force detach metric with reason
  1683  func testForceDetachMetric(t *testing.T, inputForceDetachMetricCounter int, reason string) {
  1684  	t.Helper()
  1685  
  1686  	actualForceDetachMericCounter, err := metricstestutil.GetCounterMetricValue(metrics.ForceDetachMetricCounter.WithLabelValues(reason))
  1687  	if err != nil {
  1688  		t.Errorf("Error getting actualForceDetachMericCounter")
  1689  	}
  1690  	if actualForceDetachMericCounter != float64(inputForceDetachMetricCounter) {
  1691  		t.Errorf("Expected desiredForceDetachMericCounter to be %d, got %v", inputForceDetachMetricCounter, actualForceDetachMericCounter)
  1692  	}
  1693  }