Skip to content

Commit cbd691d

Browse files
committed
add "additionalArchives" config option
Signed-off-by: Justin Alvarez <[email protected]>
1 parent e2652c5 commit cbd691d

File tree

6 files changed

+100
-37
lines changed

6 files changed

+100
-37
lines changed

cmd/limactl/hostagent.go

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func newHostagentCommand() *cobra.Command {
2828
hostagentCommand.Flags().StringP("pidfile", "p", "", "write pid to file")
2929
hostagentCommand.Flags().String("socket", "", "hostagent socket")
3030
hostagentCommand.Flags().String("nerdctl-archive", "", "local file path (not URL) of nerdctl-full-VERSION-linux-GOARCH.tar.gz")
31+
hostagentCommand.Flags().String("additional-archive", "", "local file path (not URL) of an arbitrary archive to add to CIDATA")
3132
return hostagentCommand
3233
}
3334

@@ -70,6 +71,13 @@ func hostagentAction(cmd *cobra.Command, args []string) error {
7071
if nerdctlArchive != "" {
7172
opts = append(opts, hostagent.WithNerdctlArchive(nerdctlArchive))
7273
}
74+
additionalArchive, err := cmd.Flags().GetString("additional-archive")
75+
if err != nil {
76+
return err
77+
}
78+
if additionalArchive != "" {
79+
opts = append(opts, hostagent.WithAdditionalArchive(additionalArchive))
80+
}
7381
ha, err := hostagent.New(instName, stdout, sigintCh, opts...)
7482
if err != nil {
7583
return err

examples/default.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,19 @@ containerd:
196196
# vim was not installed in the guest. Make sure the package system is working correctly.
197197
# Also see "/var/log/cloud-init-output.log" in the guest.
198198

199+
# Adds an additional archive which matches the system architecture to the CIDATA image which is mounted on boot.
200+
# The additional archive will be available on the CIDATA disk at /additional.tgz.
201+
# Useful for provisioning scripts that run before mounts (like `mode: dependency`) in case they need any file resources.
202+
# See pkg/cidata/cidata.TEMPLATE.d/boot/40-install-containerd.sh for an example of how to use an archive
203+
# from a provisioning script.
204+
# additionalArchives:
205+
# - location: "~/additional.amd64.tar.gz"
206+
# arch: "x86_64"
207+
# digest: "sha256:..."
208+
# - location: "~/additional.aarch64.tar.gz"
209+
# arch: "aarch64"
210+
# digest: "sha256:..."
211+
199212
# ===================================================================== #
200213
# FURTHER ADVANCED CONFIGURATION
201214
# ===================================================================== #

pkg/cidata/cidata.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) {
104104
return env, nil
105105
}
106106

107-
func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive string) error {
107+
func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort, tcpDNSLocalPort int, nerdctlArchive, additionalArchive string) error {
108108
if err := limayaml.Validate(*y, false); err != nil {
109109
return err
110110
}
@@ -287,6 +287,19 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
287287
})
288288
}
289289

290+
if additionalArchive != "" {
291+
additionaltgzR, err := os.Open(additionalArchive)
292+
if err != nil {
293+
return err
294+
}
295+
defer additionaltgzR.Close()
296+
layout = append(layout, iso9660util.Entry{
297+
// ISO9660 requires len(Path) <= 30
298+
Path: "additional.tgz",
299+
Reader: additionaltgzR,
300+
})
301+
}
302+
290303
return iso9660util.Write(filepath.Join(instDir, filenames.CIDataISO), "cidata", layout)
291304
}
292305

pkg/hostagent/hostagent.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ type HostAgent struct {
5757
}
5858

5959
type options struct {
60-
nerdctlArchive string // local path, not URL
60+
nerdctlArchive string // local path, not URL
61+
additionalArchive string // local path, not URL
6162
}
6263

6364
type Opt func(*options) error
@@ -69,6 +70,13 @@ func WithNerdctlArchive(s string) Opt {
6970
}
7071
}
7172

73+
func WithAdditionalArchive(s string) Opt {
74+
return func(o *options) error {
75+
o.additionalArchive = s
76+
return nil
77+
}
78+
}
79+
7280
// New creates the HostAgent.
7381
//
7482
// stdout is for emitting JSON lines of Events.
@@ -107,7 +115,7 @@ func New(instName string, stdout io.Writer, sigintCh chan os.Signal, opts ...Opt
107115
}
108116
}
109117

