From 8e516a1b4cdc36e6d4f5acb1ab662d7e41886bab Mon Sep 17 00:00:00 2001 From: Lucas Bremgartner Date: Tue, 26 Nov 2024 16:15:27 +0100 Subject: [PATCH] client: invalidate simple streams cache if download by hash fails with 404 not found. Signed-off-by: Lucas Bremgartner --- client/simplestreams_images.go | 6 ++++++ shared/simplestreams/simplestreams.go | 4 ++++ shared/util/net.go | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/client/simplestreams_images.go b/client/simplestreams_images.go index 32260698293..bffbdda899c 100644 --- a/client/simplestreams_images.go +++ b/client/simplestreams_images.go @@ -3,6 +3,7 @@ package incus import ( "context" "crypto/sha256" + "errors" "fmt" "io" "net/http" @@ -13,6 +14,7 @@ import ( "time" "github.com/lxc/incus/v6/shared/api" + "github.com/lxc/incus/v6/shared/logger" "github.com/lxc/incus/v6/shared/subprocess" "github.com/lxc/incus/v6/shared/util" ) @@ -121,6 +123,10 @@ func (r *ProtocolSimpleStreams) GetImageFile(fingerprint string, req ImageFileRe size, err = util.DownloadFileHash(context.TODO(), &httpClient, r.httpUserAgent, req.ProgressHandler, req.Canceler, filename, uri, hash, sha256.New(), target) if err != nil { + if errors.Is(err, util.ErrNotFound) { + logger.Info("Unable to download file by hash, invalidate potentially outdated cache", logger.Ctx{"filename": filename, "uri": uri, "hash": hash}) + r.ssClient.InvalidateCache() + } return -1, err } } diff --git a/shared/simplestreams/simplestreams.go b/shared/simplestreams/simplestreams.go index d91c5fe5fda..1ee3ba312cf 100644 --- a/shared/simplestreams/simplestreams.go +++ b/shared/simplestreams/simplestreams.go @@ -92,6 +92,10 @@ func (s *SimpleStreams) readCache(path string) ([]byte, bool) { return body, expired } +func (s *SimpleStreams) InvalidateCache() { + _ = os.RemoveAll(s.cachePath) +} + func (s *SimpleStreams) cachedDownload(path string) ([]byte, error) { fields := strings.Split(path, "/") fileName := fields[len(fields)-1] diff --git a/shared/util/net.go b/shared/util/net.go index 74bbef1c1df..21d88ff80e4 100644 --- a/shared/util/net.go +++ b/shared/util/net.go @@ -2,6 +2,7 @@ package util import ( "context" + "errors" "fmt" "hash" "io" @@ -12,6 +13,10 @@ import ( "github.com/lxc/incus/v6/shared/units" ) +// ErrNotFound is used to explicitly signal error cases, where a resource +// can not be found (404 HTTP status code). +var ErrNotFound = errors.New("resource not found") + func DownloadFileHash(ctx context.Context, httpClient *http.Client, useragent string, progress func(progress ioprogress.ProgressData), canceler *cancel.HTTPRequestCanceller, filename string, url string, hash string, hashFunc hash.Hash, target io.WriteSeeker) (int64, error) { // Always seek to the beginning _, _ = target.Seek(0, io.SeekStart) @@ -44,6 +49,9 @@ func DownloadFileHash(ctx context.Context, httpClient *http.Client, useragent st defer close(doneCh) if r.StatusCode != http.StatusOK { + if r.StatusCode == http.StatusNotFound { + return -1, fmt.Errorf("Unable to fetch %s: %w", url, ErrNotFound) + } return -1, fmt.Errorf("Unable to fetch %s: %s", url, r.Status) }