...

Source file src/k8s.io/kubernetes/pkg/kubelet/volumemanager/cache/actual_state_of_world_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/volumemanager/cache

     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 cache
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/api/resource"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    26  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    27  
    28  	"github.com/stretchr/testify/require"
    29  	v1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/klog/v2/ktesting"
    32  	"k8s.io/kubernetes/pkg/features"
    33  	"k8s.io/kubernetes/pkg/volume"
    34  	volumetesting "k8s.io/kubernetes/pkg/volume/testing"
    35  	"k8s.io/kubernetes/pkg/volume/util"
    36  	"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
    37  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    38  )
    39  
    40  var emptyVolumeName = v1.UniqueVolumeName("")
    41  
    42  // Calls MarkVolumeAsAttached() once to add volume
    43  // Verifies newly added volume exists in GetUnmountedVolumes()
    44  // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes()
    45  func Test_MarkVolumeAsAttached_Positive_NewVolume(t *testing.T) {
    46  	// Arrange
    47  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
    48  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
    49  	pod := &v1.Pod{
    50  		ObjectMeta: metav1.ObjectMeta{
    51  			Name: "pod1",
    52  			UID:  "pod1uid",
    53  		},
    54  		Spec: v1.PodSpec{
    55  			Volumes: []v1.Volume{
    56  				{
    57  					Name: "volume-name",
    58  					VolumeSource: v1.VolumeSource{
    59  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
    60  							PDName: "fake-device1",
    61  						},
    62  					},
    63  				},
    64  			},
    65  		},
    66  	}
    67  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
    68  	devicePath := "fake/device/path"
    69  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
    70  	if err != nil {
    71  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
    72  	}
    73  
    74  	// Act
    75  	logger, _ := ktesting.NewTestContext(t)
    76  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
    77  
    78  	// Assert
    79  	if err != nil {
    80  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
    81  	}
    82  
    83  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
    84  	verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw)
    85  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw)
    86  }
    87  
    88  // Calls MarkVolumeAsAttached() once to add volume, specifying a name --
    89  // establishes that the supplied volume name is used to register the volume
    90  // rather than the generated one.
    91  // Verifies newly added volume exists in GetUnmountedVolumes()
    92  // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes()
    93  func Test_MarkVolumeAsAttached_SuppliedVolumeName_Positive_NewVolume(t *testing.T) {
    94  	// Arrange
    95  	volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t)
    96  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
    97  	pod := &v1.Pod{
    98  		ObjectMeta: metav1.ObjectMeta{
    99  			Name: "pod1",
   100  			UID:  "pod1uid",
   101  		},
   102  		Spec: v1.PodSpec{
   103  			Volumes: []v1.Volume{
   104  				{
   105  					Name: "volume-name",
   106  					VolumeSource: v1.VolumeSource{
   107  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   108  							PDName: "fake-device1",
   109  						},
   110  					},
   111  				},
   112  			},
   113  		},
   114  	}
   115  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   116  	devicePath := "fake/device/path"
   117  	volumeName := v1.UniqueVolumeName("this-would-never-be-a-volume-name")
   118  
   119  	// Act
   120  	logger, _ := ktesting.NewTestContext(t)
   121  	err := asw.MarkVolumeAsAttached(logger, volumeName, volumeSpec, "" /* nodeName */, devicePath)
   122  
   123  	// Assert
   124  	if err != nil {
   125  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   126  	}
   127  
   128  	verifyVolumeExistsAsw(t, volumeName, true /* shouldExist */, asw)
   129  	verifyVolumeExistsInUnmountedVolumes(t, volumeName, asw)
   130  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, volumeName, asw)
   131  }
   132  
   133  // Calls MarkVolumeAsAttached() twice to add the same volume
   134  // Verifies second call doesn't fail
   135  // Verifies newly added volume exists in GetUnmountedVolumes()
   136  // Verifies newly added volume doesn't exist in GetGloballyMountedVolumes()
   137  func Test_MarkVolumeAsAttached_Positive_ExistingVolume(t *testing.T) {
   138  	// Arrange
   139  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   140  	devicePath := "fake/device/path"
   141  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   142  	pod := &v1.Pod{
   143  		ObjectMeta: metav1.ObjectMeta{
   144  			Name: "pod1",
   145  			UID:  "pod1uid",
   146  		},
   147  		Spec: v1.PodSpec{
   148  			Volumes: []v1.Volume{
   149  				{
   150  					Name: "volume-name",
   151  					VolumeSource: v1.VolumeSource{
   152  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   153  							PDName: "fake-device1",
   154  						},
   155  					},
   156  				},
   157  			},
   158  		},
   159  	}
   160  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   161  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   162  	if err != nil {
   163  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   164  	}
   165  	logger, _ := ktesting.NewTestContext(t)
   166  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   167  	if err != nil {
   168  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   169  	}
   170  
   171  	// Act
   172  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   173  
   174  	// Assert
   175  	if err != nil {
   176  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   177  	}
   178  
   179  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
   180  	verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw)
   181  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw)
   182  }
   183  
   184  // Populates data struct with a volume
   185  // Calls AddPodToVolume() to add a pod to the volume
   186  // Verifies volume/pod combo exist using PodExistsInVolume()
   187  func Test_AddPodToVolume_Positive_ExistingVolumeNewNode(t *testing.T) {
   188  	// Arrange
   189  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   190  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   191  	devicePath := "fake/device/path"
   192  
   193  	pod := &v1.Pod{
   194  		ObjectMeta: metav1.ObjectMeta{
   195  			Name: "pod1",
   196  			UID:  "pod1uid",
   197  		},
   198  		Spec: v1.PodSpec{
   199  			Volumes: []v1.Volume{
   200  				{
   201  					Name: "volume-name",
   202  					VolumeSource: v1.VolumeSource{
   203  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   204  							PDName: "fake-device1",
   205  						},
   206  					},
   207  				},
   208  			},
   209  		},
   210  	}
   211  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   212  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   213  	if err != nil {
   214  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   215  	}
   216  	logger, _ := ktesting.NewTestContext(t)
   217  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   218  	if err != nil {
   219  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   220  	}
   221  	podName := util.GetUniquePodName(pod)
   222  
   223  	mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{})
   224  	if err != nil {
   225  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   226  	}
   227  
   228  	mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{})
   229  	if err != nil {
   230  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   231  	}
   232  
   233  	// Act
   234  	markVolumeOpts := operationexecutor.MarkVolumeOpts{
   235  		PodName:             podName,
   236  		PodUID:              pod.UID,
   237  		VolumeName:          generatedVolumeName,
   238  		Mounter:             mounter,
   239  		BlockVolumeMapper:   mapper,
   240  		OuterVolumeSpecName: volumeSpec.Name(),
   241  		VolumeSpec:          volumeSpec,
   242  	}
   243  	err = asw.AddPodToVolume(markVolumeOpts)
   244  	// Assert
   245  	if err != nil {
   246  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   247  	}
   248  
   249  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
   250  	verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw)
   251  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw)
   252  	verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw)
   253  	verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw)
   254  	verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw)
   255  }
   256  
   257  // Populates data struct with a volume
   258  // Calls AddPodToVolume() twice to add the same pod to the volume
   259  // Verifies volume/pod combo exist using PodExistsInVolume() and the second call
   260  // did not fail.
   261  func Test_AddPodToVolume_Positive_ExistingVolumeExistingNode(t *testing.T) {
   262  	// Arrange
   263  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   264  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   265  	devicePath := "fake/device/path"
   266  
   267  	pod := &v1.Pod{
   268  		ObjectMeta: metav1.ObjectMeta{
   269  			Name: "pod1",
   270  			UID:  "pod1uid",
   271  		},
   272  		Spec: v1.PodSpec{
   273  			Volumes: []v1.Volume{
   274  				{
   275  					Name: "volume-name",
   276  					VolumeSource: v1.VolumeSource{
   277  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   278  							PDName: "fake-device1",
   279  						},
   280  					},
   281  				},
   282  			},
   283  		},
   284  	}
   285  
   286  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   287  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(
   288  		plugin, volumeSpec)
   289  	if err != nil {
   290  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   291  	}
   292  	logger, _ := ktesting.NewTestContext(t)
   293  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   294  	if err != nil {
   295  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   296  	}
   297  	podName := util.GetUniquePodName(pod)
   298  
   299  	mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{})
   300  	if err != nil {
   301  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   302  	}
   303  
   304  	mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{})
   305  	if err != nil {
   306  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   307  	}
   308  
   309  	markVolumeOpts := operationexecutor.MarkVolumeOpts{
   310  		PodName:             podName,
   311  		PodUID:              pod.UID,
   312  		VolumeName:          generatedVolumeName,
   313  		Mounter:             mounter,
   314  		BlockVolumeMapper:   mapper,
   315  		OuterVolumeSpecName: volumeSpec.Name(),
   316  		VolumeSpec:          volumeSpec,
   317  	}
   318  	err = asw.AddPodToVolume(markVolumeOpts)
   319  	if err != nil {
   320  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   321  	}
   322  
   323  	// Act
   324  	err = asw.AddPodToVolume(markVolumeOpts)
   325  	// Assert
   326  	if err != nil {
   327  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   328  	}
   329  
   330  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
   331  	verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw)
   332  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw)
   333  	verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw)
   334  	verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw)
   335  	verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw)
   336  }
   337  
   338  // Populates data struct with a volume
   339  // Calls AddPodToVolume() twice to add the same pod to the volume
   340  // Verifies volume/pod combo exist using PodExistsInVolume() and the second call
   341  // did not fail.
   342  func Test_AddTwoPodsToVolume_Positive(t *testing.T) {
   343  	// Arrange
   344  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   345  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   346  	devicePath := "fake/device/path"
   347  
   348  	pod1 := &v1.Pod{
   349  		ObjectMeta: metav1.ObjectMeta{
   350  			Name: "pod1",
   351  			UID:  "pod1uid",
   352  		},
   353  		Spec: v1.PodSpec{
   354  			Volumes: []v1.Volume{
   355  				{
   356  					Name: "volume-name-1",
   357  					VolumeSource: v1.VolumeSource{
   358  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   359  							PDName: "fake-device1",
   360  						},
   361  					},
   362  				},
   363  			},
   364  		},
   365  	}
   366  
   367  	pod2 := &v1.Pod{
   368  		ObjectMeta: metav1.ObjectMeta{
   369  			Name: "pod2",
   370  			UID:  "pod2uid",
   371  		},
   372  		Spec: v1.PodSpec{
   373  			Volumes: []v1.Volume{
   374  				{
   375  					Name: "volume-name-2",
   376  					VolumeSource: v1.VolumeSource{
   377  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   378  							PDName: "fake-device1",
   379  						},
   380  					},
   381  				},
   382  			},
   383  		},
   384  	}
   385  	volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]}
   386  	volumeSpec2 := &volume.Spec{Volume: &pod2.Spec.Volumes[0]}
   387  	generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec(
   388  		plugin, volumeSpec1)
   389  	require.NoError(t, err)
   390  	generatedVolumeName2, err := util.GetUniqueVolumeNameFromSpec(
   391  		plugin, volumeSpec2)
   392  	require.NoError(t, err)
   393  
   394  	if generatedVolumeName1 != generatedVolumeName2 {
   395  		t.Fatalf(
   396  			"Unique volume names should be the same. unique volume name 1: <%q> unique volume name 2: <%q>, spec1 %v, spec2 %v",
   397  			generatedVolumeName1,
   398  			generatedVolumeName2, volumeSpec1, volumeSpec2)
   399  	}
   400  	logger, _ := ktesting.NewTestContext(t)
   401  	err = asw.MarkVolumeAsAttached(logger, generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath)
   402  	if err != nil {
   403  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   404  	}
   405  	podName1 := util.GetUniquePodName(pod1)
   406  
   407  	mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{})
   408  	if err != nil {
   409  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   410  	}
   411  
   412  	mapper1, err := plugin.NewBlockVolumeMapper(volumeSpec1, pod1, volume.VolumeOptions{})
   413  	if err != nil {
   414  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   415  	}
   416  
   417  	markVolumeOpts1 := operationexecutor.MarkVolumeOpts{
   418  		PodName:             podName1,
   419  		PodUID:              pod1.UID,
   420  		VolumeName:          generatedVolumeName1,
   421  		Mounter:             mounter1,
   422  		BlockVolumeMapper:   mapper1,
   423  		OuterVolumeSpecName: volumeSpec1.Name(),
   424  		VolumeSpec:          volumeSpec1,
   425  	}
   426  	err = asw.AddPodToVolume(markVolumeOpts1)
   427  	if err != nil {
   428  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   429  	}
   430  
   431  	podName2 := util.GetUniquePodName(pod2)
   432  
   433  	mounter2, err := plugin.NewMounter(volumeSpec2, pod2, volume.VolumeOptions{})
   434  	if err != nil {
   435  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   436  	}
   437  
   438  	mapper2, err := plugin.NewBlockVolumeMapper(volumeSpec2, pod2, volume.VolumeOptions{})
   439  	if err != nil {
   440  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   441  	}
   442  
   443  	markVolumeOpts2 := operationexecutor.MarkVolumeOpts{
   444  		PodName:             podName2,
   445  		PodUID:              pod2.UID,
   446  		VolumeName:          generatedVolumeName1,
   447  		Mounter:             mounter2,
   448  		BlockVolumeMapper:   mapper2,
   449  		OuterVolumeSpecName: volumeSpec2.Name(),
   450  		VolumeSpec:          volumeSpec2,
   451  	}
   452  	err = asw.AddPodToVolume(markVolumeOpts2)
   453  	if err != nil {
   454  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   455  	}
   456  
   457  	verifyVolumeExistsAsw(t, generatedVolumeName1, true /* shouldExist */, asw)
   458  	verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName1, asw)
   459  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName1, asw)
   460  	verifyPodExistsInVolumeAsw(t, podName1, generatedVolumeName1, "fake/device/path" /* expectedDevicePath */, asw)
   461  	verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName1, volumeSpec1.Name(), asw)
   462  	verifyPodExistsInVolumeAsw(t, podName2, generatedVolumeName2, "fake/device/path" /* expectedDevicePath */, asw)
   463  	verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName2, volumeSpec2.Name(), asw)
   464  	verifyVolumeSpecNameInVolumeAsw(t, podName1, []*volume.Spec{volumeSpec1}, asw)
   465  	verifyVolumeSpecNameInVolumeAsw(t, podName2, []*volume.Spec{volumeSpec2}, asw)
   466  	verifyVolumeMountedElsewhere(t, podName1, generatedVolumeName1, true /*expectedMountedElsewhere */, asw)
   467  	verifyVolumeMountedElsewhere(t, podName2, generatedVolumeName2, true /*expectedMountedElsewhere */, asw)
   468  }
   469  
   470  // Test if volumes that were recorded to be read from disk during reconstruction
   471  // are handled correctly by the ASOW.
   472  func TestActualStateOfWorld_FoundDuringReconstruction(t *testing.T) {
   473  	tests := []struct {
   474  		name           string
   475  		opCallback     func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error
   476  		verifyCallback func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error
   477  	}{
   478  		{
   479  			name: "marking volume mounted should remove volume from found during reconstruction",
   480  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   481  				volumeOpts.VolumeMountState = operationexecutor.VolumeMounted
   482  				return asw.MarkVolumeAsMounted(volumeOpts)
   483  			},
   484  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   485  				ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName)
   486  				if ok {
   487  					return fmt.Errorf("found unexpected volume in reconstructed volume list")
   488  				}
   489  				return nil
   490  			},
   491  		},
   492  		{
   493  			name: "removing volume from pod should remove volume from found during reconstruction",
   494  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   495  				return asw.MarkVolumeAsUnmounted(volumeOpts.PodName, volumeOpts.VolumeName)
   496  			},
   497  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   498  				ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName)
   499  				if ok {
   500  					return fmt.Errorf("found unexpected volume in reconstructed volume list")
   501  				}
   502  				return nil
   503  			},
   504  		},
   505  		{
   506  			name: "removing volume entirely from ASOW should remove volume from found during reconstruction",
   507  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   508  				err := asw.MarkVolumeAsUnmounted(volumeOpts.PodName, volumeOpts.VolumeName)
   509  				if err != nil {
   510  					return err
   511  				}
   512  				asw.MarkVolumeAsDetached(volumeOpts.VolumeName, "")
   513  				return nil
   514  			},
   515  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   516  				ok := asw.IsVolumeReconstructed(volumeOpts.VolumeName, volumeOpts.PodName)
   517  				if ok {
   518  					return fmt.Errorf("found unexpected volume in reconstructed volume list")
   519  				}
   520  				aswInstance, _ := asw.(*actualStateOfWorld)
   521  				_, found := aswInstance.foundDuringReconstruction[volumeOpts.VolumeName]
   522  				if found {
   523  					return fmt.Errorf("found unexpected volume in reconstructed map")
   524  				}
   525  				return nil
   526  			},
   527  		},
   528  		{
   529  			name: "uncertain attachability is resolved to attachable",
   530  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   531  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true)
   532  				return nil
   533  			},
   534  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   535  				verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityTrue)
   536  				return nil
   537  			},
   538  		},
   539  		{
   540  			name: "uncertain attachability is resolved to non-attachable",
   541  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   542  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false)
   543  				return nil
   544  			},
   545  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   546  				verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityFalse)
   547  				return nil
   548  			},
   549  		},
   550  		{
   551  			name: "certain (false) attachability cannot be changed",
   552  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   553  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false)
   554  				// This function should be NOOP:
   555  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true)
   556  				return nil
   557  			},
   558  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   559  				verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityFalse)
   560  				return nil
   561  			},
   562  		},
   563  		{
   564  			name: "certain (true) attachability cannot be changed",
   565  			opCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   566  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, true)
   567  				// This function should be NOOP:
   568  				asw.UpdateReconstructedVolumeAttachability(volumeOpts.VolumeName, false)
   569  				return nil
   570  			},
   571  			verifyCallback: func(asw ActualStateOfWorld, volumeOpts operationexecutor.MarkVolumeOpts) error {
   572  				verifyVolumeAttachability(t, volumeOpts.VolumeName, asw, volumeAttachabilityTrue)
   573  				return nil
   574  			},
   575  		},
   576  	}
   577  	for _, tc := range tests {
   578  		t.Run(tc.name, func(t *testing.T) {
   579  			volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   580  			asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   581  			devicePath := "fake/device/path"
   582  
   583  			pod1 := getTestPod("pod1", "pod1uid", "volume-name-1", "fake-device1")
   584  			volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]}
   585  			generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec(
   586  				plugin, volumeSpec1)
   587  			require.NoError(t, err)
   588  			err = asw.AddAttachUncertainReconstructedVolume(generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath)
   589  			if err != nil {
   590  				t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   591  			}
   592  			podName1 := util.GetUniquePodName(pod1)
   593  
   594  			mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{})
   595  			if err != nil {
   596  				t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   597  			}
   598  
   599  			mapper1, err := plugin.NewBlockVolumeMapper(volumeSpec1, pod1, volume.VolumeOptions{})
   600  			if err != nil {
   601  				t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   602  			}
   603  
   604  			markVolumeOpts1 := operationexecutor.MarkVolumeOpts{
   605  				PodName:             podName1,
   606  				PodUID:              pod1.UID,
   607  				VolumeName:          generatedVolumeName1,
   608  				Mounter:             mounter1,
   609  				BlockVolumeMapper:   mapper1,
   610  				OuterVolumeSpecName: volumeSpec1.Name(),
   611  				VolumeSpec:          volumeSpec1,
   612  				VolumeMountState:    operationexecutor.VolumeMountUncertain,
   613  			}
   614  			_, err = asw.CheckAndMarkVolumeAsUncertainViaReconstruction(markVolumeOpts1)
   615  			if err != nil {
   616  				t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   617  			}
   618  			// make sure state is as we expect it to be
   619  			verifyVolumeExistsAsw(t, generatedVolumeName1, true /* shouldExist */, asw)
   620  			verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName1, asw)
   621  			verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName1, asw)
   622  			verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName1, volumeSpec1.Name(), asw)
   623  			verifyVolumeSpecNameInVolumeAsw(t, podName1, []*volume.Spec{volumeSpec1}, asw)
   624  			verifyVolumeFoundInReconstruction(t, podName1, generatedVolumeName1, asw)
   625  			verifyVolumeAttachability(t, generatedVolumeName1, asw, volumeAttachabilityUncertain)
   626  
   627  			if tc.opCallback != nil {
   628  				err = tc.opCallback(asw, markVolumeOpts1)
   629  				if err != nil {
   630  					t.Fatalf("for test %s: %v", tc.name, err)
   631  				}
   632  			}
   633  			err = tc.verifyCallback(asw, markVolumeOpts1)
   634  			if err != nil {
   635  				t.Fatalf("for test %s verification failed: %v", tc.name, err)
   636  			}
   637  		})
   638  	}
   639  }
   640  
   641  // Call MarkVolumeAsDetached() on a volume which mounted by pod(s) should be skipped
   642  func Test_MarkVolumeAsDetached_Negative_PodInVolume(t *testing.T) {
   643  	// Arrange
   644  	volumePluginMgr, plugin := volumetesting.GetTestVolumePluginMgr(t)
   645  	devicePath := "fake/device/path"
   646  	asw := NewActualStateOfWorld("mynode", volumePluginMgr)
   647  	pod := &v1.Pod{
   648  		ObjectMeta: metav1.ObjectMeta{
   649  			Name: "pod1",
   650  			UID:  "pod1uid",
   651  		},
   652  		Spec: v1.PodSpec{
   653  			Volumes: []v1.Volume{
   654  				{
   655  					Name: "volume-name",
   656  					VolumeSource: v1.VolumeSource{
   657  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   658  							PDName: "fake-device1",
   659  						},
   660  					},
   661  				},
   662  			},
   663  		},
   664  	}
   665  	logger, _ := ktesting.NewTestContext(t)
   666  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   667  	err := asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   668  	if err != nil {
   669  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   670  	}
   671  
   672  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   673  	if err != nil {
   674  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   675  	}
   676  
   677  	podName := util.GetUniquePodName(pod)
   678  	mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{})
   679  	if err != nil {
   680  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   681  	}
   682  
   683  	mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{})
   684  	if err != nil {
   685  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   686  	}
   687  
   688  	markVolumeOpts := operationexecutor.MarkVolumeOpts{
   689  		PodName:             podName,
   690  		PodUID:              pod.UID,
   691  		VolumeName:          generatedVolumeName,
   692  		Mounter:             mounter,
   693  		BlockVolumeMapper:   mapper,
   694  		OuterVolumeSpecName: volumeSpec.Name(),
   695  		VolumeSpec:          volumeSpec,
   696  	}
   697  	err = asw.AddPodToVolume(markVolumeOpts)
   698  	if err != nil {
   699  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   700  	}
   701  
   702  	// Act
   703  	asw.MarkVolumeAsDetached(generatedVolumeName, "" /* nodeName */)
   704  
   705  	// Assert
   706  	verifyPodExistsInVolumeAsw(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, asw)
   707  }
   708  
   709  func getTestPod(podName, podUID, outerVolumeName, pdName string) *v1.Pod {
   710  	pod := &v1.Pod{
   711  		ObjectMeta: metav1.ObjectMeta{
   712  			Name: podName,
   713  			UID:  types.UID(podUID),
   714  		},
   715  		Spec: v1.PodSpec{
   716  			Volumes: []v1.Volume{
   717  				{
   718  					Name: outerVolumeName,
   719  					VolumeSource: v1.VolumeSource{
   720  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   721  							PDName: pdName,
   722  						},
   723  					},
   724  				},
   725  			},
   726  		},
   727  	}
   728  	return pod
   729  }
   730  
   731  // Calls AddPodToVolume() to add pod to empty data struct
   732  // Verifies call fails with "volume does not exist" error.
   733  func Test_AddPodToVolume_Negative_VolumeDoesntExist(t *testing.T) {
   734  	// Arrange
   735  	volumePluginMgr, _ := volumetesting.GetTestKubeletVolumePluginMgr(t)
   736  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   737  
   738  	pod := &v1.Pod{
   739  		ObjectMeta: metav1.ObjectMeta{
   740  			Name: "pod1",
   741  			UID:  "pod1uid",
   742  		},
   743  		Spec: v1.PodSpec{
   744  			Volumes: []v1.Volume{
   745  				{
   746  					Name: "volume-name",
   747  					VolumeSource: v1.VolumeSource{
   748  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   749  							PDName: "fake-device1",
   750  						},
   751  					},
   752  				},
   753  			},
   754  		},
   755  	}
   756  
   757  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   758  	plugin, err := volumePluginMgr.FindPluginBySpec(volumeSpec)
   759  	if err != nil {
   760  		t.Fatalf(
   761  			"volumePluginMgr.FindPluginBySpec failed to find volume plugin for %#v with: %v",
   762  			volumeSpec,
   763  			err)
   764  	}
   765  
   766  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(
   767  		plugin, volumeSpec)
   768  	require.NoError(t, err)
   769  
   770  	blockplugin, err := volumePluginMgr.FindMapperPluginBySpec(volumeSpec)
   771  	if err != nil {
   772  		t.Fatalf(
   773  			"volumePluginMgr.FindMapperPluginBySpec failed to find volume plugin for %#v with: %v",
   774  			volumeSpec,
   775  			err)
   776  	}
   777  
   778  	volumeName, err := util.GetUniqueVolumeNameFromSpec(
   779  		plugin, volumeSpec)
   780  	require.NoError(t, err)
   781  
   782  	podName := util.GetUniquePodName(pod)
   783  
   784  	mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{})
   785  	if err != nil {
   786  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   787  	}
   788  
   789  	mapper, err := blockplugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{})
   790  	if err != nil {
   791  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   792  	}
   793  
   794  	// Act
   795  	markVolumeOpts := operationexecutor.MarkVolumeOpts{
   796  		PodName:             podName,
   797  		PodUID:              pod.UID,
   798  		VolumeName:          volumeName,
   799  		Mounter:             mounter,
   800  		BlockVolumeMapper:   mapper,
   801  		OuterVolumeSpecName: volumeSpec.Name(),
   802  		VolumeSpec:          volumeSpec,
   803  	}
   804  	err = asw.AddPodToVolume(markVolumeOpts)
   805  	// Assert
   806  	if err == nil {
   807  		t.Fatalf("AddPodToVolume did not fail. Expected: <\"no volume with the name ... exists in the list of attached volumes\"> Actual: <no error>")
   808  	}
   809  
   810  	verifyVolumeExistsAsw(t, volumeName, false /* shouldExist */, asw)
   811  	verifyVolumeDoesntExistInUnmountedVolumes(t, volumeName, asw)
   812  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, volumeName, asw)
   813  	verifyPodDoesntExistInVolumeAsw(
   814  		t,
   815  		podName,
   816  		volumeName,
   817  		false, /* expectVolumeToExist */
   818  		asw)
   819  	verifyVolumeDoesntExistWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw)
   820  	verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw)
   821  }
   822  
   823  // Calls MarkVolumeAsAttached() once to add volume
   824  // Calls MarkDeviceAsMounted() to mark volume as globally mounted.
   825  // Verifies newly added volume exists in GetUnmountedVolumes()
   826  // Verifies newly added volume exists in GetGloballyMountedVolumes()
   827  func Test_MarkDeviceAsMounted_Positive_NewVolume(t *testing.T) {
   828  	// Arrange
   829  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   830  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   831  	pod := &v1.Pod{
   832  		ObjectMeta: metav1.ObjectMeta{
   833  			Name: "pod1",
   834  			UID:  "pod1uid",
   835  		},
   836  		Spec: v1.PodSpec{
   837  			Volumes: []v1.Volume{
   838  				{
   839  					Name: "volume-name",
   840  					VolumeSource: v1.VolumeSource{
   841  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   842  							PDName: "fake-device1",
   843  						},
   844  					},
   845  				},
   846  			},
   847  		},
   848  	}
   849  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   850  	devicePath := "fake/device/path"
   851  	deviceMountPath := "fake/device/mount/path"
   852  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   853  	if err != nil {
   854  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   855  	}
   856  	logger, _ := ktesting.NewTestContext(t)
   857  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   858  	if err != nil {
   859  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   860  	}
   861  
   862  	// Act
   863  	err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath, "")
   864  
   865  	// Assert
   866  	if err != nil {
   867  		t.Fatalf("MarkDeviceAsMounted failed. Expected: <no error> Actual: <%v>", err)
   868  	}
   869  
   870  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
   871  	verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw)
   872  	verifyVolumeExistsInGloballyMountedVolumes(t, generatedVolumeName, asw)
   873  }
   874  
   875  // Populates data struct with a volume with a SELinux context.
   876  // Calls AddPodToVolume() to add a pod to the volume
   877  // Verifies volume/pod combo exist using PodExistsInVolume()
   878  func Test_AddPodToVolume_Positive_SELinux(t *testing.T) {
   879  	// Arrange
   880  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
   881  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   882  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   883  	devicePath := "fake/device/path"
   884  
   885  	pod := &v1.Pod{
   886  		ObjectMeta: metav1.ObjectMeta{
   887  			Name: "pod1",
   888  			UID:  "pod1uid",
   889  		},
   890  		Spec: v1.PodSpec{
   891  			Volumes: []v1.Volume{
   892  				{
   893  					Name: "volume-name",
   894  					VolumeSource: v1.VolumeSource{
   895  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   896  							PDName: "fake-device1",
   897  						},
   898  					},
   899  				},
   900  			},
   901  		},
   902  	}
   903  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   904  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   905  	if err != nil {
   906  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   907  	}
   908  	logger, _ := ktesting.NewTestContext(t)
   909  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   910  	if err != nil {
   911  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   912  	}
   913  	podName := util.GetUniquePodName(pod)
   914  
   915  	mounter, err := plugin.NewMounter(volumeSpec, pod, volume.VolumeOptions{})
   916  	if err != nil {
   917  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
   918  	}
   919  
   920  	mapper, err := plugin.NewBlockVolumeMapper(volumeSpec, pod, volume.VolumeOptions{})
   921  	if err != nil {
   922  		t.Fatalf("NewBlockVolumeMapper failed. Expected: <no error> Actual: <%v>", err)
   923  	}
   924  
   925  	// Act
   926  	markVolumeOpts := operationexecutor.MarkVolumeOpts{
   927  		PodName:             podName,
   928  		PodUID:              pod.UID,
   929  		VolumeName:          generatedVolumeName,
   930  		Mounter:             mounter,
   931  		BlockVolumeMapper:   mapper,
   932  		OuterVolumeSpecName: volumeSpec.Name(),
   933  		VolumeSpec:          volumeSpec,
   934  		SELinuxMountContext: "system_u:object_r:container_file_t:s0:c0,c1",
   935  		VolumeMountState:    operationexecutor.VolumeMounted,
   936  	}
   937  	err = asw.AddPodToVolume(markVolumeOpts)
   938  	// Assert
   939  	if err != nil {
   940  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
   941  	}
   942  
   943  	verifyVolumeExistsAswWithSELinux(t, generatedVolumeName, "system_u:object_r:container_file_t:s0:c0,c1", asw)
   944  	verifyVolumeDoesntExistInUnmountedVolumes(t, generatedVolumeName, asw)
   945  	verifyVolumeDoesntExistInGloballyMountedVolumes(t, generatedVolumeName, asw)
   946  	verifyPodExistsInVolumeAswWithSELinux(t, podName, generatedVolumeName, "fake/device/path" /* expectedDevicePath */, "system_u:object_r:container_file_t:s0:c0,c1", asw)
   947  	verifyPodExistsInVolumeSELinuxMismatch(t, podName, generatedVolumeName, "" /* wrong SELinux label */, asw)
   948  	verifyVolumeExistsWithSpecNameInVolumeAsw(t, podName, volumeSpec.Name(), asw)
   949  	verifyVolumeMountedElsewhere(t, podName, generatedVolumeName, false /*expectedMountedElsewhere */, asw)
   950  }
   951  
   952  // Calls MarkVolumeAsAttached() once to add volume
   953  // Calls MarkDeviceAsMounted() with SELinux to mark volume as globally mounted.
   954  // Verifies newly added volume exists in GetUnmountedVolumes()
   955  // Verifies newly added volume exists in GetGloballyMountedVolumes()
   956  func Test_MarkDeviceAsMounted_Positive_SELinux(t *testing.T) {
   957  	// Arrange
   958  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.SELinuxMountReadWriteOncePod, true)()
   959  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
   960  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
   961  	pod := &v1.Pod{
   962  		ObjectMeta: metav1.ObjectMeta{
   963  			Name: "pod1",
   964  			UID:  "pod1uid",
   965  		},
   966  		Spec: v1.PodSpec{
   967  			Volumes: []v1.Volume{
   968  				{
   969  					Name: "volume-name",
   970  					VolumeSource: v1.VolumeSource{
   971  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
   972  							PDName: "fake-device1",
   973  						},
   974  					},
   975  				},
   976  			},
   977  		},
   978  	}
   979  	volumeSpec := &volume.Spec{Volume: &pod.Spec.Volumes[0]}
   980  	devicePath := "fake/device/path"
   981  	deviceMountPath := "fake/device/mount/path"
   982  	generatedVolumeName, err := util.GetUniqueVolumeNameFromSpec(plugin, volumeSpec)
   983  	if err != nil {
   984  		t.Fatalf("GetUniqueVolumeNameFromSpec failed. Expected: <no error> Actual: <%v>", err)
   985  	}
   986  	logger, _ := ktesting.NewTestContext(t)
   987  	err = asw.MarkVolumeAsAttached(logger, emptyVolumeName, volumeSpec, "" /* nodeName */, devicePath)
   988  	if err != nil {
   989  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
   990  	}
   991  
   992  	// Act
   993  	err = asw.MarkDeviceAsMounted(generatedVolumeName, devicePath, deviceMountPath, "system_u:system_r:container_t:s0:c0,c1")
   994  
   995  	// Assert
   996  	if err != nil {
   997  		t.Fatalf("MarkDeviceAsMounted failed. Expected: <no error> Actual: <%v>", err)
   998  	}
   999  
  1000  	verifyVolumeExistsAsw(t, generatedVolumeName, true /* shouldExist */, asw)
  1001  	verifyVolumeExistsInUnmountedVolumes(t, generatedVolumeName, asw)
  1002  	verifyVolumeExistsInGloballyMountedVolumesWithSELinux(t, generatedVolumeName, "system_u:system_r:container_t:s0:c0,c1", asw)
  1003  }
  1004  
  1005  func TestUncertainVolumeMounts(t *testing.T) {
  1006  	// Arrange
  1007  	volumePluginMgr, plugin := volumetesting.GetTestKubeletVolumePluginMgr(t)
  1008  	asw := NewActualStateOfWorld("mynode" /* nodeName */, volumePluginMgr)
  1009  	devicePath := "fake/device/path"
  1010  
  1011  	pod1 := &v1.Pod{
  1012  		ObjectMeta: metav1.ObjectMeta{
  1013  			Name: "pod1",
  1014  			UID:  "pod1uid",
  1015  		},
  1016  		Spec: v1.PodSpec{
  1017  			Volumes: []v1.Volume{
  1018  				{
  1019  					Name: "volume-name-1",
  1020  					VolumeSource: v1.VolumeSource{
  1021  						GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{
  1022  							PDName: "fake-device1",
  1023  						},
  1024  					},
  1025  				},
  1026  			},
  1027  		},
  1028  	}
  1029  	volumeSpec1 := &volume.Spec{Volume: &pod1.Spec.Volumes[0]}
  1030  	generatedVolumeName1, err := util.GetUniqueVolumeNameFromSpec(
  1031  		plugin, volumeSpec1)
  1032  	require.NoError(t, err)
  1033  	logger, _ := ktesting.NewTestContext(t)
  1034  	err = asw.MarkVolumeAsAttached(logger, generatedVolumeName1, volumeSpec1, "" /* nodeName */, devicePath)
  1035  	if err != nil {
  1036  		t.Fatalf("MarkVolumeAsAttached failed. Expected: <no error> Actual: <%v>", err)
  1037  	}
  1038  	podName1 := util.GetUniquePodName(pod1)
  1039  
  1040  	mounter1, err := plugin.NewMounter(volumeSpec1, pod1, volume.VolumeOptions{})
  1041  	if err != nil {
  1042  		t.Fatalf("NewMounter failed. Expected: <no error> Actual: <%v>", err)
  1043  	}
  1044  
  1045  	markVolumeOpts1 := operationexecutor.MarkVolumeOpts{
  1046  		PodName:             podName1,
  1047  		PodUID:              pod1.UID,
  1048  		VolumeName:          generatedVolumeName1,
  1049  		Mounter:             mounter1,
  1050  		OuterVolumeSpecName: volumeSpec1.Name(),
  1051  		VolumeSpec:          volumeSpec1,
  1052  		VolumeMountState:    operationexecutor.VolumeMountUncertain,
  1053  	}
  1054  	err = asw.AddPodToVolume(markVolumeOpts1)
  1055  	if err != nil {
  1056  		t.Fatalf("AddPodToVolume failed. Expected: <no error> Actual: <%v>", err)
  1057  	}
  1058  	mountedVolumes := asw.GetMountedVolumesForPod(podName1)
  1059  	volumeFound := false
  1060  	for _, volume := range mountedVolumes {
  1061  		if volume.InnerVolumeSpecName == volumeSpec1.Name() {
  1062  			volumeFound = true
  1063  		}
  1064  	}
  1065  	if volumeFound {
  1066  		t.Fatalf("expected volume %s to be not found in asw.GetMountedVolumesForPod", volumeSpec1.Name())
  1067  	}
  1068  
  1069  	possiblyMountedVolumes := asw.GetPossiblyMountedVolumesForPod(podName1)
  1070  	volumeFound = false
  1071  	for _, volume := range possiblyMountedVolumes {
  1072  		if volume.InnerVolumeSpecName == volumeSpec1.Name() {
  1073  			volumeFound = true
  1074  		}
  1075  	}
  1076  	if !volumeFound {
  1077  		t.Fatalf("expected volume %s to be found in aws.GetPossiblyMountedVolumesForPod", volumeSpec1.Name())
  1078  	}
  1079  
  1080  	volExists, _, _ := asw.PodExistsInVolume(podName1, generatedVolumeName1, resource.Quantity{}, "")
  1081  	if volExists {
  1082  		t.Fatalf("expected volume %s to not exist in asw", generatedVolumeName1)
  1083  	}
  1084  	removed := asw.PodRemovedFromVolume(podName1, generatedVolumeName1)
  1085  	if removed {
  1086  		t.Fatalf("expected volume %s not to be removed in asw", generatedVolumeName1)
  1087  	}
  1088  }
  1089  
  1090  func verifyVolumeExistsInGloballyMountedVolumes(
  1091  	t *testing.T, expectedVolumeName v1.UniqueVolumeName, asw ActualStateOfWorld) {
  1092  	globallyMountedVolumes := asw.GetGloballyMountedVolumes()
  1093  	for _, volume := range globallyMountedVolumes {
  1094  		if volume.VolumeName == expectedVolumeName {
  1095  			return
  1096  		}
  1097  	}
  1098  
  1099  	t.Fatalf(
  1100  		"Could not find volume %v in the list of GloballyMountedVolumes for actual state of world %+v",
  1101  		expectedVolumeName,
  1102  		globallyMountedVolumes)
  1103  }
  1104  
  1105  func verifyVolumeExistsInGloballyMountedVolumesWithSELinux(
  1106  	t *testing.T, expectedVolumeName v1.UniqueVolumeName, expectedSELinuxContext string, asw ActualStateOfWorld) {
  1107  	globallyMountedVolumes := asw.GetGloballyMountedVolumes()
  1108  	for _, volume := range globallyMountedVolumes {
  1109  		if volume.VolumeName == expectedVolumeName {
  1110  			if volume.SELinuxMountContext == expectedSELinuxContext {
  1111  				return
  1112  			}
  1113  			t.Errorf(
  1114  				"Volume %q has wrong SELinux context. Expected %q, got %q",
  1115  				expectedVolumeName,
  1116  				expectedSELinuxContext,
  1117  				volume.SELinuxMountContext)
  1118  		}
  1119  	}
  1120  
  1121  	t.Fatalf(
  1122  		"Could not find volume %v in the list of GloballyMountedVolumes for actual state of world %+v",
  1123  		expectedVolumeName,
  1124  		globallyMountedVolumes)
  1125  }
  1126  
  1127  func verifyVolumeDoesntExistInGloballyMountedVolumes(
  1128  	t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) {
  1129  	globallyMountedVolumes := asw.GetGloballyMountedVolumes()
  1130  	for _, volume := range globallyMountedVolumes {
  1131  		if volume.VolumeName == volumeToCheck {
  1132  			t.Fatalf(
  1133  				"Found volume %v in the list of GloballyMountedVolumes. Expected it not to exist.",
  1134  				volumeToCheck)
  1135  		}
  1136  	}
  1137  }
  1138  
  1139  func verifyVolumeExistsAsw(
  1140  	t *testing.T,
  1141  	expectedVolumeName v1.UniqueVolumeName,
  1142  	shouldExist bool,
  1143  	asw ActualStateOfWorld) {
  1144  	volumeExists := asw.VolumeExists(expectedVolumeName)
  1145  	if shouldExist != volumeExists {
  1146  		t.Fatalf(
  1147  			"VolumeExists(%q) response incorrect. Expected: <%v> Actual: <%v>",
  1148  			expectedVolumeName,
  1149  			shouldExist,
  1150  			volumeExists)
  1151  	}
  1152  }
  1153  
  1154  func verifyVolumeExistsAswWithSELinux(
  1155  	t *testing.T,
  1156  	expectedVolumeName v1.UniqueVolumeName,
  1157  	expectedSELinuxContext string,
  1158  	asw ActualStateOfWorld) {
  1159  	volumes := asw.GetMountedVolumes()
  1160  	for _, vol := range volumes {
  1161  		if vol.VolumeName == expectedVolumeName {
  1162  			if vol.SELinuxMountContext == expectedSELinuxContext {
  1163  				return
  1164  			}
  1165  			t.Errorf(
  1166  				"Volume %q has wrong SELinux context, expected %q, got %q",
  1167  				expectedVolumeName,
  1168  				expectedSELinuxContext,
  1169  				vol.SELinuxMountContext)
  1170  		}
  1171  	}
  1172  	t.Errorf("Volume %q not found in ASW", expectedVolumeName)
  1173  }
  1174  
  1175  func verifyVolumeExistsInUnmountedVolumes(
  1176  	t *testing.T, expectedVolumeName v1.UniqueVolumeName, asw ActualStateOfWorld) {
  1177  	unmountedVolumes := asw.GetUnmountedVolumes()
  1178  	for _, volume := range unmountedVolumes {
  1179  		if volume.VolumeName == expectedVolumeName {
  1180  			return
  1181  		}
  1182  	}
  1183  
  1184  	t.Fatalf(
  1185  		"Could not find volume %v in the list of UnmountedVolumes for actual state of world %+v",
  1186  		expectedVolumeName,
  1187  		unmountedVolumes)
  1188  }
  1189  
  1190  func verifyVolumeDoesntExistInUnmountedVolumes(
  1191  	t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) {
  1192  	unmountedVolumes := asw.GetUnmountedVolumes()
  1193  	for _, volume := range unmountedVolumes {
  1194  		if volume.VolumeName == volumeToCheck {
  1195  			t.Fatalf(
  1196  				"Found volume %v in the list of UnmountedVolumes. Expected it not to exist.",
  1197  				volumeToCheck)
  1198  		}
  1199  	}
  1200  }
  1201  
  1202  func verifyPodExistsInVolumeAsw(
  1203  	t *testing.T,
  1204  	expectedPodName volumetypes.UniquePodName,
  1205  	expectedVolumeName v1.UniqueVolumeName,
  1206  	expectedDevicePath string,
  1207  	asw ActualStateOfWorld) {
  1208  	verifyPodExistsInVolumeAswWithSELinux(t, expectedPodName, expectedVolumeName, expectedDevicePath, "", asw)
  1209  }
  1210  
  1211  func verifyPodExistsInVolumeAswWithSELinux(
  1212  	t *testing.T,
  1213  	expectedPodName volumetypes.UniquePodName,
  1214  	expectedVolumeName v1.UniqueVolumeName,
  1215  	expectedDevicePath string,
  1216  	expectedSELinuxLabel string,
  1217  	asw ActualStateOfWorld) {
  1218  	podExistsInVolume, devicePath, err :=
  1219  		asw.PodExistsInVolume(expectedPodName, expectedVolumeName, resource.Quantity{}, expectedSELinuxLabel)
  1220  	if err != nil {
  1221  		t.Fatalf(
  1222  			"ASW PodExistsInVolume failed. Expected: <no error> Actual: <%v>", err)
  1223  	}
  1224  
  1225  	if !podExistsInVolume {
  1226  		t.Fatalf(
  1227  			"ASW PodExistsInVolume result invalid. Expected: <true> Actual: <%v>",
  1228  			podExistsInVolume)
  1229  	}
  1230  
  1231  	if devicePath != expectedDevicePath {
  1232  		t.Fatalf(
  1233  			"Invalid devicePath. Expected: <%q> Actual: <%q> ",
  1234  			expectedDevicePath,
  1235  			devicePath)
  1236  	}
  1237  }
  1238  
  1239  func verifyVolumeMountedElsewhere(
  1240  	t *testing.T,
  1241  	expectedPodName volumetypes.UniquePodName,
  1242  	expectedVolumeName v1.UniqueVolumeName,
  1243  	expectedMountedElsewhere bool,
  1244  	asw ActualStateOfWorld) {
  1245  	mountedElsewhere := asw.IsVolumeMountedElsewhere(expectedVolumeName, expectedPodName)
  1246  	if mountedElsewhere != expectedMountedElsewhere {
  1247  		t.Fatalf(
  1248  			"IsVolumeMountedElsewhere assertion failure. Expected : <%t> Actual: <%t>",
  1249  			expectedMountedElsewhere,
  1250  			mountedElsewhere)
  1251  	}
  1252  }
  1253  
  1254  func verifyPodDoesntExistInVolumeAsw(
  1255  	t *testing.T,
  1256  	podToCheck volumetypes.UniquePodName,
  1257  	volumeToCheck v1.UniqueVolumeName,
  1258  	expectVolumeToExist bool,
  1259  	asw ActualStateOfWorld) {
  1260  	podExistsInVolume, devicePath, err :=
  1261  		asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{}, "")
  1262  	if !expectVolumeToExist && err == nil {
  1263  		t.Fatalf(
  1264  			"ASW PodExistsInVolume did not return error. Expected: <error indicating volume does not exist> Actual: <%v>", err)
  1265  	}
  1266  
  1267  	if expectVolumeToExist && err != nil {
  1268  		t.Fatalf(
  1269  			"ASW PodExistsInVolume failed. Expected: <no error> Actual: <%v>", err)
  1270  	}
  1271  
  1272  	if podExistsInVolume {
  1273  		t.Fatalf(
  1274  			"ASW PodExistsInVolume result invalid. Expected: <false> Actual: <%v>",
  1275  			podExistsInVolume)
  1276  	}
  1277  
  1278  	if devicePath != "" {
  1279  		t.Fatalf(
  1280  			"Invalid devicePath. Expected: <\"\"> Actual: <%q> ",
  1281  			devicePath)
  1282  	}
  1283  }
  1284  
  1285  func verifyPodExistsInVolumeSELinuxMismatch(
  1286  	t *testing.T,
  1287  	podToCheck volumetypes.UniquePodName,
  1288  	volumeToCheck v1.UniqueVolumeName,
  1289  	unexpectedSELinuxLabel string,
  1290  	asw ActualStateOfWorld) {
  1291  
  1292  	podExistsInVolume, _, err := asw.PodExistsInVolume(podToCheck, volumeToCheck, resource.Quantity{}, unexpectedSELinuxLabel)
  1293  	if podExistsInVolume {
  1294  		t.Errorf("expected Pod %s not to exists, but it does", podToCheck)
  1295  	}
  1296  	if err == nil {
  1297  		t.Error("expected PodExistsInVolume to return error, but it returned nil")
  1298  	}
  1299  
  1300  	if !IsSELinuxMountMismatchError(err) {
  1301  		t.Errorf("expected PodExistsInVolume to return SELinuxMountMismatchError, got %s", err)
  1302  	}
  1303  }
  1304  
  1305  func verifyVolumeExistsWithSpecNameInVolumeAsw(
  1306  	t *testing.T,
  1307  	expectedPodName volumetypes.UniquePodName,
  1308  	expectedVolumeName string,
  1309  	asw ActualStateOfWorld) {
  1310  	podExistsInVolume :=
  1311  		asw.VolumeExistsWithSpecName(expectedPodName, expectedVolumeName)
  1312  
  1313  	if !podExistsInVolume {
  1314  		t.Fatalf(
  1315  			"ASW VolumeExistsWithSpecName result invalid. Expected: <true> Actual: <%v>",
  1316  			podExistsInVolume)
  1317  	}
  1318  }
  1319  
  1320  func verifyVolumeDoesntExistWithSpecNameInVolumeAsw(
  1321  	t *testing.T,
  1322  	podToCheck volumetypes.UniquePodName,
  1323  	volumeToCheck string,
  1324  	asw ActualStateOfWorld) {
  1325  	podExistsInVolume :=
  1326  		asw.VolumeExistsWithSpecName(podToCheck, volumeToCheck)
  1327  
  1328  	if podExistsInVolume {
  1329  		t.Fatalf(
  1330  			"ASW VolumeExistsWithSpecName result invalid. Expected: <false> Actual: <%v>",
  1331  			podExistsInVolume)
  1332  	}
  1333  }
  1334  
  1335  func verifyVolumeSpecNameInVolumeAsw(
  1336  	t *testing.T,
  1337  	podToCheck volumetypes.UniquePodName,
  1338  	volumeSpecs []*volume.Spec,
  1339  	asw ActualStateOfWorld) {
  1340  	mountedVolumes :=
  1341  		asw.GetMountedVolumesForPod(podToCheck)
  1342  
  1343  	for i, volume := range mountedVolumes {
  1344  		if volume.InnerVolumeSpecName != volumeSpecs[i].Name() {
  1345  			t.Fatalf("Volume spec name does not match Expected: <%q> Actual: <%q>", volumeSpecs[i].Name(), volume.InnerVolumeSpecName)
  1346  		}
  1347  	}
  1348  }
  1349  
  1350  func verifyVolumeFoundInReconstruction(t *testing.T, podToCheck volumetypes.UniquePodName, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld) {
  1351  	isRecontructed := asw.IsVolumeReconstructed(volumeToCheck, podToCheck)
  1352  	if !isRecontructed {
  1353  		t.Fatalf("ASW IsVolumeReconstructed result invalid. expected <true> Actual <false>")
  1354  	}
  1355  }
  1356  
  1357  func verifyVolumeAttachability(t *testing.T, volumeToCheck v1.UniqueVolumeName, asw ActualStateOfWorld, expected volumeAttachability) {
  1358  	attached := asw.GetAttachedVolumes()
  1359  	attachable := false
  1360  
  1361  	for _, volume := range attached {
  1362  		if volume.VolumeName == volumeToCheck {
  1363  			attachable = volume.PluginIsAttachable
  1364  			break
  1365  		}
  1366  	}
  1367  
  1368  	switch expected {
  1369  	case volumeAttachabilityTrue:
  1370  		if !attachable {
  1371  			t.Errorf("ASW reports %s as not-attachable, when %s was expected", volumeToCheck, expected)
  1372  		}
  1373  	// ASW does not have any special difference between False and Uncertain.
  1374  	// Uncertain only allows to be changed to True / False.
  1375  	case volumeAttachabilityUncertain, volumeAttachabilityFalse:
  1376  		if attachable {
  1377  			t.Errorf("ASW reports %s as attachable, when %s was expected", volumeToCheck, expected)
  1378  		}
  1379  	}
  1380  }
  1381  

View as plain text