disk: move partition creation to disk package

This commit is contained in:
Gianluca Zuccarelli 2021-08-18 13:13:54 +01:00 committed by Tom Gundersen
parent 87c176503a
commit e21eee273c
5 changed files with 216 additions and 200 deletions

View file

@ -0,0 +1,179 @@
package disk
import (
"io"
"math/rand"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/distro"
)
const (
sectorSize = 512
BIOSBootPartitionGUID = "21686148-6449-6E6F-744E-656564454649"
BIOSBootPartitionUUID = "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
FilesystemDataGUID = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
FilesystemDataUUID = "CB07C243-BC44-4717-853E-28852021225B"
EFISystemPartitionGUID = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
EFISystemPartitionUUID = "68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
EFIFilesystemUUID = "7B77-95E7"
RootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562"
)
func CreatePartitionTable(
mountpoints []blueprint.FilesystemCustomization,
imageOptions distro.ImageOptions,
arch distro.Arch,
basePartitionTable PartitionTable,
bootType distro.BootType,
ec2 bool,
rng *rand.Rand,
) PartitionTable {
archName := arch.Name()
basePartitionTable.Size = imageOptions.Size
partitions := []Partition{}
var start uint64 = 2048
if archName == distro.X86_64ArchName {
biosBootPartition := createPartition("bios", 2048, start, archName, rng)
partitions = append(partitions, biosBootPartition)
start += biosBootPartition.Size
if bootType != distro.LegacyBootType {
bootEFIPartition := createPartition("/boot/efi", 204800, start, archName, rng)
partitions = append(partitions, bootEFIPartition)
start += bootEFIPartition.Size
}
} else if archName == distro.Aarch64ArchName {
if ec2 {
bootEFIParition := createPartition("/boot/efi", 409600, start, archName, rng)
partitions = append(partitions, bootEFIParition)
start += bootEFIParition.Size
bootPartition := createPartition("/boot", 1048576, start, archName, rng)
partitions = append(partitions, bootPartition)
start += bootPartition.Size
} else {
bootEFIPartition := createPartition("/boot/efi", 204800, start, archName, rng)
partitions = append(partitions, bootEFIPartition)
start += bootEFIPartition.Size
}
} else if archName == distro.Ppc64leArchName {
biosBootPartition := createPartition("bios", 8192, start, archName, rng)
partitions = append(partitions, biosBootPartition)
start += biosBootPartition.Size
}
for _, m := range mountpoints {
if m.Mountpoint != "/" {
partitionSize := uint64(m.MinSize) / sectorSize
partition := createPartition(m.Mountpoint, partitionSize, start, archName, rng)
partitions = append(partitions, partition)
start += uint64(m.MinSize / sectorSize)
}
}
// treat the root partition as a special case
// by setting it last and setting the size
// dynamically
rootSize := (imageOptions.Size / sectorSize) - start - 100
rootPartition := createPartition("/", rootSize, start, archName, rng)
partitions = append(partitions, rootPartition)
basePartitionTable.Partitions = append(basePartitionTable.Partitions, partitions...)
return basePartitionTable
}
func createPartition(mountpoint string, size uint64, start uint64, archName string, rng *rand.Rand) Partition {
if mountpoint == "bios" {
diskPartition := Partition{
Start: start,
Size: size,
Bootable: true,
}
if archName == distro.X86_64ArchName {
diskPartition.Type = BIOSBootPartitionGUID
diskPartition.UUID = BIOSBootPartitionUUID
return diskPartition
}
diskPartition.Type = "41"
return diskPartition
}
var filesystem Filesystem
// EFI system is a special case
// return early
if mountpoint == "/boot/efi" {
filesystem = createFilesystemDisk(mountpoint, EFIFilesystemUUID)
return Partition{
Start: start,
Size: size,
Type: EFISystemPartitionGUID,
UUID: EFISystemPartitionUUID,
Filesystem: &filesystem,
}
}
partition := Partition{
Start: start,
Size: size,
Filesystem: &filesystem,
}
diskUUID := uuid.Must(newRandomUUIDFromReader(rng)).String()
filesystem = createFilesystemDisk(mountpoint, diskUUID)
if mountpoint == "/boot" {
partition.Type = FilesystemDataGUID
partition.UUID = FilesystemDataUUID
return partition
}
if archName == distro.X86_64ArchName || archName == distro.Aarch64ArchName {
if mountpoint == "/" {
// set Label for root mountpoint
filesystem.Label = "root"
partition.Type = FilesystemDataGUID
partition.UUID = RootPartitionUUID
return partition
}
partition.Type = FilesystemDataGUID
partition.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String()
return partition
}
if mountpoint == "/" && archName == distro.S390xArchName {
partition.Bootable = true
}
return partition
}
func createFilesystemDisk(mountpoint string, uuid string) Filesystem {
if mountpoint == "/boot/efi" {
return Filesystem{
Type: "vfat",
UUID: uuid,
Mountpoint: mountpoint,
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
}
}
return Filesystem{
Type: "xfs",
UUID: uuid,
Mountpoint: mountpoint,
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
}
}
func newRandomUUIDFromReader(r io.Reader) (uuid.UUID, error) {
var id uuid.UUID
_, err := io.ReadFull(r, id[:])
if err != nil {
return uuid.Nil, err
}
id[6] = (id[6] & 0x0f) | 0x40 // Version 4
id[8] = (id[8] & 0x3f) | 0x80 // Variant is 10
return id, nil
}

