debian-forge-composer/internal/disk/disk_test.go
Christian Kellner b562d144ca distro/*: allow /boot to be customized
Since the LVM support was added to all distros, our disk
related code is adaptive, i.e. we will set the correct BLS
and grub2 prefix if there a `boot` partiton is present in
the layout after all customizations happen, which includes
LVMification.
One thing that was not yet fully working was layouts that
do not yet have a `/boot` partition but allow LVMification.
In that case `NewPartitionTable` and if `/boot` was the
first (or only) customization, would LVMify the partition
which in turn would create the `/boot` partition; but after
`newPT.ensureLVM()` the call to `newPT.createFilesystem`
with `/boot` would try to create another `/boot` mountpoint.
In order to deal with this situation correctly we are now
using a two phase approach: 1) enlarge existing mountpoints
and collect new ones. 2) if there are new ones and LMVify
was allowed, switch to LVM layout. Do a second pass and now
create or enlarge existing partitions, handling `/boot` in
the process.
2022-08-08 18:05:05 +02:00

887 lines
23 KiB
Go

package disk
import (
"fmt"
"math/rand"
"strings"
"testing"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/stretchr/testify/assert"
)
const (
KiB = 1024
MiB = 1024 * KiB
GiB = 1024 * MiB
)
func TestDisk_AlignUp(t *testing.T) {
pt := PartitionTable{}
firstAligned := DefaultGrainBytes
tests := []struct {
size uint64
want uint64
}{
{0, 0},
{1, firstAligned},
{firstAligned - 1, firstAligned},
{firstAligned, firstAligned}, // grain is already aligned => no change
{firstAligned / 2, firstAligned},
{firstAligned + 1, firstAligned * 2},
}
for _, tt := range tests {
got := pt.AlignUp(tt.size)
assert.Equal(t, tt.want, got, "Expected %d, got %d", tt.want, got)
}
}
func TestDisk_DynamicallyResizePartitionTable(t *testing.T) {
mountpoints := []blueprint.FilesystemCustomization{
{
MinSize: 2 * GiB,
Mountpoint: "/usr",
},
}
pt := PartitionTable{
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 2048,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
}
var expectedSize uint64 = 2 * GiB
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(rand.NewSource(0))
newpt, err := NewPartitionTable(&pt, mountpoints, 1024, false, rng)
assert.NoError(t, err)
assert.GreaterOrEqual(t, newpt.Size, expectedSize)
}
var testPartitionTables = map[string]PartitionTable{
"plain": {
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 1 * MiB,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Size: 200 * MiB,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Payload: &Filesystem{
Type: "vfat",
UUID: EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 500 * MiB,
Type: FilesystemDataGUID,
UUID: FilesystemDataUUID,
Payload: &Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
"plain-noboot": {
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 1 * MiB,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Size: 200 * MiB,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Payload: &Filesystem{
Type: "vfat",
UUID: EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
"luks": {
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 1 * MiB,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Size: 200 * MiB,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Payload: &Filesystem{
Type: "vfat",
UUID: EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 500 * MiB,
Type: FilesystemDataGUID,
UUID: FilesystemDataUUID,
Payload: &Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Payload: &LUKSContainer{
UUID: "",
Label: "crypt_root",
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
"luks+lvm": {
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 1 * MiB,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Size: 200 * MiB,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Payload: &Filesystem{
Type: "vfat",
UUID: EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 500 * MiB,
Type: FilesystemDataGUID,
UUID: FilesystemDataUUID,
Payload: &Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Size: 5 * GiB,
Payload: &LUKSContainer{
UUID: "",
Payload: &LVMVolumeGroup{
Name: "",
Description: "",
LogicalVolumes: []LVMLogicalVolume{
{
Size: 2 * GiB,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Size: 2 * GiB,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/home",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
},
},
},
},
},
},
"btrfs": {
UUID: "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
Type: "gpt",
Partitions: []Partition{
{
Size: 1 * MiB,
Bootable: true,
Type: BIOSBootPartitionGUID,
UUID: BIOSBootPartitionUUID,
},
{
Size: 200 * MiB,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Payload: &Filesystem{
Type: "vfat",
UUID: EFIFilesystemUUID,
Mountpoint: "/boot/efi",
Label: "EFI-SYSTEM",
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
},
},
{
Size: 500 * MiB,
Type: FilesystemDataGUID,
UUID: FilesystemDataUUID,
Payload: &Filesystem{
Type: "xfs",
Mountpoint: "/boot",
Label: "boot",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
},
{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Size: 10 * GiB,
Payload: &Btrfs{
UUID: "",
Label: "",
Mountpoint: "",
Subvolumes: []BtrfsSubvolume{
{
Size: 0,
Mountpoint: "/",
GroupID: 0,
},
{
Size: 5 * GiB,
Mountpoint: "/var",
GroupID: 0,
},
},
},
},
},
},
}
var testBlueprints = map[string][]blueprint.FilesystemCustomization{
"bp1": {
{
Mountpoint: "/",
MinSize: 10 * GiB,
},
{
Mountpoint: "/home",
MinSize: 20 * GiB,
},
{
Mountpoint: "/opt",
MinSize: 7 * GiB,
},
},
"bp2": {
{
Mountpoint: "/opt",
MinSize: 7 * GiB,
},
},
"small": {
{
Mountpoint: "/opt",
MinSize: 20 * MiB,
},
{
Mountpoint: "/home",
MinSize: 500 * MiB,
},
},
"empty": nil,
}
func TestDisk_ForEachEntity(t *testing.T) {
count := 0
plain := testPartitionTables["plain"]
err := plain.ForEachEntity(func(e Entity, path []Entity) error {
assert.NotNil(t, e)
assert.NotNil(t, path)
count += 1
return nil
})
assert.NoError(t, err)
// PartitionTable, 4 partitions, 3 filesystems -> 8 entities
assert.Equal(t, 8, count)
}
func TestCreatePartitionTable(t *testing.T) {
assert := assert.New(t)
sizeCheckCB := func(mnt Mountable, path []Entity) error {
if strings.HasPrefix(mnt.GetMountpoint(), "/boot") {
// /boot and subdirectories is exempt from this rule
return nil
}
// go up the path and check every sizeable
for idx, ent := range path {
if sz, ok := ent.(Sizeable); ok {
size := sz.GetSize()
if size < 1*GiB {
return fmt.Errorf("entity %d in the path from %s is smaller than the minimum 1 GiB (%d)", idx, mnt.GetMountpoint(), size)
}
}
}
return nil
}
sumSizes := func(bp []blueprint.FilesystemCustomization) (sum uint64) {
for _, mnt := range bp {
sum += mnt.MinSize
}
return sum
}
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(rand.NewSource(13))
for ptName := range testPartitionTables {
pt := testPartitionTables[ptName]
for bpName, bp := range testBlueprints {
mpt, err := NewPartitionTable(&pt, bp, uint64(13*MiB), false, rng)
assert.NoError(err, "Partition table generation failed: PT %q BP %q (%s)", ptName, bpName, err)
assert.NotNil(mpt, "Partition table generation failed: PT %q BP %q (nil partition table)", ptName, bpName)
assert.Greater(mpt.GetSize(), sumSizes(bp))
assert.NotNil(mpt.Type, "Partition table generation failed: PT %q BP %q (nil partition table type)", ptName, bpName)
mnt := pt.FindMountable("/")
assert.NotNil(mnt, "PT %q BP %q: failed to find root mountable", ptName, bpName)
assert.NoError(mpt.ForEachMountable(sizeCheckCB))
}
}
}
func TestCreatePartitionTableLVMify(t *testing.T) {
assert := assert.New(t)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(rand.NewSource(13))
for bpName, tbp := range testBlueprints {
for ptName := range testPartitionTables {
pt := testPartitionTables[ptName]
if tbp != nil && (ptName == "btrfs" || ptName == "luks") {
assert.Panics(func() {
_, _ = NewPartitionTable(&pt, tbp, uint64(13*MiB), true, rng)
}, fmt.Sprintf("PT %q BP %q: should panic", ptName, bpName))
continue
}
mpt, err := NewPartitionTable(&pt, tbp, uint64(13*MiB), true, rng)
assert.NoError(err, "PT %q BP %q: Partition table generation failed: (%s)", ptName, bpName, err)
rootPath := entityPath(mpt, "/")
if rootPath == nil {
panic(fmt.Sprintf("PT %q BP %q: no root mountpoint", ptName, bpName))
}
bootPath := entityPath(mpt, "/boot")
if tbp != nil && bootPath == nil {
panic(fmt.Sprintf("PT %q BP %q: no boot mountpoint", ptName, bpName))
}
if tbp != nil {
parent := rootPath[1]
_, ok := parent.(*LVMLogicalVolume)
assert.True(ok, "PT %q BP %q: root's parent (%q) is not an LVM logical volume", ptName, bpName, parent)
}
}
}
}
func TestMinimumSizes(t *testing.T) {
assert := assert.New(t)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(rand.NewSource(13))
pt := testPartitionTables["plain"]
type testCase struct {
Blueprint []blueprint.FilesystemCustomization
ExpectedMinSizes map[string]uint64
}
testCases := []testCase{
{ // specify small /usr -> / and /usr get default size
Blueprint: []blueprint.FilesystemCustomization{
{
Mountpoint: "/usr",
MinSize: 1 * MiB,
},
},
ExpectedMinSizes: map[string]uint64{
"/usr": 2 * GiB,
"/": 1 * GiB,
},
},
{ // specify small / and /usr -> / and /usr get default size
Blueprint: []blueprint.FilesystemCustomization{
{
Mountpoint: "/",
MinSize: 1 * MiB,
},
{
Mountpoint: "/usr",
MinSize: 1 * KiB,
},
},
ExpectedMinSizes: map[string]uint64{
"/usr": 2 * GiB,
"/": 1 * GiB,
},
},
{ // big /usr -> / gets default size
Blueprint: []blueprint.FilesystemCustomization{
{
Mountpoint: "/usr",
MinSize: 10 * GiB,
},
},
ExpectedMinSizes: map[string]uint64{
"/usr": 10 * GiB,
"/": 1 * GiB,
},
},
{
Blueprint: []blueprint.FilesystemCustomization{
{
Mountpoint: "/",
MinSize: 10 * GiB,
},
{
Mountpoint: "/home",
MinSize: 1 * MiB,
},
},
ExpectedMinSizes: map[string]uint64{
"/": 10 * GiB,
"/home": 1 * GiB,
},
},
{ // no separate /usr and no size for / -> / gets sum of default sizes for / and /usr
Blueprint: []blueprint.FilesystemCustomization{
{
Mountpoint: "/opt",
MinSize: 10 * GiB,
},
},
ExpectedMinSizes: map[string]uint64{
"/opt": 10 * GiB,
"/": 3 * GiB,
},
},
}
for idx, tc := range testCases {
{ // without LVM
mpt, err := NewPartitionTable(&pt, tc.Blueprint, uint64(3*GiB), false, rng)
assert.NoError(err)
for mnt, minSize := range tc.ExpectedMinSizes {
path := entityPath(mpt, mnt)
assert.NotNil(path, "[%d] mountpoint %q not found", idx, mnt)
parent := path[1]
part, ok := parent.(*Partition)
assert.True(ok, "%q parent (%v) is not a partition", mnt, parent)
assert.GreaterOrEqual(part.GetSize(), minSize,
"[%d] %q size %d should be greater or equal to %d", idx, mnt, part.GetSize(), minSize)
}
}
{ // with LVM
mpt, err := NewPartitionTable(&pt, tc.Blueprint, uint64(3*GiB), true, rng)
assert.NoError(err)
for mnt, minSize := range tc.ExpectedMinSizes {
path := entityPath(mpt, mnt)
assert.NotNil(path, "[%d] mountpoint %q not found", idx, mnt)
parent := path[1]
part, ok := parent.(*LVMLogicalVolume)
assert.True(ok, "[%d] %q parent (%v) is not an LVM logical volume", idx, mnt, parent)
assert.GreaterOrEqual(part.GetSize(), minSize,
"[%d] %q size %d should be greater or equal to %d", idx, mnt, part.GetSize(), minSize)
}
}
}
}
func TestNewBootWithSizeLVMify(t *testing.T) {
pt := testPartitionTables["plain-noboot"]
assert := assert.New(t)
// math/rand is good enough in this case
/* #nosec G404 */
rng := rand.New(rand.NewSource(13))
custom := []blueprint.FilesystemCustomization{
{
Mountpoint: "/boot",
MinSize: 700 * MiB,
},
}
mpt, err := NewPartitionTable(&pt, custom, uint64(3*GiB), true, rng)
assert.NoError(err)
for idx, c := range custom {
mnt, minSize := c.Mountpoint, c.MinSize
path := entityPath(mpt, mnt)
assert.NotNil(path, "[%d] mountpoint %q not found", idx, mnt)
parent := path[1]
part, ok := parent.(*Partition)
assert.True(ok, "%q parent (%v) is not a partition", mnt, parent)
assert.GreaterOrEqual(part.GetSize(), minSize,
"[%d] %q size %d should be greater or equal to %d", idx, mnt, part.GetSize(), minSize)
}
}
func collectEntities(pt *PartitionTable) []Entity {
entities := make([]Entity, 0)
collector := func(ent Entity, path []Entity) error {
entities = append(entities, ent)
return nil
}
_ = pt.ForEachEntity(collector)
return entities
}
func TestClone(t *testing.T) {
for name := range testPartitionTables {
basePT := testPartitionTables[name]
baseEntities := collectEntities(&basePT)
clonePT := basePT.Clone().(*PartitionTable)
cloneEntities := collectEntities(clonePT)
for idx := range baseEntities {
for jdx := range cloneEntities {
if fmt.Sprintf("%p", baseEntities[idx]) == fmt.Sprintf("%p", cloneEntities[jdx]) {
t.Fatalf("found reference to same entity %#v in list of clones for partition table %q", baseEntities[idx], name)
}
}
}
}
}
func TestFindDirectoryPartition(t *testing.T) {
assert := assert.New(t)
usr := Partition{
Type: FilesystemDataGUID,
UUID: RootPartitionUUID,
Payload: &Filesystem{
Type: "xfs",
Label: "root",
Mountpoint: "/usr",
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
},
}
{
pt := testPartitionTables["plain"]
assert.Equal("/", pt.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/boot/efi", pt.findDirectoryEntityPath("/boot/efi/Linux")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot/loader")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot")[0].(Mountable).GetMountpoint())
ptMod := pt.Clone().(*PartitionTable)
ptMod.Partitions = append(ptMod.Partitions, usr)
assert.Equal("/", ptMod.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr/bin")[0].(Mountable).GetMountpoint())
// invalid dir should return nil
assert.Nil(pt.findDirectoryEntityPath("invalid"))
}
{
pt := testPartitionTables["plain-noboot"]
assert.Equal("/", pt.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/", pt.findDirectoryEntityPath("/boot")[0].(Mountable).GetMountpoint())
assert.Equal("/", pt.findDirectoryEntityPath("/boot/loader")[0].(Mountable).GetMountpoint())
ptMod := pt.Clone().(*PartitionTable)
ptMod.Partitions = append(ptMod.Partitions, usr)
assert.Equal("/", ptMod.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr/bin")[0].(Mountable).GetMountpoint())
// invalid dir should return nil
assert.Nil(pt.findDirectoryEntityPath("invalid"))
}
{
pt := testPartitionTables["luks"]
assert.Equal("/", pt.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot/loader")[0].(Mountable).GetMountpoint())
ptMod := pt.Clone().(*PartitionTable)
ptMod.Partitions = append(ptMod.Partitions, usr)
assert.Equal("/", ptMod.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr/bin")[0].(Mountable).GetMountpoint())
// invalid dir should return nil
assert.Nil(pt.findDirectoryEntityPath("invalid"))
}
{
pt := testPartitionTables["luks+lvm"]
assert.Equal("/", pt.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot/loader")[0].(Mountable).GetMountpoint())
ptMod := pt.Clone().(*PartitionTable)
ptMod.Partitions = append(ptMod.Partitions, usr)
assert.Equal("/", ptMod.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr/bin")[0].(Mountable).GetMountpoint())
// invalid dir should return nil
assert.Nil(pt.findDirectoryEntityPath("invalid"))
}
{
pt := testPartitionTables["btrfs"]
assert.Equal("/", pt.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot")[0].(Mountable).GetMountpoint())
assert.Equal("/boot", pt.findDirectoryEntityPath("/boot/loader")[0].(Mountable).GetMountpoint())
ptMod := pt.Clone().(*PartitionTable)
ptMod.Partitions = append(ptMod.Partitions, usr)
assert.Equal("/", ptMod.findDirectoryEntityPath("/opt")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr")[0].(Mountable).GetMountpoint())
assert.Equal("/usr", ptMod.findDirectoryEntityPath("/usr/bin")[0].(Mountable).GetMountpoint())
// invalid dir should return nil
assert.Nil(pt.findDirectoryEntityPath("invalid"))
}
{
pt := PartitionTable{} // pt with no root should return nil
assert.Nil(pt.findDirectoryEntityPath("/var"))
}
}
func TestEnsureDirectorySizes(t *testing.T) {
assert := assert.New(t)
varSizes := map[string]uint64{
"/var/lib": uint64(3 * GiB),
"/var/cache": uint64(2 * GiB),
"/var/log/journal": uint64(2 * GiB),
}
varAndHomeSizes := map[string]uint64{
"/var/lib": uint64(3 * GiB),
"/var/cache": uint64(2 * GiB),
"/var/log/journal": uint64(2 * GiB),
"/home/user/data": uint64(10 * GiB),
}
{
pt := testPartitionTables["plain"]
pt = *pt.Clone().(*PartitionTable) // don't modify the original test data
{
// make sure we have the correct volume
// guard against changes in the test pt
rootPart := pt.Partitions[3]
rootPayload := rootPart.Payload.(*Filesystem)
assert.Equal("/", rootPayload.Mountpoint)
assert.Equal(uint64(0), rootPart.Size)
}
{
// add requirements for /var subdirs that are > 5 GiB
pt.EnsureDirectorySizes(varSizes)
rootPart := pt.Partitions[3]
assert.Equal(uint64(7*GiB), rootPart.Size)
// invalid
assert.Panics(func() { pt.EnsureDirectorySizes(map[string]uint64{"invalid": uint64(300)}) })
}
}
{
pt := testPartitionTables["luks+lvm"]
pt = *pt.Clone().(*PartitionTable) // don't modify the original test data
{
// make sure we have the correct volume
// guard against changes in the test pt
rootPart := pt.Partitions[3]
rootLUKS := rootPart.Payload.(*LUKSContainer)
rootVG := rootLUKS.Payload.(*LVMVolumeGroup)
rootLV := rootVG.LogicalVolumes[0]
rootFS := rootLV.Payload.(*Filesystem)
homeLV := rootVG.LogicalVolumes[1]
homeFS := homeLV.Payload.(*Filesystem)
assert.Equal(uint64(5*GiB), rootPart.Size)
assert.Equal("/", rootFS.Mountpoint)
assert.Equal(uint64(2*GiB), rootLV.Size)
assert.Equal("/home", homeFS.Mountpoint)
assert.Equal(uint64(2*GiB), homeLV.Size)
}
{
// add requirements for /var subdirs that are > 5 GiB
pt.EnsureDirectorySizes(varAndHomeSizes)
rootPart := pt.Partitions[3]
rootLUKS := rootPart.Payload.(*LUKSContainer)
rootVG := rootLUKS.Payload.(*LVMVolumeGroup)
rootLV := rootVG.LogicalVolumes[0]
homeLV := rootVG.LogicalVolumes[1]
assert.Equal(uint64(17*GiB)+rootVG.MetadataSize(), rootPart.Size)
assert.Equal(uint64(7*GiB), rootLV.Size)
assert.Equal(uint64(10*GiB), homeLV.Size)
// invalid
assert.Panics(func() { pt.EnsureDirectorySizes(map[string]uint64{"invalid": uint64(300)}) })
}
}
{
pt := testPartitionTables["btrfs"]
pt = *pt.Clone().(*PartitionTable) // don't modify the original test data
{
// make sure we have the correct volume
// guard against changes in the test pt
rootPart := pt.Partitions[3]
rootPayload := rootPart.Payload.(*Btrfs)
assert.Equal("/", rootPayload.Subvolumes[0].Mountpoint)
assert.Equal(uint64(0), rootPayload.Subvolumes[0].Size)
assert.Equal("/var", rootPayload.Subvolumes[1].Mountpoint)
assert.Equal(uint64(5*GiB), rootPayload.Subvolumes[1].Size)
}
{
// add requirements for /var subdirs that are > 5 GiB
pt.EnsureDirectorySizes(varSizes)
rootPart := pt.Partitions[3]
rootPayload := rootPart.Payload.(*Btrfs)
assert.Equal(uint64(7*GiB), rootPayload.Subvolumes[1].Size)
// invalid
assert.Panics(func() { pt.EnsureDirectorySizes(map[string]uint64{"invalid": uint64(300)}) })
}
}
}