From 30f81c3d1007ed3710f557cbdf07aba068dde50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Sun, 9 Jun 2024 12:59:31 +0200 Subject: [PATCH 1/9] Add possibility to download IPFS images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index cdafa8727ff..6b14fecc988 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -271,8 +271,14 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, if err := writeFirst(shadURL, []byte(remote), 0o644); err != nil { return nil, err } - if err := downloadHTTP(ctx, shadData, shadTime, shadType, remote, o.description, o.expectedDigest); err != nil { - return nil, err + if IsIPFS(remote) { + if err := downloadIPFS(ctx, shadData, remote); err != nil { + return nil, err + } + } else { + if err := downloadHTTP(ctx, shadData, shadTime, shadType, remote, o.description, o.expectedDigest); err != nil { + return nil, err + } } if shadDigest != "" && o.expectedDigest != "" { if err := writeFirst(shadDigest, []byte(o.expectedDigest.String()), 0o644); err != nil { @@ -370,6 +376,10 @@ func IsLocal(s string) bool { return !strings.Contains(s, "://") || strings.HasPrefix(s, "file://") } +func IsIPFS(s string) bool { + return strings.HasPrefix(s, "ipfs://") +} + // canonicalLocalPath canonicalizes the local path string. // - Make sure the file has no scheme, or the `file://` scheme // - If it has the `file://` scheme, strip the scheme and make sure the filename is absolute @@ -712,6 +722,15 @@ func writeFirst(path string, data []byte, perm os.FileMode) error { }) } +func downloadIPFS(ctx context.Context, localPath, url string) error { + address := strings.Replace(url, "ipfs://", "", 1) + address = strings.Split(address, "/")[0] // remove file name from path + cmd := exec.CommandContext(ctx, "ipfs", "get", "-o", localPath, address) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + // CacheEntries returns a map of cache entries. // The key is the SHA256 of the URL. // The value is the path to the cache entry. From a8437e483a9418e74bddfc3e03d4bff065e8393f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Mon, 10 Jun 2024 11:51:16 +0200 Subject: [PATCH 2/9] Refactor: download separate from http MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 6b14fecc988..5339da09450 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -627,7 +627,20 @@ func downloadHTTP(ctx context.Context, localPath, lastModified, contentType, url } } defer resp.Body.Close() - bar, err := progressbar.New(resp.ContentLength) + return download(resp.Body, resp.ContentLength, localPath, url, description, expectedDigest) +} + +func downloadIPFS(ctx context.Context, localPath, url string) error { + address := strings.Replace(url, "ipfs://", "", 1) + address = strings.Split(address, "/")[0] // remove file name from path + cmd := exec.CommandContext(ctx, "ipfs", "get", "-o", localPath, address) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func download(reader io.Reader, size int64, localPath, url, description string, expectedDigest digest.Digest) error { + bar, err := progressbar.New(size) if err != nil { return err } @@ -664,7 +677,7 @@ func downloadHTTP(ctx context.Context, localPath, lastModified, contentType, url fmt.Fprintf(os.Stderr, "Downloading %s\n", description) } bar.Start() - if _, err := io.Copy(multiWriter, bar.NewProxyReader(resp.Body)); err != nil { + if _, err := io.Copy(multiWriter, bar.NewProxyReader(reader)); err != nil { return err } bar.Finish() @@ -722,15 +735,6 @@ func writeFirst(path string, data []byte, perm os.FileMode) error { }) } -func downloadIPFS(ctx context.Context, localPath, url string) error { - address := strings.Replace(url, "ipfs://", "", 1) - address = strings.Split(address, "/")[0] // remove file name from path - cmd := exec.CommandContext(ctx, "ipfs", "get", "-o", localPath, address) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - // CacheEntries returns a map of cache entries. // The key is the SHA256 of the URL. // The value is the path to the cache entry. From 0a21255b3648e672b03e62980be8de92ea250614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Mon, 10 Jun 2024 11:52:04 +0200 Subject: [PATCH 3/9] Use internal progress also for ipfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 44 +++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 5339da09450..80449674ccc 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -12,6 +12,7 @@ import ( "os/exec" "path" "path/filepath" + "strconv" "strings" "sync/atomic" "time" @@ -272,7 +273,7 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, return nil, err } if IsIPFS(remote) { - if err := downloadIPFS(ctx, shadData, remote); err != nil { + if err := downloadIPFS(ctx, shadData, remote, o.description, o.expectedDigest); err != nil { return nil, err } } else { @@ -630,13 +631,44 @@ func downloadHTTP(ctx context.Context, localPath, lastModified, contentType, url return download(resp.Body, resp.ContentLength, localPath, url, description, expectedDigest) } -func downloadIPFS(ctx context.Context, localPath, url string) error { +func downloadIPFS(ctx context.Context, localPath, url, description string, expectedDigest digest.Digest) error { + if localPath == "" { + return fmt.Errorf("downloadIPFS: got empty localPath") + } + logrus.Debugf("downloading %q into %q", url, localPath) + address := strings.Replace(url, "ipfs://", "", 1) address = strings.Split(address, "/")[0] // remove file name from path - cmd := exec.CommandContext(ctx, "ipfs", "get", "-o", localPath, address) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() + cmd := exec.CommandContext(ctx, "ipfs", "ls", address) + out, err := cmd.Output() + if err != nil { + return err + } + size := int64(0) + for _, line := range strings.Split(string(out), "\n") { + // Hash Size Name + f := strings.Fields(line) + if len(f) >= 2 { + s, err := strconv.Atoi(f[1]) + if err != nil { + return err + } + size += int64(s) + } + } + + cmd = exec.CommandContext(ctx, "ipfs", "cat", "--progress=false", address) + stdout, err := cmd.StdoutPipe() + if err != nil { + return err + } + if err := cmd.Start(); err != nil { + return err + } + if err := download(stdout, size, localPath, url, description, expectedDigest); err != nil { + return err + } + return cmd.Wait() } func download(reader io.Reader, size int64, localPath, url, description string, expectedDigest digest.Digest) error { From 6a5ab9980e6b438dbb3dc4f3494580c94db88ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Tue, 11 Jun 2024 12:48:17 +0200 Subject: [PATCH 4/9] Show stderr from the ipfs commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 80449674ccc..a0429c12880 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -640,6 +640,7 @@ func downloadIPFS(ctx context.Context, localPath, url, description string, expec address := strings.Replace(url, "ipfs://", "", 1) address = strings.Split(address, "/")[0] // remove file name from path cmd := exec.CommandContext(ctx, "ipfs", "ls", address) + cmd.Stderr = os.Stderr out, err := cmd.Output() if err != nil { return err @@ -658,6 +659,7 @@ func downloadIPFS(ctx context.Context, localPath, url, description string, expec } cmd = exec.CommandContext(ctx, "ipfs", "cat", "--progress=false", address) + cmd.Stderr = os.Stderr stdout, err := cmd.StdoutPipe() if err != nil { return err From 448fc17cb8dc3b3913cb160234d9557f95d44b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Sun, 23 Jun 2024 17:53:46 +0200 Subject: [PATCH 5/9] Allow adding CID to existing files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 19 +++++++++++++++++-- pkg/fileutils/download.go | 3 +++ pkg/limayaml/limayaml.go | 1 + pkg/limayaml/validate.go | 13 +++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index a0429c12880..29f0b145e80 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -42,6 +42,7 @@ const ( StatusDownloaded Status = "downloaded" StatusSkipped Status = "skipped" StatusUsedCache Status = "used-cache" + StatusUsedIPFS Status = "used-ipfs" ) type Result struct { @@ -57,6 +58,7 @@ type options struct { decompress bool // default: false (keep compression) description string // default: url expectedDigest digest.Digest + cid string } type Opt func(*options) error @@ -123,6 +125,13 @@ func WithExpectedDigest(expectedDigest digest.Digest) Opt { } } +func WithContentIdentifier(cid string) Opt { + return func(o *options) error { + o.cid = cid + return nil + } +} + func readFile(path string) string { if path == "" { return "" @@ -272,11 +281,17 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, if err := writeFirst(shadURL, []byte(remote), 0o644); err != nil { return nil, err } + status := StatusDownloaded + if o.cid != "" { + if err := downloadIPFS(ctx, shadData, fmt.Sprintf("ipfs://%s", o.cid), o.description, o.expectedDigest); err == nil { + status = StatusUsedIPFS + } + } if IsIPFS(remote) { if err := downloadIPFS(ctx, shadData, remote, o.description, o.expectedDigest); err != nil { return nil, err } - } else { + } else if status != StatusUsedIPFS { if err := downloadHTTP(ctx, shadData, shadTime, shadType, remote, o.description, o.expectedDigest); err != nil { return nil, err } @@ -291,7 +306,7 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, return nil, err } res := &Result{ - Status: StatusDownloaded, + Status: status, CachePath: shadData, LastModified: readTime(shadTime), ContentType: readFile(shadType), diff --git a/pkg/fileutils/download.go b/pkg/fileutils/download.go index 97bf6d30d61..4a03483f715 100644 --- a/pkg/fileutils/download.go +++ b/pkg/fileutils/download.go @@ -26,6 +26,7 @@ func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress downloader.WithDecompress(decompress), downloader.WithDescription(fmt.Sprintf("%s (%s)", description, path.Base(f.Location))), downloader.WithExpectedDigest(f.Digest), + downloader.WithContentIdentifier(f.Cid), ) if err != nil { return "", fmt.Errorf("failed to download %q: %w", f.Location, err) @@ -36,6 +37,8 @@ func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress logrus.Infof("Downloaded %s from %q", description, f.Location) case downloader.StatusUsedCache: logrus.Infof("Using cache %q", res.CachePath) + case downloader.StatusUsedIPFS: + logrus.Infof("Used ipfs %q", f.Cid) default: logrus.Warnf("Unexpected result from downloader.Download(): %+v", res) } diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index dc27723e512..9f3711eb998 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -100,6 +100,7 @@ type File struct { Location string `yaml:"location" json:"location"` // REQUIRED Arch Arch `yaml:"arch,omitempty" json:"arch,omitempty"` Digest digest.Digest `yaml:"digest,omitempty" json:"digest,omitempty"` + Cid string `yaml:"cid,omitempty" json:"cid,omitempty"` } type FileWithVMType struct { diff --git a/pkg/limayaml/validate.go b/pkg/limayaml/validate.go index 6c1a5d6d658..1bc0b7fef74 100644 --- a/pkg/limayaml/validate.go +++ b/pkg/limayaml/validate.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "os" + "os/exec" "path" "path/filepath" "regexp" @@ -42,6 +43,18 @@ func validateFileObject(f File, fieldName string) error { return fmt.Errorf("field `%s.digest` is invalid: %s: %w", fieldName, f.Digest.String(), err) } } + if f.Cid != "" { + if _, err := exec.LookPath("ipfs"); err == nil { + cmd := exec.Command("ipfs", "cid", "format", f.Cid) + if cid, err := cmd.CombinedOutput(); err != nil || strings.TrimSuffix(string(cid), "\n") != f.Cid { + // unfortunately, the `ipfs cid` command does not return any proper exit codes + if err == nil { + return fmt.Errorf("field `%s.cid` is invalid: %s", fieldName, string(cid)) + } + return fmt.Errorf("field `%s.cid` is invalid: %s: %w", fieldName, f.Cid, err) + } + } + } return nil } From 4e22822cb6aebade7690b1fd63805b94877fb8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Wed, 9 Oct 2024 13:42:06 +0200 Subject: [PATCH 6/9] Allow using an http ipfs gateway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/downloader/downloader.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 29f0b145e80..8e5a0013834 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -653,7 +653,18 @@ func downloadIPFS(ctx context.Context, localPath, url, description string, expec logrus.Debugf("downloading %q into %q", url, localPath) address := strings.Replace(url, "ipfs://", "", 1) + + // Possibly use an ipfs getway such as "https://ipfs.io" or "http://127.0.0.1:8080" + if gateway := os.Getenv("IPFS_GATEWAY"); gateway != "" { + if strings.HasPrefix(gateway, "http") { + url = fmt.Sprintf("%s/ipfs/%s", gateway, address) + return downloadHTTP(ctx, localPath, "", "", url, description, expectedDigest) + } + return fmt.Errorf("unknown gateway: %q", gateway) + } + address = strings.Split(address, "/")[0] // remove file name from path + cmd := exec.CommandContext(ctx, "ipfs", "ls", address) cmd.Stderr = os.Stderr out, err := cmd.Output() From 1bcf40239a61313fc5613fad2ff8a663d6900f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Wed, 9 Oct 2024 14:11:38 +0200 Subject: [PATCH 7/9] Add config for enabling IPFS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- examples/default.yaml | 6 ++++++ pkg/downloader/downloader.go | 10 +++++++++- pkg/fileutils/download.go | 3 ++- pkg/instance/start.go | 2 +- pkg/limayaml/defaults.go | 10 ++++++++++ pkg/limayaml/defaults_test.go | 5 +++++ pkg/limayaml/limayaml.go | 1 + pkg/qemu/qemu.go | 8 ++++---- pkg/vz/disk.go | 6 +++--- pkg/wsl2/fs.go | 2 +- .../content/en/docs/releases/experimental/_index.md | 1 + 11 files changed, 43 insertions(+), 11 deletions(-) diff --git a/examples/default.yaml b/examples/default.yaml index 802ab5f9d9d..53efdcad85f 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -310,6 +310,12 @@ rosetta: # 🟢 Builtin default: use name from /etc/timezone or deduce from symlink target of /etc/localtime timezone: null +# Allow using IPFS for downloading files with a provided CID. +# If set to `true`, this will try to use ipfs cid before the location url. +# It requires either the "ipfs" tool (kubo), or setting the IPFS_GATEWAY. +# 🟢 Builtin default: false +ipfs: null + firmware: # Use legacy BIOS instead of UEFI. Ignored for aarch64 and vz. # 🟢 Builtin default: false diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 8e5a0013834..1cf2ddd3e30 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -58,6 +58,7 @@ type options struct { decompress bool // default: false (keep compression) description string // default: url expectedDigest digest.Digest + ipfs bool cid string } @@ -125,6 +126,13 @@ func WithExpectedDigest(expectedDigest digest.Digest) Opt { } } +func WithIPFS(ipfs bool) Opt { + return func(o *options) error { + o.ipfs = ipfs + return nil + } +} + func WithContentIdentifier(cid string) Opt { return func(o *options) error { o.cid = cid @@ -282,7 +290,7 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result, return nil, err } status := StatusDownloaded - if o.cid != "" { + if o.ipfs && o.cid != "" { if err := downloadIPFS(ctx, shadData, fmt.Sprintf("ipfs://%s", o.cid), o.description, o.expectedDigest); err == nil { status = StatusUsedIPFS } diff --git a/pkg/fileutils/download.go b/pkg/fileutils/download.go index 4a03483f715..1aa890dca6a 100644 --- a/pkg/fileutils/download.go +++ b/pkg/fileutils/download.go @@ -15,7 +15,7 @@ import ( var ErrSkipped = errors.New("skipped to download") // DownloadFile downloads a file to the cache, optionally copying it to the destination. Returns path in cache. -func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress bool, description string, expectedArch limayaml.Arch) (string, error) { +func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress, ipfs bool, description string, expectedArch limayaml.Arch) (string, error) { if f.Arch != expectedArch { return "", fmt.Errorf("%w: %q: unsupported arch: %q", ErrSkipped, f.Location, f.Arch) } @@ -26,6 +26,7 @@ func DownloadFile(ctx context.Context, dest string, f limayaml.File, decompress downloader.WithDecompress(decompress), downloader.WithDescription(fmt.Sprintf("%s (%s)", description, path.Base(f.Location))), downloader.WithExpectedDigest(f.Digest), + downloader.WithIPFS(ipfs), downloader.WithContentIdentifier(f.Cid), ) if err != nil { diff --git a/pkg/instance/start.go b/pkg/instance/start.go index 4ccd2d93a77..ad6eed52df0 100644 --- a/pkg/instance/start.go +++ b/pkg/instance/start.go @@ -54,7 +54,7 @@ func ensureNerdctlArchiveCache(ctx context.Context, y *limayaml.LimaYAML, create return path, nil } } - path, err := fileutils.DownloadFile(ctx, "", f, false, "the nerdctl archive", *y.Arch) + path, err := fileutils.DownloadFile(ctx, "", f, false, *y.IPFS, "the nerdctl archive", *y.Arch) if err != nil { errs[i] = err continue diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 18305a9f980..ac9faaae098 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -333,6 +333,16 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { y.TimeZone = ptr.Of(hostTimeZone()) } + if y.IPFS == nil { + y.IPFS = d.IPFS + } + if o.IPFS != nil { + y.IPFS = o.IPFS + } + if y.IPFS == nil { + y.IPFS = ptr.Of(false) + } + if y.SSH.LocalPort == nil { y.SSH.LocalPort = d.SSH.LocalPort } diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index 848dc8036ef..4d504d197a9 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -86,6 +86,7 @@ func TestFillDefault(t *testing.T) { ForwardX11Trusted: ptr.Of(false), }, TimeZone: ptr.Of(hostTimeZone()), + IPFS: ptr.Of(false), Firmware: Firmware{ LegacyBIOS: ptr.Of(false), }, @@ -175,6 +176,7 @@ func TestFillDefault(t *testing.T) { }, }, TimeZone: ptr.Of("Antarctica/Troll"), + IPFS: ptr.Of(true), Firmware: Firmware{ LegacyBIOS: ptr.Of(false), Images: []FileWithVMType{ @@ -286,6 +288,7 @@ func TestFillDefault(t *testing.T) { } expect.TimeZone = y.TimeZone + expect.IPFS = y.IPFS expect.Firmware = y.Firmware expect.Firmware.Images = slices.Clone(y.Firmware.Images) @@ -338,6 +341,7 @@ func TestFillDefault(t *testing.T) { ForwardX11Trusted: ptr.Of(false), }, TimeZone: ptr.Of("Zulu"), + IPFS: ptr.Of(true), Firmware: Firmware{ LegacyBIOS: ptr.Of(true), Images: []FileWithVMType{ @@ -545,6 +549,7 @@ func TestFillDefault(t *testing.T) { ForwardX11Trusted: ptr.Of(false), }, TimeZone: ptr.Of("Universal"), + IPFS: ptr.Of(true), Firmware: Firmware{ LegacyBIOS: ptr.Of(true), }, diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index 9f3711eb998..b0c35daabd3 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -46,6 +46,7 @@ type LimaYAML struct { Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"` TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"` + IPFS *bool `yaml:"ipfs,omitempty" json:"ipfs,omitempty" jsonschema:"nullable"` NestedVirtualization *bool `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty" jsonschema:"nullable"` } diff --git a/pkg/qemu/qemu.go b/pkg/qemu/qemu.go index c4981c763c3..e6954b40124 100644 --- a/pkg/qemu/qemu.go +++ b/pkg/qemu/qemu.go @@ -64,12 +64,12 @@ func EnsureDisk(ctx context.Context, cfg Config) error { var ensuredBaseDisk bool errs := make([]error, len(cfg.LimaYAML.Images)) for i, f := range cfg.LimaYAML.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *cfg.LimaYAML.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, *cfg.LimaYAML.IPFS, "the image", *cfg.LimaYAML.Arch); err != nil { errs[i] = err continue } if f.Kernel != nil { - if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, false, "the kernel", *cfg.LimaYAML.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, false, *cfg.LimaYAML.IPFS, "the kernel", *cfg.LimaYAML.Arch); err != nil { errs[i] = err continue } @@ -81,7 +81,7 @@ func EnsureDisk(ctx context.Context, cfg Config) error { } } if f.Initrd != nil { - if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *cfg.LimaYAML.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, *cfg.LimaYAML.IPFS, "the initrd", *cfg.LimaYAML.Arch); err != nil { errs[i] = err continue } @@ -604,7 +604,7 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er switch f.VMType { case "", limayaml.QEMU: if f.Arch == *y.Arch { - if _, err = fileutils.DownloadFile(ctx, downloadedFirmware, f.File, true, "UEFI code "+f.Location, *y.Arch); err != nil { + if _, err = fileutils.DownloadFile(ctx, downloadedFirmware, f.File, true, *y.IPFS, "UEFI code "+f.Location, *y.Arch); err != nil { logrus.WithError(err).Warnf("failed to download %q", f.Location) continue loop } diff --git a/pkg/vz/disk.go b/pkg/vz/disk.go index 4e5c7b2327a..1eb012ca354 100644 --- a/pkg/vz/disk.go +++ b/pkg/vz/disk.go @@ -30,13 +30,13 @@ func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error { var ensuredBaseDisk bool errs := make([]error, len(driver.Instance.Config.Images)) for i, f := range driver.Instance.Config.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *driver.Instance.Config.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, *driver.Instance.Config.IPFS, "the image", *driver.Instance.Config.Arch); err != nil { errs[i] = err continue } if f.Kernel != nil { // ensure decompress kernel because vz expects it to be decompressed - if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, true, "the kernel", *driver.Instance.Config.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, true, *driver.Instance.Config.IPFS, "the kernel", *driver.Instance.Config.Arch); err != nil { errs[i] = err continue } @@ -48,7 +48,7 @@ func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error { } } if f.Initrd != nil { - if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *driver.Instance.Config.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, *driver.Instance.Config.IPFS, "the initrd", *driver.Instance.Config.Arch); err != nil { errs[i] = err continue } diff --git a/pkg/wsl2/fs.go b/pkg/wsl2/fs.go index b21186e09e5..6f88621b262 100644 --- a/pkg/wsl2/fs.go +++ b/pkg/wsl2/fs.go @@ -19,7 +19,7 @@ func EnsureFs(ctx context.Context, driver *driver.BaseDriver) error { var ensuredBaseDisk bool errs := make([]error, len(driver.Instance.Config.Images)) for i, f := range driver.Instance.Config.Images { - if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, "the image", *driver.Instance.Config.Arch); err != nil { + if _, err := fileutils.DownloadFile(ctx, baseDisk, f.File, true, *driver.Instance.Config.IPFS, "the image", *driver.Instance.Config.Arch); err != nil { errs[i] = err continue } diff --git a/website/content/en/docs/releases/experimental/_index.md b/website/content/en/docs/releases/experimental/_index.md index 92f6d2ff0bb..8f569c72157 100644 --- a/website/content/en/docs/releases/experimental/_index.md +++ b/website/content/en/docs/releases/experimental/_index.md @@ -13,6 +13,7 @@ The following features are experimental and subject to change: - `audio.device` - `arch: armv7l` - `mountInotify: true` +- `ipfs: true` The following commands are experimental and subject to change: From cc3004e7a130b021aaaaeb172cb58f24e3ef0c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Sun, 23 Jun 2024 17:54:10 +0200 Subject: [PATCH 8/9] Add cid for containerd archives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- pkg/limayaml/containerd.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/limayaml/containerd.yaml b/pkg/limayaml/containerd.yaml index fe4afe6e32f..976f9f54565 100644 --- a/pkg/limayaml/containerd.yaml +++ b/pkg/limayaml/containerd.yaml @@ -2,8 +2,10 @@ archives: - location: https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-amd64.tar.gz arch: x86_64 digest: sha256:2c841e097fcfb5a1760bd354b3778cb695b44cd01f9f271c17507dc4a0b25606 + cid: bafybeieipdaxd3fzy3j7syzzxdaqxramk65j7ajzcqgmi6b5jyq4jgbwue - location: https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-full-1.7.6-linux-arm64.tar.gz arch: aarch64 digest: sha256:77c747f09853ee3d229d77e8de0dd3c85622537d82be57433dc1fca4493bab95 + cid: bafybeibptqoynryoxytxffgyuqjnmwpuujwp6wlps4spygapuwphzkeieq # No arm-v7 # No riscv64 From a0b72aba348f4c016d9f07ecdbefaf76c16d5287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Tue, 22 Oct 2024 15:46:39 +0200 Subject: [PATCH 9/9] Add cid for ubuntu images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anders F Björklund --- examples/default.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/default.yaml b/examples/default.yaml index 53efdcad85f..d6ad27675cb 100644 --- a/examples/default.yaml +++ b/examples/default.yaml @@ -39,9 +39,11 @@ images: - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-amd64.img" arch: "x86_64" digest: "sha256:0e25ca6ee9f08ec5d4f9910054b66ae7163c6152e81a3e67689d89bd6e4dfa69" + cid: "bafybeievi2i673t7kgzx6vsxc6lod3bvagzc364e6kes43p6catfowgone" - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-arm64.img" arch: "aarch64" digest: "sha256:5ecac6447be66a164626744a87a27fd4e6c6606dc683e0a233870af63df4276a" + cid: "bafybeich5idqhqtdh3f4nxq6kv6l2fd2nsvynha3vdqek4a7mu7nawp6sm" - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-riscv64.img" arch: "riscv64" digest: "sha256:f5886ad4e405e689585dfef0e96c31b06478e0cb12bc7f3fae965759a32d729e"