110-
if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive); err != nil {
118+
if err := cidata.GenerateISO9660(inst.Dir, instName, y, udpDNSLocalPort, tcpDNSLocalPort, o.nerdctlArchive, o.additionalArchive); err != nil {
111119
return nil, err
112120
}
113121

pkg/limayaml/limayaml.go

+25-24
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,31 @@ import (
77
)
88

99
type LimaYAML struct {
10-
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"`
11-
Images []Image `yaml:"images" json:"images"` // REQUIRED
12-
CPUType map[Arch]string `yaml:"cpuType,omitempty" json:"cpuType,omitempty"`
13-
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
14-
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
15-
Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes
16-
Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
17-
MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty"`
18-
SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME)
19-
Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"`
20-
Video Video `yaml:"video,omitempty" json:"video,omitempty"`
21-
Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"`
22-
Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"`
23-
Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"`
24-
PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"`
25-
Message string `yaml:"message,omitempty" json:"message,omitempty"`
26-
Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty"`
27-
Network NetworkDeprecated `yaml:"network,omitempty" json:"network,omitempty"` // DEPRECATED, use `networks` instead
28-
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
29-
DNS []net.IP `yaml:"dns,omitempty" json:"dns,omitempty"`
30-
HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"`
31-
UseHostResolver *bool `yaml:"useHostResolver,omitempty" json:"useHostResolver,omitempty"` // DEPRECATED, use `HostResolver.Enabled` instead
32-
PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"`
33-
CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
10+
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"`
11+
Images []Image `yaml:"images" json:"images"` // REQUIRED
12+
CPUType map[Arch]string `yaml:"cpuType,omitempty" json:"cpuType,omitempty"`
13+
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
14+
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
15+
Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes
16+
Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
17+
MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty"`
18+
SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME)
19+
Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"`
20+
Video Video `yaml:"video,omitempty" json:"video,omitempty"`
21+
Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"`
22+
Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"`
23+
Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"`
24+
PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"`
25+
Message string `yaml:"message,omitempty" json:"message,omitempty"`
26+
Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty"`
27+
Network NetworkDeprecated `yaml:"network,omitempty" json:"network,omitempty"` // DEPRECATED, use `networks` instead
28+
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
29+
DNS []net.IP `yaml:"dns,omitempty" json:"dns,omitempty"`
30+
HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"`
31+
UseHostResolver *bool `yaml:"useHostResolver,omitempty" json:"useHostResolver,omitempty"` // DEPRECATED, use `HostResolver.Enabled` instead
32+
PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"`
33+
CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
34+
AdditionalArchives []File `yaml:"additionalArchives,omitempty" json:"additionalArchives,omitempty"`
3435
}
3536

3637
type Arch = string

pkg/start/start.go

+30-10
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,35 @@ func ensureNerdctlArchiveCache(y *limayaml.LimaYAML) (string, error) {
4343
return "", nil
4444
}
4545

46-
errs := make([]error, len(y.Containerd.Archives))
47-
for i := range y.Containerd.Archives {
48-
f := &y.Containerd.Archives[i]
49-
if f.Arch != *y.Arch {
46+
location, errs := downloadAndCacheArchiveForArch(y.Containerd.Archives, *y.Arch, "nerdctl")
47+
if location == "" {
48+
return "", fmt.Errorf("failed to download the nerdctl archive, attempted %d candidates, errors=%v",
49+
len(y.Containerd.Archives), errs)
50+
}
51+
52+
return location, nil
53+
}
54+
55+
// downloadAndCacheArchiveForArch iterates through a slice of File and tries to download the provided
56+
// file which matches the supplied arch.
57+
// The downloader caches remote downloads to disk, and then returns a file path to the archive.
58+
func downloadAndCacheArchiveForArch(files []limayaml.File, arch limayaml.Arch, archiveType string) (string, []error) {
59+
errs := make([]error, len(files))
60+
for i := range files {
61+
f := &files[i]
62+
if f.Arch != arch {
5063
errs[i] = fmt.Errorf("unsupported arch: %q", f.Arch)
5164
continue
5265
}
53-
logrus.WithField("digest", f.Digest).Infof("Attempting to download the nerdctl archive from %q", f.Location)
66+
logrus.WithField("digest", f.Digest).Infof("Attempting to download the %s archive from %q", archiveType, f.Location)
5467
res, err := downloader.Download("", f.Location, downloader.WithCache(), downloader.WithExpectedDigest(f.Digest))
5568
if err != nil {
5669
errs[i] = fmt.Errorf("failed to download %q: %w", f.Location, err)
5770
continue
5871
}
5972
switch res.Status {
6073
case downloader.StatusDownloaded:
61-
logrus.Infof("Downloaded the nerdctl archive from %q", f.Location)
74+
logrus.Infof("Downloaded the %s archive from %q", archiveType, f.Location)
6275
case downloader.StatusUsedCache:
6376
logrus.Infof("Using cache %q", res.CachePath)
6477
default:
@@ -68,13 +81,11 @@ func ensureNerdctlArchiveCache(y *limayaml.LimaYAML) (string, error) {
6881
if downloader.IsLocal(f.Location) {
6982
return f.Location, nil
7083
}
71-
return "", fmt.Errorf("cache did not contain %q", f.Location)
84+
errs[i] = fmt.Errorf("cache did not contain %q", f.Location)
7285
}
7386
return res.CachePath, nil
7487
}
75-
76-
return "", fmt.Errorf("failed to download the nerdctl archive, attempted %d candidates, errors=%v",
77-
len(y.Containerd.Archives), errs)
88+
return "", errs
7889
}
7990

8091
func Start(ctx context.Context, inst *store.Instance) error {
@@ -132,6 +143,15 @@ func Start(ctx context.Context, inst *store.Instance) error {
132143
if nerdctlArchiveCache != "" {
133144
args = append(args, "--nerdctl-archive", nerdctlArchiveCache)
134145
}
146+
if len(y.AdditionalArchives) > 0 {
147+
location, errs := downloadAndCacheArchiveForArch(y.AdditionalArchives, *y.Arch, "additionalArchive")
148+
if location == "" {
149+
return fmt.Errorf("failed to download the additionalArchive archive, attempted %d candidates, errors=%v",
150+
len(y.AdditionalArchives), errs)
151+
}
152+
args = append(args, "--additional-archive", location)
153+
}
154+
135155
args = append(args, inst.Name)
136156
haCmd := exec.CommandContext(ctx, self, args...)
137157

0 commit comments

Comments
 (0)