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

introduce BTRFS #300

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions platform/disk/formatter_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ type FileSystemType string

const (
FileSystemSwap FileSystemType = "swap"
FileSystemBTRFS FileSystemType = "btrfs"
FileSystemExt4 FileSystemType = "ext4"
FileSystemXFS FileSystemType = "xfs"
FileSystemDefault FileSystemType = ""

FileSystemExtResizeUtility = "resize2fs"
FileSystemXFSResizeUtility = "xfs_growfs"
FileSystemBTRFSResizeUtility = "btrfs"
FileSystemExtResizeUtility = "resize2fs"
FileSystemXFSResizeUtility = "xfs_growfs"
)

type Formatter interface {
Expand Down
2 changes: 1 addition & 1 deletion platform/disk/linux_disk_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func NewLinuxDiskManager(
return linuxDiskManager{
ephemeralPartitioner: ephemeralPartitioner,
diskUtil: diskUtil,
formatter: NewLinuxFormatter(runner, fs),
formatter: NewLinuxFormatter(runner, fs, mounter),
fs: fs,
logger: logger,
mounter: mounter,
Expand Down
41 changes: 35 additions & 6 deletions platform/disk/linux_formatter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package disk

import (
"os"
"regexp"
"strings"

Expand All @@ -9,14 +10,16 @@ import (
)

type linuxFormatter struct {
runner boshsys.CmdRunner
fs boshsys.FileSystem
runner boshsys.CmdRunner
fs boshsys.FileSystem
mounter Mounter
}

func NewLinuxFormatter(runner boshsys.CmdRunner, fs boshsys.FileSystem) Formatter {
func NewLinuxFormatter(runner boshsys.CmdRunner, fs boshsys.FileSystem, m Mounter) Formatter {
return linuxFormatter{
runner: runner,
fs: fs,
runner: runner,
fs: fs,
mounter: m,
}
}

Expand All @@ -31,7 +34,7 @@ func (f linuxFormatter) Format(partitionPath string, fsType FileSystemType) erro
return err
}
// swap is not user-configured, so we're not concerned about reformatting
} else if existingFsType == FileSystemExt4 || existingFsType == FileSystemXFS {
} else if existingFsType == FileSystemBTRFS || existingFsType == FileSystemExt4 || existingFsType == FileSystemXFS {
// never reformat if it is already formatted in a supported format
return err
}
Expand All @@ -43,6 +46,12 @@ func (f linuxFormatter) Format(partitionPath string, fsType FileSystemType) erro
return bosherr.WrapError(err, "Shelling out to mkswap")
}

case FileSystemBTRFS:
_, _, _, err = f.runner.RunCommand("mkfs.btrfs", partitionPath)
if err != nil {
return bosherr.WrapError(err, "Shelling out to mkfs.btrfs")
}

case FileSystemExt4:
err = f.makeFileSystemExt4(partitionPath)
if err != nil {
Expand Down Expand Up @@ -73,6 +82,26 @@ func (f linuxFormatter) GrowFilesystem(partitionPath string) error {
}

switch existingFsType {
case FileSystemBTRFS:
// unlike other filesystems, BTRFS requires to be mounted to be resized
msg := "Failed to grow BTRFS filesystem"
tempDir, err := os.MkdirTemp("", "btrfs-mount")
if err != nil {
return bosherr.WrapError(err, msg+": failed to create temporary directory")
}
defer os.RemoveAll(tempDir)

err = f.mounter.Mount(partitionPath, tempDir)
if err != nil {
return bosherr.WrapError(err, msg+": failed to mount the partition")
}
defer f.mounter.Unmount(tempDir)

_, _, _, err = f.runner.RunCommand("btrfs", "filesystem", "resize", "max", tempDir)
if err != nil {
return bosherr.WrapError(err, msg)
}

case FileSystemExt4:
_, _, _, err := f.runner.RunCommand(
"resize2fs",
Expand Down
106 changes: 89 additions & 17 deletions platform/disk/linux_formatter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package disk_test

import (
"github.com/cloudfoundry/bosh-agent/platform/disk/diskfakes"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

Expand All @@ -12,14 +13,19 @@ import (
)

var _ = Describe("Linux Formatter", func() {
var fakeMounter Mounter

BeforeEach(func() {
fakeMounter = NewLinuxBindMounter(&diskfakes.FakeMounter{})
})
Describe("Format", func() {
Context("when using swap", func() {
It("format as swap disk if partition has not been formatted", func() {
fakeRunner := fakesys.NewFakeCmdRunner()
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{ExitStatus: 2, Error: errors.New("Exit code 2")})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemSwap)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -32,7 +38,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext4" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemSwap)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -45,7 +51,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="swap" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemSwap)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -54,6 +60,55 @@ var _ = Describe("Linux Formatter", func() {
})
})

Context("when using btrfs", func() {
It("formats a blank disk with type btrfs", func() {
fakeRunner := fakesys.NewFakeCmdRunner()
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult(
"blkid -p /dev/xvda2",
fakesys.FakeCmdResult{ExitStatus: 2, Error: errors.New("Exit code 2")},
)

formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemBTRFS)
Expect(err).NotTo(HaveOccurred())

Expect(2).To(Equal(len(fakeRunner.RunCommands)))
Expect(fakeRunner.RunCommands[1]).To(Equal([]string{"mkfs.btrfs", "/dev/xvda2"}))
})

for _, format := range []string{"btrfs", "ext4", "xfs"} {
It("does not re-partition if fs is already "+format, func() {
fakeRunner := fakesys.NewFakeCmdRunner()
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult(
"blkid -p /dev/xvda1",
fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="` + format + `" yyyy zzzz`},
)

formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemBTRFS)
Expect(err).NotTo(HaveOccurred())

Expect(1).To(Equal(len(fakeRunner.RunCommands)))
Expect(fakeRunner.RunCommands[0]).To(Equal([]string{"blkid", "-p", "/dev/xvda1"}))
})
}

It("throws an error if formatting filesystem fails", func() {
fakeRunner := fakesys.NewFakeCmdRunner()
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("mkfs.btrfs /dev/xvda2", fakesys.FakeCmdResult{Error: errors.New("Sadness")})
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stderr: "", ExitStatus: 2})

formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemBTRFS)

Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Shelling out to mkfs.btrfs: Sadness"))
})
})

Context("when using ext4", func() {
It("allows lazy itable support", func() {
fakeRunner := fakesys.NewFakeCmdRunner()
Expand All @@ -62,7 +117,7 @@ var _ = Describe("Linux Formatter", func() {
Expect(err).NotTo(HaveOccurred())
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext2" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err = formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand Down Expand Up @@ -93,7 +148,7 @@ var _ = Describe("Linux Formatter", func() {
fakeRunner.AddCmdResult(mkeCmd, fakesys.FakeCmdResult{
ExitStatus: 0,
})
formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -106,7 +161,7 @@ var _ = Describe("Linux Formatter", func() {
fakeRunner.AddCmdResult(mkeCmd, fakesys.FakeCmdResult{
Error: errors.New(`some other error`),
})
formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).To(HaveOccurred())

Expand All @@ -120,7 +175,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext2" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -133,7 +188,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext4" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -146,7 +201,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="xfs" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -159,7 +214,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="somethingelse" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemExt4)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -174,7 +229,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{ExitStatus: 2, Error: errors.New("Exit code 2")})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemXFS)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -187,7 +242,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext4" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemXFS)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -200,7 +255,7 @@ var _ = Describe("Linux Formatter", func() {
fakeFs := fakesys.NewFakeFileSystem()
fakeRunner.AddCmdResult("blkid -p /dev/xvda1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="xfs" yyyy zzzz`})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda1", FileSystemXFS)
Expect(err).NotTo(HaveOccurred())

Expand All @@ -214,7 +269,7 @@ var _ = Describe("Linux Formatter", func() {
fakeRunner.AddCmdResult("mkfs.xfs /dev/xvda2", fakesys.FakeCmdResult{Error: errors.New("Sadness")})
fakeRunner.AddCmdResult("blkid -p /dev/xvda2", fakesys.FakeCmdResult{Stderr: "", ExitStatus: 2})

formatter := NewLinuxFormatter(fakeRunner, fakeFs)
formatter := NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
err := formatter.Format("/dev/xvda2", FileSystemXFS)

Expect(err).To(HaveOccurred())
Expand All @@ -238,7 +293,7 @@ var _ = Describe("Linux Formatter", func() {
Context("when determining partition filesystem fails", func() {
BeforeEach(func() {
fakeRunner.AddCmdResult("blkid -p /dev/nvme2n1p1", fakesys.FakeCmdResult{ExitStatus: 1, Error: errors.New("No GPT found")})
formatter = NewLinuxFormatter(fakeRunner, fakeFs)
formatter = NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
})

It("returns an error", func() {
Expand All @@ -249,10 +304,27 @@ var _ = Describe("Linux Formatter", func() {
})
})

Context("when using BTRFS", func() {
BeforeEach(func() {
fakeRunner.AddCmdResult("blkid -p /dev/nvme2n1p1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="btrfs" yyyy zzzz`})
formatter = NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
})

It("grows the BTRFS filesystem", func() {
err := formatter.GrowFilesystem("/dev/nvme2n1p1")

Expect(err).NotTo(HaveOccurred())
// because the last item is a temporary directory, strip it from the test
Expect(fakeRunner.RunCommands[1][:4]).To(Equal([]string{"btrfs", "filesystem", "resize", "max"}))
})

// FIXME: I don't know how to fake the "when btrfs fails" context
})

Context("when using Ext4", func() {
BeforeEach(func() {
fakeRunner.AddCmdResult("blkid -p /dev/nvme2n1p1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="ext4" yyyy zzzz`})
formatter = NewLinuxFormatter(fakeRunner, fakeFs)
formatter = NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
})

It("grows the Ext4 filesystem", func() {
Expand Down Expand Up @@ -280,7 +352,7 @@ var _ = Describe("Linux Formatter", func() {
Context("when using XFS", func() {
BeforeEach(func() {
fakeRunner.AddCmdResult("blkid -p /dev/nvme2n1p1", fakesys.FakeCmdResult{Stdout: `xxxxx TYPE="xfs" yyyy zzzz`})
formatter = NewLinuxFormatter(fakeRunner, fakeFs)
formatter = NewLinuxFormatter(fakeRunner, fakeFs, fakeMounter)
})

It("grows the XFS filesystem", func() {
Expand Down
7 changes: 6 additions & 1 deletion platform/linux_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ func (p linux) SetupRootDisk(ephemeralDiskPath string) error {
case boshdisk.FileSystemExt4:
resizeCmd = boshdisk.FileSystemExtResizeUtility
resizeCmdArgs = []string{"-f", rootDevice}
case boshdisk.FileSystemBTRFS:
resizeCmd = boshdisk.FileSystemBTRFSResizeUtility
resizeCmdArgs = []string{"filesystem", "resize", "max", rootDevicePath}
default:
return bosherr.Errorf("Cannot get filesystem type for root file system")
}
Expand Down Expand Up @@ -1255,7 +1258,7 @@ func (p linux) AdjustPersistentDiskPartitioning(diskSetting boshsettings.DiskSet

persistentDiskFS := diskSetting.FileSystemType
switch persistentDiskFS {
case boshdisk.FileSystemExt4, boshdisk.FileSystemXFS:
case boshdisk.FileSystemBTRFS, boshdisk.FileSystemExt4, boshdisk.FileSystemXFS:
case boshdisk.FileSystemDefault:
persistentDiskFS = boshdisk.FileSystemExt4
case boshdisk.FileSystemSwap:
Expand Down Expand Up @@ -1533,6 +1536,7 @@ func (p linux) calculateEphemeralDiskPartitionSizes(diskSizeInBytes uint64, desi
return swapSizeInBytes, linuxSizeInBytes, nil
}

// findRootDevicePathAndNumber return the device path of the / filesystem and it's partition number (ie: /dev/xvda, 1)
func (p linux) findRootDevicePathAndNumber() (string, int, error) {
mounts, err := p.diskManager.GetMountsSearcher().SearchMounts()
if err != nil {
Expand Down Expand Up @@ -1690,6 +1694,7 @@ func (p linux) RemoveStaticLibraries(staticLibrariesListFilePath string) error {
return nil
}

// partitionPath concatenate a device path and partition number (ie: /dev/sda, 3 → /dev/sda3)
func (p linux) partitionPath(devicePath string, partitionNumber int) string {
switch {
case strings.HasPrefix(devicePath, "/dev/nvme"):
Expand Down