chore: clean up the output of the imager

Use `Progress`, and options to pass around the way messages are written.

Fixed some tiny issues in the code, but otherwise no functional changes.

To make colored output work with `docker run`, switched back image
generation to use volume mount for output (old mode is still
functioning, but it's not the default, and it works when docker is not
running on the same host).

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
This commit is contained in:
Andrey Smirnov 2023-08-04 23:11:16 +04:00 committed by Andrey Smirnov
parent fb536af4d1
commit e0f383598e
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
34 changed files with 355 additions and 171 deletions

View File

@ -300,7 +300,7 @@ image-%: ## Builds the specified image. Valid options are aws, azure, digital-oc
@docker pull $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG)
@for platform in $(subst $(,),$(space),$(PLATFORM)); do \
arch=$$(basename "$${platform}") && \
docker run --rm -v /dev:/dev -v $(PWD)/$(ARTIFACTS):/secureboot:ro --network=host --privileged $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG) $* --arch $$arch --tar-to-stdout $(IMAGER_ARGS) | tar xz -C $(ARTIFACTS) ; \
docker run --rm -t -v /dev:/dev -v $(PWD)/$(ARTIFACTS):/secureboot:ro -v $(PWD)/$(ARTIFACTS):/out --network=host --privileged $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG) $* --arch $$arch $(IMAGER_ARGS) ; \
done
images-essential: image-aws image-gcp image-metal secureboot-installer ## Builds only essential images used in the CI (AWS, GCP, and Metal).
@ -309,7 +309,7 @@ images: image-aws image-azure image-digital-ocean image-exoscale image-gcp image
sbc-%: ## Builds the specified SBC image. Valid options are rpi_generic, rock64, bananapi_m64, libretech_all_h3_cc_h5, rockpi_4, rockpi_4c, pine64, jetson_nano and nanopi_r4s (e.g. sbc-rpi_generic)
@docker pull $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG)
@docker run --rm -v /dev:/dev --network=host --privileged $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG) $* --arch arm64 --tar-to-stdout $(IMAGER_ARGS) | tar xz -C $(ARTIFACTS)
@docker run --rm -t -v /dev:/dev -v $(PWD)/$(ARTIFACTS):/out --network=host --privileged $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG) $* --arch arm64 $(IMAGER_ARGS)
sbcs: sbc-rpi_generic sbc-rock64 sbc-bananapi_m64 sbc-libretech_all_h3_cc_h5 sbc-rockpi_4 sbc-rockpi_4c sbc-pine64 sbc-jetson_nano sbc-nanopi_r4s ## Builds all known SBC images (Raspberry Pi 4, Rock64, Banana Pi M64, Radxa ROCK Pi 4, Radxa ROCK Pi 4c, Pine64, Libre Computer Board ALL-H3-CC, Jetson Nano and Nano Pi R4S).

View File

