osbuild2: add support for LVM stages

Stage options implement a validate() method for checking values against
schema constraints.
This commit is contained in:
Achilleas Koutsou 2021-08-18 12:37:19 +02:00 committed by Tom Gundersen
parent b777444319
commit 39b0cf39d6
6 changed files with 230 additions and 0 deletions

View file

@ -0,0 +1,51 @@
package osbuild2
import (
"fmt"
"regexp"
)
const lvmVolNameRegex = "^[a-zA-Z0-9+_.][a-zA-Z0-9+_.-]*$"
// Create LVM2 physical volumes, volume groups, and logical volumes
type LVM2CreateStageOptions struct {
Volumes []LogicalVolume `json:"volumes"`
}
func (LVM2CreateStageOptions) isStageOptions() {}
func (o LVM2CreateStageOptions) validate() error {
if len(o.Volumes) == 0 {
return fmt.Errorf("at least one volume is required")
}
nameRegex := regexp.MustCompile(lvmVolNameRegex)
for _, volume := range o.Volumes {
fmt.Printf("testing volume %q\n", volume.Name)
if !nameRegex.MatchString(volume.Name) {
return fmt.Errorf("volume name %q doesn't conform to schema (%s)", volume.Name, nameRegex.String())
} else {
fmt.Printf("volume.Name %q is ok\n", volume.Name)
}
}
return nil
}
type LogicalVolume struct {
Name string `json:"name"`
Size string `json:"size"`
}
func NewLVM2CreateStage(options *LVM2CreateStageOptions, device *Device) *Stage {
if err := options.validate(); err != nil {
panic(err)
}
return &Stage{
Type: "org.osbuild.lvm2.create",
Options: options,
Devices: Devices{"device": *device},
}
}

View file

@ -0,0 +1,60 @@
package osbuild2
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewLVM2CreateStageValidation(t *testing.T) {
assert := assert.New(t)
okOptions := LVM2CreateStageOptions{
Volumes: []LogicalVolume{
{
Name: "a_volume_name",
Size: "",
},
{
Name: "good-volume.name",
Size: "10G",
},
{
Name: "99-luft+volumes",
Size: "10737418240",
},
{
Name: "++",
Size: "1337",
},
{
Name: "_",
Size: "0",
},
},
}
assert.NoError(okOptions.validate())
badVolumes := []LogicalVolume{
{
Name: "!bad-bad-volume-name",
Size: "1337",
},
{
Name: "even worse",
},
{
Name: "-",
},
}
for _, vol := range badVolumes {
options := LVM2CreateStageOptions{
Volumes: []LogicalVolume{vol},
}
assert.Error(options.validate(), vol.Name)
}
empty := LVM2CreateStageOptions{}
assert.Error(empty.validate())
}

View file

@ -0,0 +1,17 @@
package osbuild2
// Provide access to LVM2 Logical Volume (LV)
type LVM2LVDeviceOptions struct {
// Logical volume to activate
Volume string `json:"volume"`
}
func (LVM2LVDeviceOptions) isDeviceOptions() {}
func NewLVM2LVDevice(options *LoopbackDeviceOptions) *Device {
return &Device{
Type: "org.osbuild.lvm2.lv",
Options: options,
}
}

View file

@ -0,0 +1 @@
package osbuild2

View file

@ -0,0 +1,46 @@
package osbuild2
import (
"fmt"
"regexp"
"strconv"
)
// Set LVM2 Volume Group metadata
type LVM2MetadataStageOptions struct {
CreationHost string `json:"creation_host,omitempty"`
// Creation time (uint64 represented as string)
CreationTime string `json:"creation_time,omitempty"`
Description string `json:"description,omitempty"`
VGName string `json:"vg_name"`
}
func (LVM2MetadataStageOptions) isStageOptions() {}
func (o LVM2MetadataStageOptions) validate() error {
nameRegex := regexp.MustCompile(lvmVolNameRegex)
if !nameRegex.MatchString(o.VGName) {
return fmt.Errorf("volume group name %q doesn't conform to schema (%s)", o.VGName, nameRegex.String())
}
if _, err := strconv.ParseUint(o.CreationTime, 10, 64); err != nil {
return fmt.Errorf("invalid volume creation time: %s", o.CreationTime)
}
return nil
}
func NewLVM2MetadataStage(options *LVM2MetadataStageOptions, device *Device) *Stage {
if err := options.validate(); err != nil {
panic(err)
}
return &Stage{
Type: "org.osbuild.lvm2.metadata",
Options: options,
Devices: Devices{"device": *device},
}
}

View file

@ -0,0 +1,55 @@
package osbuild2
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewLVM2MetadataStageValidation(t *testing.T) {
assert := assert.New(t)
okOptions := []LVM2MetadataStageOptions{
{
VGName: "a_volume_name",
CreationTime: "0",
},
{
VGName: "good-volume.name",
CreationTime: "1629282647",
},
{
VGName: "99-luft+volumes",
CreationTime: "2147483648",
},
{
VGName: "++",
CreationTime: "42",
},
{
VGName: "_",
CreationTime: "4294967297",
},
}
for _, o := range okOptions {
assert.NoError(o.validate(), o)
}
badOptions := []LVM2MetadataStageOptions{
{
VGName: "ok-name-bad-time",
CreationTime: "-10",
},
{
VGName: "!bad-name",
CreationTime: "1629282647",
},
{
VGName: "worse.time",
CreationTime: "TIME",
},
}
for _, o := range badOptions {
assert.Error(o.validate(), o)
}
}