...

Source file src/k8s.io/kubernetes/pkg/volume/csi/csi_block_test.go

Documentation: k8s.io/kubernetes/pkg/volume/csi

     1  /*
     2  Copyright 2018 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 csi
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"testing"
    26  
    27  	"google.golang.org/grpc/codes"
    28  	"google.golang.org/grpc/status"
    29  
    30  	api "k8s.io/api/core/v1"
    31  	storagev1 "k8s.io/api/storage/v1"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	fakeclient "k8s.io/client-go/kubernetes/fake"
    34  	"k8s.io/kubernetes/pkg/volume"
    35  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    36  )
    37  
    38  func prepareBlockMapperTest(plug *csiPlugin, specVolumeName string, t *testing.T) (*csiBlockMapper, *volume.Spec, *api.PersistentVolume, error) {
    39  	registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t)
    40  	pv := makeTestPV(specVolumeName, 10, testDriver, testVol)
    41  	spec := volume.NewSpecFromPersistentVolume(pv, pv.Spec.PersistentVolumeSource.CSI.ReadOnly)
    42  	mapper, err := plug.NewBlockVolumeMapper(
    43  		spec,
    44  		&api.Pod{ObjectMeta: metav1.ObjectMeta{UID: testPodUID, Namespace: testns, Name: testPod}},
    45  		volume.VolumeOptions{},
    46  	)
    47  	if err != nil {
    48  		return nil, nil, nil, fmt.Errorf("failed to make a new Mapper: %w", err)
    49  	}
    50  	csiMapper := mapper.(*csiBlockMapper)
    51  	return csiMapper, spec, pv, nil
    52  }
    53  
    54  func TestBlockMapperGetGlobalMapPath(t *testing.T) {
    55  	plug, tmpDir := newTestPlugin(t, nil)
    56  	defer os.RemoveAll(tmpDir)
    57  
    58  	// TODO (vladimirvivien) specName with slashes will not work
    59  	testCases := []struct {
    60  		name           string
    61  		specVolumeName string
    62  		path           string
    63  	}{
    64  		{
    65  			name:           "simple specName",
    66  			specVolumeName: "spec-0",
    67  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/%s/%s", "spec-0", "dev")),
    68  		},
    69  		{
    70  			name:           "specName with dots",
    71  			specVolumeName: "test.spec.1",
    72  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/%s/%s", "test.spec.1", "dev")),
    73  		},
    74  	}
    75  	for _, tc := range testCases {
    76  		t.Logf("test case: %s", tc.name)
    77  		csiMapper, spec, _, err := prepareBlockMapperTest(plug, tc.specVolumeName, t)
    78  		if err != nil {
    79  			t.Fatalf("Failed to make a new Mapper: %v", err)
    80  		}
    81  
    82  		path, err := csiMapper.GetGlobalMapPath(spec)
    83  		if err != nil {
    84  			t.Errorf("mapper GetGlobalMapPath failed: %v", err)
    85  		}
    86  
    87  		if tc.path != path {
    88  			t.Errorf("expecting path %s, got %s", tc.path, path)
    89  		}
    90  	}
    91  }
    92  
    93  func TestBlockMapperGetStagingPath(t *testing.T) {
    94  	plug, tmpDir := newTestPlugin(t, nil)
    95  	defer os.RemoveAll(tmpDir)
    96  
    97  	testCases := []struct {
    98  		name           string
    99  		specVolumeName string
   100  		path           string
   101  	}{
   102  		{
   103  			name:           "simple specName",
   104  			specVolumeName: "spec-0",
   105  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/staging/%s", "spec-0")),
   106  		},
   107  		{
   108  			name:           "specName with dots",
   109  			specVolumeName: "test.spec.1",
   110  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/staging/%s", "test.spec.1")),
   111  		},
   112  	}
   113  	for _, tc := range testCases {
   114  		t.Logf("test case: %s", tc.name)
   115  		csiMapper, _, _, err := prepareBlockMapperTest(plug, tc.specVolumeName, t)
   116  		if err != nil {
   117  			t.Fatalf("Failed to make a new Mapper: %v", err)
   118  		}
   119  
   120  		path := csiMapper.GetStagingPath()
   121  
   122  		if tc.path != path {
   123  			t.Errorf("expecting path %s, got %s", tc.path, path)
   124  		}
   125  	}
   126  }
   127  
   128  func TestBlockMapperGetPublishPath(t *testing.T) {
   129  	plug, tmpDir := newTestPlugin(t, nil)
   130  	defer os.RemoveAll(tmpDir)
   131  
   132  	testCases := []struct {
   133  		name           string
   134  		specVolumeName string
   135  		path           string
   136  	}{
   137  		{
   138  			name:           "simple specName",
   139  			specVolumeName: "spec-0",
   140  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/publish/%s/%s", "spec-0", testPodUID)),
   141  		},
   142  		{
   143  			name:           "specName with dots",
   144  			specVolumeName: "test.spec.1",
   145  			path:           filepath.Join(tmpDir, fmt.Sprintf("plugins/kubernetes.io/csi/volumeDevices/publish/%s/%s", "test.spec.1", testPodUID)),
   146  		},
   147  	}
   148  	for _, tc := range testCases {
   149  		t.Logf("test case: %s", tc.name)
   150  		csiMapper, _, _, err := prepareBlockMapperTest(plug, tc.specVolumeName, t)
   151  		if err != nil {
   152  			t.Fatalf("Failed to make a new Mapper: %v", err)
   153  		}
   154  
   155  		path := csiMapper.getPublishPath()
   156  
   157  		if tc.path != path {
   158  			t.Errorf("expecting path %s, got %s", tc.path, path)
   159  		}
   160  	}
   161  }
   162  
   163  func TestBlockMapperGetDeviceMapPath(t *testing.T) {
   164  	plug, tmpDir := newTestPlugin(t, nil)
   165  	defer os.RemoveAll(tmpDir)
   166  
   167  	testCases := []struct {
   168  		name           string
   169  		specVolumeName string
   170  		path           string
   171  	}{
   172  		{
   173  			name:           "simple specName",
   174  			specVolumeName: "spec-0",
   175  			path:           filepath.Join(tmpDir, fmt.Sprintf("pods/%s/volumeDevices/kubernetes.io~csi", testPodUID)),
   176  		},
   177  		{
   178  			name:           "specName with dots",
   179  			specVolumeName: "test.spec.1",
   180  			path:           filepath.Join(tmpDir, fmt.Sprintf("pods/%s/volumeDevices/kubernetes.io~csi", testPodUID)),
   181  		},
   182  	}
   183  	for _, tc := range testCases {
   184  		t.Logf("test case: %s", tc.name)
   185  		csiMapper, _, _, err := prepareBlockMapperTest(plug, tc.specVolumeName, t)
   186  		if err != nil {
   187  			t.Fatalf("Failed to make a new Mapper: %v", err)
   188  		}
   189  
   190  		path, volName := csiMapper.GetPodDeviceMapPath()
   191  
   192  		if tc.path != path {
   193  			t.Errorf("expecting path %s, got %s", tc.path, path)
   194  		}
   195  
   196  		if tc.specVolumeName != volName {
   197  			t.Errorf("expecting volName %s, got %s", tc.specVolumeName, volName)
   198  		}
   199  	}
   200  }
   201  
   202  func TestBlockMapperSetupDevice(t *testing.T) {
   203  	plug, tmpDir := newTestPlugin(t, nil)
   204  	defer os.RemoveAll(tmpDir)
   205  
   206  	csiMapper, _, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   207  	if err != nil {
   208  		t.Fatalf("Failed to make a new Mapper: %v", err)
   209  	}
   210  
   211  	pvName := pv.GetName()
   212  	nodeName := string(plug.host.GetNodeName())
   213  
   214  	csiMapper.csiClient = setupClient(t, true)
   215  
   216  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), string(nodeName))
   217  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   218  	attachment.Status.Attached = true
   219  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
   220  	if err != nil {
   221  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   222  	}
   223  	t.Log("created attachment ", attachID)
   224  
   225  	stagingPath, err := csiMapper.SetUpDevice()
   226  	if err != nil {
   227  		t.Fatalf("mapper failed to SetupDevice: %v", err)
   228  	}
   229  
   230  	// Check if NodeStageVolume staged to the right path
   231  	svols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodeStagedVolumes()
   232  	svol, ok := svols[csiMapper.volumeID]
   233  	if !ok {
   234  		t.Error("csi server may not have received NodeStageVolume call")
   235  	}
   236  	if svol.Path != stagingPath {
   237  		t.Errorf("csi server expected device path %s, got %s", stagingPath, svol.Path)
   238  	}
   239  }
   240  
   241  func TestBlockMapperSetupDeviceError(t *testing.T) {
   242  	plug, tmpDir := newTestPlugin(t, nil)
   243  	defer os.RemoveAll(tmpDir)
   244  
   245  	csiMapper, _, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   246  	if err != nil {
   247  		t.Fatalf("Failed to make a new Mapper: %v", err)
   248  	}
   249  
   250  	pvName := pv.GetName()
   251  	nodeName := string(plug.host.GetNodeName())
   252  
   253  	csiMapper.csiClient = setupClient(t, true)
   254  	fClient := csiMapper.csiClient.(*fakeCsiDriverClient)
   255  	fClient.nodeClient.SetNextError(status.Error(codes.InvalidArgument, "mock final error"))
   256  
   257  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), string(nodeName))
   258  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   259  	attachment.Status.Attached = true
   260  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.Background(), attachment, metav1.CreateOptions{})
   261  	if err != nil {
   262  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   263  	}
   264  	t.Log("created attachment ", attachID)
   265  
   266  	stagingPath, err := csiMapper.SetUpDevice()
   267  	if err == nil {
   268  		t.Fatal("mapper unexpectedly succeeded")
   269  	}
   270  
   271  	// Check that all directories have been cleaned
   272  	// Check that all metadata / staging / publish directories were deleted
   273  	dataDir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   274  	if _, err := os.Stat(dataDir); err == nil {
   275  		t.Errorf("volume publish data directory %s was not deleted", dataDir)
   276  	}
   277  	devDir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   278  	if _, err := os.Stat(devDir); err == nil {
   279  		t.Errorf("volume publish device directory %s was not deleted", devDir)
   280  	}
   281  
   282  	if _, err := os.Stat(stagingPath); err == nil {
   283  		t.Errorf("volume staging path %s was not deleted", stagingPath)
   284  	}
   285  }
   286  
   287  func TestBlockMapperSetupDeviceNoClientError(t *testing.T) {
   288  	transientError := volumetypes.NewTransientOperationFailure("")
   289  	plug, tmpDir := newTestPlugin(t, nil)
   290  	defer os.RemoveAll(tmpDir)
   291  
   292  	csiMapper, _, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   293  	if err != nil {
   294  		t.Fatalf("Failed to make a new Mapper: %v", err)
   295  	}
   296  
   297  	pvName := pv.GetName()
   298  	nodeName := string(plug.host.GetNodeName())
   299  
   300  	csiMapper.csiClient = setupClient(t, true)
   301  
   302  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), string(nodeName))
   303  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   304  	attachment.Status.Attached = true
   305  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
   306  	if err != nil {
   307  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   308  	}
   309  	t.Log("created attachment ", attachID)
   310  
   311  	// Clear out the clients
   312  	// The lookup to generate a new client will fail when it tries to query a driver with an unknown name
   313  	csiMapper.csiClient = nil
   314  	csiMapper.csiClientGetter.csiClient = nil
   315  	// Note that prepareBlockMapperTest above will create a driver with a name of "test-driver"
   316  	csiMapper.csiClientGetter.driverName = "unknown-driver"
   317  
   318  	_, err = csiMapper.SetUpDevice()
   319  	if err == nil {
   320  		t.Errorf("test should fail, but no error occurred")
   321  	} else if reflect.TypeOf(transientError) != reflect.TypeOf(err) {
   322  		t.Fatalf("expected exitError type: %v got: %v (%v)", reflect.TypeOf(transientError), reflect.TypeOf(err), err)
   323  	}
   324  }
   325  
   326  func TestBlockMapperMapPodDevice(t *testing.T) {
   327  	plug, tmpDir := newTestPlugin(t, nil)
   328  	defer os.RemoveAll(tmpDir)
   329  
   330  	csiMapper, _, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   331  	if err != nil {
   332  		t.Fatalf("Failed to make a new Mapper: %v", err)
   333  	}
   334  
   335  	pvName := pv.GetName()
   336  	nodeName := string(plug.host.GetNodeName())
   337  
   338  	csiMapper.csiClient = setupClient(t, true)
   339  
   340  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), nodeName)
   341  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   342  	attachment.Status.Attached = true
   343  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.Background(), attachment, metav1.CreateOptions{})
   344  	if err != nil {
   345  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   346  	}
   347  	t.Log("created attachment ", attachID)
   348  
   349  	// Map device to global and pod device map path
   350  	path, err := csiMapper.MapPodDevice()
   351  	if err != nil {
   352  		t.Fatalf("mapper failed to GetGlobalMapPath: %v", err)
   353  	}
   354  
   355  	// Check if NodePublishVolume published to the right path
   356  	pvols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   357  	pvol, ok := pvols[csiMapper.volumeID]
   358  	if !ok {
   359  		t.Error("csi server may not have received NodePublishVolume call")
   360  	}
   361  
   362  	publishPath := csiMapper.getPublishPath()
   363  	if pvol.Path != publishPath {
   364  		t.Errorf("csi server expected path %s, got %s", publishPath, pvol.Path)
   365  	}
   366  	if path != publishPath {
   367  		t.Errorf("csi server expected path %s, but MapPodDevice returned %s", publishPath, path)
   368  	}
   369  }
   370  
   371  func TestBlockMapperMapPodDeviceNotSupportAttach(t *testing.T) {
   372  	fakeClient := fakeclient.NewSimpleClientset()
   373  	attachRequired := false
   374  	fakeDriver := &storagev1.CSIDriver{
   375  		ObjectMeta: metav1.ObjectMeta{
   376  			Name: testDriver,
   377  		},
   378  		Spec: storagev1.CSIDriverSpec{
   379  			AttachRequired: &attachRequired,
   380  		},
   381  	}
   382  	_, err := fakeClient.StorageV1().CSIDrivers().Create(context.TODO(), fakeDriver, metav1.CreateOptions{})
   383  	if err != nil {
   384  		t.Fatalf("Failed to create a fakeDriver: %v", err)
   385  	}
   386  
   387  	// after the driver is created, create the plugin. newTestPlugin waits for the informer to sync,
   388  	// such that csiMapper.SetUpDevice below sees the VolumeAttachment object in the lister.
   389  
   390  	plug, tmpDir := newTestPlugin(t, fakeClient)
   391  	defer os.RemoveAll(tmpDir)
   392  
   393  	csiMapper, _, _, err := prepareBlockMapperTest(plug, "test-pv", t)
   394  	if err != nil {
   395  		t.Fatalf("Failed to make a new Mapper: %v", err)
   396  	}
   397  	csiMapper.csiClient = setupClient(t, true)
   398  
   399  	// Map device to global and pod device map path
   400  	path, err := csiMapper.MapPodDevice()
   401  	if err != nil {
   402  		t.Fatalf("mapper failed to GetGlobalMapPath: %v", err)
   403  	}
   404  	publishPath := csiMapper.getPublishPath()
   405  	if path != publishPath {
   406  		t.Errorf("path %s and %s doesn't match", path, publishPath)
   407  	}
   408  }
   409  
   410  func TestBlockMapperMapPodDeviceWithPodInfo(t *testing.T) {
   411  	fakeClient := fakeclient.NewSimpleClientset()
   412  	attachRequired := false
   413  	podInfo := true
   414  	fakeDriver := &storagev1.CSIDriver{
   415  		ObjectMeta: metav1.ObjectMeta{
   416  			Name: testDriver,
   417  		},
   418  		Spec: storagev1.CSIDriverSpec{
   419  			PodInfoOnMount: &podInfo,
   420  			AttachRequired: &attachRequired,
   421  		},
   422  	}
   423  	_, err := fakeClient.StorageV1().CSIDrivers().Create(context.TODO(), fakeDriver, metav1.CreateOptions{})
   424  	if err != nil {
   425  		t.Fatalf("Failed to create a fakeDriver: %v", err)
   426  	}
   427  
   428  	// after the driver is created, create the plugin. newTestPlugin waits for the informer to sync,
   429  	// such that csiMapper.SetUpDevice below sees the VolumeAttachment object in the lister.
   430  
   431  	plug, tmpDir := newTestPlugin(t, fakeClient)
   432  	defer os.RemoveAll(tmpDir)
   433  
   434  	csiMapper, _, _, err := prepareBlockMapperTest(plug, "test-pv", t)
   435  	if err != nil {
   436  		t.Fatalf("Failed to make a new Mapper: %v", err)
   437  	}
   438  	csiMapper.csiClient = setupClient(t, true)
   439  
   440  	// Map device to global and pod device map path
   441  	_, err = csiMapper.MapPodDevice()
   442  	if err != nil {
   443  		t.Fatalf("mapper failed to GetGlobalMapPath: %v", err)
   444  	}
   445  	pvols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   446  	pvol, ok := pvols[csiMapper.volumeID]
   447  	if !ok {
   448  		t.Error("csi server may not have received NodePublishVolume call")
   449  	}
   450  
   451  	if !reflect.DeepEqual(pvol.VolumeContext, map[string]string{"csi.storage.k8s.io/pod.uid": "test-pod", "csi.storage.k8s.io/serviceAccount.name": "", "csi.storage.k8s.io/pod.name": "test-pod", "csi.storage.k8s.io/pod.namespace": "test-ns", "csi.storage.k8s.io/ephemeral": "false"}) {
   452  		t.Error("csi mapper check pod info failed")
   453  	}
   454  }
   455  
   456  func TestBlockMapperMapPodDeviceNoClientError(t *testing.T) {
   457  	transientError := volumetypes.NewTransientOperationFailure("")
   458  	plug, tmpDir := newTestPlugin(t, nil)
   459  	defer os.RemoveAll(tmpDir)
   460  
   461  	csiMapper, _, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   462  	if err != nil {
   463  		t.Fatalf("Failed to make a new Mapper: %v", err)
   464  	}
   465  
   466  	pvName := pv.GetName()
   467  	nodeName := string(plug.host.GetNodeName())
   468  
   469  	csiMapper.csiClient = setupClient(t, true)
   470  
   471  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), nodeName)
   472  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   473  	attachment.Status.Attached = true
   474  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.Background(), attachment, metav1.CreateOptions{})
   475  	if err != nil {
   476  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   477  	}
   478  	t.Log("created attachment ", attachID)
   479  
   480  	// Clear out the clients
   481  	// The lookup to generate a new client will fail when it tries to query a driver with an unknown name
   482  	csiMapper.csiClient = nil
   483  	csiMapper.csiClientGetter.csiClient = nil
   484  	// Note that prepareBlockMapperTest above will create a driver with a name of "test-driver"
   485  	csiMapper.csiClientGetter.driverName = "unknown-driver"
   486  
   487  	_, err = csiMapper.MapPodDevice()
   488  	if err == nil {
   489  		t.Errorf("test should fail, but no error occurred")
   490  	} else if reflect.TypeOf(transientError) != reflect.TypeOf(err) {
   491  		t.Fatalf("expected exitError type: %v got: %v (%v)", reflect.TypeOf(transientError), reflect.TypeOf(err), err)
   492  	}
   493  }
   494  
   495  func TestBlockMapperTearDownDevice(t *testing.T) {
   496  	plug, tmpDir := newTestPlugin(t, nil)
   497  	defer os.RemoveAll(tmpDir)
   498  
   499  	_, spec, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   500  	if err != nil {
   501  		t.Fatalf("Failed to make a new Mapper: %v", err)
   502  	}
   503  
   504  	// save volume data
   505  	dir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   506  	if err := os.MkdirAll(dir, 0755); err != nil && !os.IsNotExist(err) {
   507  		t.Errorf("failed to create dir [%s]: %v", dir, err)
   508  	}
   509  
   510  	if err := saveVolumeData(
   511  		dir,
   512  		volDataFileName,
   513  		map[string]string{
   514  			volDataKey.specVolID:  pv.ObjectMeta.Name,
   515  			volDataKey.driverName: testDriver,
   516  			volDataKey.volHandle:  testVol,
   517  		},
   518  	); err != nil {
   519  		t.Fatalf("failed to save volume data: %v", err)
   520  	}
   521  
   522  	unmapper, err := plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, testPodUID)
   523  	if err != nil {
   524  		t.Fatalf("failed to make a new Unmapper: %v", err)
   525  	}
   526  
   527  	csiUnmapper := unmapper.(*csiBlockMapper)
   528  	csiUnmapper.csiClient = setupClient(t, true)
   529  
   530  	globalMapPath, err := csiUnmapper.GetGlobalMapPath(spec)
   531  	if err != nil {
   532  		t.Fatalf("unmapper failed to GetGlobalMapPath: %v", err)
   533  	}
   534  
   535  	err = csiUnmapper.TearDownDevice(globalMapPath, "/dev/test")
   536  	if err != nil {
   537  		t.Fatal(err)
   538  	}
   539  
   540  	// ensure csi client call and node unpblished
   541  	pubs := csiUnmapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   542  	if _, ok := pubs[csiUnmapper.volumeID]; ok {
   543  		t.Error("csi server may not have received NodeUnpublishVolume call")
   544  	}
   545  
   546  	// ensure csi client call and node unstaged
   547  	vols := csiUnmapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodeStagedVolumes()
   548  	if _, ok := vols[csiUnmapper.volumeID]; ok {
   549  		t.Error("csi server may not have received NodeUnstageVolume call")
   550  	}
   551  }
   552  
   553  func TestBlockMapperTearDownDeviceNoClientError(t *testing.T) {
   554  	transientError := volumetypes.NewTransientOperationFailure("")
   555  	plug, tmpDir := newTestPlugin(t, nil)
   556  	defer os.RemoveAll(tmpDir)
   557  
   558  	_, spec, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   559  	if err != nil {
   560  		t.Fatalf("Failed to make a new Mapper: %v", err)
   561  	}
   562  
   563  	// save volume data
   564  	dir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   565  	if err := os.MkdirAll(dir, 0755); err != nil && !os.IsNotExist(err) {
   566  		t.Errorf("failed to create dir [%s]: %v", dir, err)
   567  	}
   568  
   569  	if err := saveVolumeData(
   570  		dir,
   571  		volDataFileName,
   572  		map[string]string{
   573  			volDataKey.specVolID:  pv.ObjectMeta.Name,
   574  			volDataKey.driverName: testDriver,
   575  			volDataKey.volHandle:  testVol,
   576  		},
   577  	); err != nil {
   578  		t.Fatalf("failed to save volume data: %v", err)
   579  	}
   580  
   581  	unmapper, err := plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, testPodUID)
   582  	if err != nil {
   583  		t.Fatalf("failed to make a new Unmapper: %v", err)
   584  	}
   585  
   586  	csiUnmapper := unmapper.(*csiBlockMapper)
   587  	csiUnmapper.csiClient = setupClient(t, true)
   588  
   589  	globalMapPath, err := csiUnmapper.GetGlobalMapPath(spec)
   590  	if err != nil {
   591  		t.Fatalf("unmapper failed to GetGlobalMapPath: %v", err)
   592  	}
   593  
   594  	// Clear out the clients
   595  	// The lookup to generate a new client will fail when it tries to query a driver with an unknown name
   596  	csiUnmapper.csiClient = nil
   597  	csiUnmapper.csiClientGetter.csiClient = nil
   598  	// Note that prepareBlockMapperTest above will create a driver with a name of "test-driver"
   599  	csiUnmapper.csiClientGetter.driverName = "unknown-driver"
   600  
   601  	err = csiUnmapper.TearDownDevice(globalMapPath, "/dev/test")
   602  	if err == nil {
   603  		t.Errorf("test should fail, but no error occurred")
   604  	} else if reflect.TypeOf(transientError) != reflect.TypeOf(err) {
   605  		t.Fatalf("expected exitError type: %v got: %v (%v)", reflect.TypeOf(transientError), reflect.TypeOf(err), err)
   606  	}
   607  }
   608  
   609  func TestVolumeSetupTeardown(t *testing.T) {
   610  	// Follow volume setup + teardown sequences at top of cs_block.go and set up / clean up one CSI block device.
   611  	// Focus on testing that there were no leftover files present after the cleanup.
   612  
   613  	plug, tmpDir := newTestPlugin(t, nil)
   614  	defer os.RemoveAll(tmpDir)
   615  
   616  	csiMapper, spec, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   617  	if err != nil {
   618  		t.Fatalf("Failed to make a new Mapper: %v", err)
   619  	}
   620  
   621  	pvName := pv.GetName()
   622  	nodeName := string(plug.host.GetNodeName())
   623  
   624  	csiMapper.csiClient = setupClient(t, true)
   625  
   626  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), string(nodeName))
   627  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   628  	attachment.Status.Attached = true
   629  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
   630  	if err != nil {
   631  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   632  	}
   633  	t.Log("created attachment ", attachID)
   634  
   635  	stagingPath, err := csiMapper.SetUpDevice()
   636  	if err != nil {
   637  		t.Fatalf("mapper failed to SetupDevice: %v", err)
   638  	}
   639  	// Check if NodeStageVolume staged to the right path
   640  	svols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodeStagedVolumes()
   641  	svol, ok := svols[csiMapper.volumeID]
   642  	if !ok {
   643  		t.Error("csi server may not have received NodeStageVolume call")
   644  	}
   645  	if svol.Path != stagingPath {
   646  		t.Errorf("csi server expected device path %s, got %s", stagingPath, svol.Path)
   647  	}
   648  
   649  	path, err := csiMapper.MapPodDevice()
   650  	if err != nil {
   651  		t.Fatalf("mapper failed to GetGlobalMapPath: %v", err)
   652  	}
   653  	pvols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   654  	pvol, ok := pvols[csiMapper.volumeID]
   655  	if !ok {
   656  		t.Error("csi server may not have received NodePublishVolume call")
   657  	}
   658  	publishPath := csiMapper.getPublishPath()
   659  	if pvol.Path != publishPath {
   660  		t.Errorf("csi server expected path %s, got %s", publishPath, pvol.Path)
   661  	}
   662  	if path != publishPath {
   663  		t.Errorf("csi server expected path %s, but MapPodDevice returned %s", publishPath, path)
   664  	}
   665  
   666  	unmapper, err := plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, testPodUID)
   667  	if err != nil {
   668  		t.Fatalf("failed to make a new Unmapper: %v", err)
   669  	}
   670  
   671  	csiUnmapper := unmapper.(*csiBlockMapper)
   672  	csiUnmapper.csiClient = csiMapper.csiClient
   673  
   674  	globalMapPath, err := csiUnmapper.GetGlobalMapPath(spec)
   675  	if err != nil {
   676  		t.Fatalf("unmapper failed to GetGlobalMapPath: %v", err)
   677  	}
   678  
   679  	err = csiUnmapper.UnmapPodDevice()
   680  	if err != nil {
   681  		t.Errorf("unmapper failed to call UnmapPodDevice: %v", err)
   682  	}
   683  
   684  	// GenerateUnmapDeviceFunc uses "" as pod UUID, it is global operation over all pods that used the volume
   685  	unmapper, err = plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, "")
   686  	if err != nil {
   687  		t.Fatalf("failed to make a new Unmapper: %v", err)
   688  	}
   689  	csiUnmapper = unmapper.(*csiBlockMapper)
   690  	csiUnmapper.csiClient = csiMapper.csiClient
   691  
   692  	err = csiUnmapper.TearDownDevice(globalMapPath, "/dev/test")
   693  	if err != nil {
   694  		t.Fatal(err)
   695  	}
   696  	pubs := csiUnmapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   697  	if _, ok := pubs[csiUnmapper.volumeID]; ok {
   698  		t.Error("csi server may not have received NodeUnpublishVolume call")
   699  	}
   700  	vols := csiUnmapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodeStagedVolumes()
   701  	if _, ok := vols[csiUnmapper.volumeID]; ok {
   702  		t.Error("csi server may not have received NodeUnstageVolume call")
   703  	}
   704  
   705  	// Check that all metadata / staging / publish directories were deleted
   706  	dataDir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   707  	if _, err := os.Stat(dataDir); err == nil {
   708  		t.Errorf("volume publish data directory %s was not deleted", dataDir)
   709  	}
   710  	devDir := getVolumeDeviceDataDir(pv.ObjectMeta.Name, plug.host)
   711  	if _, err := os.Stat(devDir); err == nil {
   712  		t.Errorf("volume publish device directory %s was not deleted", devDir)
   713  	}
   714  	if _, err := os.Stat(publishPath); err == nil {
   715  		t.Errorf("volume publish path %s was not deleted", publishPath)
   716  	}
   717  	publishDir := filepath.Dir(publishPath)
   718  	if _, err := os.Stat(publishDir); err == nil {
   719  		t.Errorf("volume publish parent directory %s was not deleted", publishDir)
   720  	}
   721  	if _, err := os.Stat(stagingPath); err == nil {
   722  		t.Errorf("volume staging path %s was not deleted", stagingPath)
   723  	}
   724  }
   725  
   726  func TestUnmapPodDeviceNoClientError(t *testing.T) {
   727  	transientError := volumetypes.NewTransientOperationFailure("")
   728  	plug, tmpDir := newTestPlugin(t, nil)
   729  	defer os.RemoveAll(tmpDir)
   730  
   731  	csiMapper, spec, pv, err := prepareBlockMapperTest(plug, "test-pv", t)
   732  	if err != nil {
   733  		t.Fatalf("Failed to make a new Mapper: %v", err)
   734  	}
   735  
   736  	pvName := pv.GetName()
   737  	nodeName := string(plug.host.GetNodeName())
   738  
   739  	csiMapper.csiClient = setupClient(t, true)
   740  
   741  	attachID := getAttachmentName(csiMapper.volumeID, string(csiMapper.driverName), string(nodeName))
   742  	attachment := makeTestAttachment(attachID, nodeName, pvName)
   743  	attachment.Status.Attached = true
   744  	_, err = csiMapper.k8s.StorageV1().VolumeAttachments().Create(context.TODO(), attachment, metav1.CreateOptions{})
   745  	if err != nil {
   746  		t.Fatalf("failed to setup VolumeAttachment: %v", err)
   747  	}
   748  	t.Log("created attachment ", attachID)
   749  
   750  	stagingPath, err := csiMapper.SetUpDevice()
   751  	if err != nil {
   752  		t.Fatalf("mapper failed to SetupDevice: %v", err)
   753  	}
   754  	// Check if NodeStageVolume staged to the right path
   755  	svols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodeStagedVolumes()
   756  	svol, ok := svols[csiMapper.volumeID]
   757  	if !ok {
   758  		t.Error("csi server may not have received NodeStageVolume call")
   759  	}
   760  	if svol.Path != stagingPath {
   761  		t.Errorf("csi server expected device path %s, got %s", stagingPath, svol.Path)
   762  	}
   763  
   764  	path, err := csiMapper.MapPodDevice()
   765  	if err != nil {
   766  		t.Fatalf("mapper failed to GetGlobalMapPath: %v", err)
   767  	}
   768  	pvols := csiMapper.csiClient.(*fakeCsiDriverClient).nodeClient.GetNodePublishedVolumes()
   769  	pvol, ok := pvols[csiMapper.volumeID]
   770  	if !ok {
   771  		t.Error("csi server may not have received NodePublishVolume call")
   772  	}
   773  	publishPath := csiMapper.getPublishPath()
   774  	if pvol.Path != publishPath {
   775  		t.Errorf("csi server expected path %s, got %s", publishPath, pvol.Path)
   776  	}
   777  	if path != publishPath {
   778  		t.Errorf("csi server expected path %s, but MapPodDevice returned %s", publishPath, path)
   779  	}
   780  
   781  	unmapper, err := plug.NewBlockVolumeUnmapper(pv.ObjectMeta.Name, testPodUID)
   782  	if err != nil {
   783  		t.Fatalf("failed to make a new Unmapper: %v", err)
   784  	}
   785  
   786  	csiUnmapper := unmapper.(*csiBlockMapper)
   787  	csiUnmapper.csiClient = csiMapper.csiClient
   788  
   789  	_, err = csiUnmapper.GetGlobalMapPath(spec)
   790  	if err != nil {
   791  		t.Fatalf("unmapper failed to GetGlobalMapPath: %v", err)
   792  	}
   793  
   794  	// Clear out the clients
   795  	// The lookup to generate a new client will fail when it tries to query a driver with an unknown name
   796  	csiUnmapper.csiClient = nil
   797  	csiUnmapper.csiClientGetter.csiClient = nil
   798  	// Note that prepareBlockMapperTest above will create a driver with a name of "test-driver"
   799  	csiUnmapper.csiClientGetter.driverName = "unknown-driver"
   800  
   801  	err = csiUnmapper.UnmapPodDevice()
   802  	if err == nil {
   803  		t.Errorf("test should fail, but no error occurred")
   804  	} else if reflect.TypeOf(transientError) != reflect.TypeOf(err) {
   805  		t.Fatalf("expected exitError type: %v got: %v (%v)", reflect.TypeOf(transientError), reflect.TypeOf(err), err)
   806  	}
   807  }
   808  

View as plain text