Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ID Device path resolver #343

Merged
merged 14 commits into from
Jan 16, 2025
55 changes: 33 additions & 22 deletions infrastructure/devicepathresolver/id_device_path_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,36 @@ import (
boshudev "github.com/cloudfoundry/bosh-agent/v2/platform/udevdevice"
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)

type idDevicePathResolver struct {
diskWaitTimeout time.Duration
udev boshudev.UdevDevice
fs boshsys.FileSystem
stripVolumeRegex string
stripVolumeCompiled *regexp.Regexp
diskWaitTimeout time.Duration
udev boshudev.UdevDevice
fs boshsys.FileSystem
DiskIDTransformPattern string
DiskIDTransformReplacement string
logTag string
logger boshlog.Logger
}

func NewIDDevicePathResolver(
diskWaitTimeout time.Duration,
udev boshudev.UdevDevice,
fs boshsys.FileSystem,
stripVolumeRegex string,
DiskIDTransformPattern string,
DiskIDTransformReplacement string,
logger boshlog.Logger,
) DevicePathResolver {
return &idDevicePathResolver{
diskWaitTimeout: diskWaitTimeout,
udev: udev,
fs: fs,
stripVolumeRegex: stripVolumeRegex,
stripVolumeCompiled: nil,
diskWaitTimeout: diskWaitTimeout,
udev: udev,
fs: fs,
DiskIDTransformPattern: DiskIDTransformPattern,
DiskIDTransformReplacement: DiskIDTransformReplacement,
logTag: "IdDevicePathResolver",
logger: logger,
}
}

