Skip to content
Merged
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
34 changes: 34 additions & 0 deletions pkg/bib/osinfo/osinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import (
"strings"

"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"

"github.com/osbuild/blueprint/pkg/blueprint"
"github.com/osbuild/images/pkg/bib/blueprintload"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/distro"
)

// XXX: use image-builder instead?
const bibPathPrefix = "usr/lib/bootc-image-builder"

type OSRelease struct {
Expand All @@ -37,6 +40,8 @@ type Info struct {
SELinuxPolicy string
ImageCustomization *blueprint.Customizations
KernelInfo *KernelInfo

PartitionTable *disk.PartitionTable
}

func validateOSRelease(osrelease map[string]string) error {
Expand Down Expand Up @@ -125,6 +130,29 @@ func readImageCustomization(root string) (*blueprint.Customizations, error) {
return config.Customizations, nil
}

type diskYAML struct {
PartitionTable *disk.PartitionTable `json:"partition_table" yaml:"partition_table"`
}

func readPartitionTable(root string) (*disk.PartitionTable, error) {
p := path.Join(root, bibPathPrefix, "disk.yaml")
var disk diskYAML
f, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("cannot load disk definitions from %q: %w", p, err)
}
defer f.Close()

if err := yaml.NewDecoder(f).Decode(&disk); err != nil {
return nil, fmt.Errorf("cannot parse disk definitions from %q: %w", p, err)
}

return disk.PartitionTable, nil
}

func readKernelInfo(root string) (*KernelInfo, error) {
modulesDir := path.Join(root, "usr/lib/modules")
entries, err := os.ReadDir(modulesDir)
Expand Down Expand Up @@ -177,6 +205,11 @@ func Load(root string) (*Info, error) {
return nil, err
}

pt, err := readPartitionTable(root)
if err != nil {
return nil, err
}

kernelInfo, err := readKernelInfo(root)
if err != nil {
logrus.Debugf("cannot read kernel info: %v", err)
Expand Down Expand Up @@ -206,5 +239,6 @@ func Load(root string) (*Info, error) {
SELinuxPolicy: selinuxPolicy,
ImageCustomization: customization,
KernelInfo: kernelInfo,
PartitionTable: pt,
}, nil
}
56 changes: 56 additions & 0 deletions pkg/bib/osinfo/osinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/disk"
)

func writeOSRelease(root, id, versionID, name, platformID, variantID, idLike string) error {
Expand Down Expand Up @@ -212,3 +215,56 @@ func TestLoadInfoKernel(t *testing.T) {
})
}
}

var fakePartitionTableYAML = `
.common:
partitioning:
guids:
- &bios_boot_partition_guid "21686148-6449-6E6F-744E-656564454649"

partition_table:
type: "gpt"
partitions:
- &bios_boot_partition
size: 1 MiB
uuid: 2866630c-0c7e-469c-bc82-c458e3fd6223
bootable: true
type: *bios_boot_partition_guid
`

func createPartitionTable(root, fakePartitionTableYAML string) error {
dst := path.Join(root, "/usr/lib/bootc-image-builder/disk.yaml")
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
return err
}
return os.WriteFile(dst, []byte(fakePartitionTableYAML), 0644)
}

func TestLoadInfoPartitionTableHappy(t *testing.T) {
root := t.TempDir()
require.NoError(t, writeOSRelease(root, "fedora", "40", "Fedora Linux", "fedora", "platform:f40", "coreos"))
require.NoError(t, createPartitionTable(root, fakePartitionTableYAML))

info, err := Load(root)
require.NoError(t, err)
assert.Equal(t, &disk.PartitionTable{
Type: disk.PT_GPT,
Partitions: []disk.Partition{
{
Bootable: true,
Size: 1 * datasizes.MiB,
Type: "21686148-6449-6E6F-744E-656564454649",
UUID: "2866630c-0c7e-469c-bc82-c458e3fd6223",
},
},
}, info.PartitionTable)
}

func TestLoadInfoPartitionTableSad(t *testing.T) {
root := t.TempDir()
require.NoError(t, writeOSRelease(root, "fedora", "40", "Fedora Linux", "fedora", "platform:f40", "coreos"))
require.NoError(t, createPartitionTable(root, "@invalidYAML"))

_, err := Load(root)
assert.EqualError(t, err, fmt.Sprintf(`cannot parse disk definitions from "%s/usr/lib/bootc-image-builder/disk.yaml": yaml: found character that cannot start any token`, root))
}
6 changes: 6 additions & 0 deletions pkg/distro/bootc/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ var (
UpdateFilesystemSizes = updateFilesystemSizes
CreateRand = createRand
CalcRequiredDirectorySizes = calcRequiredDirectorySizes

TestDiskContainers = diskContainers
)

