...

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

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

     1  /*
     2  Copyright 2019 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  	"fmt"
    21  	"math/rand"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  	"time"
    26  
    27  	api "k8s.io/api/core/v1"
    28  	storage "k8s.io/api/storage/v1"
    29  	meta "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/apimachinery/pkg/util/wait"
    33  	"k8s.io/client-go/informers"
    34  	fakeclient "k8s.io/client-go/kubernetes/fake"
    35  	utiltesting "k8s.io/client-go/util/testing"
    36  	"k8s.io/kubernetes/pkg/volume"
    37  	volumetest "k8s.io/kubernetes/pkg/volume/testing"
    38  )
    39  
    40  // TestCSI_VolumeAll runs a close approximation of volume workflow
    41  // based on operations from the volume manager/reconciler/operation executor
    42  func TestCSI_VolumeAll(t *testing.T) {
    43  	defaultFSGroupPolicy := storage.ReadWriteOnceWithFSTypeFSGroupPolicy
    44  
    45  	tests := []struct {
    46  		name                 string
    47  		specName             string
    48  		driver               string
    49  		volName              string
    50  		specFunc             func(specName, driver, volName string) *volume.Spec
    51  		podFunc              func() *api.Pod
    52  		isInline             bool
    53  		findPluginShouldFail bool
    54  		driverSpec           *storage.CSIDriverSpec
    55  		watchTimeout         time.Duration
    56  	}{
    57  		{
    58  			name:     "PersistentVolume",
    59  			specName: "pv2",
    60  			driver:   "simple-driver",
    61  			volName:  "vol2",
    62  			specFunc: func(specName, driver, volName string) *volume.Spec {
    63  				return volume.NewSpecFromPersistentVolume(makeTestPV(specName, 20, driver, volName), false)
    64  			},
    65  			podFunc: func() *api.Pod {
    66  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
    67  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
    68  			},
    69  		},
    70  		{
    71  			name:     "PersistentVolume with driver info",
    72  			specName: "pv2",
    73  			driver:   "simple-driver",
    74  			volName:  "vol2",
    75  			specFunc: func(specName, driver, volName string) *volume.Spec {
    76  				return volume.NewSpecFromPersistentVolume(makeTestPV(specName, 20, driver, volName), false)
    77  			},
    78  			podFunc: func() *api.Pod {
    79  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
    80  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
    81  			},
    82  			driverSpec: &storage.CSIDriverSpec{
    83  				// Required for the driver to be accepted for the persistent volume.
    84  				VolumeLifecycleModes: []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent},
    85  				FSGroupPolicy:        &defaultFSGroupPolicy,
    86  			},
    87  		},
    88  		{
    89  			name:     "PersistentVolume with wrong mode in driver info",
    90  			specName: "pv2",
    91  			driver:   "simple-driver",
    92  			volName:  "vol2",
    93  			specFunc: func(specName, driver, volName string) *volume.Spec {
    94  				return volume.NewSpecFromPersistentVolume(makeTestPV(specName, 20, driver, volName), false)
    95  			},
    96  			podFunc: func() *api.Pod {
    97  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
    98  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
    99  			},
   100  			driverSpec: &storage.CSIDriverSpec{
   101  				// This will cause the volume to be rejected.
   102  				VolumeLifecycleModes: []storage.VolumeLifecycleMode{storage.VolumeLifecycleEphemeral},
   103  				FSGroupPolicy:        &defaultFSGroupPolicy,
   104  			},
   105  		},
   106  		{
   107  			name:    "ephemeral inline supported",
   108  			driver:  "inline-driver-1",
   109  			volName: "test.vol2",
   110  			specFunc: func(specName, driver, volName string) *volume.Spec {
   111  				return volume.NewSpecFromVolume(makeTestVol(specName, driver))
   112  			},
   113  			podFunc: func() *api.Pod {
   114  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   115  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   116  			},
   117  			isInline: true,
   118  			driverSpec: &storage.CSIDriverSpec{
   119  				// Required for the driver to be accepted for the inline volume.
   120  				VolumeLifecycleModes: []storage.VolumeLifecycleMode{storage.VolumeLifecycleEphemeral},
   121  				FSGroupPolicy:        &defaultFSGroupPolicy,
   122  			},
   123  		},
   124  		{
   125  			name:    "ephemeral inline also supported",
   126  			driver:  "inline-driver-1",
   127  			volName: "test.vol2",
   128  			specFunc: func(specName, driver, volName string) *volume.Spec {
   129  				return volume.NewSpecFromVolume(makeTestVol(specName, driver))
   130  			},
   131  			podFunc: func() *api.Pod {
   132  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   133  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   134  			},
   135  			isInline: true,
   136  			driverSpec: &storage.CSIDriverSpec{
   137  				// Required for the driver to be accepted for the inline volume.
   138  				VolumeLifecycleModes: []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent, storage.VolumeLifecycleEphemeral},
   139  				FSGroupPolicy:        &defaultFSGroupPolicy,
   140  			},
   141  		},
   142  		{
   143  			name:    "ephemeral inline without CSIDriver info",
   144  			driver:  "inline-driver-2",
   145  			volName: "test.vol3",
   146  			specFunc: func(specName, driver, volName string) *volume.Spec {
   147  				return volume.NewSpecFromVolume(makeTestVol(specName, driver))
   148  			},
   149  			podFunc: func() *api.Pod {
   150  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   151  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   152  			},
   153  			isInline: true,
   154  		},
   155  		{
   156  			name:    "ephemeral inline with driver that has no mode",
   157  			driver:  "inline-driver-3",
   158  			volName: "test.vol4",
   159  			specFunc: func(specName, driver, volName string) *volume.Spec {
   160  				return volume.NewSpecFromVolume(makeTestVol(specName, driver))
   161  			},
   162  			podFunc: func() *api.Pod {
   163  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   164  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   165  			},
   166  			isInline: true,
   167  			driverSpec: &storage.CSIDriverSpec{
   168  				// This means the driver *cannot* handle the inline volume because
   169  				// the default is "persistent".
   170  				VolumeLifecycleModes: nil,
   171  				FSGroupPolicy:        &defaultFSGroupPolicy,
   172  			},
   173  		},
   174  		{
   175  			name:    "ephemeral inline with driver that has wrong mode",
   176  			driver:  "inline-driver-3",
   177  			volName: "test.vol4",
   178  			specFunc: func(specName, driver, volName string) *volume.Spec {
   179  				return volume.NewSpecFromVolume(makeTestVol(specName, driver))
   180  			},
   181  			podFunc: func() *api.Pod {
   182  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   183  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   184  			},
   185  			isInline: true,
   186  			driverSpec: &storage.CSIDriverSpec{
   187  				// This means the driver *cannot* handle the inline volume.
   188  				VolumeLifecycleModes: []storage.VolumeLifecycleMode{storage.VolumeLifecyclePersistent},
   189  				FSGroupPolicy:        &defaultFSGroupPolicy,
   190  			},
   191  		},
   192  		{
   193  			name:     "missing spec",
   194  			specName: "pv2",
   195  			driver:   "simple-driver",
   196  			volName:  "vol2",
   197  			specFunc: func(specName, driver, volName string) *volume.Spec {
   198  				return nil
   199  			},
   200  			podFunc: func() *api.Pod {
   201  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   202  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   203  			},
   204  			findPluginShouldFail: true,
   205  		},
   206  		{
   207  			name:     "incomplete spec",
   208  			specName: "pv2",
   209  			driver:   "simple-driver",
   210  			volName:  "vol2",
   211  			specFunc: func(specName, driver, volName string) *volume.Spec {
   212  				return &volume.Spec{ReadOnly: true}
   213  			},
   214  			podFunc: func() *api.Pod {
   215  				podUID := types.UID(fmt.Sprintf("%08X", rand.Uint64()))
   216  				return &api.Pod{ObjectMeta: meta.ObjectMeta{UID: podUID, Namespace: testns}}
   217  			},
   218  			findPluginShouldFail: true,
   219  		},
   220  	}
   221  
   222  	for _, test := range tests {
   223  		t.Run(test.name, func(t *testing.T) {
   224  			tmpDir, err := utiltesting.MkTmpdir("csi-test")
   225  			if err != nil {
   226  				t.Fatalf("can't create temp dir: %v", err)
   227  			}
   228  			defer os.RemoveAll(tmpDir)
   229  
   230  			var driverInfo *storage.CSIDriver
   231  			objs := []runtime.Object{}
   232  			if test.driverSpec != nil {
   233  				driverInfo = &storage.CSIDriver{
   234  					ObjectMeta: meta.ObjectMeta{
   235  						Name: test.driver,
   236  					},
   237  					Spec: *test.driverSpec,
   238  				}
   239  				objs = append(objs, driverInfo)
   240  			}
   241  			objs = append(objs, &api.Node{
   242  				ObjectMeta: meta.ObjectMeta{
   243  					Name: "fakeNode",
   244  				},
   245  				Spec: api.NodeSpec{},
   246  			})
   247  
   248  			client := fakeclient.NewSimpleClientset(objs...)
   249  
   250  			factory := informers.NewSharedInformerFactory(client, time.Hour /* disable resync */)
   251  			csiDriverInformer := factory.Storage().V1().CSIDrivers()
   252  			volumeAttachmentInformer := factory.Storage().V1().VolumeAttachments()
   253  			if driverInfo != nil {
   254  				csiDriverInformer.Informer().GetStore().Add(driverInfo)
   255  			}
   256  
   257  			factory.Start(wait.NeverStop)
   258  			factory.WaitForCacheSync(wait.NeverStop)
   259  
   260  			attachDetachVolumeHost := volumetest.NewFakeAttachDetachVolumeHostWithCSINodeName(t,
   261  				tmpDir,
   262  				client,
   263  				ProbeVolumePlugins(),
   264  				"fakeNode",
   265  				csiDriverInformer.Lister(),
   266  				volumeAttachmentInformer.Lister(),
   267  			)
   268  			attachDetachPlugMgr := attachDetachVolumeHost.GetPluginMgr()
   269  			csiClient := setupClient(t, true)
   270  
   271  			volSpec := test.specFunc(test.specName, test.driver, test.volName)
   272  			pod := test.podFunc()
   273  			attachName := getAttachmentName(test.volName, test.driver, string(attachDetachVolumeHost.GetNodeName()))
   274  			t.Log("csiTest.VolumeAll starting...")
   275  
   276  			// *************** Attach/Mount volume resources ****************//
   277  			// attach volume
   278  			t.Log("csiTest.VolumeAll Attaching volume...")
   279  			attachPlug, err := attachDetachPlugMgr.FindAttachablePluginBySpec(volSpec)
   280  			if err != nil {
   281  				if !test.findPluginShouldFail {
   282  					t.Fatalf("csiTest.VolumeAll PluginManager.FindAttachablePluginBySpec failed: %v", err)
   283  				} else {
   284  					t.Log("csiTest.VolumeAll failed: ", err)
   285  					return
   286  				}
   287  			}
   288  
   289  			if test.isInline && attachPlug != nil {
   290  				t.Fatal("csiTest.VolumeAll AttachablePlugin found with ephemeral volume")
   291  			}
   292  			if !test.isInline && attachPlug == nil {
   293  				t.Fatal("csiTest.VolumeAll AttachablePlugin not found with PV")
   294  			}
   295  
   296  			var devicePath string
   297  			if attachPlug != nil {
   298  				t.Log("csiTest.VolumeAll attacher.Attach starting")
   299  
   300  				var volAttacher volume.Attacher
   301  
   302  				volAttacher, err := attachPlug.NewAttacher()
   303  				if err != nil {
   304  					t.Fatal("csiTest.VolumeAll failed to create new attacher: ", err)
   305  				}
   306  
   307  				// creates VolumeAttachment and blocks until it is marked attached (done by external attacher)
   308  				go func() {
   309  					attachID, err := volAttacher.Attach(volSpec, attachDetachVolumeHost.GetNodeName())
   310  					if err != nil {
   311  						t.Errorf("csiTest.VolumeAll attacher.Attach failed: %s", err)
   312  						return
   313  					}
   314  					t.Logf("csiTest.VolumeAll got attachID %s", attachID)
   315  				}()
   316  
   317  				// Simulates external-attacher and marks VolumeAttachment.Status.Attached = true
   318  				markVolumeAttached(t, attachDetachVolumeHost.GetKubeClient(), nil, attachName, storage.VolumeAttachmentStatus{Attached: true})
   319  
   320  				// Observe attach on this node.
   321  				devicePath, err = volAttacher.WaitForAttach(volSpec, "", pod, 500*time.Millisecond)
   322  				if err != nil {
   323  					t.Fatal("csiTest.VolumeAll attacher.WaitForAttach failed:", err)
   324  				}
   325  
   326  				if devicePath != attachName {
   327  					t.Fatalf("csiTest.VolumeAll attacher.WaitForAttach got unexpected value %s", devicePath)
   328  				}
   329  
   330  				t.Log("csiTest.VolumeAll attacher.WaitForAttach succeeded OK, attachment ID:", devicePath)
   331  
   332  			} else {
   333  				t.Log("csiTest.VolumeAll volume attacher not found, skipping attachment")
   334  			}
   335  
   336  			// The reason for separate volume hosts here is because the attach/detach behavior is exclusive to the
   337  			// CSI plugin running in the AttachDetachController. Similarly, the mount/unmount behavior is exclusive
   338  			// to the CSI plugin running in the Kubelet.
   339  			kubeletVolumeHost := volumetest.NewFakeKubeletVolumeHostWithCSINodeName(t,
   340  				tmpDir,
   341  				client,
   342  				ProbeVolumePlugins(),
   343  				"fakeNode",
   344  				csiDriverInformer.Lister(),
   345  				volumeAttachmentInformer.Lister(),
   346  			)
   347  			kubeletPlugMgr := kubeletVolumeHost.GetPluginMgr()
   348  
   349  			// Mount Device
   350  			t.Log("csiTest.VolumeAll Mouting device...")
   351  			devicePlug, err := kubeletPlugMgr.FindDeviceMountablePluginBySpec(volSpec)
   352  			if err != nil {
   353  				t.Fatalf("csiTest.VolumeAll PluginManager.FindDeviceMountablePluginBySpec failed: %v", err)
   354  			}
   355  
   356  			if test.isInline && devicePlug != nil {
   357  				t.Fatal("csiTest.VolumeAll DeviceMountablePlugin found with ephemeral volume")
   358  			}
   359  			if !test.isInline && devicePlug == nil {
   360  				t.Fatal("csiTest.VolumeAll DeviceMountablePlugin not found with PV")
   361  			}
   362  
   363  			var devMounter volume.DeviceMounter
   364  			if devicePlug != nil {
   365  				devMounter, err = devicePlug.NewDeviceMounter()
   366  				if err != nil {
   367  					t.Fatal("csiTest.VolumeAll failed to create new device mounter: ", err)
   368  				}
   369  			}
   370  
   371  			if devMounter != nil {
   372  				csiDevMounter := getCsiAttacherFromDeviceMounter(devMounter, test.watchTimeout)
   373  				csiDevMounter.csiClient = csiClient
   374  				devMountPath, err := csiDevMounter.GetDeviceMountPath(volSpec)
   375  				if err != nil {
   376  					t.Fatalf("csiTest.VolumeAll deviceMounter.GetdeviceMountPath failed %s", err)
   377  				}
   378  				if err := csiDevMounter.MountDevice(volSpec, devicePath, devMountPath, volume.DeviceMounterArgs{}); err != nil {
   379  					t.Fatalf("csiTest.VolumeAll deviceMounter.MountDevice failed: %v", err)
   380  				}
   381  				t.Log("csiTest.VolumeAll device mounted at path:", devMountPath)
   382  			} else {
   383  				t.Log("csiTest.VolumeAll DeviceMountablePlugin not found, skipping deviceMounter.MountDevice")
   384  			}
   385  
   386  			// mount volume
   387  			t.Log("csiTest.VolumeAll Mouting volume...")
   388  			volPlug, err := kubeletPlugMgr.FindPluginBySpec(volSpec)
   389  			if err != nil || volPlug == nil {
   390  				t.Fatalf("csiTest.VolumeAll PluginMgr.FindPluginBySpec failed: %v", err)
   391  			}
   392  
   393  			if volPlug == nil {
   394  				t.Fatalf("csiTest.VolumeAll volumePlugin is nil")
   395  			}
   396  
   397  			if !volPlug.CanSupport(volSpec) {
   398  				t.Fatal("csiTest.VolumeAll volumePlugin.CanSupport returned false")
   399  			}
   400  
   401  			mounter, err := volPlug.NewMounter(volSpec, pod, volume.VolumeOptions{})
   402  			if err != nil || mounter == nil {
   403  				t.Fatalf("csiTest.VolumeAll volPlugin.NewMounter is nil or error: %s", err)
   404  			}
   405  
   406  			var fsGroup *int64
   407  			if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.FSGroup != nil {
   408  				fsGroup = pod.Spec.SecurityContext.FSGroup
   409  			}
   410  
   411  			csiMounter := mounter.(*csiMountMgr)
   412  			csiMounter.csiClient = csiClient
   413  			var mounterArgs volume.MounterArgs
   414  			mounterArgs.FsGroup = fsGroup
   415  			err = csiMounter.SetUp(mounterArgs)
   416  			if test.isInline && (test.driverSpec == nil || !containsVolumeMode(test.driverSpec.VolumeLifecycleModes, storage.VolumeLifecycleEphemeral)) {
   417  				// This *must* fail because a CSIDriver.Spec.VolumeLifecycleModes entry "ephemeral"
   418  				// is required.
   419  				if err == nil {
   420  					t.Fatalf("csiTest.VolumeAll volPlugin.NewMounter should have failed for inline volume due to lack of support for inline volumes, got: %+v, %s", mounter, err)
   421  				}
   422  				return
   423  			}
   424  			if !test.isInline && test.driverSpec != nil && !containsVolumeMode(test.driverSpec.VolumeLifecycleModes, storage.VolumeLifecyclePersistent) {
   425  				// This *must* fail because a CSIDriver.Spec.VolumeLifecycleModes entry "persistent"
   426  				// is required when a driver object is available.
   427  				if err == nil {
   428  					t.Fatalf("csiTest.VolumeAll volPlugin.NewMounter should have failed for persistent volume due to lack of support for persistent volumes, got: %+v, %s", mounter, err)
   429  				}
   430  				return
   431  			}
   432  			if err != nil {
   433  				t.Fatalf("csiTest.VolumeAll mounter.Setup(fsGroup) failed: %s", err)
   434  			}
   435  			t.Log("csiTest.VolumeAll mounter.Setup(fsGroup) done OK")
   436  
   437  			dataFile := filepath.Join(filepath.Dir(mounter.GetPath()), volDataFileName)
   438  			if _, err := os.Stat(dataFile); err != nil {
   439  				t.Fatalf("csiTest.VolumeAll metadata JSON file not found: %s", dataFile)
   440  			}
   441  			t.Log("csiTest.VolumeAll JSON datafile generated OK:", dataFile)
   442  
   443  			// ******** Volume Reconstruction ************* //
   444  			volPath := filepath.Dir(csiMounter.GetPath())
   445  			t.Log("csiTest.VolumeAll entering plugin.ConstructVolumeSpec for path", volPath)
   446  			rec, err := volPlug.ConstructVolumeSpec(test.volName, volPath)
   447  			if err != nil {
   448  				t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec failed: %s", err)
   449  			} else {
   450  				if rec.Spec == nil {
   451  					t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec returned nil spec")
   452  				} else {
   453  					volSpec = rec.Spec
   454  
   455  					if test.isInline {
   456  						if volSpec.Volume == nil || volSpec.Volume.CSI == nil {
   457  							t.Fatal("csiTest.VolumeAll reconstruction of ephemeral volumeSpec missing CSI Volume source")
   458  						}
   459  						if volSpec.Volume.CSI.Driver == "" {
   460  							t.Fatal("csiTest.VolumeAll reconstruction ephemral volume missing driver name")
   461  						}
   462  					} else {
   463  						if volSpec.PersistentVolume == nil || volSpec.PersistentVolume.Spec.CSI == nil {
   464  							t.Fatal("csiTest.VolumeAll reconstruction of volumeSpec missing CSI PersistentVolume source")
   465  						}
   466  						csi := volSpec.PersistentVolume.Spec.CSI
   467  						if csi.Driver == "" {
   468  							t.Fatal("csiTest.VolumeAll reconstruction of PV missing driver name")
   469  						}
   470  						if csi.VolumeHandle == "" {
   471  							t.Fatal("csiTest.VolumeAll reconstruction of PV missing volume handle")
   472  						}
   473  					}
   474  				}
   475  			}
   476  
   477  			// ************* Teardown everything **************** //
   478  			t.Log("csiTest.VolumeAll Tearing down...")
   479  			// unmount volume
   480  			t.Log("csiTest.VolumeAll Unmouting volume...")
   481  			volPlug, err = kubeletPlugMgr.FindPluginBySpec(volSpec)
   482  			if err != nil || volPlug == nil {
   483  				t.Fatalf("csiTest.VolumeAll PluginMgr.FindPluginBySpec failed: %v", err)
   484  			}
   485  			if volPlug == nil {
   486  				t.Fatalf("csiTest.VolumeAll volumePlugin is nil")
   487  			}
   488  			mounter, err = volPlug.NewMounter(volSpec, pod, volume.VolumeOptions{})
   489  			if err != nil || mounter == nil {
   490  				t.Fatalf("csiTest.VolumeAll volPlugin.NewMounter is nil or error: %s", err)
   491  			}
   492  
   493  			unmounter, err := volPlug.NewUnmounter(test.specName, pod.GetUID())
   494  			if err != nil {
   495  				t.Fatal("csiTest.VolumeAll volumePlugin.NewUnmounter failed:", err)
   496  			}
   497  			csiUnmounter := unmounter.(*csiMountMgr)
   498  			csiUnmounter.csiClient = csiClient
   499  
   500  			if err := csiUnmounter.TearDownAt(mounter.GetPath()); err != nil {
   501  				t.Fatal("csiTest.VolumeAll unmounter.TearDownAt failed:", err)
   502  			}
   503  			t.Log("csiTest.VolumeAll unmounter.TearDownAt done OK for dir:", mounter.GetPath())
   504  
   505  			// unmount device
   506  			t.Log("csiTest.VolumeAll Unmouting device...")
   507  			devicePlug, err = kubeletPlugMgr.FindDeviceMountablePluginBySpec(volSpec)
   508  			if err != nil {
   509  				t.Fatalf("csiTest.VolumeAll failed to create mountable device plugin: %s", err)
   510  			}
   511  
   512  			if test.isInline && devicePlug != nil {
   513  				t.Fatal("csiTest.VolumeAll DeviceMountablePlugin found with ephemeral volume")
   514  			}
   515  			if !test.isInline && devicePlug == nil {
   516  				t.Fatal("csiTest.VolumeAll DeviceMountablePlugin not found with PV")
   517  			}
   518  
   519  			var devUnmounter volume.DeviceUnmounter
   520  			if devicePlug != nil {
   521  				t.Log("csiTest.VolumeAll found DeviceMountablePlugin, entering device unmouting ...")
   522  				devMounter, err = devicePlug.NewDeviceMounter()
   523  				if err != nil {
   524  					t.Fatal("csiTest.VolumeAll failed to create new device mounter: ", err)
   525  				}
   526  				devUnmounter, err = devicePlug.NewDeviceUnmounter()
   527  				if err != nil {
   528  					t.Fatal("csiTest.VolumeAll failed to create new device unmounter: ", err)
   529  				}
   530  
   531  				if devMounter != nil && devUnmounter != nil {
   532  					csiDevMounter := getCsiAttacherFromDeviceMounter(devMounter, test.watchTimeout)
   533  					csiDevUnmounter := getCsiAttacherFromDeviceUnmounter(devUnmounter, test.watchTimeout)
   534  					csiDevUnmounter.csiClient = csiClient
   535  
   536  					devMountPath, err := csiDevMounter.GetDeviceMountPath(volSpec)
   537  					if err != nil {
   538  						t.Fatalf("csiTest.VolumeAll deviceMounter.GetdeviceMountPath failed %s", err)
   539  					}
   540  					if err := csiDevUnmounter.UnmountDevice(devMountPath); err != nil {
   541  						t.Fatalf("csiTest.VolumeAll deviceMounter.UnmountDevice failed: %s", err)
   542  					}
   543  					t.Log("csiTest.VolumeAll deviceUnmounter.UnmountDevice done OK for path", devMountPath)
   544  				}
   545  			} else {
   546  				t.Log("csiTest.VolumeAll DeviceMountablePluginBySpec did not find a plugin, skipping unmounting.")
   547  			}
   548  
   549  			// detach volume
   550  			t.Log("csiTest.VolumeAll Detaching volume...")
   551  			attachPlug, err = attachDetachPlugMgr.FindAttachablePluginBySpec(volSpec)
   552  			if err != nil {
   553  				t.Fatalf("csiTest.VolumeAll PluginManager.FindAttachablePluginBySpec failed: %v", err)
   554  			}
   555  
   556  			if test.isInline && attachPlug != nil {
   557  				t.Fatal("csiTest.VolumeAll AttachablePlugin found with ephemeral volume")
   558  			}
   559  			if !test.isInline && attachPlug == nil {
   560  				t.Fatal("csiTest.VolumeAll AttachablePlugin not found with PV")
   561  			}
   562  
   563  			if attachPlug != nil {
   564  				volDetacher, err := attachPlug.NewDetacher()
   565  				if err != nil {
   566  					t.Fatal("csiTest.VolumeAll failed to create new detacher: ", err)
   567  				}
   568  
   569  				t.Log("csiTest.VolumeAll preparing detacher.Detach...")
   570  				volName, err := volPlug.GetVolumeName(volSpec)
   571  				if err != nil {
   572  					t.Fatal("csiTest.VolumeAll volumePlugin.GetVolumeName failed:", err)
   573  				}
   574  				csiDetacher := getCsiAttacherFromVolumeDetacher(volDetacher, test.watchTimeout)
   575  				csiDetacher.csiClient = csiClient
   576  				if err := csiDetacher.Detach(volName, attachDetachVolumeHost.GetNodeName()); err != nil {
   577  					t.Fatal("csiTest.VolumeAll detacher.Detach failed:", err)
   578  				}
   579  				t.Log("csiTest.VolumeAll detacher.Detach succeeded for volume", volName)
   580  
   581  			} else {
   582  				t.Log("csiTest.VolumeAll attachable plugin not found for plugin.Detach call, skipping")
   583  			}
   584  		})
   585  	}
   586  }
   587  

View as plain text