Expand Down Expand Up @@ -60,12 +67,16 @@ func (idpr *idDevicePathResolver) GetRealDevicePath(diskSettings boshsettings.Di
var realPath string

diskID := diskSettings.ID
strippedDiskID, err := idpr.stripVolumeIfRequired(diskID)
TransformedDiskID, err := idpr.TransformDiskID(diskID)
if err != nil {
return "", false, err
}

deviceGlobPattern := fmt.Sprintf("*%s", strippedDiskID)
deviceGlobPattern := TransformedDiskID
if idpr.DiskIDTransformPattern == "" {
deviceGlobPattern = fmt.Sprintf("*%s", TransformedDiskID)
}

deviceIDPathGlobPattern := path.Join("/", "dev", "disk", "by-id", deviceGlobPattern)

for !found {
Expand Down Expand Up @@ -99,17 +110,17 @@ func (idpr *idDevicePathResolver) GetRealDevicePath(diskSettings boshsettings.Di
return realPath, false, nil
}

func (idpr *idDevicePathResolver) stripVolumeIfRequired(diskID string) (string, error) {
if idpr.stripVolumeRegex == "" {
func (idpr *idDevicePathResolver) TransformDiskID(diskID string) (string, error) {
if idpr.DiskIDTransformPattern == "" {
idpr.logger.Debug(idpr.logTag, "DiskIDTransformRules is empty, returning diskID as is")
return diskID, nil
}

if idpr.stripVolumeCompiled == nil {
var err error
idpr.stripVolumeCompiled, err = regexp.Compile(idpr.stripVolumeRegex)
if err != nil {
return "", bosherr.WrapError(err, "Compiling stripVolumeRegex")
}
transformed := diskID
re := regexp.MustCompile(idpr.DiskIDTransformPattern)
if re.MatchString(transformed) {
transformed = re.ReplaceAllString(transformed, idpr.DiskIDTransformReplacement)
idpr.logger.Debug(idpr.logTag, "DiskIDTransformRules: Original: '%+v' -> Transformed: '%+v'\n", diskID, transformed)
}
return idpr.stripVolumeCompiled.ReplaceAllLiteralString(diskID, ""), nil
return transformed, nil
}
23 changes: 13 additions & 10 deletions infrastructure/devicepathresolver/id_device_path_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

fakeudev "github.com/cloudfoundry/bosh-agent/v2/platform/udevdevice/fakes"
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
fakesys "github.com/cloudfoundry/bosh-utils/system/fakes"

. "github.com/onsi/ginkgo/v2"
Expand All @@ -18,11 +19,12 @@ import (

var _ = Describe("IDDevicePathResolver", func() {
var (
fs *fakesys.FakeFileSystem
udev *fakeudev.FakeUdevDevice
diskSettings boshsettings.DiskSettings
pathResolver DevicePathResolver
stripVolumeRegex string
fs *fakesys.FakeFileSystem
udev *fakeudev.FakeUdevDevice
diskSettings boshsettings.DiskSettings
pathResolver DevicePathResolver
DiskIDTransformPattern string
DiskIDTransformReplacement string
)

BeforeEach(func() {
Expand All @@ -34,7 +36,7 @@ var _ = Describe("IDDevicePathResolver", func() {
})

JustBeforeEach(func() {
pathResolver = NewIDDevicePathResolver(500*time.Millisecond, udev, fs, stripVolumeRegex)
pathResolver = NewIDDevicePathResolver(500*time.Millisecond, udev, fs, DiskIDTransformPattern, DiskIDTransformReplacement, boshlog.NewLogger(boshlog.LevelNone))
})

Describe("GetRealDevicePath", func() {
Expand Down Expand Up @@ -206,22 +208,23 @@ var _ = Describe("IDDevicePathResolver", func() {
})
})

Context("when stripVolumeRegex option is used to remove mismatched disk ID prefix", func() {
Context("when DiskIDTransformRules are used to match and transform the diskid", func() {
BeforeEach(func() {
diskSettings = boshsettings.DiskSettings{
ID: "vol-fake-disk-id-include-longname",
}
stripVolumeRegex = "^vol-"
DiskIDTransformPattern = "^(vol-.+)$"
DiskIDTransformReplacement = "test-${1}"
err := fs.MkdirAll("/dev/fake-device-path", os.FileMode(0750))
Expect(err).ToNot(HaveOccurred())

err = fs.Symlink("/dev/fake-device-path", "/dev/intermediate/fake-device-path")
Expect(err).ToNot(HaveOccurred())

err = fs.Symlink("/dev/intermediate/fake-device-path", "/dev/disk/by-id/virtio-fake-disk-id-include-longname")
err = fs.Symlink("/dev/intermediate/fake-device-path", "/dev/disk/by-id/test-vol-fake-disk-id-include-longname")
Expect(err).ToNot(HaveOccurred())

fs.SetGlob("/dev/disk/by-id/*fake-disk-id-include-longname", []string{"/dev/disk/by-id/virtio-fake-disk-id-include-longname"})
fs.SetGlob("/dev/disk/by-id/test-vol-fake-disk-id-include-longname", []string{"/dev/disk/by-id/test-vol-fake-disk-id-include-longname"})
})

It("removes prefix and returns fully resolved path", func() {
Expand Down
7 changes: 4 additions & 3 deletions platform/linux_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ type LinuxOptions struct {
// possible values: systemd, ""
ServiceManager string

// Regular expression specifying what part of volume ID to strip.
// possible values: valid RE2 regex e.g. "^vol-", "" (default is not to strip)
StripVolumeRegex string
// Regular expression specifying what part of disk ID to strip and transform
// example: "pattern": "^(disk-.+)$", "replacement": "google-${1}",
DiskIDTransformPattern string
DiskIDTransformReplacement string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, bosh.io links to golang docs that document these flags

}

type linux struct {
Expand Down
2 changes: 1 addition & 1 deletion platform/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func NewProvider(logger boshlog.Logger, dirProvider boshdirs.Provider, statsColl
switch options.Linux.DevicePathResolutionType {
case "virtio":
udev := boshudev.NewConcreteUdevDevice(runner, logger)
idDevicePathResolver := devicepathresolver.NewIDDevicePathResolver(500*time.Millisecond, udev, fs, options.Linux.StripVolumeRegex)
idDevicePathResolver := devicepathresolver.NewIDDevicePathResolver(500*time.Millisecond, udev, fs, options.Linux.DiskIDTransformPattern, options.Linux.DiskIDTransformReplacement, logger)
mappedDevicePathResolver := devicepathresolver.NewMappedDevicePathResolver(30000*time.Millisecond, fs)
devicePathResolver = devicepathresolver.NewVirtioDevicePathResolver(idDevicePathResolver, mappedDevicePathResolver, logger)
case "scsi":
Expand Down
Loading