talos/pkg/imager/iso/grub.go
Andrey Smirnov 0a30ef7845
fix: imager should support different Talos versions
Add some quirks to make images generated with newer Talos compatible
with images generated by older Talos.

Specifically, reset options were adding in Talos 1.4, so we shouldn't
add them for older versions.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2023-12-22 16:13:34 +04:00

121 lines
2.7 KiB
Go

// 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 iso
import (
"bytes"
_ "embed"
"fmt"
"os"
"path/filepath"
"text/template"
"time"
"github.com/siderolabs/go-cmd/pkg/cmd"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub"
"github.com/siderolabs/talos/pkg/imager/quirks"
"github.com/siderolabs/talos/pkg/imager/utils"
)
// GRUBOptions described the input for the CreateGRUB function.
type GRUBOptions struct {
KernelPath string
InitramfsPath string
Cmdline string
Version string
ScratchDir string
OutPath string
}
//go:embed grub.cfg
var grubCfgTemplate string
// CreateGRUB creates a GRUB-based ISO image.
//
// This iso supports both BIOS and UEFI booting.
func CreateGRUB(printf func(string, ...any), options GRUBOptions) error {
if err := utils.CopyFiles(
printf,
utils.SourceDestination(options.KernelPath, filepath.Join(options.ScratchDir, "boot", "vmlinuz")),
utils.SourceDestination(options.InitramfsPath, filepath.Join(options.ScratchDir, "boot", "initramfs.xz")),
); err != nil {
return err
}
printf("creating grub.cfg")
var grubCfg bytes.Buffer
tmpl, err := template.New("grub.cfg").
Funcs(template.FuncMap{
"quote": grub.Quote,
}).
Parse(grubCfgTemplate)
if err != nil {
return err
}
if err = tmpl.Execute(&grubCfg, struct {
Cmdline string
AddResetOption bool
}{
Cmdline: options.Cmdline,
AddResetOption: quirks.New(options.Version).SupportsResetGRUBOption(),
}); err != nil {
return err
}
cfgPath := filepath.Join(options.ScratchDir, "boot/grub/grub.cfg")
if err = os.MkdirAll(filepath.Dir(cfgPath), 0o755); err != nil {
return err
}
if err = os.WriteFile(cfgPath, grubCfg.Bytes(), 0o666); err != nil {
return err
}
if err = utils.TouchFiles(printf, options.ScratchDir); err != nil {
return err
}
printf("creating ISO image")
return grubMkrescue(options.OutPath, options.ScratchDir)
}
func grubMkrescue(isoPath, scratchPath string) error {
args := []string{
"--compress=xz",
"--output=" + isoPath,
scratchPath,
}
if epoch, ok, err := utils.SourceDateEpoch(); err != nil {
return err
} else if ok {
// set EFI FAT image serial number
if err := os.Setenv("GRUB_FAT_SERIAL_NUMBER", fmt.Sprintf("%x", uint32(epoch))); err != nil {
return err
}
args = append(args,
"--",
"-volume_date", "all_file_dates", fmt.Sprintf("=%d", epoch),
"-volume_date", "uuid", time.Unix(epoch, 0).Format("2006010215040500"),
)
}
_, err := cmd.Run("grub-mkrescue", args...)
if err != nil {
return fmt.Errorf("failed to create ISO: %w", err)
}
return nil
}