diff --git a/cmd/installer/cmd/imager/root.go b/cmd/installer/cmd/imager/root.go index ef81d53bd1..fea064f637 100644 --- a/cmd/installer/cmd/imager/root.go +++ b/cmd/installer/cmd/imager/root.go @@ -124,6 +124,8 @@ var rootCmd = &cobra.Command{ }, ExtraOptions: extraOverlayOptions, } + + prof.Input.OverlayInstaller.ImageRef = cmdFlags.OverlayImage } prof.Input.SystemExtensions = xslices.Map( diff --git a/cmd/installer/cmd/installer/root.go b/cmd/installer/cmd/installer/root.go index ae150b325d..6196e87319 100644 --- a/cmd/installer/cmd/installer/root.go +++ b/cmd/installer/cmd/installer/root.go @@ -48,16 +48,21 @@ func Execute() { } } -var options = &install.Options{} +var options = &install.Options{ + Board: constants.BoardNone, +} -var bootloader bool +var ( + bootloader bool + dummy string +) func init() { rootCmd.PersistentFlags().StringVar(&options.ConfigSource, "config", "", "The value of "+constants.KernelParamConfig) rootCmd.PersistentFlags().StringVar(&options.Disk, "disk", "", "The path to the disk to install to") rootCmd.PersistentFlags().StringVar(&options.Platform, "platform", "", "The value of "+constants.KernelParamPlatform) rootCmd.PersistentFlags().StringVar(&options.Arch, "arch", runtime.GOARCH, "The target architecture") - rootCmd.PersistentFlags().StringVar(&options.Board, "board", constants.BoardNone, "Deprecated: no op") + rootCmd.PersistentFlags().StringVar(&dummy, "board", constants.BoardNone, "Deprecated: no op") rootCmd.PersistentFlags().StringArrayVar(&options.ExtraKernelArgs, "extra-kernel-arg", []string{}, "Extra argument to pass to the kernel") rootCmd.PersistentFlags().BoolVar(&bootloader, "bootloader", true, "Deprecated: no op") rootCmd.PersistentFlags().BoolVar(&options.Upgrade, "upgrade", false, "Indicates that the install is being performed by an upgrade") diff --git a/cmd/installer/pkg/install/install.go b/cmd/installer/pkg/install/install.go index 581870ae28..d8bffaceb6 100644 --- a/cmd/installer/pkg/install/install.go +++ b/cmd/installer/pkg/install/install.go @@ -47,6 +47,7 @@ type Options struct { LegacyBIOSSupport bool MetaValues MetaValues OverlayInstaller overlay.Installer[overlay.ExtraOptions] + OverlayName string OverlayExtractedDir string ExtraOptions overlay.ExtraOptions @@ -85,6 +86,25 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options) return fmt.Errorf("using standard installer image is not supported for board: %s, use an installer with overlay", b) } + if overlayPresent { + extraOptionsBytes, err := os.ReadFile(constants.ImagerOverlayExtraOptionsPath) + if err != nil { + return err + } + + var extraOptions overlay.ExtraOptions + + decoder := yaml.NewDecoder(bytes.NewReader(extraOptionsBytes)) + decoder.KnownFields(true) + + if err := decoder.Decode(&extraOptions); err != nil { + return fmt.Errorf("failed to decode extra options: %w", err) + } + + opts.OverlayInstaller = executor.New(constants.ImagerOverlayInstallerDefaultPath) + opts.ExtraOptions = extraOptions + } + cmdline := procfs.NewCmdline("") cmdline.Append(constants.KernelParamPlatform, p.Name()) @@ -117,6 +137,17 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options) cmdline.SetAll(b.KernelArgs().Strings()) } + if opts.OverlayInstaller != nil { + overlayOpts, getOptsErr := opts.OverlayInstaller.GetOptions(opts.ExtraOptions) + if getOptsErr != nil { + return fmt.Errorf("failed to get overlay installer options: %w", getOptsErr) + } + + opts.OverlayName = overlayOpts.Name + + cmdline.SetAll(overlayOpts.KernelArgs) + } + if err := cmdline.AppendAll( opts.ExtraKernelArgs, procfs.WithOverwriteArgs("console"), @@ -126,25 +157,6 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options) return err } - if overlayPresent { - extraOptionsBytes, err := os.ReadFile(constants.ImagerOverlayExtraOptionsPath) - if err != nil { - return err - } - - var extraOptions overlay.ExtraOptions - - decoder := yaml.NewDecoder(bytes.NewReader(extraOptionsBytes)) - decoder.KnownFields(true) - - if err := decoder.Decode(&extraOptions); err != nil { - return fmt.Errorf("failed to decode extra options: %w", err) - } - - opts.OverlayInstaller = executor.New(constants.ImagerOverlayInstallerDefaultPath) - opts.ExtraOptions = extraOptions - } - i, err := NewInstaller(ctx, cmdline, mode, opts) if err != nil { return err @@ -338,6 +350,8 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { } if i.options.OverlayInstaller != nil { + i.options.Printf("running overlay installer %q", i.options.OverlayName) + if err = i.options.OverlayInstaller.Install(overlay.InstallOptions[overlay.ExtraOptions]{ InstallDisk: i.options.Disk, MountPrefix: i.options.MountPrefix, diff --git a/pkg/imager/out.go b/pkg/imager/out.go index 4ca8da07f4..3869a2f1a8 100644 --- a/pkg/imager/out.go +++ b/pkg/imager/out.go @@ -411,6 +411,21 @@ func (i *Imager) outInstaller(ctx context.Context, path string, report *reporter } if i.overlayInstaller != nil { + tempOverlayPath := filepath.Join(i.tempDir, "overlay-installer", constants.ImagerOverlayBasePath) + + if err := os.MkdirAll(tempOverlayPath, 0o755); err != nil { + return fmt.Errorf("failed to create overlay directory: %w", err) + } + + if err := i.prof.Input.OverlayInstaller.Extract( + ctx, + tempOverlayPath, + i.prof.Arch, + progressPrintf(report, reporter.Update{Message: "pulling overlay for installer...", Status: reporter.StatusRunning}), + ); err != nil { + return err + } + extraOpts, internalErr := yaml.Marshal(i.prof.Overlay.ExtraOptions) if internalErr != nil { return fmt.Errorf("failed to marshal extra options: %w", internalErr) @@ -430,11 +445,11 @@ func (i *Imager) outInstaller(ctx context.Context, path string, report *reporter mode os.FileMode }{ { - sourcePath: filepath.Join(i.tempDir, constants.ImagerOverlayArtifactsPath), + sourcePath: filepath.Join(i.tempDir, "overlay-installer", constants.ImagerOverlayArtifactsPath), imagePath: strings.TrimLeft(constants.ImagerOverlayArtifactsPath, "/"), }, { - sourcePath: filepath.Join(i.tempDir, constants.ImagerOverlayInstallersPath, i.prof.Overlay.Name), + sourcePath: filepath.Join(i.tempDir, "overlay-installer", constants.ImagerOverlayInstallersPath, i.prof.Overlay.Name), imagePath: strings.TrimLeft(constants.ImagerOverlayInstallerDefaultPath, "/"), mode: 0o755, }, diff --git a/pkg/imager/profile/input.go b/pkg/imager/profile/input.go index e8bdbced30..da1d7c2179 100644 --- a/pkg/imager/profile/input.go +++ b/pkg/imager/profile/input.go @@ -54,6 +54,10 @@ type Input struct { RPiFirmware FileAsset `yaml:"rpiFirmware,omitempty"` // Base installer image to mutate. BaseInstaller ContainerAsset `yaml:"baseInstaller,omitempty"` + // OverlayInstaller is an overlay image to inject into the installer. + // + // OverlayInstaller architecture should match the output installer architecture. + OverlayInstaller ContainerAsset `yaml:"overlayInstaller,omitempty"` // SecureBoot is a section with secureboot keys, only for SecureBoot enabled builds. SecureBoot *SecureBootAssets `yaml:"secureboot,omitempty"` // SystemExtensions is a list of system extensions to install.