@ -7,7 +7,6 @@ package imager
import (
"context"
"fmt"
"os"
"runtime"
@ -21,6 +20,7 @@ import (
"github.com/siderolabs/talos/pkg/imager"
"github.com/siderolabs/talos/pkg/imager/profile"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/reporter"
)
var cmdFlags struct {
@ -38,12 +38,19 @@ var cmdFlags struct {
// rootCmd represents the base command when called without any subcommands.
var rootCmd = &cobra.Command{
Use: "imager <profile>|-",
Short: "Generate various boot assets and images.",
Long: ``,
Args: cobra.ExactArgs(1),
Use: "imager <profile>|-",
Short: "Generate various boot assets and images.",
Long: ``,
Args: cobra.ExactArgs(1),
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
return cli.WithContext(context.Background(), func(ctx context.Context) error {
report := reporter.New()
report.Report(reporter.Update{
Message: "assembling the finalized profile...",
Status: reporter.StatusRunning,
})
baseProfile := args[0]
var prof profile.Profile
@ -98,7 +105,12 @@ var rootCmd = &cobra.Command{
return err
}
if err = imager.Execute(ctx, cmdFlags.OutputPath); err != nil {
if err = imager.Execute(ctx, cmdFlags.OutputPath, report); err != nil {
report.Report(reporter.Update{
Message: err.Error(),
Status: reporter.StatusError,
})
return err
}
@ -115,7 +127,6 @@ var rootCmd = &cobra.Command{
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

View File

@ -42,6 +42,7 @@ type Options struct {
ImageSecureboot bool
Version string
BootAssets bootloaderoptions.BootAssets
Printf func(string, ...any)
}
// Mode is the install mode.
@ -107,7 +108,7 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options)
return err
}
log.Printf("installation of %s complete", version.Tag)
i.options.Printf("installation of %s complete", version.Tag)
return nil
}
@ -132,6 +133,10 @@ func NewInstaller(ctx context.Context, cmdline *procfs.Cmdline, mode Mode, opts
i.options.Version = version.Tag
}
if i.options.Printf == nil {
i.options.Printf = log.Printf
}
if !i.options.Zero {
i.bootloader, err = bootloader.Probe(ctx, i.options.Disk)
if err != nil && !os.IsNotExist(err) {
@ -258,6 +263,7 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) {
Version: i.options.Version,
ImageMode: mode.IsImage(),
BootAssets: i.options.BootAssets,
Printf: i.options.Printf,
}); err != nil {
return err
}
@ -270,7 +276,7 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) {
return err
}
log.Printf("installing U-Boot for %q", b.Name())
i.options.Printf("installing U-Boot for %q", b.Name())
if err = b.Install(i.options.Disk); err != nil {
return err

View File

@ -9,7 +9,6 @@ import (
"context"
"errors"
"fmt"
"log"
"os"
"path/filepath"
"strings"
@ -33,6 +32,8 @@ type Manifest struct {
Devices map[string]Device
Targets map[string][]*Target
LegacyBIOSSupport bool
Printf func(string, ...any)
}
// Device represents device options.
@ -53,6 +54,8 @@ func NewManifest(mode Mode, uefiOnlyBoot bool, bootLoaderPresent bool, opts *Opt
Devices: map[string]Device{},
Targets: map[string][]*Target{},
LegacyBIOSSupport: opts.LegacyBIOSSupport,
Printf: opts.Printf,
}
if opts.Board != constants.BoardNone {
@ -248,7 +251,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
if device.Zero {
if err = partition.Format(device.Device, &partition.FormatOptions{
FileSystemType: partition.FilesystemTypeNone,
}); err != nil {
}, m.Printf); err != nil {
return err
}
}
@ -272,7 +275,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
return err
}
log.Printf("creating new partition table on %s", device.Device)
m.Printf("creating new partition table on %s", device.Device)
gptOpts := []gpt.Option{
gpt.WithMarkMBRBootable(m.LegacyBIOSSupport),
@ -287,8 +290,8 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
return err
}
log.Printf("logical/physical block size: %d/%d", pt.Header().LBA.LogicalBlockSize, pt.Header().LBA.PhysicalBlockSize)
log.Printf("minimum/optimal I/O size: %d/%d", pt.Header().LBA.MinimalIOSize, pt.Header().LBA.OptimalIOSize)
m.Printf("logical/physical block size: %d/%d", pt.Header().LBA.LogicalBlockSize, pt.Header().LBA.PhysicalBlockSize)
m.Printf("minimum/optimal I/O size: %d/%d", pt.Header().LBA.MinimalIOSize, pt.Header().LBA.OptimalIOSize)
if err = pt.Write(); err != nil {
return err
@ -309,7 +312,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
if !created {
if device.ResetPartitionTable {
log.Printf("resetting partition table on %s", device.Device)
m.Printf("resetting partition table on %s", device.Device)
// TODO: how should it work with zero option above?
if err = bd.Reset(); err != nil {
@ -343,7 +346,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
// delete all partitions which are not skipped
for _, part := range pt.Partitions().Items() {
if _, ok := keepPartitions[part.Name]; !ok {
log.Printf("deleting partition %s", part.Name)
m.Printf("deleting partition %s", part.Name)
if err = pt.Delete(part); err != nil {
return err
@ -363,7 +366,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
}
for i, target := range targets {
if err = target.partition(pt, i); err != nil {
if err = target.partition(pt, i, m.Printf); err != nil {
return fmt.Errorf("failed to partition device: %w", err)
}
}
@ -376,7 +379,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
target := target
err = retry.Constant(time.Minute, retry.WithUnits(100*time.Millisecond)).Retry(func() error {
e := target.Format()
e := target.Format(m.Printf)
if e != nil {
if strings.Contains(e.Error(), "No such file or directory") {
// workaround problem with partition device not being visible immediately after partitioning
@ -422,7 +425,7 @@ func (m *Manifest) preserveContents(device Device, targets []*Target) (err error
if bd, err = blockdevice.Open(device.Device); err != nil {
// failed to open the block device, probably it's damaged?
log.Printf("warning: skipping preserve contents on %q as block device failed: %s", device.Device, err)
m.Printf("warning: skipping preserve contents on %q as block device failed: %s", device.Device, err)
return nil
}
@ -432,7 +435,7 @@ func (m *Manifest) preserveContents(device Device, targets []*Target) (err error
pt, err := bd.PartitionTable()
if err != nil {
log.Printf("warning: skipping preserve contents on %q as partition table failed: %s", device.Device, err)
m.Printf("warning: skipping preserve contents on %q as partition table failed: %s", device.Device, err)
return nil
}
@ -473,13 +476,13 @@ func (m *Manifest) preserveContents(device Device, targets []*Target) (err error
}
if sourcePart == nil {
log.Printf("warning: failed to preserve contents of %q on %q, as source partition wasn't found", target.Label, device.Device)
m.Printf("warning: failed to preserve contents of %q on %q, as source partition wasn't found", target.Label, device.Device)
continue
}
if err = target.SaveContents(device, sourcePart, fileSystemType, fnmatchFilters); err != nil {
log.Printf("warning: failed to preserve contents of %q on %q: %s", target.Label, device.Device, err)
m.Printf("warning: failed to preserve contents of %q on %q: %s", target.Label, device.Device, err)
}
}

View File

@ -229,9 +229,10 @@ func (suite *manifestSuite) TestExecuteManifestClean() {
suite.skipUnderBuildkit()
manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Printf: suite.T().Logf,
})
suite.Require().NoError(err)
@ -249,9 +250,10 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
suite.skipUnderBuildkit()
manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Printf: suite.T().Logf,
})
suite.Require().NoError(err)
@ -267,10 +269,11 @@ func (suite *manifestSuite) TestExecuteManifestForce() {
// reinstall
manifest, err = install.NewManifest(install.ModeUpgrade, false, true, &install.Options{
Disk: suite.loopbackDevice.Name(),
Force: true,
Zero: true,
Board: constants.BoardNone,
Disk: suite.loopbackDevice.Name(),
Force: true,
Zero: true,
Board: constants.BoardNone,
Printf: suite.T().Logf,
})
suite.Require().NoError(err)
@ -288,9 +291,10 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
suite.skipUnderBuildkit()
manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Disk: suite.loopbackDevice.Name(),
Force: true,
Board: constants.BoardNone,
Printf: suite.T().Logf,
})
suite.Require().NoError(err)
@ -306,9 +310,10 @@ func (suite *manifestSuite) TestExecuteManifestPreserve() {
// reinstall
manifest, err = install.NewManifest(install.ModeUpgrade, false, true, &install.Options{
Disk: suite.loopbackDevice.Name(),
Force: false,
Board: constants.BoardNone,
Disk: suite.loopbackDevice.Name(),
Force: false,
Board: constants.BoardNone,
Printf: suite.T().Logf,
})
suite.Require().NoError(err)

View File

@ -200,11 +200,11 @@ func (t *Target) Locate(pt *gpt.GPT) (*gpt.Partition, error) {
}
// partition creates a new partition on the specified device.
func (t *Target) partition(pt *gpt.GPT, pos int) (err error) {
func (t *Target) partition(pt *gpt.GPT, pos int, printf func(string, ...any)) (err error) {
if t.Skip {
part := pt.Partitions().FindByName(t.Label)
if part != nil {
log.Printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
t.PartitionName, err = part.Path()
if err != nil {
@ -220,7 +220,7 @@ func (t *Target) partition(pt *gpt.GPT, pos int) (err error) {
PartitionType: t.PartitionType,
Size: t.Size,
LegacyBIOSBootable: t.LegacyBIOSBootable,
})
}, printf)
if err != nil {
return err
}
@ -231,12 +231,12 @@ func (t *Target) partition(pt *gpt.GPT, pos int) (err error) {
}
// Format creates a filesystem on the device/partition.
func (t *Target) Format() error {
func (t *Target) Format(printf func(string, ...any)) error {
if t.Skip {
return nil
}
return partition.Format(t.PartitionName, t.FormatOptions)
return partition.Format(t.PartitionName, t.FormatOptions, printf)
}
// GetLabel returns the underlaying partition label.

View File

@ -136,7 +136,7 @@ type ResetOptions interface {
// PartitionTarget provides interface to the disk partition.
type PartitionTarget interface {
fmt.Stringer
Format() error
Format(func(string, ...any)) error
GetLabel() string
}

View File

@ -7,7 +7,6 @@ package grub
import (
"bytes"
"io"
"log"
"os"
"path/filepath"
"text/template"
@ -43,7 +42,7 @@ menuentry "Reset Talos installation and return to maintenance mode" {
`
// Write the grub configuration to the given file.
func (c *Config) Write(path string) error {
func (c *Config) Write(path string, printf func(string, ...any)) error {
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, os.ModeDir); err != nil {
return err
@ -56,7 +55,7 @@ func (c *Config) Write(path string) error {
return err
}
log.Printf("writing %s to disk", path)
printf("writing %s to disk", path)
return os.WriteFile(path, wr.Bytes(), 0o600)
}

View File

@ -103,7 +103,7 @@ func TestWrite(t *testing.T) {
config := grub.NewConfig()
require.NoError(t, config.Put(grub.BootA, "cmdline A", "v0.0.1"))
err := config.Write(tempFile.Name())
err := config.Write(tempFile.Name(), t.Logf)
assert.NoError(t, err)
written, _ := os.ReadFile(tempFile.Name())

View File

@ -6,14 +6,12 @@ package grub
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"github.com/siderolabs/go-blockdevice/blockdevice"
"github.com/siderolabs/go-cmd/pkg/cmd"
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options"
"github.com/siderolabs/talos/pkg/imager/utils"
@ -36,6 +34,7 @@ func (c *Config) Install(options options.InstallOptions) error {
options.BootAssets.FillDefaults(options.Arch)
if err := utils.CopyFiles(
options.Printf,
utils.SourceDestination(options.BootAssets.KernelPath, filepath.Join(constants.BootMountPoint, string(c.Default), constants.KernelAsset)),
utils.SourceDestination(options.BootAssets.InitramfsPath, filepath.Join(constants.BootMountPoint, string(c.Default), constants.InitramfsAsset)),
); err != nil {
@ -46,7 +45,7 @@ func (c *Config) Install(options options.InstallOptions) error {
return err
}
if err := c.Write(ConfigPath); err != nil {
if err := c.Write(ConfigPath, options.Printf); err != nil {
return err
}
@ -83,13 +82,9 @@ func (c *Config) Install(options options.InstallOptions) error {
args = append(args, blk)
log.Printf("executing: grub-install %s", strings.Join(args, " "))
options.Printf("executing: grub-install %s", strings.Join(args, " "))
cmd := exec.Command("grub-install", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = cmd.Run(); err != nil {
if _, err := cmd.Run("grub-install", args...); err != nil {
return fmt.Errorf("failed to install grub: %w", err)
}
}

View File

@ -9,6 +9,7 @@ import (
"context"
"errors"
"fmt"
"log"
"os"
"path/filepath"
@ -69,7 +70,7 @@ func (c *Config) Revert(ctx context.Context) error {
return fmt.Errorf("cannot rollback to %q, label does not exist", "")
}
if err := c.Write(ConfigPath); err != nil {
if err := c.Write(ConfigPath, log.Printf); err != nil {
return fmt.Errorf("failed to revert bootloader: %v", err)
}

View File

@ -27,6 +27,9 @@ type InstallOptions struct {
// Boot assets to install.
BootAssets BootAssets
// Printf-like function to use.
Printf func(format string, v ...any)
}
// BootAssets describes the assets to be installed by the booloader.

View File

@ -157,7 +157,7 @@ func (c *Config) Install(options options.InstallOptions) error {
continue
}
log.Printf("removing old UKI: %s", file)
options.Printf("removing old UKI: %s", file)
if err = os.Remove(file); err != nil {
return err
@ -167,6 +167,7 @@ func (c *Config) Install(options options.InstallOptions) error {
options.BootAssets.FillDefaults(options.Arch)
if err := utils.CopyFiles(
options.Printf,
utils.SourceDestination(options.BootAssets.UKIPath, filepath.Join(constants.EFIMountPoint, "EFI", "Linux", ukiPath)),
utils.SourceDestination(options.BootAssets.SDBootPath, filepath.Join(constants.EFIMountPoint, "EFI", "boot", sdbootFilename)),
); err != nil {
@ -175,6 +176,8 @@ func (c *Config) Install(options options.InstallOptions) error {
// don't update EFI variables if we're installing to a loop device
if !options.ImageMode {
options.Printf("updating EFI variables")
efiCtx := efivario.NewDefaultContext()
// set the new entry as a default one

View File

@ -822,6 +822,7 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
m := &installer.Manifest{
Devices: map[string]installer.Device{},
Targets: map[string][]*installer.Target{},
Printf: logger.Printf,
}
for _, disk := range r.Config().Machine().Disks() {
@ -1618,7 +1619,7 @@ func ResetSystemDiskSpec(_ runtime.Sequence, data any) (runtime.TaskExecutionFun
}
for _, target := range in.GetSystemDiskTargets() {
if err = target.Format(); err != nil {
if err = target.Format(logger.Printf); err != nil {
return fmt.Errorf("failed wiping partition %s: %w", target, err)
}
}

View File

@ -167,7 +167,7 @@ func SystemMountPointForLabel(ctx context.Context, device *blockdevice.BlockDevi
if !o.MountFlags.Check(SkipIfNoFilesystem) {
p.fstype = opts.FileSystemType
return partition.Format(p.source, opts)
return partition.Format(p.source, opts, log.Printf)
}
return nil

View File

@ -7,7 +7,6 @@ package partition
import (
"fmt"
"log"
"github.com/siderolabs/go-blockdevice/blockdevice"
@ -28,13 +27,13 @@ func NewFormatOptions(label string) *FormatOptions {
}
// Format zeroes the device and formats it using filesystem type provided.
func Format(devname string, t *FormatOptions) error {
func Format(devname string, t *FormatOptions, printf func(string, ...any)) error {
if t.FileSystemType == FilesystemTypeNone {
return zeroPartition(devname)
return zeroPartition(devname, printf)
}
opts := []makefs.Option{makefs.WithForce(t.Force), makefs.WithLabel(t.Label)}
log.Printf("formatting the partition %q as %q with label %q\n", devname, t.FileSystemType, t.Label)
printf("formatting the partition %q as %q with label %q\n", devname, t.FileSystemType, t.Label)
switch t.FileSystemType {
case FilesystemTypeVFAT:
@ -47,8 +46,8 @@ func Format(devname string, t *FormatOptions) error {
}
// zeroPartition fills the partition with zeroes.
func zeroPartition(devname string) (err error) {
log.Printf("zeroing out %q", devname)
func zeroPartition(devname string, printf func(string, ...any)) (err error) {
printf("zeroing out %q", devname)
part, err := blockdevice.Open(devname, blockdevice.WithExclusiveLock(true))
if err != nil {

View File

@ -137,7 +137,7 @@ func (suite *manifestSuite) TestZeroPartition() {
err = partition.Format(part, &partition.FormatOptions{
FileSystemType: partition.FilesystemTypeNone,
})
}, suite.T().Logf)
suite.Require().NoError(err)
// reading 10 times more than what we wrote should still return 0 since the partition is wiped

View File

@ -6,8 +6,6 @@
package partition
import (
"log"
"github.com/dustin/go-humanize"
"github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt"
@ -40,8 +38,8 @@ func Locate(pt *gpt.GPT, label string) (*gpt.Partition, error) {
// Partition creates a new partition on the specified device.
// Returns the path to the newly created partition.
func Partition(pt *gpt.GPT, pos int, device string, partitionOpts Options) (string, error) {
log.Printf("partitioning %s - %s %q\n", device, partitionOpts.PartitionLabel, humanize.Bytes(partitionOpts.Size))
func Partition(pt *gpt.GPT, pos int, device string, partitionOpts Options, printf func(string, ...any)) (string, error) {
printf("partitioning %s - %s %q\n", device, partitionOpts.PartitionLabel, humanize.Bytes(partitionOpts.Size))
opts := []gpt.PartitionOption{
gpt.WithPartitionType(partitionOpts.PartitionType),
@ -66,7 +64,7 @@ func Partition(pt *gpt.GPT, pos int, device string, partitionOpts Options) (stri
return "", err
}
log.Printf("created %s (%s) size %d blocks", partitionName, partitionOpts.PartitionLabel, part.Length())
printf("created %s (%s) size %d blocks", partitionName, partitionOpts.PartitionLabel, part.Length())
return partitionName, nil
}

View File

@ -7,7 +7,6 @@ package uki
import (
"debug/pe"
"fmt"
"log"
"github.com/siderolabs/talos/internal/pkg/secureboot"
)
@ -23,8 +22,6 @@ func GetSBAT(path string) ([]byte, error) {
for _, section := range pefile.Sections {
if section.Name == string(secureboot.SBAT) {
log.Printf("section size: %d", section.Size)
data, err := section.Data()
if err != nil {
return nil, err

View File

@ -75,7 +75,7 @@ type Builder struct {
// - build ephemeral sections (uname, os-release), and other proposed sections
// - measure sections, generate signature, and append to the list of sections
// - assemble the final UKI file starting from sd-stub and appending generated section.
func (builder *Builder) Build() error {
func (builder *Builder) Build(printf func(string, ...any)) error {
var err error
builder.scratchDir, err = os.MkdirTemp("", "talos-uki")
@ -89,6 +89,8 @@ func (builder *Builder) Build() error {
}
}()
printf("signing systemd-boot")
builder.peSigner, err = pesign.NewSigner(builder.SigningCertPath, builder.SigningKeyPath)
if err != nil {
return fmt.Errorf("error initilazing signer: %w", err)
@ -99,6 +101,8 @@ func (builder *Builder) Build() error {
return fmt.Errorf("error signing sd-boot: %w", err)
}
printf("generating UKI sections")
// generate and build list of all sections
for _, generateSection := range []func() error{
builder.generateOSRel,
@ -118,11 +122,15 @@ func (builder *Builder) Build() error {
}
}
printf("assembling UKI")
// assemble the final UKI file
if err = builder.assemble(); err != nil {
return fmt.Errorf("error assembling UKI: %w", err)
}
printf("signing UKI")
// sign the UKI file
return builder.peSigner.Sign(builder.unsignedUKIPath, builder.OutUKIPath)
}

View File

@ -29,7 +29,7 @@ func (builder *Builder) rebuildInitramfs(tempDir string) error {
defer pipeW.Close() //nolint:errcheck
// build cpio image which contains .sqsh images and extensions.yaml
cmd1 := exec.Command("cpio", "-H", "newc", "--create", "--reproducible")
cmd1 := exec.Command("cpio", "-H", "newc", "--create", "--reproducible", "--quiet")
cmd1.Dir = tempDir
cmd1.Stdin = listing
cmd1.Stdout = pipeW
@ -51,7 +51,7 @@ func (builder *Builder) rebuildInitramfs(tempDir string) error {
defer destination.Close() //nolint:errcheck
// append compressed initramfs.sysext to the original initramfs.xz, kernel can read such format
cmd2 := exec.Command("xz", "-v", "-C", "crc32", "-0", "-e", "-T", "0", "-z")
cmd2 := exec.Command("xz", "-v", "-C", "crc32", "-0", "-e", "-T", "0", "-z", "--quiet")
cmd2.Dir = tempDir
cmd2.Stdin = pipeR
cmd2.Stdout = destination

View File

@ -8,7 +8,6 @@ package imager
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"strconv"
@ -25,6 +24,7 @@ import (
"github.com/siderolabs/talos/pkg/machinery/config/merge"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/machinery/kernel"
"github.com/siderolabs/talos/pkg/reporter"
"github.com/siderolabs/talos/pkg/version"
)
@ -80,7 +80,7 @@ func New(prof profile.Profile) (*Imager, error) {
// Execute image generation.
//
//nolint:gocyclo,cyclop
func (i *Imager) Execute(ctx context.Context, outputPath string) error {
func (i *Imager) Execute(ctx context.Context, outputPath string, report *reporter.Reporter) error {
var err error
i.tempDir, err = os.MkdirTemp("", "imager")
@ -90,13 +90,18 @@ func (i *Imager) Execute(ctx context.Context, outputPath string) error {
defer os.RemoveAll(i.tempDir) //nolint:errcheck
report.Report(reporter.Update{
Message: "profile ready:",
Status: reporter.StatusSucceeded,
})
// 0. Dump the profile.
if err = i.prof.Dump(os.Stderr); err != nil {
return err
}
// 1. Transform `initramfs.xz` with system extensions
if err = i.buildInitramfs(ctx); err != nil {
if err = i.buildInitramfs(ctx, report); err != nil {
return err
}
@ -105,11 +110,14 @@ func (i *Imager) Execute(ctx context.Context, outputPath string) error {
return err
}
log.Printf("assembled kernel command line: %s", i.cmdline)
report.Report(reporter.Update{
Message: fmt.Sprintf("kernel command line: %s", i.cmdline),
Status: reporter.StatusSucceeded,
})
// 3. Build UKI if Secure Boot is enabled.
if i.prof.SecureBootEnabled() {
if err = i.buildUKI(); err != nil {
if err = i.buildUKI(report); err != nil {
return err
}
}
@ -117,21 +125,19 @@ func (i *Imager) Execute(ctx context.Context, outputPath string) error {
// 4. Build the output.
outputAssetPath := filepath.Join(outputPath, i.prof.OutputPath())
log.Printf("output path: %s", outputAssetPath)
switch i.prof.Output.Kind {
case profile.OutKindISO:
err = i.outISO(outputAssetPath)
err = i.outISO(outputAssetPath, report)
case profile.OutKindKernel:
err = i.outKernel(outputAssetPath)
err = i.outKernel(outputAssetPath, report)
case profile.OutKindUKI:
err = i.outUKI(outputAssetPath)
err = i.outUKI(outputAssetPath, report)
case profile.OutKindInitramfs:
err = i.outInitramfs(outputAssetPath)
err = i.outInitramfs(outputAssetPath, report)
case profile.OutKindImage:
err = i.outImage(ctx, outputAssetPath)
err = i.outImage(ctx, outputAssetPath, report)
case profile.OutKindInstaller:
err = i.outInstaller(ctx, outputAssetPath)
err = i.outInstaller(ctx, outputAssetPath, report)
case profile.OutKindUnknown:
fallthrough
default:
@ -142,17 +148,22 @@ func (i *Imager) Execute(ctx context.Context, outputPath string) error {
return err
}
report.Report(reporter.Update{
Message: fmt.Sprintf("output asset path: %s", outputAssetPath),
Status: reporter.StatusSucceeded,
})
// 5. Post-process the output.
switch i.prof.Output.OutFormat {
case profile.OutFormatRaw:
// do nothing
return nil
case profile.OutFormatXZ:
return i.postProcessXz(outputAssetPath)
return i.postProcessXz(outputAssetPath, report)
case profile.OutFormatGZ:
return i.postProcessGz(outputAssetPath)
return i.postProcessGz(outputAssetPath, report)
case profile.OutFormatTar:
return i.postProcessTar(outputAssetPath)
return i.postProcessTar(outputAssetPath, report)
case profile.OutFormatUnknown:
fallthrough
default:
@ -161,18 +172,25 @@ func (i *Imager) Execute(ctx context.Context, outputPath string) error {
}
// buildInitramfs transforms `initramfs.xz` with system extensions.
func (i *Imager) buildInitramfs(ctx context.Context) error {
func (i *Imager) buildInitramfs(ctx context.Context, report *reporter.Reporter) error {
if len(i.prof.Input.SystemExtensions) == 0 {
report.Report(reporter.Update{
Message: "skipped initramfs rebuild (no system extensions)",
Status: reporter.StatusSkip,
})
// no system extensions, happy path
i.initramfsPath = i.prof.Input.Initramfs.Path
return nil
}
printf := progressPrintf(report, reporter.Update{Message: "rebuilding initramfs with system extensions...", Status: reporter.StatusRunning})
// copy the initramfs to a temporary location, as it's going to be modified during the extension build process
tempInitramfsPath := filepath.Join(i.tempDir, "initramfs.xz")
if err := utils.CopyFiles(utils.SourceDestination(i.prof.Input.Initramfs.Path, tempInitramfsPath)); err != nil {
if err := utils.CopyFiles(printf, utils.SourceDestination(i.prof.Input.Initramfs.Path, tempInitramfsPath)); err != nil {
return fmt.Errorf("failed to copy initramfs: %w", err)
}
@ -188,7 +206,7 @@ func (i *Imager) buildInitramfs(ctx context.Context) error {
return fmt.Errorf("failed to create extension directory: %w", err)
}
if err := ext.Extract(ctx, extensionDir, i.prof.Arch); err != nil {
if err := ext.Extract(ctx, extensionDir, i.prof.Arch, printf); err != nil {
return err
}
}
@ -198,10 +216,19 @@ func (i *Imager) buildInitramfs(ctx context.Context) error {
InitramfsPath: i.initramfsPath,
Arch: i.prof.Arch,
ExtensionTreePath: extensionsCheckoutDir,
Printf: log.Printf,
Printf: printf,
}
return builder.Build()
if err := builder.Build(); err != nil {
return err
}
report.Report(reporter.Update{
Message: "initramfs ready",
Status: reporter.StatusSucceeded,
})
return nil
}
// buildCmdline builds the kernel command line.
@ -262,7 +289,9 @@ func (i *Imager) buildCmdline() error {
}
// buildUKI assembles the UKI and signs it.
func (i *Imager) buildUKI() error {
func (i *Imager) buildUKI(report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "building UKI...", Status: reporter.StatusRunning})
i.sdBootPath = filepath.Join(i.tempDir, "systemd-boot.efi.signed")
i.ukiPath = filepath.Join(i.tempDir, "vmlinuz.efi.signed")
@ -283,5 +312,14 @@ func (i *Imager) buildUKI() error {
OutUKIPath: i.ukiPath,
}
return builder.Build()
if err := builder.Build(printf); err != nil {
return err
}
report.Report(reporter.Update{
Message: "UKI ready",
Status: reporter.StatusSucceeded,
})
return nil
}

View File

@ -8,7 +8,6 @@ import (
"bytes"
_ "embed"
"fmt"
"log"
"os"
"path/filepath"
"text/template"
@ -37,15 +36,16 @@ var grubCfgTemplate string
// CreateGRUB creates a GRUB-based ISO image.
//
// This iso supports both BIOS and UEFI booting.
func CreateGRUB(options GRUBOptions) error {
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
}
log.Println("creating grub.cfg")
printf("creating grub.cfg")
var grubCfg bytes.Buffer
@ -76,11 +76,11 @@ func CreateGRUB(options GRUBOptions) error {
return err
}
if err = utils.TouchFiles(options.ScratchDir); err != nil {
if err = utils.TouchFiles(printf, options.ScratchDir); err != nil {
return err
}
log.Println("creating ISO")
printf("creating ISO image")
return grubMkrescue(options.OutPath, options.ScratchDir)
}

View File

@ -47,7 +47,7 @@ const (
// The ISO created supports only booting in UEFI mode, and supports SecureBoot.
//
//nolint:gocyclo,cyclop
func CreateUEFI(options UEFIOptions) error {
func CreateUEFI(printf func(string, ...any), options UEFIOptions) error {
if err := os.MkdirAll(options.ScratchDir, 0o755); err != nil {
return err
}
@ -60,10 +60,12 @@ func CreateUEFI(options UEFIOptions) error {
isoSize = UKIISOSizeARM64
}
if err := utils.CreateRawDisk(efiBootImg, isoSize); err != nil {
if err := utils.CreateRawDisk(printf, efiBootImg, isoSize); err != nil {
return err
}
printf("creating vFAT EFI image")
fopts := []makefs.Option{
makefs.WithLabel(constants.EFIPartitionLabel),
makefs.WithReproducible(true),
@ -130,10 +132,12 @@ func CreateUEFI(options UEFIOptions) error {
}
// fixup directory timestamps recursively
if err := utils.TouchFiles(options.ScratchDir); err != nil {
if err := utils.TouchFiles(printf, options.ScratchDir); err != nil {
return err
}
printf("creating ISO image")
if _, err := cmd.Run(
"xorriso",
"-as",

View File

@ -28,25 +28,54 @@ import (
"github.com/siderolabs/talos/pkg/imager/qemuimg"
"github.com/siderolabs/talos/pkg/imager/utils"
"github.com/siderolabs/talos/pkg/machinery/constants"
"github.com/siderolabs/talos/pkg/reporter"
)
func (i *Imager) outInitramfs(path string) error {
return utils.CopyFiles(utils.SourceDestination(i.initramfsPath, path))
func (i *Imager) outInitramfs(path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "copying initramfs...", Status: reporter.StatusRunning})
if err := utils.CopyFiles(printf, utils.SourceDestination(i.initramfsPath, path)); err != nil {
return err
}
report.Report(reporter.Update{Message: "initramfs output ready", Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) outKernel(path string) error {
return utils.CopyFiles(utils.SourceDestination(i.prof.Input.Kernel.Path, path))
func (i *Imager) outKernel(path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "copying kernel...", Status: reporter.StatusRunning})
if err := utils.CopyFiles(printf, utils.SourceDestination(i.prof.Input.Kernel.Path, path)); err != nil {
return err
}
report.Report(reporter.Update{Message: "kernel output ready", Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) outUKI(path string) error {
return utils.CopyFiles(utils.SourceDestination(i.ukiPath, path))
func (i *Imager) outUKI(path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "copying kernel...", Status: reporter.StatusRunning})
if err := utils.CopyFiles(printf, utils.SourceDestination(i.ukiPath, path)); err != nil {
return err
}
report.Report(reporter.Update{Message: "UKI output ready", Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) outISO(path string) error {
func (i *Imager) outISO(path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "building ISO...", Status: reporter.StatusRunning})
scratchSpace := filepath.Join(i.tempDir, "iso")
var err error
if i.prof.SecureBootEnabled() {
return iso.CreateUEFI(iso.UEFIOptions{
err = iso.CreateUEFI(printf, iso.UEFIOptions{
UKIPath: i.ukiPath,
SDBootPath: i.sdBootPath,
@ -57,50 +86,70 @@ func (i *Imager) outISO(path string) error {
Arch: i.prof.Arch,
Version: i.prof.Version,
ScratchDir: scratchSpace,
OutPath: path,
})
} else {
err = iso.CreateGRUB(printf, iso.GRUBOptions{
KernelPath: i.prof.Input.Kernel.Path,
InitramfsPath: i.initramfsPath,
Cmdline: i.cmdline,
ScratchDir: scratchSpace,
OutPath: path,
})
}
return iso.CreateGRUB(iso.GRUBOptions{
KernelPath: i.prof.Input.Kernel.Path,
InitramfsPath: i.initramfsPath,
Cmdline: i.cmdline,
if err != nil {
return err
}
ScratchDir: scratchSpace,
OutPath: path,
})
report.Report(reporter.Update{Message: "ISO ready", Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) outImage(ctx context.Context, path string) error {
if err := i.buildImage(ctx, path); err != nil {
func (i *Imager) outImage(ctx context.Context, path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "creating disk image...", Status: reporter.StatusRunning})
if err := i.buildImage(ctx, path, printf); err != nil {
return err
}
switch i.prof.Output.ImageOptions.DiskFormat {
case profile.DiskFormatRaw:
return nil
// nothing to do
case profile.DiskFormatQCOW2:
return qemuimg.Convert("raw", "qcow2", i.prof.Output.ImageOptions.DiskFormatOptions, path)
if err := qemuimg.Convert("raw", "qcow2", i.prof.Output.ImageOptions.DiskFormatOptions, path, printf); err != nil {
return err
}
case profile.DiskFormatVPC:
return qemuimg.Convert("raw", "vpc", i.prof.Output.ImageOptions.DiskFormatOptions, path)
if err := qemuimg.Convert("raw", "vpc", i.prof.Output.ImageOptions.DiskFormatOptions, path, printf); err != nil {
return err
}
case profile.DiskFormatOVA:
scratchPath := filepath.Join(i.tempDir, "ova")
return ova.CreateOVAFromRAW(fmt.Sprintf("%s-%s", i.prof.Platform, i.prof.Arch), path, i.prof.Arch, scratchPath, i.prof.Output.ImageOptions.DiskSize)
if err := ova.CreateOVAFromRAW(fmt.Sprintf("%s-%s", i.prof.Platform, i.prof.Arch), path, i.prof.Arch, scratchPath, i.prof.Output.ImageOptions.DiskSize, printf); err != nil {
return err
}
case profile.DiskFormatUnknown:
fallthrough
default:
return fmt.Errorf("unsupported disk format: %s", i.prof.Output.ImageOptions.DiskFormat)
}
report.Report(reporter.Update{Message: "disk image ready", Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) buildImage(ctx context.Context, path string) error {
if err := utils.CreateRawDisk(path, i.prof.Output.ImageOptions.DiskSize); err != nil {
func (i *Imager) buildImage(ctx context.Context, path string, printf func(string, ...any)) error {
if err := utils.CreateRawDisk(printf, path, i.prof.Output.ImageOptions.DiskSize); err != nil {
return err
}
log.Print("attaching loopback device")
printf("attaching loopback device")
var (
loDevice string
@ -112,7 +161,7 @@ func (i *Imager) buildImage(ctx context.Context, path string) error {
}
defer func() {
log.Println("detaching loopback device")
printf("detaching loopback device")
if e := utils.Lodetach(loDevice); e != nil {
log.Println(e)
@ -136,6 +185,7 @@ func (i *Imager) buildImage(ctx context.Context, path string) error {
UKIPath: i.ukiPath,
SDBootPath: i.sdBootPath,
},
Printf: printf,
}
if opts.Board == "" {
@ -144,15 +194,21 @@ func (i *Imager) buildImage(ctx context.Context, path string) error {
installer, err := install.NewInstaller(ctx, cmdline, install.ModeImage, opts)
if err != nil {
return err
return fmt.Errorf("failed to create installer: %w", err)
}
return installer.Install(ctx, install.ModeImage)
if err := installer.Install(ctx, install.ModeImage); err != nil {
return fmt.Errorf("failed to install: %w", err)
}
return nil
}
//nolint:gocyclo
func (i *Imager) outInstaller(ctx context.Context, path string) error {
baseInstallerImg, err := i.prof.Input.BaseInstaller.Pull(ctx, i.prof.Arch)
func (i *Imager) outInstaller(ctx context.Context, path string, report *reporter.Reporter) error {
printf := progressPrintf(report, reporter.Update{Message: "building installer...", Status: reporter.StatusRunning})
baseInstallerImg, err := i.prof.Input.BaseInstaller.Pull(ctx, i.prof.Arch, printf)
if err != nil {
return err
}
@ -169,6 +225,8 @@ func (i *Imager) outInstaller(ctx context.Context, path string) error {
config := *configFile.Config.DeepCopy()
printf("creating empty image")
newInstallerImg := mutate.MediaType(empty.Image, types.OCIManifestSchema1)
newInstallerImg = mutate.ConfigMediaType(newInstallerImg, types.OCIConfigJSON)
@ -189,6 +247,8 @@ func (i *Imager) outInstaller(ctx context.Context, path string) error {
var artifacts []filemap.File
printf("generating artifacts layer")
if i.prof.SecureBootEnabled() {
artifacts = append(artifacts,
filemap.File{
@ -228,5 +288,13 @@ func (i *Imager) outInstaller(ctx context.Context, path string) error {
return fmt.Errorf("failed to parse image reference: %w", err)
}
return tarball.WriteToFile(path, ref, newInstallerImg)
printf("writing image tarball")
if err := tarball.WriteToFile(path, ref, newInstallerImg); err != nil {
return fmt.Errorf("failed to write image tarball: %w", err)
}
report.Report(reporter.Update{Message: "installer container image ready", Status: reporter.StatusSucceeded})
return nil
}

View File

@ -141,18 +141,18 @@ const ovfTpl = `<?xml version="1.0" encoding="UTF-8"?>
// CreateOVAFromRAW creates an OVA from a RAW disk.
//
//nolint:gocyclo
func CreateOVAFromRAW(name, path, arch, scratchPath string, diskSize int64) error {
func CreateOVAFromRAW(name, path, arch, scratchPath string, diskSize int64, printf func(string, ...any)) error {
if err := os.MkdirAll(scratchPath, 0o755); err != nil {
return err
}
vmdkPath := filepath.Join(scratchPath, name+".vmdk")
if err := utils.CopyFiles(utils.SourceDestination(path, vmdkPath)); err != nil {
if err := utils.CopyFiles(printf, utils.SourceDestination(path, vmdkPath)); err != nil {
return err
}
if err := qemuimg.Convert("raw", "vmdk", "compat6,subformat=streamOptimized,adapter_type=lsilogic", vmdkPath); err != nil {
if err := qemuimg.Convert("raw", "vmdk", "compat6,subformat=streamOptimized,adapter_type=lsilogic", vmdkPath, printf); err != nil {
return err
}

View File

@ -5,13 +5,18 @@
package imager
import (
"fmt"
"os"
"path/filepath"
"github.com/siderolabs/go-cmd/pkg/cmd"
"github.com/siderolabs/talos/pkg/reporter"
)
func (i *Imager) postProcessTar(filename string) error {
func (i *Imager) postProcessTar(filename string, report *reporter.Reporter) error {
report.Report(reporter.Update{Message: "processing .tar.gz", Status: reporter.StatusRunning})
dir := filepath.Dir(filename)
src := "disk.raw"
@ -25,21 +30,35 @@ func (i *Imager) postProcessTar(filename string) error {
return err
}
return os.Remove(filepath.Join(dir, src))
}
func (i *Imager) postProcessGz(filename string) error {
if _, err := cmd.Run("pigz", "-6", filename); err != nil {
if err := os.Remove(filepath.Join(dir, src)); err != nil {
return err
}
report.Report(reporter.Update{Message: fmt.Sprintf("archive is ready: %s", outPath), Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) postProcessXz(filename string) error {
if _, err := cmd.Run("xz", "-0", "-T", "0", filename); err != nil {
func (i *Imager) postProcessGz(filename string, report *reporter.Reporter) error {
report.Report(reporter.Update{Message: "compressing .gz", Status: reporter.StatusRunning})
if _, err := cmd.Run("pigz", "-6", "-f", filename); err != nil {
return err
}
report.Report(reporter.Update{Message: fmt.Sprintf("compression done: %s.gz", filename), Status: reporter.StatusSucceeded})
return nil
}
func (i *Imager) postProcessXz(filename string, report *reporter.Reporter) error {
report.Report(reporter.Update{Message: "compressing .xz", Status: reporter.StatusRunning})
if _, err := cmd.Run("xz", "-0", "-f", "-T", "0", filename); err != nil {
return err
}
report.Report(reporter.Update{Message: fmt.Sprintf("compression done: %s.xz", filename), Status: reporter.StatusSucceeded})
return nil
}

View File

@ -8,7 +8,6 @@ import (
"context"
"fmt"
"io"
"log"
"os"
"path/filepath"
@ -144,8 +143,8 @@ func fileExists(path string) bool {
}
// Pull the container asset to the path.
func (c *ContainerAsset) Pull(ctx context.Context, arch string) (v1.Image, error) {
log.Printf("pulling %s...", c.ImageRef)
func (c *ContainerAsset) Pull(ctx context.Context, arch string, printf func(string, ...any)) (v1.Image, error) {
printf("pulling %s...", c.ImageRef)
img, err := crane.Pull(c.ImageRef, crane.WithPlatform(&v1.Platform{
Architecture: arch,
@ -159,8 +158,8 @@ func (c *ContainerAsset) Pull(ctx context.Context, arch string) (v1.Image, error
}
// Extract the container asset to the path.
func (c *ContainerAsset) Extract(ctx context.Context, destination, arch string) error {
img, err := c.Pull(ctx, arch)
func (c *ContainerAsset) Extract(ctx context.Context, destination, arch string, printf func(string, ...any)) error {
img, err := c.Pull(ctx, arch, printf)
if err != nil {
return err
}

View File

@ -102,7 +102,7 @@ func (p *Profile) Validate() error {
return fmt.Errorf("customization of meta partition is not supported for %s output", p.Output.Kind)
}
case OutKindUKI:
if p.SecureBootEnabled() {
if !p.SecureBootEnabled() {
return fmt.Errorf("!secureboot is not supported for %s output", p.Output.Kind)
}
}

28
pkg/imager/progress.go Normal file
View File

@ -0,0 +1,28 @@
// 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 imager
import (
"fmt"
"github.com/siderolabs/talos/pkg/reporter"
)
// progressPrintf wraps a reporter.Reporter to report progress via Printf logging.
func progressPrintf(report *reporter.Reporter, status reporter.Update) func(format string, args ...any) {
return func(format string, args ...any) {
msg := status.Message
extra := fmt.Sprintf(format, args...)
if extra != "" {
msg += "\n\t" + extra
}
report.Report(reporter.Update{
Message: msg,
Status: status.Status,
})
}
}

View File

@ -12,10 +12,12 @@ import (
)
// Convert converts an image from one format to another.
func Convert(inputFmt, outputFmt, options, path string) error {
func Convert(inputFmt, outputFmt, options, path string, printf func(string, ...any)) error {
src := path + ".in"
dest := path
printf("converting %s to %s", inputFmt, outputFmt)
if err := os.Rename(path, src); err != nil {
return err
}

View File

@ -7,7 +7,6 @@ package utils
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
@ -23,7 +22,7 @@ func SourceDestination(src, dest string) CopyInstruction {
}
// CopyFiles copies files according to the given instructions.
func CopyFiles(instructions ...CopyInstruction) error {
func CopyFiles(printf func(string, ...any), instructions ...CopyInstruction) error {
for _, instruction := range instructions {
if err := func(instruction CopyInstruction) error {
src, dest := instruction.F1, instruction.F2
@ -32,7 +31,7 @@ func CopyFiles(instructions ...CopyInstruction) error {
return err
}
log.Printf("copying %s to %s", src, dest)
printf("copying %s to %s", src, dest)
from, err := os.Open(src)
if err != nil {
@ -52,7 +51,7 @@ func CopyFiles(instructions ...CopyInstruction) error {
return err
}(instruction); err != nil {
return fmt.Errorf("error copying %s -> %s", instruction.F1, instruction.F2)
return fmt.Errorf("error copying %s -> %s: %w", instruction.F1, instruction.F2, err)
}
}

View File

@ -6,7 +6,6 @@ package utils
import (
"fmt"
"log"
"os"
"syscall"
@ -14,8 +13,8 @@ import (
)
// CreateRawDisk creates a raw disk image of the specified size.
func CreateRawDisk(path string, diskSize int64) error {
log.Printf("creating raw disk of size %s", humanize.Bytes(uint64(diskSize)))
func CreateRawDisk(printf func(string, ...any), path string, diskSize int64) error {
printf("creating raw disk of size %s", humanize.Bytes(uint64(diskSize)))
f, err := os.Create(path)
if err != nil {

View File

@ -6,14 +6,13 @@ package utils
import (
"io/fs"
"log"
"os"
"path/filepath"
"time"
)
// TouchFiles updates mtime for all the files under root if SOURCE_DATE_EPOCH is set.
func TouchFiles(root string) error {
func TouchFiles(printf func(string, ...any), root string) error {
epochInt, ok, err := SourceDateEpoch()
if err != nil {
return err
@ -25,7 +24,7 @@ func TouchFiles(root string) error {
timestamp := time.Unix(epochInt, 0)
log.Printf("changing timestamps under %q to %s", root, timestamp)
printf("changing timestamps under %q to %s", root, timestamp)
return filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if err != nil {