Skip to content

Commit 54297b1

Browse files
authored
Merge pull request #1918 from davis-haba/force-timeout-nodeunstagevolume
Force timeout nodeunstagevolume
2 parents 10f3fdb + f15a491 commit 54297b1

File tree

15 files changed

+1118
-18
lines changed

15 files changed

+1118
-18
lines changed

cmd/gce-pd-csi-driver/main.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ var (
6464
waitForOpBackoffSteps = flag.Int("wait-op-backoff-steps", 100, "Steps for wait for operation backoff")
6565
waitForOpBackoffCap = flag.Duration("wait-op-backoff-cap", 0, "Cap for wait for operation backoff")
6666

67+
enableDeviceInUseCheck = flag.Bool("enable-device-in-use-check-on-node-unstage", true, "If set to true, block NodeUnstageVolume requests until the specified device is not in use")
68+
deviceInUseTimeout = flag.Duration("device-in-use-timeout", 30*time.Second, "Max time to wait for a device to be unused when attempting to unstage. Exceeding the timeout will cause an unstage request to return success and ignore the device in use check.")
69+
6770
maxProcs = flag.Int("maxprocs", 1, "GOMAXPROCS override")
6871
maxConcurrentFormat = flag.Int("max-concurrent-format", 1, "The maximum number of concurrent format exec calls")
6972
concurrentFormatTimeout = flag.Duration("concurrent-format-timeout", 1*time.Minute, "The maximum duration of a format operation before its concurrency token is released")
@@ -241,7 +244,11 @@ func handle() {
241244
if err != nil {
242245
klog.Fatalf("Failed to set up metadata service: %v", err.Error())
243246
}
244-
nodeServer = driver.NewNodeServer(gceDriver, mounter, deviceUtils, meta, statter)
247+
nsArgs := driver.NodeServerArgs{
248+
EnableDeviceInUseCheck: *enableDeviceInUseCheck,
249+
DeviceInUseTimeout: *deviceInUseTimeout,
250+
}
251+
nodeServer = driver.NewNodeServer(gceDriver, mounter, deviceUtils, meta, statter, nsArgs)
245252
if *maxConcurrentFormatAndMount > 0 {
246253
nodeServer = nodeServer.WithSerializedFormatAndMount(*formatAndMountTimeout, *maxConcurrentFormatAndMount)
247254
}

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/google/go-cmp v0.6.0
1414
github.com/google/uuid v1.6.0
1515
github.com/googleapis/gax-go/v2 v2.12.4
16+
github.com/hashicorp/golang-lru/v2 v2.0.7
1617
github.com/kubernetes-csi/csi-proxy/client v1.1.3
1718
github.com/kubernetes-csi/csi-test/v5 v5.3.0
1819
github.com/onsi/ginkgo/v2 v2.20.1

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
15501550
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
15511551
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
15521552
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
1553+
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
1554+
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
15531555
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
15541556
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
15551557
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package gceGCEDriver
16+
17+
import (
18+
"sync"
19+
"time"
20+
21+
"github.com/hashicorp/golang-lru/v2/expirable"
22+
"k8s.io/klog/v2"
23+
)
24+
25+
// maxDeviceCacheSize specifies the maximum number if in-use devices to cache.
26+
// 256 was selected since it is twice the number of max PDs per VM (128)
27+
const maxDeviceCacheSize = 256
28+
29+
// currentTime is used to stub time.Now in unit tests
30+
var currentTime = time.Now
31+
32+
// deviceErrMap is an atomic data datastructure for recording deviceInUseError times
33+
// for specified devices
34+
type deviceErrMap struct {
35+
timeout time.Duration
36+
mux sync.Mutex
37+
cache *expirable.LRU[string, time.Time]
38+
}
39+
40+
func newDeviceErrMap(timeout time.Duration) *deviceErrMap {
41+
c := expirable.NewLRU[string, time.Time](maxDeviceCacheSize, nil, timeout*2)
42+
43+
return &deviceErrMap{
44+
cache: c,
45+
timeout: timeout,
46+
}
47+
}
48+
49+
// deviceErrorExpired returns true if an error for the specified device is expired,
50+
// where the expiration is specified by `--device-in-use-timeout`
51+
func (devErrMap *deviceErrMap) deviceErrorExpired(deviceName string) bool {
52+
devErrMap.mux.Lock()
53+
defer devErrMap.mux.Unlock()
54+
55+
firstEncounteredErrTime, exists := devErrMap.cache.Get(deviceName)
56+
if !exists {
57+
// If the deviceName does not exist in the map, then this is the first time
58+
// an error was encountered for that device. We return false since it cannot be
59+
// expired yet.
60+
return false
61+
}
62+
expirationTime := firstEncounteredErrTime.Add(devErrMap.timeout)
63+
return currentTime().After(expirationTime)
64+
}
65+
66+
// markDeviceError updates the internal `cache` map to denote an error was encounted
67+
// for the specified deviceName at the current time. If an error had previously been recorded, the
68+
// time will not be updated.
69+
func (devErrMap *deviceErrMap) markDeviceError(deviceName string) {
70+
devErrMap.mux.Lock()
71+
defer devErrMap.mux.Unlock()
72+
73+
// If an earlier error has already been recorded, do not overwrite it
74+
if _, exists := devErrMap.cache.Get(deviceName); !exists {
75+
now := currentTime()
76+
klog.V(4).Infof("Recording in-use error for device %s at time %s", deviceName, now)
77+
devErrMap.cache.Add(deviceName, now)
78+
}
79+
}
80+
81+
// deleteDevice removes a specified device name from the map
82+
func (devErrMap *deviceErrMap) deleteDevice(deviceName string) {
83+
devErrMap.mux.Lock()
84+
defer devErrMap.mux.Unlock()
85+
devErrMap.cache.Remove(deviceName)
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package gceGCEDriver
16+
17+
import (
18+
"testing"
19+
"time"
20+
)
21+
22+
func TestDeviceErrorMap(t *testing.T) {
23+
timeout := time.Second * 10
24+
dName := "fake-device"
25+
eMap := newDeviceErrMap(timeout)
26+
defer func() { currentTime = time.Now }()
27+
28+
// Register an error. Checking the timeout right after should return false
29+
stubCurrentTime(0)
30+
eMap.markDeviceError(dName)
31+
isTimedOut := eMap.deviceErrorExpired(dName)
32+
if isTimedOut {
33+
t.Errorf("checkDeviceErrorTimeout expected to be false if called immediately after marking an error")
34+
}
35+
36+
// Advance time. Checking the timeout should now return true
37+
stubCurrentTime(int64(timeout.Seconds()) + 1)
38+
isTimedOut = eMap.deviceErrorExpired(dName)
39+
if !isTimedOut {
40+
t.Errorf("checkDeviceErrorTimeout expected to be true after waiting for timeout")
41+
}
42+
43+
// Deleting the device and checking the timout should return false
44+
eMap.deleteDevice(dName)
45+
isTimedOut = eMap.deviceErrorExpired(dName)
46+
if isTimedOut {
47+
t.Errorf("checkDeviceErrorTimeout expected to be false after deleting device from map")
48+
}
49+
}
50+
51+
func stubCurrentTime(unixTime int64) {
52+
currentTime = func() time.Time {
53+
return time.Unix(unixTime, 0)
54+
}
55+
}

pkg/gce-pd-csi-driver/gce-pd-driver.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,16 @@ func NewIdentityServer(gceDriver *GCEDriver) *GCEIdentityServer {
145145
}
146146
}
147147

148-
func NewNodeServer(gceDriver *GCEDriver, mounter *mount.SafeFormatAndMount, deviceUtils deviceutils.DeviceUtils, meta metadataservice.MetadataService, statter mountmanager.Statter) *GCENodeServer {
148+
func NewNodeServer(gceDriver *GCEDriver, mounter *mount.SafeFormatAndMount, deviceUtils deviceutils.DeviceUtils, meta metadataservice.MetadataService, statter mountmanager.Statter, args NodeServerArgs) *GCENodeServer {
149149
return &GCENodeServer{
150-
Driver: gceDriver,
151-
Mounter: mounter,
152-
DeviceUtils: deviceUtils,
153-
MetadataService: meta,
154-
volumeLocks: common.NewVolumeLocks(),
155-
VolumeStatter: statter,
150+
Driver: gceDriver,
151+
Mounter: mounter,
152+
DeviceUtils: deviceUtils,
153+
MetadataService: meta,
154+
volumeLocks: common.NewVolumeLocks(),
155+
VolumeStatter: statter,
156+
enableDeviceInUseCheck: args.EnableDeviceInUseCheck,
157+
deviceInUseErrors: newDeviceErrMap(args.DeviceInUseTimeout),
156158
}
157159
}
158160

pkg/gce-pd-csi-driver/node.go

+28-6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ type GCENodeServer struct {
5151
// for that same volume (as defined by VolumeID) return an Aborted error
5252
volumeLocks *common.VolumeLocks
5353

54+
// enableDeviceInUseCheck, if true, will block NodeUnstageVolume requests if the specified
55+
// device is still in use (or until --device-in-use-timeout is reached, if specified)
56+
enableDeviceInUseCheck bool
57+
// deviceInUseErrors keeps tracks of device names and a timestamp for when an error is
58+
// encounted for that device
59+
deviceInUseErrors *deviceErrMap
60+
5461
// If set, this semaphore will be used to serialize formatAndMount. It will be raised
5562
// when the operation starts, and lowered either when finished, or when
5663
// formatAndMountTimeout has expired.
@@ -65,6 +72,14 @@ type GCENodeServer struct {
6572
csi.UnimplementedNodeServer
6673
}
6774

75+
type NodeServerArgs struct {
76+
// EnableDeviceInUseCheck enables functionality which will block NodeUnstageVolume request
77+
// until the device is not in use
78+
EnableDeviceInUseCheck bool
79+
80+
DeviceInUseTimeout time.Duration
81+
}
82+
6883
var _ csi.NodeServer = &GCENodeServer{}
6984

7085
// The constants are used to map from the machine type to the limit of
@@ -94,6 +109,7 @@ func getDefaultFsType() string {
94109
return defaultLinuxFsType
95110
}
96111
}
112+
97113
func (ns *GCENodeServer) isVolumePathMounted(path string) bool {
98114
notMnt, err := ns.Mounter.Interface.IsLikelyNotMountPoint(path)
99115
klog.V(4).Infof("Checking volume path %s is mounted %t: error %v", path, !notMnt, err)
@@ -455,13 +471,19 @@ func (ns *GCENodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUns
455471
return nil, status.Error(codes.Internal, fmt.Sprintf("NodeUnstageVolume failed: %v\nUnmounting arguments: %s\n", err.Error(), stagingTargetPath))
456472
}
457473

458-
if err := ns.confirmDeviceUnused(volumeID); err != nil {
459-
var targetErr *ignoreableError
460-
if errors.As(err, &targetErr) {
461-
klog.Warningf("Unabled to check if device for %s is unused. Device has been unmounted successfully. Ignoring and continuing with unstaging. (%v)", volumeID, err)
462-
} else {
463-
return nil, status.Errorf(codes.Internal, "NodeUnstageVolume for volume %s failed: %v", volumeID, err)
474+
if ns.enableDeviceInUseCheck {
475+
if err := ns.confirmDeviceUnused(volumeID); err != nil {
476+
var ignoreableErr *ignoreableError
477+
if errors.As(err, &ignoreableErr) {
478+
klog.Warningf("Unable to check if device for %s is unused. Device has been unmounted successfully. Ignoring and continuing with unstaging. (%v)", volumeID, err)
479+
} else if ns.deviceInUseErrors.deviceErrorExpired(volumeID) {
480+
klog.Warningf("Device %s could not be released after timeout of %f seconds. NodeUnstageVolume will return success.", volumeID, ns.deviceInUseErrors.timeout.Seconds())
481+
} else {
482+
ns.deviceInUseErrors.markDeviceError(volumeID)
483+
return nil, status.Errorf(codes.Internal, "NodeUnstageVolume for volume %s failed: %v", volumeID, err)
484+
}
464485
}
486+
ns.deviceInUseErrors.deleteDevice(volumeID)
465487
}
466488

467489
klog.V(4).Infof("NodeUnstageVolume succeeded on %v from %s", volumeID, stagingTargetPath)

pkg/gce-pd-csi-driver/node_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func getTestGCEDriverWithCustomMounter(t *testing.T, mounter *mount.SafeFormatAn
5151

5252
func getCustomTestGCEDriver(t *testing.T, mounter *mount.SafeFormatAndMount, deviceUtils deviceutils.DeviceUtils, metaService metadataservice.MetadataService) *GCEDriver {
5353
gceDriver := GetGCEDriver()
54-
nodeServer := NewNodeServer(gceDriver, mounter, deviceUtils, metaService, mountmanager.NewFakeStatter(mounter))
54+
nodeServer := NewNodeServer(gceDriver, mounter, deviceUtils, metaService, mountmanager.NewFakeStatter(mounter), NodeServerArgs{true, 0})
5555
err := gceDriver.SetupGCEDriver(driver, "test-vendor", nil, nil, nil, nil, nodeServer)
5656
if err != nil {
5757
t.Fatalf("Failed to setup GCE Driver: %v", err)
@@ -62,7 +62,7 @@ func getCustomTestGCEDriver(t *testing.T, mounter *mount.SafeFormatAndMount, dev
6262
func getTestBlockingMountGCEDriver(t *testing.T, readyToExecute chan chan struct{}) *GCEDriver {
6363
gceDriver := GetGCEDriver()
6464
mounter := mountmanager.NewFakeSafeBlockingMounter(readyToExecute)
65-
nodeServer := NewNodeServer(gceDriver, mounter, deviceutils.NewFakeDeviceUtils(false), metadataservice.NewFakeService(), mountmanager.NewFakeStatter(mounter))
65+
nodeServer := NewNodeServer(gceDriver, mounter, deviceutils.NewFakeDeviceUtils(false), metadataservice.NewFakeService(), mountmanager.NewFakeStatter(mounter), NodeServerArgs{true, 0})
6666
err := gceDriver.SetupGCEDriver(driver, "test-vendor", nil, nil, nil, nil, nodeServer)
6767
if err != nil {
6868
t.Fatalf("Failed to setup GCE Driver: %v", err)
@@ -73,7 +73,7 @@ func getTestBlockingMountGCEDriver(t *testing.T, readyToExecute chan chan struct
7373
func getTestBlockingFormatAndMountGCEDriver(t *testing.T, readyToExecute chan chan struct{}) *GCEDriver {
7474
gceDriver := GetGCEDriver()
7575
mounter := mountmanager.NewFakeSafeBlockingMounter(readyToExecute)
76-
nodeServer := NewNodeServer(gceDriver, mounter, deviceutils.NewFakeDeviceUtils(false), metadataservice.NewFakeService(), mountmanager.NewFakeStatter(mounter)).WithSerializedFormatAndMount(5*time.Second, 1)
76+
nodeServer := NewNodeServer(gceDriver, mounter, deviceutils.NewFakeDeviceUtils(false), metadataservice.NewFakeService(), mountmanager.NewFakeStatter(mounter), NodeServerArgs{true, 0}).WithSerializedFormatAndMount(5*time.Second, 1)
7777

7878
err := gceDriver.SetupGCEDriver(driver, "test-vendor", nil, nil, nil, nil, nodeServer)
7979
if err != nil {

test/e2e/tests/single_zone_e2e_test.go

+76
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,82 @@ var _ = Describe("GCE PD CSI Driver", func() {
14381438
}()
14391439
})
14401440

1441+
It("Should unpublish if there is an error unpublishing and device has been in use longer than timeout", func() {
1442+
testContext := getRandomTestContext()
1443+
1444+
p, z, _ := testContext.Instance.GetIdentity()
1445+
client := testContext.Client
1446+
instance := testContext.Instance
1447+
1448+
// Create Disk
1449+
volName, volID := createAndValidateUniqueZonalDisk(client, p, z, standardDiskType)
1450+
1451+
defer func() {
1452+
// Delete Disk
1453+
err := client.DeleteVolume(volID)
1454+
Expect(err).To(BeNil(), "DeleteVolume failed")
1455+
1456+
// Validate Disk Deleted
1457+
_, err = computeService.Disks.Get(p, z, volName).Do()
1458+
Expect(gce.IsGCEError(err, "notFound")).To(BeTrue(), "Expected disk to not be found")
1459+
}()
1460+
1461+
// Attach Disk
1462+
err := client.ControllerPublishVolumeReadWrite(volID, instance.GetNodeID(), false /* forceAttach */)
1463+
Expect(err).To(BeNil(), "ControllerPublishVolume failed with error for disk %v on node %v: %v", volID, instance.GetNodeID(), err)
1464+
1465+
defer func() {
1466+
// Detach Disk
1467+
err = client.ControllerUnpublishVolume(volID, instance.GetNodeID())
1468+
if err != nil {
1469+
klog.Errorf("Failed to detach disk: %v", err)
1470+
}
1471+
}()
1472+
1473+
// Stage Disk
1474+
stageDir := filepath.Join("/tmp/", volName, "stage")
1475+
err = client.NodeStageExt4Volume(volID, stageDir)
1476+
Expect(err).To(BeNil(), "failed to stage volume: %v", err)
1477+
1478+
// Create private bind mount to keep the device's state as "in use"
1479+
boundMountStageDir := filepath.Join("/tmp/bindmount", volName, "bindmount")
1480+
boundMountStageMkdirOutput, err := instance.SSH("mkdir", "-p", boundMountStageDir)
1481+
Expect(err).To(BeNil(), "mkdir failed on instance %v: output: %v: %v", instance.GetNodeID(), boundMountStageMkdirOutput, err)
1482+
bindMountOutput, err := instance.SSH("mount", "--rbind", "--make-private", stageDir, boundMountStageDir)
1483+
Expect(err).To(BeNil(), "Bind mount failed on instance %v: output: %v: %v", instance.GetNodeID(), bindMountOutput, err)
1484+
1485+
privateBindMountRemoved := false
1486+
unmountAndRmPrivateBindMount := func() {
1487+
if !privateBindMountRemoved {
1488+
// Umount and delete private mount staging directory
1489+
bindUmountOutput, err := instance.SSH("umount", boundMountStageDir)
1490+
Expect(err).To(BeNil(), "Bind mount failed on instance %v: output: %v: %v", instance.GetNodeID(), bindUmountOutput, err)
1491+
err = testutils.RmAll(instance, boundMountStageDir)
1492+
Expect(err).To(BeNil(), "Failed to rm mount stage dir %s: %v", boundMountStageDir, err)
1493+
}
1494+
privateBindMountRemoved = true
1495+
}
1496+
1497+
defer func() {
1498+
unmountAndRmPrivateBindMount()
1499+
}()
1500+
1501+
// Unstage Disk. This should record a "deviceInUse" error
1502+
err = client.NodeUnstageVolume(volID, stageDir)
1503+
Expect(err).ToNot(BeNil(), "Expected failure during unstage")
1504+
Expect(err).To(MatchError(ContainSubstring(("is still in use"))))
1505+
1506+
// Wait 12s (10s timeout specified in CLI + 2s buffer) and try again
1507+
time.Sleep(12 * time.Second)
1508+
err = client.NodeUnstageVolume(volID, stageDir)
1509+
Expect(err).To(BeNil(), "Failed to unpublish after 10s in-use timeout for volume: %s, stageDir: %s, unexpected err: %s", volID, stageDir, err)
1510+
1511+
// Unstage Disk
1512+
fp := filepath.Join("/tmp/", volName)
1513+
err = testutils.RmAll(instance, fp)
1514+
Expect(err).To(BeNil(), "Failed to rm file path %s: %v", fp, err)
1515+
})
1516+
14411517
It("Should block unstage if filesystem mounted", func() {
14421518
testContext := getRandomTestContext()
14431519

test/e2e/utils/utils.go

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func GCEClientAndDriverSetup(instance *remote.InstanceInfo, driverConfig DriverC
6969
"--supports-dynamic-iops-provisioning=hyperdisk-balanced,hyperdisk-extreme",
7070
"--supports-dynamic-throughput-provisioning=hyperdisk-balanced,hyperdisk-throughput,hyperdisk-ml",
7171
"--allow-hdha-provisioning",
72+
"--device-in-use-timeout=10s", // Set lower than the usual value to expedite tests
7273
fmt.Sprintf("--fallback-requisite-zones=%s", strings.Join(driverConfig.Zones, ",")),
7374
}
7475
extra_flags = append(extra_flags, fmt.Sprintf("--compute-endpoint=%s", driverConfig.ComputeEndpoint))

test/sanity/sanity_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func TestSanity(t *testing.T) {
7777
identityServer := driver.NewIdentityServer(gceDriver)
7878
controllerServer := driver.NewControllerServer(gceDriver, cloudProvider, 0, 5*time.Minute, fallbackRequisiteZones, enableStoragePools, multiZoneVolumeHandleConfig, listVolumesConfig, provisionableDisksConfig, true)
7979
fakeStatter := mountmanager.NewFakeStatterWithOptions(mounter, mountmanager.FakeStatterOptions{IsBlock: false})
80-
nodeServer := driver.NewNodeServer(gceDriver, mounter, deviceUtils, metadataservice.NewFakeService(), fakeStatter)
80+
nodeServer := driver.NewNodeServer(gceDriver, mounter, deviceUtils, metadataservice.NewFakeService(), fakeStatter, driver.NodeServerArgs{EnableDeviceInUseCheck: true, DeviceInUseTimeout: 0})
8181
err = gceDriver.SetupGCEDriver(driverName, vendorVersion, extraLabels, nil, identityServer, controllerServer, nodeServer)
8282
if err != nil {
8383
t.Fatalf("Failed to initialize GCE CSI Driver: %v", err.Error())

0 commit comments

Comments
 (0)