View file

@ -23,6 +23,15 @@ const (
S390xArchName = "s390x"
)
type BootType string
const (
UnsetBootType BootType = ""
LegacyBootType BootType = "legacy"
UEFIBootType BootType = "uefi"
HybridBootType BootType = "hybrid"
)
// A Distro represents composer's notion of what a given distribution is.
type Distro interface {
// Returns the name of the distro.

View file

@ -53,17 +53,8 @@ const (
blueprintPkgsKey = "blueprint"
)
type BootType string
type ValidArches map[string]disk.PartitionTable
const (
UnsetBootType BootType = ""
LegacyBootType BootType = "legacy"
UEFIBootType BootType = "uefi"
HybridBootType BootType = "hybrid"
)
var mountpointAllowList = []string{"/", "/var", "/var/*", "/home", "/opt", "/srv", "/usr"}
type distribution struct {
@ -127,7 +118,7 @@ type architecture struct {
imageTypeAliases map[string]string
packageSets map[string]rpmmd.PackageSet
legacy string
bootType BootType
bootType distro.BootType
}
func (a *architecture) Name() string {
@ -206,7 +197,7 @@ type imageType struct {
// bootable image
bootable bool
// If set to a value, it is preferred over the architecture value
bootType BootType
bootType distro.BootType
// List of valid arches for the image type
validArches ValidArches
}
@ -275,11 +266,11 @@ func (t *imageType) PackageSets(bp blueprint.Blueprint) map[string]rpmmd.Package
var addUEFIBootPkg bool
switch bt := t.getBootType(); bt {
case LegacyBootType:
case distro.LegacyBootType:
addLegacyBootPkg = true
case UEFIBootType:
case distro.UEFIBootType:
addUEFIBootPkg = true
case HybridBootType:
case distro.HybridBootType:
addLegacyBootPkg = true
addUEFIBootPkg = true
default:
@ -326,9 +317,9 @@ func (t *imageType) Exports() []string {
// getBootType returns the BootType which should be used for this particular
// combination of architecture and image type.
func (t *imageType) getBootType() BootType {
func (t *imageType) getBootType() distro.BootType {
bootType := t.arch.bootType
if t.bootType != UnsetBootType {
if t.bootType != distro.UnsetBootType {
bootType = t.bootType
}
return bootType
@ -336,7 +327,7 @@ func (t *imageType) getBootType() BootType {
func (t *imageType) supportsUEFI() bool {
bootType := t.getBootType()
if bootType == HybridBootType || bootType == UEFIBootType {
if bootType == distro.HybridBootType || bootType == distro.UEFIBootType {
return true
}
return false
@ -505,7 +496,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
edgePkgsKey: x8664EdgeCommitPackageSet(),
},
legacy: "i386-pc",
bootType: HybridBootType,
bootType: distro.HybridBootType,
}
aarch64 := architecture{
@ -515,7 +506,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
bootUEFIPkgsKey: aarch64UEFIBootPackageSet(),
edgePkgsKey: aarch64EdgeCommitPackageSet(),
},
bootType: UEFIBootType,
bootType: distro.UEFIBootType,
}
ppc64le := architecture{
@ -526,7 +517,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
buildPkgsKey: ppc64leBuildPackageSet(),
},
legacy: "powerpc-ieee1275",
bootType: LegacyBootType,
bootType: distro.LegacyBootType,
}
s390x := architecture{
distro: rd,
@ -534,7 +525,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
packageSets: map[string]rpmmd.PackageSet{
bootLegacyPkgsKey: s390xLegacyBootPackageSet(),
},
bootType: LegacyBootType,
bootType: distro.LegacyBootType,
}
// Shared Services
@ -688,7 +679,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
enabledServices: ec2EnabledServices,
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
bootType: LegacyBootType,
bootType: distro.LegacyBootType,
defaultSize: 10 * GigaByte,
pipelines: ec2Pipelines,
exports: []string{"image"},
@ -725,7 +716,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
enabledServices: ec2EnabledServices,
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
bootType: LegacyBootType,
bootType: distro.LegacyBootType,
defaultSize: 10 * GigaByte,
pipelines: rhelEc2Pipelines,
exports: []string{"archive"},
@ -762,7 +753,7 @@ func newDistro(name, modulePlatformID, ostreeRef string) distro.Distro {
enabledServices: ec2EnabledServices,
kernelOptions: "console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto",
bootable: true,
bootType: LegacyBootType,
bootType: distro.LegacyBootType,
defaultSize: 10 * GigaByte,
pipelines: rhelEc2Pipelines,
exports: []string{"archive"},

View file

@ -1,32 +1,10 @@
package rhel85
import (
"io"
"math/rand"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/disk"
"github.com/osbuild/osbuild-composer/internal/distro"
)
const (
sectorSize = 512
biosBootPartitionType = "21686148-6449-6E6F-744E-656564454649"
biosBootPartitionUUID = "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
bootPartitionType = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
bootPartitionUUID = "CB07C243-BC44-4717-853E-28852021225B"
bootEFIPartitionType = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
bootEFIPartitionUUID = "68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
bootEFIFilesystemUUID = "7B77-95E7"
defaultPartitionType = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
rootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562"
)
var defaultArches = map[string]disk.PartitionTable{
distro.X86_64ArchName: gptPartitionTable,
distro.Aarch64ArchName: gptPartitionTable,
@ -51,159 +29,13 @@ var dosPartitionTable = disk.PartitionTable{
Partitions: []disk.Partition{},
}
func createPartitionTable(
mountpoints []blueprint.FilesystemCustomization,
imageOptions distro.ImageOptions,
t *imageType,
ec2 bool,
rng *rand.Rand,
) disk.PartitionTable {
archName := t.arch.Name()
partitionTable, ok := t.validArches[archName]
func getBasePartitionTable(arch distro.Arch, validArches ValidArches) disk.PartitionTable {
archName := arch.Name()
partitionTable, ok := validArches[archName]
if !ok {
panic("unknown arch: " + archName)
}
partitionTable.Size = imageOptions.Size
partitions := []disk.Partition{}
var start uint64 = 2048
if archName == distro.X86_64ArchName {
biosBootPartition := createPartition("bios", 2048, start, archName, rng)
partitions = append(partitions, biosBootPartition)
start += biosBootPartition.Size
if t.bootType != LegacyBootType {
bootEFIPartition := createPartition("/boot/efi", 204800, start, archName, rng)
partitions = append(partitions, bootEFIPartition)
start += bootEFIPartition.Size
}
} else if archName == distro.Aarch64ArchName {
if ec2 {
bootEFIParition := createPartition("/boot/efi", 409600, start, archName, rng)
partitions = append(partitions, bootEFIParition)
start += bootEFIParition.Size
bootPartition := createPartition("/boot", 1048576, 411648, archName, rng)
partitions = append(partitions, bootPartition)
start += bootPartition.Size
} else {
bootEFIPartition := createPartition("/boot/efi", 204800, start, archName, rng)
partitions = append(partitions, bootEFIPartition)
start += bootEFIPartition.Size
}
} else if archName == distro.Ppc64leArchName {
biosBootPartition := createPartition("bios", 8192, start, archName, rng)
partitions = append(partitions, biosBootPartition)
start += biosBootPartition.Size
}
for _, m := range mountpoints {
if m.Mountpoint != "/" {
partitionSize := uint64(m.MinSize) / sectorSize
partition := createPartition(m.Mountpoint, partitionSize, start, archName, rng)
partitions = append(partitions, partition)
start += uint64(m.MinSize / sectorSize)
}
}
// treat the root partition as a special case
// by setting it last and setting the size
// dynamically
rootSize := (imageOptions.Size / sectorSize) - start - 100
rootPartition := createPartition("/", rootSize, start, archName, rng)
partitions = append(partitions, rootPartition)
partitionTable.Partitions = append(partitionTable.Partitions, partitions...)
return partitionTable
}
func createPartition(mountpoint string, size uint64, start uint64, archName string, rng *rand.Rand) disk.Partition {
if mountpoint == "bios" {
diskPartition := disk.Partition{
Start: start,
Size: size,
Bootable: true,
}
if archName == distro.X86_64ArchName {
diskPartition.Type = biosBootPartitionType
diskPartition.UUID = biosBootPartitionUUID
return diskPartition
}
diskPartition.Type = "41"
return diskPartition
}
var filesystem disk.Filesystem
// /boot/efi mountpoint is a special case
// return early
if mountpoint == "/boot/efi" {
filesystem = createFilesystemDisk(mountpoint, bootEFIFilesystemUUID)
return disk.Partition{
Start: start,
Size: size,
Type: bootEFIPartitionType,
UUID: bootEFIPartitionUUID,
Filesystem: &filesystem,
}
}
partition := disk.Partition{
Start: start,
Size: size,
Filesystem: &filesystem,
}
diskUUID := uuid.Must(newRandomUUIDFromReader(rng)).String()
filesystem = createFilesystemDisk(mountpoint, diskUUID)
if mountpoint == "/boot" {
partition.Type = bootPartitionType
partition.UUID = bootPartitionUUID
return partition
}
if archName == distro.X86_64ArchName || archName == distro.Aarch64ArchName {
if mountpoint == "/" {
// set Label for root mountpoint
filesystem.Label = "root"
partition.Type = defaultPartitionType
partition.UUID = rootPartitionUUID
return partition
}
partition.Type = defaultPartitionType
partition.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String()
return partition
}
if mountpoint == "/" && archName == distro.S390xArchName {
partition.Bootable = true
}
return partition
}
func createFilesystemDisk(mountpoint string, uuid string) disk.Filesystem {
if mountpoint == "/boot/efi" {
return disk.Filesystem{
Type: "vfat",
UUID: uuid,
Mountpoint: mountpoint,
FSTabOptions: "defaults,uid=0,gid=0,umask=077,shortname=winnt",
FSTabFreq: 0,
FSTabPassNo: 2,
}
}
return disk.Filesystem{
Type: "xfs",
UUID: uuid,
Mountpoint: mountpoint,
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
}
}
func newRandomUUIDFromReader(r io.Reader) (uuid.UUID, error) {
var id uuid.UUID
_, err := io.ReadFull(r, id[:])
if err != nil {
return uuid.Nil, err
}
id[6] = (id[6] & 0x0f) | 0x40 // Version 4
id[8] = (id[8] & 0x3f) | 0x80 // Variant is 10
return id, nil
}

View file

@ -23,7 +23,8 @@ func qcow2Pipelines(t *imageType, customizations *blueprint.Customizations, opti
return nil, err
}
partitionTable := createPartitionTable(customizations.GetFilesystems(), options, t, false, rng)
basePartitionTable := getBasePartitionTable(t.Arch(), t.validArches)
partitionTable := disk.CreatePartitionTable(customizations.GetFilesystems(), options, t.Arch(), basePartitionTable, t.bootType, false, rng)
treePipeline = prependKernelCmdlineStage(treePipeline, t, &partitionTable)
if options.Subscription == nil {
@ -76,7 +77,8 @@ func vhdPipelines(t *imageType, customizations *blueprint.Customizations, option
return nil, err
}
partitionTable := createPartitionTable(customizations.GetFilesystems(), options, t, false, rng)
basePartitionTable := getBasePartitionTable(t.Arch(), t.validArches)
partitionTable := disk.CreatePartitionTable(customizations.GetFilesystems(), options, t.Arch(), basePartitionTable, t.bootType, false, rng)
treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2()))
kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name())
treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer))
@ -103,7 +105,8 @@ func vmdkPipelines(t *imageType, customizations *blueprint.Customizations, optio
return nil, err
}
partitionTable := createPartitionTable(customizations.GetFilesystems(), options, t, false, rng)
basePartitionTable := getBasePartitionTable(t.Arch(), t.validArches)
partitionTable := disk.CreatePartitionTable(customizations.GetFilesystems(), options, t.Arch(), basePartitionTable, t.bootType, false, rng)
treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2()))
kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name())
treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer))
@ -130,7 +133,8 @@ func openstackPipelines(t *imageType, customizations *blueprint.Customizations,
return nil, err
}
partitionTable := createPartitionTable(customizations.GetFilesystems(), options, t, false, rng)
basePartitionTable := getBasePartitionTable(t.Arch(), t.validArches)
partitionTable := disk.CreatePartitionTable(customizations.GetFilesystems(), options, t.Arch(), basePartitionTable, t.bootType, false, rng)
treePipeline.AddStage(osbuild.NewFSTabStage(partitionTable.FSTabStageOptionsV2()))
kernelVer := kernelVerStr(packageSetSpecs[blueprintPkgsKey], customizations.GetKernel().Name, t.Arch().Name())
treePipeline.AddStage(bootloaderConfigStage(t, partitionTable, customizations.GetKernel(), kernelVer))
@ -392,7 +396,8 @@ func ec2CommonPipelines(t *imageType, customizations *blueprint.Customizations,
pipelines := make([]osbuild.Pipeline, 0)
pipelines = append(pipelines, *buildPipeline(repos, packageSetSpecs[buildPkgsKey]))
partitionTable := createPartitionTable(customizations.GetFilesystems(), options, t, true, rng)
basePartitionTable := getBasePartitionTable(t.Arch(), t.validArches)
partitionTable := disk.CreatePartitionTable(customizations.GetFilesystems(), options, t.Arch(), basePartitionTable, t.bootType, true, rng)
var treePipeline *osbuild.Pipeline
var err error
switch arch := t.arch.Name(); arch {