Skip to content

Commit

Permalink
client: invalidate simple streams cache
Browse files Browse the repository at this point in the history
if download by hash fails with 404 not found.

Signed-off-by: Lucas Bremgartner <[email protected]>
  • Loading branch information
breml committed Nov 26, 2024
1 parent 21eee07 commit 3fbf349
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
7 changes: 7 additions & 0 deletions client/simplestreams_images.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package incus
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"io"
"net/http"
Expand All @@ -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"
)
Expand Down Expand Up @@ -121,6 +123,11 @@ 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
}
}
Expand Down
10 changes: 8 additions & 2 deletions shared/simplestreams/simplestreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ func (s *SimpleStreams) readCache(path string) ([]byte, bool) {
return body, expired
}

// InvalidateCache removes the on-disk cache for the SimpleStreams remote.
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]
Expand Down Expand Up @@ -165,7 +170,7 @@ func (s *SimpleStreams) cachedDownload(path string) ([]byte, error) {
if s.cachePath != "" {
cacheName := filepath.Join(s.cachePath, fileName)
_ = os.Remove(cacheName)
_ = os.WriteFile(cacheName, body, 0644)
_ = os.WriteFile(cacheName, body, 0o644)
}

return body, nil
Expand Down Expand Up @@ -375,7 +380,8 @@ func (s *SimpleStreams) GetFiles(fingerprint string) (map[string]DownloadableFil
files[path[2]] = DownloadableFile{
Path: path[0],
Sha256: path[1],
Size: size}
Size: size,
}
}

return files, nil
Expand Down
9 changes: 9 additions & 0 deletions shared/util/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package util

import (
"context"
"errors"
"fmt"
"hash"
"io"
Expand All @@ -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)
Expand Down Expand Up @@ -44,6 +49,10 @@ 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)
}

Expand Down

0 comments on commit 3fbf349

Please sign in to comment.