func NewTestBootcImageType() *BootcImageType {
Expand All @@ -40,6 +42,10 @@ func NewTestBootcImageType() *BootcImageType {
return imgType
}

func (t *BootcImageType) SetSourceInfoPartitionTable(basept *disk.PartitionTable) {
t.arch.distro.sourceInfo.PartitionTable = basept
}

func (t *BootcImageType) GenPartitionTable(customizations *blueprint.Customizations, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
return t.genPartitionTable(customizations, rootfsMinSize, rng)
}
19 changes: 19 additions & 0 deletions pkg/distro/bootc/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/osbuild/blueprint/pkg/blueprint"

"github.com/osbuild/images/internal/common"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/disk"
"github.com/osbuild/images/pkg/disk/partition"
Expand Down Expand Up @@ -660,3 +661,21 @@ func TestManifestDirCustomizationsSad(t *testing.T) {
_, _, err := imgType.Manifest(bp, distro.ImageOptions{}, nil, common.ToPtr(int64(0)))
assert.EqualError(t, err, `the following custom directories are not allowed: ["/dir/not/allowed"]`)
}

func TestGenPartitionTableFromOSInfo(t *testing.T) {
var bp blueprint.Blueprint
imgType := bootc.NewTestBootcImageType()
// pretend a custom partition table is set via the bootc
// container sourceInfo mechanism
newPt := bootc.PartitionTables[arch.Current().String()]
newPt.UUID = "01010101-01011-01011-01011-01010101"
imgType.SetSourceInfoPartitionTable(&newPt)

// validate that the container uuid is part of the generated
// manifest
mf, _, err := imgType.Manifest(&bp, distro.ImageOptions{}, nil, common.ToPtr(int64(0)))
assert.NoError(t, err)
manifestJson, err := mf.Serialize(nil, bootc.TestDiskContainers, nil, nil)
assert.NoError(t, err)
assert.Contains(t, string(manifestJson), "01010101-01011-01011-01011-01010101")
}
32 changes: 23 additions & 9 deletions pkg/distro/bootc/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,28 @@ var (
})
)

func (t *BootcImageType) basePartitionTable() (*disk.PartitionTable, error) {
// base partition table can come from the container
if t.arch.distro.sourceInfo != nil && t.arch.distro.sourceInfo.PartitionTable != nil {
return t.arch.distro.sourceInfo.PartitionTable, nil
}
// get it from the build-in fallback partition tables
if pt, ok := partitionTables[t.arch.Name()]; ok {
return &pt, nil
}
return nil, fmt.Errorf("cannot find a base partition table for %q", t.Name())
}

func (t *BootcImageType) genPartitionTable(customizations *blueprint.Customizations, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
fsCust := customizations.GetFilesystems()
diskCust, err := customizations.GetPartitioning()
if err != nil {
return nil, fmt.Errorf("error reading disk customizations: %w", err)
}
basept, err := t.basePartitionTable()
if err != nil {
return nil, err
}

// Embedded disk customization applies if there was no local customization
if fsCust == nil && diskCust == nil && t.arch.distro.sourceInfo != nil && t.arch.distro.sourceInfo.ImageCustomization != nil {
Expand All @@ -85,12 +101,12 @@ func (t *BootcImageType) genPartitionTable(customizations *blueprint.Customizati
case fsCust != nil && diskCust != nil:
return nil, fmt.Errorf("cannot combine disk and filesystem customizations")
case diskCust != nil:
partitionTable, err = t.genPartitionTableDiskCust(diskCust, rootfsMinSize, rng)
partitionTable, err = t.genPartitionTableDiskCust(basept, diskCust, rootfsMinSize, rng)
if err != nil {
return nil, err
}
default:
partitionTable, err = t.genPartitionTableFsCust(fsCust, rootfsMinSize, rng)
partitionTable, err = t.genPartitionTableFsCust(basept, fsCust, rootfsMinSize, rng)
if err != nil {
return nil, err
}
Expand All @@ -110,15 +126,14 @@ func (t *BootcImageType) genPartitionTable(customizations *blueprint.Customizati
return partitionTable, nil
}

func (t *BootcImageType) genPartitionTableDiskCust(diskCust *blueprint.DiskCustomization, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
func (t *BootcImageType) genPartitionTableDiskCust(basept *disk.PartitionTable, diskCust *blueprint.DiskCustomization, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
if err := diskCust.ValidateLayoutConstraints(); err != nil {
return nil, fmt.Errorf("cannot use disk customization: %w", err)
}

diskCust.MinSize = max(diskCust.MinSize, rootfsMinSize)

basept, ok := partitionTables[t.arch.Name()]
if !ok {
if basept == nil {
return nil, fmt.Errorf("pipelines: no partition tables defined for %s", t.arch.Name())
}
defaultFSType, err := disk.NewFSType(t.arch.distro.defaultFs)
Expand All @@ -140,9 +155,8 @@ func (t *BootcImageType) genPartitionTableDiskCust(diskCust *blueprint.DiskCusto
return disk.NewCustomPartitionTable(diskCust, partOptions, rng)
}

func (t *BootcImageType) genPartitionTableFsCust(fsCust []blueprint.FilesystemCustomization, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
basept, ok := partitionTables[t.arch.Name()]
if !ok {
func (t *BootcImageType) genPartitionTableFsCust(basept *disk.PartitionTable, fsCust []blueprint.FilesystemCustomization, rootfsMinSize uint64, rng *rand.Rand) (*disk.PartitionTable, error) {
if basept == nil {
return nil, fmt.Errorf("pipelines: no partition tables defined for %s", t.arch.Name())
}

Expand All @@ -155,7 +169,7 @@ func (t *BootcImageType) genPartitionTableFsCust(fsCust []blueprint.FilesystemCu
}
fsCustomizations := updateFilesystemSizes(fsCust, rootfsMinSize)

pt, err := disk.NewPartitionTable(&basept, fsCustomizations, DEFAULT_SIZE, partitioningMode, t.arch.arch, nil, rng)
pt, err := disk.NewPartitionTable(basept, fsCustomizations, DEFAULT_SIZE, partitioningMode, t.arch.arch, nil, rng)
if err != nil {
return nil, err
}
Expand Down
Loading