Skip to content

Commit ad8df8f

Browse files
authored
Merge pull request #1082 from wongma7/nodestageidempotent
Search for nvme device path even if non-nvme exists
2 parents 4d5d7e7 + 0d8f988 commit ad8df8f

File tree

10 files changed

+695
-308
lines changed

10 files changed

+695
-308
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ word-hyphen = $(word $2,$(subst -, ,$1))
5050

5151
.EXPORT_ALL_VARIABLES:
5252

53-
.PHONY: linux/$(ARCH)
53+
.PHONY: linux/$(ARCH) bin/aws-ebs-csi-driver
5454
linux/$(ARCH): bin/aws-ebs-csi-driver
5555
bin/aws-ebs-csi-driver: | bin
5656
CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -mod=vendor -ldflags ${LDFLAGS} -o bin/aws-ebs-csi-driver ./cmd/
5757

58-
.PHONY: windows/$(ARCH)
58+
.PHONY: windows/$(ARCH) bin/aws-ebs-csi-driver.exe
5959
windows/$(ARCH): bin/aws-ebs-csi-driver.exe
6060
bin/aws-ebs-csi-driver.exe: | bin
6161
CGO_ENABLED=0 GOOS=windows GOARCH=$(ARCH) go build -mod=vendor -ldflags ${LDFLAGS} -o bin/aws-ebs-csi-driver.exe ./cmd/

hack/e2e/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ REGION=${AWS_REGION:-us-west-2}
4242
ZONES=${AWS_AVAILABILITY_ZONES:-us-west-2a,us-west-2b,us-west-2c}
4343
FIRST_ZONE=$(echo "${ZONES}" | cut -d, -f1)
4444
NODE_COUNT=${NODE_COUNT:-3}
45-
INSTANCE_TYPE=${INSTANCE_TYPE:-c4.large}
45+
INSTANCE_TYPE=${INSTANCE_TYPE:-c5.large}
4646

4747
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
4848
IMAGE_NAME=${IMAGE_NAME:-${AWS_ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${DRIVER_NAME}}

pkg/driver/mock_mount.go

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/driver/mount.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ limitations under the License.
1717
package driver
1818

1919
import (
20+
"os"
21+
"path/filepath"
22+
2023
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/mounter"
2124
mountutils "k8s.io/mount-utils"
2225
)
@@ -54,3 +57,27 @@ func newNodeMounter() (Mounter, error) {
5457
}
5558
return &NodeMounter{safeMounter}, nil
5659
}
60+
61+
// DeviceIdentifier is for mocking os io functions used for the driver to
62+
// identify an EBS volume's corresponding device (in Linux, the path under
63+
// /dev; in Windows, the volume number) so that it can mount it. For volumes
64+
// already mounted, see GetDeviceNameFromMount.
65+
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html#identify-nvme-ebs-device
66+
type DeviceIdentifier interface {
67+
Lstat(name string) (os.FileInfo, error)
68+
EvalSymlinks(path string) (string, error)
69+
}
70+
71+
type nodeDeviceIdentifier struct{}
72+
73+
func newNodeDeviceIdentifier() DeviceIdentifier {
74+
return &nodeDeviceIdentifier{}
75+
}
76+
77+
func (i *nodeDeviceIdentifier) Lstat(name string) (os.FileInfo, error) {
78+
return os.Lstat(name)
79+
}
80+
81+
func (i *nodeDeviceIdentifier) EvalSymlinks(path string) (string, error) {
82+
return filepath.EvalSymlinks(path)
83+
}

pkg/driver/node.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,11 @@ var (
7373

7474
// nodeService represents the node service of CSI driver
7575
type nodeService struct {
76-
metadata cloud.MetadataService
77-
mounter Mounter
78-
inFlight *internal.InFlight
79-
driverOptions *DriverOptions
76+
metadata cloud.MetadataService
77+
mounter Mounter
78+
deviceIdentifier DeviceIdentifier
79+
inFlight *internal.InFlight
80+
driverOptions *DriverOptions
8081
}
8182

8283
// newNodeService creates a new node service
@@ -94,10 +95,11 @@ func newNodeService(driverOptions *DriverOptions) nodeService {
9495
}
9596

9697
return nodeService{
97-
metadata: metadata,
98-
mounter: nodeMounter,
99-
inFlight: internal.NewInFlight(),
100-
driverOptions: driverOptions,
98+
metadata: metadata,
99+
mounter: nodeMounter,
100+
deviceIdentifier: newNodeDeviceIdentifier(),
101+
inFlight: internal.NewInFlight(),
102+
driverOptions: driverOptions,
101103
}
102104
}
103105

