From e0074392a042c008dc521106584614629cdd5f0d Mon Sep 17 00:00:00 2001 From: Justin Alvarez Date: Thu, 6 Oct 2022 17:06:51 -0400 Subject: [PATCH] add "additionalArchives" config option Signed-off-by: Justin Alvarez --- cmd/limactl/hostagent.go | 8 ++++++++ examples/default.yaml | 14 ++++++++++++++ pkg/cidata/cidata.go | 15 ++++++++++++++- pkg/hostagent/hostagent.go | 15 +++++++++++++-- pkg/limayaml/limayaml.go | 7 ++++--- pkg/start/start.go | 37 +++++++++++++++++++++++++++++++++---- pkg/vz/vz_driver_darwin.go | 1 + 7 files changed, 87 insertions(+), 10 deletions(-) diff --git a/cmd/limactl/hostagent.go b/cmd/limactl/hostagent.go index 2c0d19e2256..fed58f7dd06 100644 --- a/cmd/limactl/hostagent.go +++ b/cmd/limactl/hostagent.go @@ -28,6 +28,7 @@ func newHostagentCommand() *cobra.Command { hostagentCommand.Flags().StringP("pidfile", "p", "", "write pid to file") hostagentCommand.Flags().String("socket", "", "hostagent socket") hostagentCommand.Flags().String("nerdctl-archive", "", "local file path (not URL) of nerdctl-full-VERSION-linux-GOARCH.tar.gz") + hostagentCommand.Flags().StringToString("additional-archive", map[string]string{}, "local file path (not URL) of an arbitrary archive to add to CIDATA") return hostagentCommand } @@ -70,6 +71,13 @@ func hostagentAction(cmd *cobra.Command, args []string) error { if nerdctlArchive != "" { opts = append(opts, hostagent.WithNerdctlArchive(nerdctlArchive)) } + additionalArchives, err := cmd.Flags().GetStringToString("additional-archive") + if err != nil { + return err + } + for archName, archLocation := range additionalArchives { + opts = append(opts, hostagent.WithAdditionalArchive(archName, archLocation)) + } ha, err := hostagent.New(instName, stdout, sigintCh, opts...) if err != nil { return err diff --git a/examples/default.yaml b/examples/default.yaml index 44c6e2506ec..33b428941f1 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -217,6 +217,20 @@ containerd: # vim was not installed in the guest. Make sure the package system is working correctly. # Also see "/var/log/cloud-init-output.log" in the guest. +# Adds an additional archive which matches the system architecture to the CIDATA image which is mounted on boot. +# The additional archive will be available on the CIDATA disk at /archive.tgz (depending on the key name). +# Useful for provisioning scripts that run before mounts (like `mode: dependency`) in case they need any file resources. +# See pkg/cidata/cidata.TEMPLATE.d/boot/40-install-containerd.sh for an example of how to use an archive +# from a provisioning script. +# additionalArchives: +# archive.tgz: +# - location: "/path/to/additional.x86_64.tar.gz" +# arch: "x86_64" +# digest: "sha256:..." +# - location: "/path/to/additional.aarch64.tar.gz" +# arch: "aarch64" +# digest: "sha256:..." + # ===================================================================== # # FURTHER ADVANCED CONFIGURATION # ===================================================================== # diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index 8e52d1bae6b..3c82dee0fdd 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -105,7 +105,7 @@ func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) { return env, nil } -func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive string) error { +func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive string, additionalArchives map[string]string) error { if err := limayaml.Validate(*y, false); err != nil { return err } @@ -304,6 +304,19 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort }) } + for archName, archLocation := range additionalArchives { + additionaltgzR, err := os.Open(archLocation) + if err != nil { + return err + } + defer additionaltgzR.Close() + layout = append(layout, iso9660util.Entry{ + // ISO9660 requires len(Path) <= 30 + Path: archName, + Reader: additionaltgzR, + }) + } + return iso9660util.Write(filepath.Join(instDir, filenames.CIDataISO), "cidata", layout) } diff --git a/pkg/hostagent/hostagent.go b/pkg/hostagent/hostagent.go index bb57f856716..8277f1b44b6 100644 --- a/pkg/hostagent/hostagent.go +++ b/pkg/hostagent/hostagent.go @@ -55,7 +55,8 @@ type HostAgent struct { } type options struct { - nerdctlArchive string // local path, not URL + nerdctlArchive string // local path, not URL + additionalArchives map[string]string // archive name => local path, not URL } type Opt func(*options) error @@ -67,6 +68,16 @@ func WithNerdctlArchive(s string) Opt { } } +func WithAdditionalArchive(name string, location string) Opt { + return func(o *options) error { + if o.additionalArchives == nil { + o.additionalArchives = make(map[string]string) + } + o.additionalArchives[name] = location + return nil + } +} + // New creates the HostAgent. // // stdout is for emitting JSON lines of Events. @@ -105,7 +116,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt } } - if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive); err != nil { + if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive, o.additionalArchives); err != nil { return nil, err } diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index a32bfb7e7de..538a52af95f 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -32,9 +32,10 @@ type LimaYAML struct { DNS []net.IP `yaml:"dns,omitempty" json:"dns,omitempty"` HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"` // `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead. - PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"` - CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"` - Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` + PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"` + CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"` + Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` + AdditionalArchives map[string][]File `yaml:"additionalArchives,omitempty" json:"additionalArchives,omitempty"` } type Arch = string diff --git a/pkg/start/start.go b/pkg/start/start.go index 3c8b9f772cc..e71555f292f 100644 --- a/pkg/start/start.go +++ b/pkg/start/start.go @@ -37,9 +37,27 @@ func ensureNerdctlArchiveCache(y *limayaml.LimaYAML) (string, error) { return "", nil } - errs := make([]error, len(y.Containerd.Archives)) - for i, f := range y.Containerd.Archives { - path, err := fileutils.DownloadFile("", f, false, "the nerdctl archive", *y.Arch) + location, errs := downloadAndCacheArchiveForArch(y.Containerd.Archives, *y.Arch, "nerdctl") + if location == "" { + return "", fmt.Errorf("failed to download the nerdctl archive, attempted %d candidates, errors=%v", + len(y.Containerd.Archives), errs) + } + + return location, nil +} + +// downloadAndCacheArchiveForArch iterates through a slice of File and tries to download the provided +// file which matches the supplied arch. +// The downloader caches remote downloads to disk, and then returns a file path to the archive. +func downloadAndCacheArchiveForArch(files []limayaml.File, arch limayaml.Arch, archiveDescription string) (string, error) { + errs := make([]error, len(files)) + for i := range files { + f := &files[i] + if f.Arch != arch { + errs[i] = fmt.Errorf("unsupported arch: %q", f.Arch) + continue + } + path, err := fileutils.DownloadFile("", *f, false, archiveDescription, arch) if err != nil { errs[i] = err continue @@ -48,7 +66,7 @@ func ensureNerdctlArchiveCache(y *limayaml.LimaYAML) (string, error) { if downloader.IsLocal(f.Location) { return f.Location, nil } - return "", fmt.Errorf("cache did not contain %q", f.Location) + errs[i] = fmt.Errorf("cache did not contain %q", f.Location) } return path, nil } @@ -120,6 +138,17 @@ func Start(ctx context.Context, inst *store.Instance) error { if nerdctlArchiveCache != "" { args = append(args, "--nerdctl-archive", nerdctlArchiveCache) } + if len(y.AdditionalArchives) > 0 { + for archName, archPath := range y.AdditionalArchives { + location, errs := downloadAndCacheArchiveForArch(archPath, *y.Arch, fmt.Sprintf("additional archive (%s)", archName)) + if location == "" { + return fmt.Errorf("failed to download the additionalArchive archive (%s), attempted %d candidates, errors=%v", + archName, len(y.AdditionalArchives), errs) + } + args = append(args, "--additional-archive", fmt.Sprintf("%s=%s", archName, location)) + } + } + args = append(args, inst.Name) haCmd := exec.CommandContext(ctx, self, args...) diff --git a/pkg/vz/vz_driver_darwin.go b/pkg/vz/vz_driver_darwin.go index e01bbbca211..a9821ad49f0 100644 --- a/pkg/vz/vz_driver_darwin.go +++ b/pkg/vz/vz_driver_darwin.go @@ -65,6 +65,7 @@ func (l *LimaVzDriver) Validate() error { "CACertificates", "Rosetta", "AdditionalDisks", + "AdditionalArchives", ); len(unknown) > 0 { logrus.Warnf("Ignoring: vmType %s: %+v", *l.Yaml.VMType, unknown) }