disk/lvm: generate logical volume name

When creating a new logical volume via the `CreateVolume` method,
the logical volume name was left blank. Generate an name based
on the mountpoint.
We will detect collisions for names and will try to correct them
by attaching a suffix. We do give up after 100 attempts though.
Add a simple test for it.
This commit is contained in:
Christian Kellner 2022-02-25 16:12:37 +01:00 committed by Achilleas Koutsou
parent 9b89df57b6
commit a9ef16a95e
2 changed files with 80 additions and 1 deletions

View file

@ -1,6 +1,9 @@
package disk
import "fmt"
import (
"fmt"
"strings"
)
type LVMVolumeGroup struct {
Name string
@ -66,7 +69,33 @@ func (vg *LVMVolumeGroup) CreateVolume(mountpoint string, size uint64) (Entity,
FSTabPassNo: 0,
}
names := make(map[string]bool, len(vg.LogicalVolumes))
for _, lv := range vg.LogicalVolumes {
names[lv.Name] = true
}
base := lvname(mountpoint)
var exists bool
name := base
// Make sure that we don't collide with an existing volume, e.g. 'home/test'
// and /home/test_test would collide. We try 100 times and then give up. This
// is mimicking what blivet does. See blivet/blivet.py#L1060 commit 2eb4bd4
for i := 0; i < 100; i++ {
exists = names[name]
if !exists {
break
}
name = fmt.Sprintf("%s%02d", base, i)
}
if exists {
return nil, fmt.Errorf("could not create logical volume: name collision")
}
lv := LVMLogicalVolume{
Name: name,
Size: size,
Payload: &filesystem,
}
@ -128,3 +157,13 @@ func (lv *LVMLogicalVolume) EnsureSize(s uint64) bool {
}
return false
}
// lvname returns a name for a logical volume based on the mountpoint.
func lvname(path string) string {
if path == "/" {
return "rootlv"
}
path = strings.TrimLeft(path, "/")
return strings.ReplaceAll(path, "/", "_") + "lv"
}

40
internal/disk/lvm_test.go Normal file
View file

@ -0,0 +1,40 @@
package disk
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLVMVGCreateVolume(t *testing.T) {
assert := assert.New(t)
vg := &LVMVolumeGroup{
Name: "root",
Description: "root volume group",
}
entity, err := vg.CreateVolume("/", 0)
assert.NoError(err)
rootlv := entity.(*LVMLogicalVolume)
assert.Equal("rootlv", rootlv.Name)
_, err = vg.CreateVolume("/home_test", 0)
assert.NoError(err)
entity, err = vg.CreateVolume("/home/test", 0)
assert.NoError(err)
dedup := entity.(*LVMLogicalVolume)
assert.Equal("home_testlv00", dedup.Name)
// Lets collide it
for i := 0; i < 98; i++ {
_, err = vg.CreateVolume("/home/test", 0)
assert.NoError(err)
}
_, err = vg.CreateVolume("/home/test", 0)
assert.Error(err)
}