pkg/driver/node_linux.go

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,41 +33,62 @@ import (
3333
// findDevicePath finds path of device and verifies its existence
3434
// if the device is not nvme, return the path directly
3535
// if the device is nvme, finds and returns the nvme device path eg. /dev/nvme1n1
36-
func (d *nodeService) findDevicePath(devicePath, volumeID string, partition string) (string, error) {
36+
func (d *nodeService) findDevicePath(devicePath, volumeID, partition string) (string, error) {
37+
canonicalDevicePath := ""
38+
39+
// If the given path exists, the device MAY be nvme. Further, it MAY be a
40+
// symlink to the nvme device path like:
41+
// | $ stat /dev/xvdba
42+
// | File: ‘/dev/xvdba’ -> ‘nvme1n1’
43+
// Since these are maybes, not guarantees, the search for the nvme device
44+
// path below must happen and must rely on volume ID
3745
exists, err := d.mounter.PathExists(devicePath)
3846
if err != nil {
39-
return "", err
47+
return "", fmt.Errorf("failed to check if path %q exists: %v", devicePath, err)
4048
}
4149

42-
// If the path exists, assume it is not nvme device
4350
if exists {
4451
if partition != "" {
4552
devicePath = devicePath + diskPartitionSuffix + partition
4653
}
47-
return devicePath, nil
54+
canonicalDevicePath = devicePath
4855
}
4956

50-
// Else find the nvme device path using volume ID
51-
// This is the magic name on which AWS presents NVME devices under /dev/disk/by-id/
52-
// For example, vol-0fab1d5e3f72a5e23 creates a symlink at
57+
// AWS recommends identifying devices by volume ID
58+
// (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html),
59+
// so find the nvme device path using volume ID. This is the magic name on
60+
// which AWS presents NVME devices under /dev/disk/by-id/. For example,
61+
// vol-0fab1d5e3f72a5e23 creates a symlink at
5362
// /dev/disk/by-id/nvme-Amazon_Elastic_Block_Store_vol0fab1d5e3f72a5e23
5463
nvmeName := "nvme-Amazon_Elastic_Block_Store_" + strings.Replace(volumeID, "-", "", -1)
5564

56-
nvmeDevicePath, err := findNvmeVolume(nvmeName)
57-
if err != nil {
58-
return "", err
65+
nvmeDevicePath, err := findNvmeVolume(d.deviceIdentifier, nvmeName)
66+
67+
if err == nil {
68+
if partition != "" {
69+
nvmeDevicePath = nvmeDevicePath + nvmeDiskPartitionSuffix + partition
70+
}
71+
canonicalDevicePath = nvmeDevicePath
72+
} else {
73+
klog.V(5).Infof("[Debug] error searching for nvme path %q: %v", nvmeName, err)
5974
}
60-
if partition != "" {
61-
nvmeDevicePath = nvmeDevicePath + nvmeDiskPartitionSuffix + partition
75+
76+
if canonicalDevicePath == "" {
77+
return "", errNoDevicePathFound(devicePath, volumeID)
6278
}
63-
return nvmeDevicePath, nil
79+
80+
return canonicalDevicePath, nil
81+
}
82+
83+
func errNoDevicePathFound(devicePath, volumeID string) error {
84+
return fmt.Errorf("no device path for device %q volume %q found!", devicePath, volumeID)
6485
}
6586

6687
// findNvmeVolume looks for the nvme volume with the specified name
6788
// It follows the symlink (if it exists) and returns the absolute path to the device
68-
func findNvmeVolume(findName string) (device string, err error) {
89+
func findNvmeVolume(deviceIdentifier DeviceIdentifier, findName string) (device string, err error) {
6990
p := filepath.Join("/dev/disk/by-id/", findName)
70-
stat, err := os.Lstat(p)
91+
stat, err := deviceIdentifier.Lstat(p)
7192
if err != nil {
7293
if os.IsNotExist(err) {
7394
klog.V(5).Infof("[Debug] nvme path %q not found", p)
@@ -82,7 +103,7 @@ func findNvmeVolume(findName string) (device string, err error) {
82103
}
83104
// Find the target, resolving to an absolute path
84105
// For example, /dev/disk/by-id/nvme-Amazon_Elastic_Block_Store_vol0fab1d5e3f72a5e23 -> ../../nvme2n1
85-
resolved, err := filepath.EvalSymlinks(p)
106+
resolved, err := deviceIdentifier.EvalSymlinks(p)
86107
if err != nil {
87108
return "", fmt.Errorf("error reading target of symlink %q: %v", p, err)
88109
}

0 commit comments

Comments
 (0)