feat: support bootloader option for ISO

Support selecting bootloader option for ISO.

Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
Noel Georgi 2025-10-23 21:15:42 +05:30
parent d110727263
commit 61e95cb4b7
No known key found for this signature in database
GPG Key ID: 21A9F444075C9E36
13 changed files with 350 additions and 103 deletions

View File

@ -83,14 +83,14 @@ func NewAuto() Bootloader {
// New returns a new bootloader based on the secureboot flag and architecture.
func New(bootloader, talosVersion, arch string) (Bootloader, error) {
switch bootloader {
case profile.DiskImageBootloaderGrub.String():
case profile.BootLoaderKindGrub.String():
g := grub.NewConfig()
g.AddResetOption = quirks.New(talosVersion).SupportsResetGRUBOption()
return g, nil
case profile.DiskImageBootloaderSDBoot.String():
case profile.BootLoaderKindSDBoot.String():
return sdboot.New(), nil
case profile.DiskImageBootloaderDualBoot.String():
case profile.BootLoaderKindDualBoot.String():
return dual.New(), nil
default:
return nil, fmt.Errorf("unsupported bootloader %q", bootloader)

View File

@ -104,7 +104,7 @@ func (*Sequencer) Initialize(r runtime.Runtime) []runtime.Phase {
return false
}
return r.State().Machine().Installed() && val == profile.DiskImageBootloaderDualBoot.String()
return r.State().Machine().Installed() && val == profile.BootLoaderKindDualBoot.String()
},
"cleanupBootloader",
CleanupBootloader,

View File

@ -20,29 +20,6 @@ import (
"github.com/siderolabs/talos/pkg/makefs"
)
// UEFIOptions describe the input for the CreateUEFI function.
type UEFIOptions struct {
UKIPath string
SDBootPath string
// A value in loader.conf secure-boot-enroll: off, manual, if-safe, force.
SDBootSecureBootEnrollKeys string
// UKISigningCertDer is the DER encoded UKI signing certificate.
UKISigningCertDerPath string
// optional, for auto-enrolling secureboot keys
PlatformKeyPath string
KeyExchangeKeyPath string
SignatureKeyPath string
Arch string
Version string
ScratchDir string
OutPath string
}
const (
// mib is the size of a megabyte.
mib = 1024 * 1024

View File

@ -188,6 +188,43 @@ func (i *Imager) outISO(ctx context.Context, path string, report *reporter.Repor
if err != nil {
return err
}
case quirks.New(i.prof.Version).ISOSupportsSettingBootloader():
options := iso.Options{
KernelPath: i.prof.Input.Kernel.Path,
InitramfsPath: i.initramfsPath,
Cmdline: i.cmdline,
UKIPath: i.ukiPath,
SDBootPath: i.sdBootPath,
SDBootSecureBootEnrollKeys: "off",
Arch: i.prof.Arch,
Version: i.prof.Version,
ScratchDir: scratchSpace,
OutPath: path,
}
switch i.prof.Output.ISOOptions.Bootloader {
case profile.BootLoaderKindDualBoot:
generator, err = options.CreateHybrid(printf)
if err != nil {
return err
}
case profile.BootLoaderKindSDBoot:
generator, err = options.CreateUEFI(printf)
if err != nil {
return err
}
case profile.BootLoaderKindGrub:
generator, err = options.CreateGRUB(printf)
if err != nil {
return err
}
case profile.BootLoaderKindNone:
return fmt.Errorf("cannot create ISO with no bootloader")
}
case quirks.New(i.prof.Version).UseSDBootForUEFI():
options := iso.Options{
KernelPath: i.prof.Input.Kernel.Path,
@ -324,10 +361,10 @@ func (i *Imager) buildImage(ctx context.Context, path string, printf func(string
if i.prof.Arch == "amd64" && !i.prof.SecureBootEnabled() && quirks.New(i.prof.Version).UseSDBootForUEFI() {
// allow overriding the bootloader if provided
if i.prof.Output.ImageOptions.Bootloader == profile.DiskImageBootloaderDualBoot {
if i.prof.Output.ImageOptions.Bootloader == profile.BootLoaderKindDualBoot {
metaContents = append(metaContents, meta.Value{
Key: meta.DiskImageBootloader,
Value: profile.DiskImageBootloaderDualBoot.String(),
Value: profile.BootLoaderKindDualBoot.String(),
})
}
}

View File

@ -43,7 +43,7 @@ type ImageOptions struct {
DiskFormatOptions string `yaml:"diskFormatOptions,omitempty"`
// Bootloader is the bootloader to use for the disk image.
// If not set, it defaults to dual-boot.
Bootloader DiskImageBootloader `yaml:"bootloader"`
Bootloader BootloaderKind `yaml:"bootloader,omitempty"`
}
// ISOOptions describes options for the 'iso' output.
@ -52,6 +52,9 @@ type ISOOptions struct {
//
// If not set, it defaults to if-safe.
SDBootEnrollKeys SDBootEnrollKeys `yaml:"sdBootEnrollKeys"`
// Bootloader is the bootloader to use for the iso image.
// If not set, it defaults to dual-boot.
Bootloader BootloaderKind `yaml:"bootloader,omitempty"`
}
// OutputKind is output specification.
@ -105,53 +108,73 @@ const (
SDBootEnrollKeysOff // off
)
// DiskImageBootloader is a bootloader for the disk image.
type DiskImageBootloader int
// BootloaderKind is a bootloader for the disk image.
type BootloaderKind int
const (
// DiskImageBootloaderDualBoot is the dual-boot bootloader
// BootLoaderKindNone is the zero value.
BootLoaderKindNone BootloaderKind = iota // none
// BootLoaderKindDualBoot is the dual-boot bootloader.
// using sd-boot for UEFI and GRUB for BIOS.
DiskImageBootloaderDualBoot DiskImageBootloader = iota // dual-boot
// DiskImageBootloaderSDBoot is the sd-boot bootloader.
DiskImageBootloaderSDBoot // sd-boot
// DiskImageBootloaderGrub is the GRUB bootloader.
DiskImageBootloaderGrub // grub
BootLoaderKindDualBoot // dual-boot
// BootLoaderKindSDBoot is the sd-boot bootloader.
BootLoaderKindSDBoot // sd-boot
// BootLoaderKindGrub is the GRUB bootloader.
BootLoaderKindGrub // grub
)
// FillDefaults fills default values for the output.
func (o *Output) FillDefaults(arch, version string, secureboot bool) {
if o.Kind == OutKindImage {
switch o.Kind { //nolint:exhaustive
case OutKindImage:
if o.ImageOptions == nil {
o.ImageOptions = &ImageOptions{}
}
useSDBoot := quirks.New(version).UseSDBootForUEFI()
switch {
case o.ImageOptions.Bootloader != DiskImageBootloaderDualBoot:
// allow user to override bootloader
case secureboot:
// secureboot is always using sd-boot
o.ImageOptions.Bootloader = DiskImageBootloaderSDBoot
case arch == "arm64" && useSDBoot:
// arm64 always uses sd-boot for Talos >= 1.10
o.ImageOptions.Bootloader = DiskImageBootloaderSDBoot
case !useSDBoot:
// legacy versions of Talos use GRUB for BIOS/UEFI
o.ImageOptions.Bootloader = DiskImageBootloaderGrub
default:
// Default to dual-boot.
o.ImageOptions.Bootloader = DiskImageBootloaderDualBoot
}
o.ImageOptions.Bootloader = o.selectBootloader(o.ImageOptions.Bootloader, arch, version, secureboot)
ps := quirks.New(version).PartitionSizes()
// bump default image size for expanded boot
o.ImageOptions.DiskSize += int64(ps.GrubBootSize()) - 1000*1024*1024 // 1000 MiB
if o.ImageOptions.Bootloader == DiskImageBootloaderDualBoot {
if o.ImageOptions.Bootloader == BootLoaderKindDualBoot {
// add extra space for BIOS and BOOT partitions
o.ImageOptions.DiskSize += int64(ps.GrubBIOSSize()) + int64(ps.GrubBootSize())
}
case OutKindISO:
if !quirks.New(version).ISOSupportsSettingBootloader() {
return
}
if o.ISOOptions == nil {
o.ISOOptions = &ISOOptions{}
}
o.ISOOptions.Bootloader = o.selectBootloader(o.ISOOptions.Bootloader, arch, version, secureboot)
}
}
func (o *Output) selectBootloader(current BootloaderKind, arch, version string, secureboot bool) BootloaderKind {
useSDBoot := quirks.New(version).UseSDBootForUEFI()
switch {
case secureboot:
// secureboot is always using sd-boot
return BootLoaderKindSDBoot
case arch == "arm64" && useSDBoot:
// arm64 always uses sd-boot for Talos >= 1.10
return BootLoaderKindSDBoot
case !useSDBoot:
// legacy versions of Talos use GRUB for BIOS/UEFI
return BootLoaderKindGrub
default:
// Default to dual-boot if not overridden.
if current == BootLoaderKindNone {
return BootLoaderKindDualBoot
}
return current
}
}

View File

@ -0,0 +1,172 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package profile_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/siderolabs/talos/pkg/imager/profile"
"github.com/siderolabs/talos/pkg/machinery/imager/quirks"
)
func createOutputWithDefaults(kind profile.OutputKind, arch, version string, secureBoot bool) profile.Output {
out := profile.Output{
Kind: kind,
}
out.FillDefaults(arch, version, secureBoot)
return out
}
func createOutputWithOverride(kind profile.OutputKind, bootloader profile.BootloaderKind, arch, version string, secureBoot bool) profile.Output {
out := profile.Output{
Kind: kind,
}
switch kind { //nolint:exhaustive
case profile.OutKindImage:
out.ImageOptions = &profile.ImageOptions{
Bootloader: bootloader,
}
case profile.OutKindISO:
if quirks.New(version).ISOSupportsSettingBootloader() {
out.ISOOptions = &profile.ISOOptions{
Bootloader: bootloader,
}
}
}
out.FillDefaults(arch, version, secureBoot)
return out
}
func TestBootloaderSetting(t *testing.T) {
t.Parallel()
tests := []struct {
arch string
version string
secureBoot bool
wantImage profile.BootloaderKind
}{
// Talos < 1.10: GRUB for both amd64/arm64, ISO options not supported
{"amd64", "1.9.0", false, profile.BootLoaderKindGrub},
{"amd64", "1.9.0", true, profile.BootLoaderKindSDBoot},
{"arm64", "1.9.0", false, profile.BootLoaderKindGrub},
{"arm64", "1.9.0", true, profile.BootLoaderKindSDBoot},
// Talos 1.10-1.11: amd64=dual-boot, arm64=sd-boot, ISO options not supported
{"amd64", "1.10.0", false, profile.BootLoaderKindDualBoot},
{"amd64", "1.10.0", true, profile.BootLoaderKindSDBoot},
{"arm64", "1.10.0", false, profile.BootLoaderKindSDBoot},
{"arm64", "1.10.0", true, profile.BootLoaderKindSDBoot},
{"amd64", "1.11.0", false, profile.BootLoaderKindDualBoot},
{"amd64", "1.11.0", true, profile.BootLoaderKindSDBoot},
{"arm64", "1.11.0", false, profile.BootLoaderKindSDBoot},
{"arm64", "1.11.0", true, profile.BootLoaderKindSDBoot},
// Talos >= 1.12: amd64=dual-boot, arm64=sd-boot, ISO options supported
{"amd64", "1.12.0", false, profile.BootLoaderKindDualBoot},
{"amd64", "1.12.0", true, profile.BootLoaderKindSDBoot},
{"arm64", "1.12.0", false, profile.BootLoaderKindSDBoot},
{"arm64", "1.12.0", true, profile.BootLoaderKindSDBoot},
}
for _, tt := range tests {
name := tt.arch + "-" + tt.version
if tt.secureBoot {
name += "-secureboot"
}
t.Run(name, func(t *testing.T) {
t.Parallel()
// Test Image output
img := createOutputWithDefaults(profile.OutKindImage, tt.arch, tt.version, tt.secureBoot)
require.NotNil(t, img.ImageOptions)
require.Equal(t, tt.wantImage, img.ImageOptions.Bootloader)
// Test ISO output
iso := createOutputWithDefaults(profile.OutKindISO, tt.arch, tt.version, tt.secureBoot)
if quirks.New(tt.version).ISOSupportsSettingBootloader() {
require.NotNil(t, iso.ISOOptions)
require.Equal(t, tt.wantImage, iso.ISOOptions.Bootloader)
} else {
require.Nil(t, iso.ISOOptions)
}
})
}
}
func TestBootloaderOverride(t *testing.T) {
t.Parallel()
tests := []struct {
arch string
version string
secureBoot bool
override profile.BootloaderKind
wantImage profile.BootloaderKind
}{
// Talos < 1.10: GRUB is forced, overrides are ignored
{"amd64", "1.9.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindGrub},
{"amd64", "1.9.0", false, profile.BootLoaderKindSDBoot, profile.BootLoaderKindGrub}, // forced to GRUB
{"amd64", "1.9.0", false, profile.BootLoaderKindDualBoot, profile.BootLoaderKindGrub}, // forced to GRUB
{"amd64", "1.9.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
{"arm64", "1.9.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindGrub},
{"arm64", "1.9.0", false, profile.BootLoaderKindSDBoot, profile.BootLoaderKindGrub}, // forced to GRUB
{"arm64", "1.9.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
// Talos 1.10-1.11: amd64 respects override, arm64 forced to sd-boot
{"amd64", "1.10.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindGrub},
{"amd64", "1.10.0", false, profile.BootLoaderKindSDBoot, profile.BootLoaderKindSDBoot},
{"amd64", "1.10.0", false, profile.BootLoaderKindDualBoot, profile.BootLoaderKindDualBoot},
{"amd64", "1.10.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
{"arm64", "1.10.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // arm64 >= 1.10 forces sd-boot
{"arm64", "1.10.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
{"amd64", "1.11.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindGrub},
{"amd64", "1.11.0", false, profile.BootLoaderKindDualBoot, profile.BootLoaderKindDualBoot},
{"amd64", "1.11.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
{"arm64", "1.11.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // arm64 >= 1.10 forces sd-boot
{"arm64", "1.11.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
// Talos >= 1.12: amd64 respects override, arm64 forced to sd-boot
{"amd64", "1.12.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindGrub},
{"amd64", "1.12.0", false, profile.BootLoaderKindSDBoot, profile.BootLoaderKindSDBoot},
{"amd64", "1.12.0", false, profile.BootLoaderKindDualBoot, profile.BootLoaderKindDualBoot},
{"amd64", "1.12.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
{"arm64", "1.12.0", false, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // arm64 >= 1.10 forces sd-boot
{"arm64", "1.12.0", true, profile.BootLoaderKindGrub, profile.BootLoaderKindSDBoot}, // secureboot forces sd-boot
}
for _, tt := range tests {
name := tt.arch + "-" + tt.version + "-override-" + tt.override.String()
if tt.secureBoot {
name += "-secureboot"
}
t.Run(name, func(t *testing.T) {
t.Parallel()
// Test Image output with override
img := createOutputWithOverride(profile.OutKindImage, tt.override, tt.arch, tt.version, tt.secureBoot)
require.NotNil(t, img.ImageOptions)
require.Equal(t, tt.wantImage, img.ImageOptions.Bootloader)
// Test ISO output with override
iso := createOutputWithOverride(profile.OutKindISO, tt.override, tt.arch, tt.version, tt.secureBoot)
if quirks.New(tt.version).ISOSupportsSettingBootloader() {
require.NotNil(t, iso.ISOOptions)
require.Equal(t, tt.wantImage, iso.ISOOptions.Bootloader)
} else {
require.Nil(t, iso.ISOOptions)
}
})
}
}

View File

@ -1,4 +1,4 @@
// Code generated by "enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys,DiskImageBootloader -linecomment -text"; DO NOT EDIT.
// Code generated by "enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys,BootloaderKind -linecomment -text"; DO NOT EDIT.
package profile
@ -395,73 +395,77 @@ func (i *SDBootEnrollKeys) UnmarshalText(text []byte) error {
return err
}
const _DiskImageBootloaderName = "dual-bootsd-bootgrub"
const _BootloaderKindName = "nonedual-bootsd-bootgrub"
var _DiskImageBootloaderIndex = [...]uint8{0, 9, 16, 20}
var _BootloaderKindIndex = [...]uint8{0, 4, 13, 20, 24}
const _DiskImageBootloaderLowerName = "dual-bootsd-bootgrub"
const _BootloaderKindLowerName = "nonedual-bootsd-bootgrub"
func (i DiskImageBootloader) String() string {
if i < 0 || i >= DiskImageBootloader(len(_DiskImageBootloaderIndex)-1) {
return fmt.Sprintf("DiskImageBootloader(%d)", i)
func (i BootloaderKind) String() string {
if i < 0 || i >= BootloaderKind(len(_BootloaderKindIndex)-1) {
return fmt.Sprintf("BootloaderKind(%d)", i)
}
return _DiskImageBootloaderName[_DiskImageBootloaderIndex[i]:_DiskImageBootloaderIndex[i+1]]
return _BootloaderKindName[_BootloaderKindIndex[i]:_BootloaderKindIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _DiskImageBootloaderNoOp() {
func _BootloaderKindNoOp() {
var x [1]struct{}
_ = x[DiskImageBootloaderDualBoot-(0)]
_ = x[DiskImageBootloaderSDBoot-(1)]
_ = x[DiskImageBootloaderGrub-(2)]
_ = x[BootLoaderKindNone-(0)]
_ = x[BootLoaderKindDualBoot-(1)]
_ = x[BootLoaderKindSDBoot-(2)]
_ = x[BootLoaderKindGrub-(3)]
}
var _DiskImageBootloaderValues = []DiskImageBootloader{DiskImageBootloaderDualBoot, DiskImageBootloaderSDBoot, DiskImageBootloaderGrub}
var _BootloaderKindValues = []BootloaderKind{BootLoaderKindNone, BootLoaderKindDualBoot, BootLoaderKindSDBoot, BootLoaderKindGrub}
var _DiskImageBootloaderNameToValueMap = map[string]DiskImageBootloader{
_DiskImageBootloaderName[0:9]: DiskImageBootloaderDualBoot,
_DiskImageBootloaderLowerName[0:9]: DiskImageBootloaderDualBoot,
_DiskImageBootloaderName[9:16]: DiskImageBootloaderSDBoot,
_DiskImageBootloaderLowerName[9:16]: DiskImageBootloaderSDBoot,
_DiskImageBootloaderName[16:20]: DiskImageBootloaderGrub,
_DiskImageBootloaderLowerName[16:20]: DiskImageBootloaderGrub,
var _BootloaderKindNameToValueMap = map[string]BootloaderKind{
_BootloaderKindName[0:4]: BootLoaderKindNone,
_BootloaderKindLowerName[0:4]: BootLoaderKindNone,
_BootloaderKindName[4:13]: BootLoaderKindDualBoot,
_BootloaderKindLowerName[4:13]: BootLoaderKindDualBoot,
_BootloaderKindName[13:20]: BootLoaderKindSDBoot,
_BootloaderKindLowerName[13:20]: BootLoaderKindSDBoot,
_BootloaderKindName[20:24]: BootLoaderKindGrub,
_BootloaderKindLowerName[20:24]: BootLoaderKindGrub,
}
var _DiskImageBootloaderNames = []string{
_DiskImageBootloaderName[0:9],
_DiskImageBootloaderName[9:16],
_DiskImageBootloaderName[16:20],
var _BootloaderKindNames = []string{
_BootloaderKindName[0:4],
_BootloaderKindName[4:13],
_BootloaderKindName[13:20],
_BootloaderKindName[20:24],
}
// DiskImageBootloaderString retrieves an enum value from the enum constants string name.
// BootloaderKindString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func DiskImageBootloaderString(s string) (DiskImageBootloader, error) {
if val, ok := _DiskImageBootloaderNameToValueMap[s]; ok {
func BootloaderKindString(s string) (BootloaderKind, error) {
if val, ok := _BootloaderKindNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _DiskImageBootloaderNameToValueMap[strings.ToLower(s)]; ok {
if val, ok := _BootloaderKindNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to DiskImageBootloader values", s)
return 0, fmt.Errorf("%s does not belong to BootloaderKind values", s)
}
// DiskImageBootloaderValues returns all values of the enum
func DiskImageBootloaderValues() []DiskImageBootloader {
return _DiskImageBootloaderValues
// BootloaderKindValues returns all values of the enum
func BootloaderKindValues() []BootloaderKind {
return _BootloaderKindValues
}
// DiskImageBootloaderStrings returns a slice of all String values of the enum
func DiskImageBootloaderStrings() []string {
strs := make([]string, len(_DiskImageBootloaderNames))
copy(strs, _DiskImageBootloaderNames)
// BootloaderKindStrings returns a slice of all String values of the enum
func BootloaderKindStrings() []string {
strs := make([]string, len(_BootloaderKindNames))
copy(strs, _BootloaderKindNames)
return strs
}
// IsADiskImageBootloader returns "true" if the value is listed in the enum definition. "false" otherwise
func (i DiskImageBootloader) IsADiskImageBootloader() bool {
for _, v := range _DiskImageBootloaderValues {
// IsABootloaderKind returns "true" if the value is listed in the enum definition. "false" otherwise
func (i BootloaderKind) IsABootloaderKind() bool {
for _, v := range _BootloaderKindValues {
if i == v {
return true
}
@ -469,14 +473,14 @@ func (i DiskImageBootloader) IsADiskImageBootloader() bool {
return false
}
// MarshalText implements the encoding.TextMarshaler interface for DiskImageBootloader
func (i DiskImageBootloader) MarshalText() ([]byte, error) {
// MarshalText implements the encoding.TextMarshaler interface for BootloaderKind
func (i BootloaderKind) MarshalText() ([]byte, error) {
return []byte(i.String()), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface for DiskImageBootloader
func (i *DiskImageBootloader) UnmarshalText(text []byte) error {
// UnmarshalText implements the encoding.TextUnmarshaler interface for BootloaderKind
func (i *BootloaderKind) UnmarshalText(text []byte) error {
var err error
*i, err = DiskImageBootloaderString(string(text))
*i, err = BootloaderKindString(string(text))
return err
}

View File

@ -13,12 +13,13 @@ import (
"github.com/siderolabs/go-pointer"
"gopkg.in/yaml.v3"
"github.com/siderolabs/talos/pkg/machinery/imager/quirks"
"github.com/siderolabs/talos/pkg/machinery/overlay"
)
//go:generate go tool github.com/siderolabs/deep-copy -type Profile -type SecureBootAssets -header-file ../../../hack/boilerplate.txt -o deep_copy.generated.go .
//go:generate go tool github.com/dmarkham/enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys,DiskImageBootloader -linecomment -text
//go:generate go tool github.com/dmarkham/enumer -type OutputKind,OutFormat,DiskFormat,SDBootEnrollKeys,BootloaderKind -linecomment -text
// Profile describes image generation result.
type Profile struct {
@ -82,11 +83,20 @@ func (p *Profile) Validate() error {
}
}
if p.SecureBootEnabled() && !quirks.New(p.Version).SupportsUKI() {
return fmt.Errorf("secureboot is not supported for Talos version %q", p.Version)
}
switch p.Output.Kind {
case OutKindUnknown:
return errors.New("unknown output kind")
case OutKindISO:
// ISO supports all kinds of customization
if quirks.New(p.Version).ISOSupportsSettingBootloader() {
if p.Output.ISOOptions != nil && p.Output.ISOOptions.Bootloader == BootLoaderKindNone {
return errors.New("bootloader cannot be 'none' for ISO output")
}
}
case OutKindCmdline:
// cmdline supports all kinds of customization
case OutKindImage:
@ -98,6 +108,10 @@ func (p *Profile) Validate() error {
if p.Output.ImageOptions.DiskSize == 0 {
return errors.New("disk size is required for image output")
}
if p.Output.ImageOptions.Bootloader == BootLoaderKindNone {
return errors.New("bootloader cannot be 'none' for disk image output")
}
case OutKindInstaller:
if len(p.Customization.MetaContents) > 0 {
return fmt.Errorf("customization of meta partition is not supported for %s output", p.Output.Kind)

View File

@ -15,4 +15,7 @@ input:
imageRef: ghcr.io/siderolabs/installer-base:1.12.0
output:
kind: iso
isoOptions:
sdBootEnrollKeys: if-safe
bootloader: dual-boot
outFormat: raw

View File

@ -15,4 +15,7 @@ input:
imageRef: ghcr.io/siderolabs/installer-base:1.12.0
output:
kind: iso
isoOptions:
sdBootEnrollKeys: if-safe
bootloader: sd-boot
outFormat: raw

View File

@ -23,4 +23,5 @@ output:
kind: iso
isoOptions:
sdBootEnrollKeys: if-safe
bootloader: sd-boot
outFormat: raw

View File

@ -23,4 +23,5 @@ output:
kind: iso
isoOptions:
sdBootEnrollKeys: if-safe
bootloader: sd-boot
outFormat: raw

View File

@ -298,3 +298,15 @@ func (q Quirks) SupportsDisablingModuleSignatureVerification() bool {
return q.v.GTE(minTalosVersionDisableModSigVerify)
}
var minTalosVersionISOSupportsSettingBootloader = semver.MustParse("1.12.0")
// ISOSupportsSettingBootloader returns true if the Talos version supports setting bootloader for ISO output.
func (q Quirks) ISOSupportsSettingBootloader() bool {
// if the version doesn't parse, we assume it's latest Talos
if q.v == nil {
return true
}
return q.v.GTE(minTalosVersionISOSupportsSettingBootloader)
}