Compare commits

...

27 Commits

Author SHA1 Message Date
Kohei Tokunaga 554629b4a1
Merge pull request #2105 from containerd/dependabot/go_modules/containerd-2f3dabfc34
build(deps): bump the containerd group across 2 directories with 1 update
2025-08-11 21:37:26 +09:00
Kohei Tokunaga a986f8c194
Merge pull request #2101 from containerd/dependabot/github_actions/actions/download-artifact-5
build(deps): bump actions/download-artifact from 4 to 5
2025-08-10 16:50:38 +09:00
Kohei Tokunaga 38cf9aa57c
Merge pull request #2104 from containerd/dependabot/go_modules/cmd/gomod-cfb98d732f
build(deps): bump the gomod group across 2 directories with 1 update
2025-08-09 12:56:57 +09:00
dependabot[bot] e07c7abb8c
build(deps): bump the containerd group across 2 directories with 1 update
Bumps the containerd group with 1 update in the / directory: [github.com/containerd/go-cni](https://github.com/containerd/go-cni).
Bumps the containerd group with 1 update in the /cmd directory: [github.com/containerd/go-cni](https://github.com/containerd/go-cni).


Updates `github.com/containerd/go-cni` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/containerd/go-cni/releases)
- [Commits](https://github.com/containerd/go-cni/compare/v1.1.12...v1.1.13)

Updates `github.com/containerd/go-cni` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/containerd/go-cni/releases)
- [Commits](https://github.com/containerd/go-cni/compare/v1.1.12...v1.1.13)

---
updated-dependencies:
- dependency-name: github.com/containerd/go-cni
  dependency-version: 1.1.13
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: containerd
- dependency-name: github.com/containerd/go-cni
  dependency-version: 1.1.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: containerd
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-08 21:07:10 +00:00
dependabot[bot] 7b508b1afe
build(deps): bump the gomod group across 2 directories with 1 update
Bumps the gomod group with 1 update in the /cmd directory: [github.com/multiformats/go-multiaddr](https://github.com/multiformats/go-multiaddr).
Bumps the gomod group with 1 update in the /ipfs directory: [github.com/multiformats/go-multiaddr](https://github.com/multiformats/go-multiaddr).


Updates `github.com/multiformats/go-multiaddr` from 0.16.0 to 0.16.1
- [Release notes](https://github.com/multiformats/go-multiaddr/releases)
- [Commits](https://github.com/multiformats/go-multiaddr/compare/v0.16.0...v0.16.1)

Updates `github.com/multiformats/go-multiaddr` from 0.16.0 to 0.16.1
- [Release notes](https://github.com/multiformats/go-multiaddr/releases)
- [Commits](https://github.com/multiformats/go-multiaddr/compare/v0.16.0...v0.16.1)

---
updated-dependencies:
- dependency-name: github.com/multiformats/go-multiaddr
  dependency-version: 0.16.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: gomod
- dependency-name: github.com/multiformats/go-multiaddr
  dependency-version: 0.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: gomod
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-07 20:39:58 +00:00
Kohei Tokunaga 08272a30af
Merge pull request #2102 from wswsmao/main
ctr-remote: support 'all' for --gpus flag
2025-08-07 23:14:01 +09:00
abushwang d09a4ffa5b ctr-remote: support 'all' for --gpus flag
Signed-off-by: abushwang <abushwang@tencent.com>
2025-08-07 20:13:47 +08:00
dependabot[bot] 1227c8e42b
build(deps): bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-06 20:29:12 +00:00
Kohei Tokunaga 21fb6a16e4
Merge pull request #2100 from containerd/dependabot/go_modules/gomod-5d31edd0e2
build(deps): bump the gomod group across 2 directories with 1 update
2025-08-01 20:28:39 +09:00
dependabot[bot] f400f935f7
build(deps): bump the gomod group across 2 directories with 1 update
Bumps the gomod group with 1 update in the / directory: [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang).
Bumps the gomod group with 1 update in the /cmd directory: [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang).


Updates `github.com/prometheus/client_golang` from 1.22.0 to 1.23.0
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.23.0/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

Updates `github.com/prometheus/client_golang` from 1.22.0 to 1.23.0
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.23.0/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: gomod
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: gomod
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-31 20:34:42 +00:00
Kohei Tokunaga d0487729a1
Merge pull request #2098 from rosstimothy/tross/remove_testing
Remove `testing` dependency from code outside tests
2025-08-01 00:34:36 +09:00
Tim Ross 2aef7a6e63
Replace testing.T references with local TestingT interface
Removes the dependency on the `testing` package in the remaining
testutil packages by defining a local TestingT interface which
contains the subset of `testing.T` required for the test helpers.

Signed-off-by: Tim Ross <tim.ross@goteleport.com>
2025-07-31 10:13:18 -04:00
Tim Ross 18e393af96
Remove testing from util/testutil package
RandomBytes now returns an error instead of taking a testing.T
and asserting the error is non nil to eliminate dependence on the
testing package outside of test files.

Signed-off-by: Tim Ross <tim.ross@goteleport.com>
2025-07-31 10:13:17 -04:00
Kohei Tokunaga 927075ba7b
Merge pull request #2099 from containerd/dependabot/go_modules/containerd-24169ab9f1
build(deps): bump the containerd group across 3 directories with 1 update
2025-07-31 09:56:52 +09:00
dependabot[bot] e53cec5266
build(deps): bump the containerd group across 3 directories with 1 update
Bumps the containerd group with 1 update in the / directory: [github.com/containerd/containerd/v2](https://github.com/containerd/containerd).
Bumps the containerd group with 1 update in the /cmd directory: [github.com/containerd/containerd/v2](https://github.com/containerd/containerd).
Bumps the containerd group with 1 update in the /ipfs directory: [github.com/containerd/containerd/v2](https://github.com/containerd/containerd).


Updates `github.com/containerd/containerd/v2` from 2.1.3 to 2.1.4
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v2.1.3...v2.1.4)

Updates `github.com/containerd/containerd/v2` from 2.1.3 to 2.1.4
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v2.1.3...v2.1.4)

Updates `github.com/containerd/containerd/v2` from 2.1.3 to 2.1.4
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v2.1.3...v2.1.4)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd/v2
  dependency-version: 2.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: containerd
- dependency-name: github.com/containerd/containerd/v2
  dependency-version: 2.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: containerd
- dependency-name: github.com/containerd/containerd/v2
  dependency-version: 2.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: containerd
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-30 20:58:05 +00:00
Kohei Tokunaga 555e167719
Merge pull request #2096 from containerd/dependabot/go_modules/gomod-f8c008d7c4
build(deps): bump the gomod group across 2 directories with 1 update
2025-07-30 10:00:29 +09:00
dependabot[bot] f72d3aecc8
build(deps): bump the gomod group across 2 directories with 1 update
Bumps the gomod group with 1 update in the / directory: [github.com/docker/cli](https://github.com/docker/cli).
Bumps the gomod group with 1 update in the /cmd directory: [github.com/docker/cli](https://github.com/docker/cli).


Updates `github.com/docker/cli` from 28.3.2+incompatible to 28.3.3+incompatible
- [Commits](https://github.com/docker/cli/compare/v28.3.2...v28.3.3)

Updates `github.com/docker/cli` from 28.3.2+incompatible to 28.3.3+incompatible
- [Commits](https://github.com/docker/cli/compare/v28.3.2...v28.3.3)

---
updated-dependencies:
- dependency-name: github.com/docker/cli
  dependency-version: 28.3.3+incompatible
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: gomod
- dependency-name: github.com/docker/cli
  dependency-version: 28.3.3+incompatible
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: gomod
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-29 20:59:10 +00:00
Kohei Tokunaga 19a5bd5157
Merge pull request #2095 from wswsmao/main
Add FadvDontNeed option to avoid double pagecache consumption
2025-07-29 18:59:43 +09:00
abushwang f62679453f Add FadvDontNeed option to avoid double pagecache consumption
Signed-off-by: abushwang <abushwang@tencent.com>
2025-07-29 16:24:11 +08:00
Kohei Tokunaga 17134ee517
Merge pull request #2092 from wswsmao/main
docs: Add Unexpected restart handling
2025-07-26 16:44:47 +09:00
abushwang 420a03fa46 docs: Add Unexpected restart handling
Signed-off-by: abushwang <abushwang@tencent.com>
2025-07-24 19:29:13 +08:00
Kohei Tokunaga 3aa69eaac5
Merge pull request #2091 from wswsmao/main
Fix file exists error when restoring remote snapshot after unexpected…
2025-07-24 15:41:38 +09:00
abushwang b3743e7916 Fix file exists error when restoring remote snapshot after unexpected restart
Signed-off-by: abushwang <abushwang@tencent.com>
2025-07-23 20:57:24 +08:00
Kohei Tokunaga 4677721cfc
Merge pull request #2089 from containerd/dependabot/docker/kindest/node-v1.33.2
build(deps): bump kindest/node from v1.33.1 to v1.33.2
2025-07-23 10:32:09 +09:00
Kohei Tokunaga 9e6b9b72af
Merge pull request #2090 from containerd/dependabot/go_modules/google-golang-d7ee4b52d7
build(deps): bump the google-golang group across 3 directories with 1 update
2025-07-23 10:31:44 +09:00
dependabot[bot] cfa57c95a9
build(deps): bump the google-golang group across 3 directories with 1 update
Bumps the google-golang group with 1 update in the / directory: [google.golang.org/grpc](https://github.com/grpc/grpc-go).
Bumps the google-golang group with 1 update in the /cmd directory: [google.golang.org/grpc](https://github.com/grpc/grpc-go).
Bumps the google-golang group with 1 update in the /ipfs directory: [google.golang.org/grpc](https://github.com/grpc/grpc-go).


Updates `google.golang.org/grpc` from 1.73.0 to 1.74.2
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.73.0...v1.74.2)

Updates `google.golang.org/grpc` from 1.73.0 to 1.74.2
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.73.0...v1.74.2)

Updates `google.golang.org/grpc` from 1.73.0 to 1.74.2
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.73.0...v1.74.2)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.74.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: google-golang
- dependency-name: google.golang.org/grpc
  dependency-version: 1.74.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: google-golang
- dependency-name: google.golang.org/grpc
  dependency-version: 1.74.2
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: google-golang
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-22 20:55:46 +00:00
dependabot[bot] 24e8a7858a
build(deps): bump kindest/node from v1.33.1 to v1.33.2
Bumps kindest/node from v1.33.1 to v1.33.2.

---
updated-dependencies:
- dependency-name: kindest/node
  dependency-version: v1.33.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-22 20:03:31 +00:00
27 changed files with 652 additions and 324 deletions

View File

@ -50,7 +50,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download Builds - name: Download Builds
uses: actions/download-artifact@v4 uses: actions/download-artifact@v5
with: with:
path: ${{ env.OUTPUT_DIR }} path: ${{ env.OUTPUT_DIR }}
- name: Create Release - name: Create Release

View File

@ -246,7 +246,7 @@ RUN apt-get update && apt-get install -y iptables && \
curl -Ls https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${TARGETARCH:-amd64}-${CNI_PLUGINS_VERSION}.tgz | tar xzv -C /opt/cni/bin curl -Ls https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${TARGETARCH:-amd64}-${CNI_PLUGINS_VERSION}.tgz | tar xzv -C /opt/cni/bin
# Image which can be used as a node image for KinD (containerd with builtin snapshotter) # Image which can be used as a node image for KinD (containerd with builtin snapshotter)
FROM kindest/node:v1.33.1 AS kind-builtin-snapshotter FROM kindest/node:v1.33.2 AS kind-builtin-snapshotter
COPY --from=containerd-snapshotter-dev /out/bin/containerd /out/bin/containerd-shim-runc-v2 /usr/local/bin/ COPY --from=containerd-snapshotter-dev /out/bin/containerd /out/bin/containerd-shim-runc-v2 /usr/local/bin/
COPY --from=snapshotter-dev /out/ctr-remote /usr/local/bin/ COPY --from=snapshotter-dev /out/ctr-remote /usr/local/bin/
COPY ./script/config/ / COPY ./script/config/ /
@ -287,7 +287,7 @@ COPY ./script/config-cri-o/ /
ENTRYPOINT [ "/usr/local/bin/entrypoint" ] ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
# Image which can be used as a node image for KinD # Image which can be used as a node image for KinD
FROM kindest/node:v1.33.1 FROM kindest/node:v1.33.2
COPY --from=containerd-dev /out/bin/containerd /out/bin/containerd-shim-runc-v2 /usr/local/bin/ COPY --from=containerd-dev /out/bin/containerd /out/bin/containerd-shim-runc-v2 /usr/local/bin/
COPY --from=snapshotter-dev /out/* /usr/local/bin/ COPY --from=snapshotter-dev /out/* /usr/local/bin/
COPY ./script/config/ / COPY ./script/config/ /

36
cache/cache.go vendored
View File

@ -27,6 +27,7 @@ import (
"github.com/containerd/stargz-snapshotter/util/cacheutil" "github.com/containerd/stargz-snapshotter/util/cacheutil"
"github.com/containerd/stargz-snapshotter/util/namedmutex" "github.com/containerd/stargz-snapshotter/util/namedmutex"
"golang.org/x/sys/unix"
) )
const ( const (
@ -61,6 +62,9 @@ type DirectoryCacheConfig struct {
// Direct forcefully enables direct mode for all operation in cache. // Direct forcefully enables direct mode for all operation in cache.
// Thus operation won't use on-memory caches. // Thus operation won't use on-memory caches.
Direct bool Direct bool
// FadvDontNeed forcefully clean fscache pagecache for saving memory.
FadvDontNeed bool
} }
// TODO: contents validation. // TODO: contents validation.
@ -173,6 +177,7 @@ func NewDirectoryCache(directory string, config DirectoryCacheConfig) (BlobCache
wipDirectory: wipdir, wipDirectory: wipdir,
bufPool: bufPool, bufPool: bufPool,
direct: config.Direct, direct: config.Direct,
fadvDontNeed: config.FadvDontNeed,
} }
dc.syncAdd = config.SyncAdd dc.syncAdd = config.SyncAdd
return dc, nil return dc, nil
@ -188,8 +193,9 @@ type directoryCache struct {
bufPool *sync.Pool bufPool *sync.Pool
syncAdd bool syncAdd bool
direct bool direct bool
fadvDontNeed bool
closed bool closed bool
closedMu sync.Mutex closedMu sync.Mutex
@ -244,6 +250,12 @@ func (dc *directoryCache) Get(key string, opts ...Option) (Reader, error) {
return &reader{ return &reader{
ReaderAt: file, ReaderAt: file,
closeFunc: func() error { closeFunc: func() error {
if dc.fadvDontNeed {
if err := dropFilePageCache(file); err != nil {
fmt.Printf("Warning: failed to drop page cache: %v\n", err)
}
}
// In passthough model, close will be toke over by go-fuse // In passthough model, close will be toke over by go-fuse
// If "passThrough" option is specified, "direct" option also will // If "passThrough" option is specified, "direct" option also will
// be specified, so adding this branch here is enough // be specified, so adding this branch here is enough
@ -301,6 +313,13 @@ func (dc *directoryCache) Add(key string, opts ...Option) (Writer, error) {
errs = append(errs, fmt.Errorf("failed to create cache directory %q: %w", c, err)) errs = append(errs, fmt.Errorf("failed to create cache directory %q: %w", c, err))
return errors.Join(errs...) return errors.Join(errs...)
} }
if dc.fadvDontNeed {
if err := dropFilePageCache(wip); err != nil {
fmt.Printf("Warning: failed to drop page cache: %v\n", err)
}
}
return os.Rename(wip.Name(), c) return os.Rename(wip.Name(), c)
}, },
abortFunc: func() error { abortFunc: func() error {
@ -463,3 +482,16 @@ func (w *writeCloser) Close() error { return w.closeFunc() }
func nopWriteCloser(w io.Writer) io.WriteCloser { func nopWriteCloser(w io.Writer) io.WriteCloser {
return &writeCloser{w, func() error { return nil }} return &writeCloser{w, func() error { return nil }}
} }
func dropFilePageCache(file *os.File) error {
if file == nil {
return nil
}
fd := file.Fd()
err := unix.Fadvise(int(fd), 0, 0, unix.FADV_DONTNEED)
if err != nil {
return fmt.Errorf("posix_fadvise failed, ret=%d", err)
}
return nil
}

View File

@ -29,15 +29,60 @@ import (
) )
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
testutil.TestReader(t, newTestableReader) testRunner := &testutil.TestRunner{
TestingT: t,
Runner: func(testingT testutil.TestingT, name string, run func(t testutil.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
testutil.TestReader(testRunner, newTestableReader)
} }
func TestFSReader(t *testing.T) { func TestFSReader(t *testing.T) {
fsreader.TestSuiteReader(t, newStore) testRunner := &fsreader.TestRunner{
TestingT: t,
Runner: func(testingT fsreader.TestingT, name string, run func(t fsreader.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
fsreader.TestSuiteReader(testRunner, newStore)
} }
func TestFSLayer(t *testing.T) { func TestFSLayer(t *testing.T) {
layer.TestSuiteLayer(t, newStore) testRunner := &layer.TestRunner{
TestingT: t,
Runner: func(testingT layer.TestingT, name string, run func(t layer.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
layer.TestSuiteLayer(testRunner, newStore)
} }
func newTestableReader(sr *io.SectionReader, opts ...metadata.Option) (testutil.TestableReader, error) { func newTestableReader(sr *io.SectionReader, opts ...metadata.Option) (testutil.TestableReader, error) {

View File

@ -26,6 +26,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv"
"strings" "strings"
containerd "github.com/containerd/containerd/v2/client" containerd "github.com/containerd/containerd/v2/client"
@ -45,6 +46,24 @@ import (
const netnsMountDir = "/var/run/netns" const netnsMountDir = "/var/run/netns"
func parseGPUs(gpuStr string) ([]int, bool) {
if gpuStr == "" {
return nil, false
}
if gpuStr == "all" {
return nil, true
}
parts := strings.Split(gpuStr, ",")
var devices []int
for _, part := range parts {
part = strings.TrimSpace(part)
if device, err := strconv.Atoi(part); err == nil {
devices = append(devices, device)
}
}
return devices, false
}
var samplerFlags = []cli.Flag{ var samplerFlags = []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: "terminal,t", Name: "terminal,t",
@ -116,9 +135,9 @@ var samplerFlags = []cli.Flag{
Name: "cni-plugin-dir", Name: "cni-plugin-dir",
Usage: "path to the CNI plugins binary directory", Usage: "path to the CNI plugins binary directory",
}, },
&cli.IntSliceFlag{ &cli.StringFlag{
Name: "gpus", Name: "gpus",
Usage: "add gpus to the container", Usage: "add gpus to the container (comma-separated list of indices or 'all')",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "net-host", Name: "net-host",
@ -213,7 +232,12 @@ func getSpecOpts(clicontext *cli.Context) func(image containerd.Image, rootfs st
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
log.L.Warn("option --gpus is not supported on Windows") log.L.Warn("option --gpus is not supported on Windows")
} else { } else {
opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(clicontext.IntSlice("gpus")...), nvidia.WithAllCapabilities)) devices, useAll := parseGPUs(clicontext.String("gpus"))
if useAll {
opts = append(opts, nvidia.WithGPUs(nvidia.WithAllCapabilities))
} else if len(devices) > 0 {
opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(devices...), nvidia.WithAllCapabilities))
}
} }
} }

View File

@ -6,8 +6,8 @@ toolchain go1.24.2
require ( require (
github.com/containerd/containerd/api v1.9.0 github.com/containerd/containerd/api v1.9.0
github.com/containerd/containerd/v2 v2.1.3 github.com/containerd/containerd/v2 v2.1.4
github.com/containerd/go-cni v1.1.12 github.com/containerd/go-cni v1.1.13
github.com/containerd/log v0.1.0 github.com/containerd/log v0.1.0
github.com/containerd/platforms v1.0.0-rc.1 github.com/containerd/platforms v1.0.0-rc.1
github.com/containerd/stargz-snapshotter v0.15.2-0.20240622031358-6405f362966d github.com/containerd/stargz-snapshotter v0.15.2-0.20240622031358-6405f362966d
@ -26,7 +26,7 @@ require (
go.etcd.io/bbolt v1.4.2 go.etcd.io/bbolt v1.4.2
golang.org/x/sync v0.16.0 golang.org/x/sync v0.16.0
golang.org/x/sys v0.34.0 golang.org/x/sys v0.34.0
google.golang.org/grpc v1.73.0 google.golang.org/grpc v1.74.2
) )
require ( require (
@ -50,14 +50,14 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect github.com/distribution/reference v0.6.0 // indirect
github.com/docker/cli v28.3.2+incompatible // indirect github.com/docker/cli v28.3.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
@ -93,7 +93,7 @@ require (
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.16.0 // indirect github.com/multiformats/go-multiaddr v0.16.1 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiformats/go-varint v0.0.7 // indirect
@ -103,10 +103,10 @@ require (
github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_golang v1.23.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
@ -119,18 +119,18 @@ require (
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.38.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.24.0 // indirect golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.38.0 // indirect golang.org/x/net v0.40.0 // indirect
golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/term v0.30.0 // indirect golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.9.0 // indirect golang.org/x/time v0.9.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect

View File

@ -27,8 +27,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0= github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI= github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
github.com/containerd/containerd/v2 v2.1.3 h1:eMD2SLcIQPdMlnlNF6fatlrlRLAeDaiGPGwmRKLZKNs= github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
github.com/containerd/containerd/v2 v2.1.3/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM= github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
@ -37,8 +37,8 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
github.com/containerd/go-cni v1.1.12 h1:wm/5VD/i255hjM4uIZjBRiEQ7y98W9ACy/mHeLi4+94= github.com/containerd/go-cni v1.1.13 h1:eFSGOKlhoYNxpJ51KRIMHZNlg5UgocXEIEBGkY7Hnis=
github.com/containerd/go-cni v1.1.12/go.mod h1:+jaqRBdtW5faJxj2Qwg1Of7GsV66xcvnCx4mSJtUlxU= github.com/containerd/go-cni v1.1.13/go.mod h1:nTieub0XDRmvCZ9VI/SBG6PyqT95N4FIhxsauF1vSBI=
github.com/containerd/go-runc v1.1.0 h1:OX4f+/i2y5sUT7LhmcJH7GYrjjhHa1QI4e8yO0gGleA= github.com/containerd/go-runc v1.1.0 h1:OX4f+/i2y5sUT7LhmcJH7GYrjjhHa1QI4e8yO0gGleA=
github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4JN5XAUZqH5U= github.com/containerd/go-runc v1.1.0/go.mod h1:xJv2hFF7GvHtTJd9JqTS2UVxMkULUYw4JN5XAUZqH5U=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
@ -66,8 +66,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v28.3.2+incompatible h1:mOt9fcLE7zaACbxW1GeS65RI67wIJrTnqS3hP2huFsY= github.com/docker/cli v28.3.3+incompatible h1:fp9ZHAr1WWPGdIWBM1b3zLtgCF+83gRdVMTJsUeiyAo=
github.com/docker/cli v28.3.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
@ -92,8 +92,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
@ -248,8 +248,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw=
github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
@ -293,22 +293,22 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
@ -369,16 +369,16 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@ -389,8 +389,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
@ -413,11 +413,11 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -444,12 +444,12 @@ golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -471,15 +471,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@ -74,10 +74,11 @@ You can enable host networking for the container using the `net-host` flag.
# ctr-remote i optimize -t -i --oci --entrypoint='[ "/bin/bash", "-c" ]' --net-host --args='[ "ip a && curl example.com" ]' ghcr.io/stargz-containers/centos:8-test registry2:5000/centos:8-test-esgz # ctr-remote i optimize -t -i --oci --entrypoint='[ "/bin/bash", "-c" ]' --net-host --args='[ "ip a && curl example.com" ]' ghcr.io/stargz-containers/centos:8-test registry2:5000/centos:8-test-esgz
``` ```
You can optimize GPU-based images using the `gpu` flag. The flag expects a comma separated list of integers. You can optimize GPU-based images using the `gpu` flag. The flag expects a comma separated list of integers or 'all'.
```console ```console
# ctr-remote i optimize --oci --gpus "0" <src> <target> # ctr-remote i optimize --oci --gpus "0" <src> <target>
# ctr-remote i optimize --oci --gpus "all" <src> <target>
``` ```
`--oci` option is highly recommended to add when you create eStargz image. `--oci` option is highly recommended to add when you create eStargz image.

View File

@ -144,6 +144,14 @@ When stopping FUSE manager for upgrading the binary or restarting the node, you
4. Restart the containerd-stargz-grpc process. This restores all snapshot mounts by lazy pulling them. `allow_invalid_mounts_on_restart` (described in the above) can still be used for controlling the behaviour of the error cases. 4. Restart the containerd-stargz-grpc process. This restores all snapshot mounts by lazy pulling them. `allow_invalid_mounts_on_restart` (described in the above) can still be used for controlling the behaviour of the error cases.
5. Restart the containers. 5. Restart the containers.
### Unexpected restart handling
When Stargz Snapshotter is killed unexpectedly (e.g., by OOM killer or system crash), the process doesn't get a chance to perform graceful cleanup. In such cases, the snapshotter can successfully restart and restore remote snapshots, but this may lead to fscache duplicating cached data.
**Recommended handling:**
Since this scenario is caused by abnormal exit, users are expected to manually clean up the cache directory after an unexpected restart to avoid cache duplication issues. The cache cleanup should be performed before restarting the snapshotter service.
## Registry-related configuration ## Registry-related configuration
You can configure stargz snapshotter for accessing registries with custom configurations. You can configure stargz snapshotter for accessing registries with custom configurations.

View File

@ -27,7 +27,22 @@ import (
// TestGzipEStargz tests gzip-based external TOC eStargz // TestGzipEStargz tests gzip-based external TOC eStargz
func TestGzipEStargz(t *testing.T) { func TestGzipEStargz(t *testing.T) {
estargz.CompressionTestSuite(t, testRunner := &estargz.TestRunner{
TestingT: t,
Runner: func(testingT estargz.TestingT, name string, run func(t estargz.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
estargz.CompressionTestSuite(testRunner,
gzipControllerWithLevel(gzip.NoCompression), gzipControllerWithLevel(gzip.NoCompression),
gzipControllerWithLevel(gzip.BestSpeed), gzipControllerWithLevel(gzip.BestSpeed),
gzipControllerWithLevel(gzip.BestCompression), gzipControllerWithLevel(gzip.BestCompression),
@ -60,11 +75,11 @@ func (gc *gzipController) String() string {
} }
// TestStream tests the passed estargz blob contains the specified list of streams. // TestStream tests the passed estargz blob contains the specified list of streams.
func (gc *gzipController) TestStreams(t *testing.T, b []byte, streams []int64) { func (gc *gzipController) TestStreams(t estargz.TestingT, b []byte, streams []int64) {
estargz.CheckGzipHasStreams(t, b, streams) estargz.CheckGzipHasStreams(t, b, streams)
} }
func (gc *gzipController) DiffIDOf(t *testing.T, b []byte) string { func (gc *gzipController) DiffIDOf(t estargz.TestingT, b []byte) string {
return estargz.GzipDiffIDOf(t, b) return estargz.GzipDiffIDOf(t, b)
} }

View File

@ -31,7 +31,22 @@ import (
// TestGzipEStargz tests gzip-based eStargz // TestGzipEStargz tests gzip-based eStargz
func TestGzipEStargz(t *testing.T) { func TestGzipEStargz(t *testing.T) {
CompressionTestSuite(t, testRunner := &TestRunner{
TestingT: t,
Runner: func(testingT TestingT, name string, run func(t TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
CompressionTestSuite(testRunner,
gzipControllerWithLevel(gzip.NoCompression), gzipControllerWithLevel(gzip.NoCompression),
gzipControllerWithLevel(gzip.BestSpeed), gzipControllerWithLevel(gzip.BestSpeed),
gzipControllerWithLevel(gzip.BestCompression), gzipControllerWithLevel(gzip.BestCompression),
@ -56,11 +71,11 @@ func (gc *gzipController) String() string {
} }
// TestStream tests the passed estargz blob contains the specified list of streams. // TestStream tests the passed estargz blob contains the specified list of streams.
func (gc *gzipController) TestStreams(t *testing.T, b []byte, streams []int64) { func (gc *gzipController) TestStreams(t TestingT, b []byte, streams []int64) {
CheckGzipHasStreams(t, b, streams) CheckGzipHasStreams(t, b, streams)
} }
func (gc *gzipController) DiffIDOf(t *testing.T, b []byte) string { func (gc *gzipController) DiffIDOf(t TestingT, b []byte) string {
return GzipDiffIDOf(t, b) return GzipDiffIDOf(t, b)
} }

View File

@ -38,7 +38,6 @@ import (
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"testing"
"time" "time"
"github.com/containerd/stargz-snapshotter/estargz/errorutil" "github.com/containerd/stargz-snapshotter/estargz/errorutil"
@ -49,16 +48,48 @@ import (
// TestingController is Compression with some helper methods necessary for testing. // TestingController is Compression with some helper methods necessary for testing.
type TestingController interface { type TestingController interface {
Compression Compression
TestStreams(t *testing.T, b []byte, streams []int64) TestStreams(t TestingT, b []byte, streams []int64)
DiffIDOf(*testing.T, []byte) string DiffIDOf(TestingT, []byte) string
String() string String() string
} }
// TestingT is the minimal set of testing.T required to run the
// tests defined in CompressionTestSuite. This interface exists to prevent
// leaking the testing package from being exposed outside tests.
type TestingT interface {
Errorf(format string, args ...any)
FailNow()
Failed() bool
Fatal(args ...any)
Fatalf(format string, args ...any)
Logf(format string, args ...any)
Parallel()
}
// Runner allows running subtests of TestingT. This exists instead of adding
// a Run method to TestingT interface because the Run implementation of
// testing.T would not satisfy the interface.
type Runner func(t TestingT, name string, fn func(t TestingT))
type TestRunner struct {
TestingT
Runner Runner
}
func (r *TestRunner) Run(name string, run func(*TestRunner)) {
r.Runner(r.TestingT, name, func(t TestingT) {
run(&TestRunner{TestingT: t, Runner: r.Runner})
})
}
// CompressionTestSuite tests this pkg with controllers can build valid eStargz blobs and parse them. // CompressionTestSuite tests this pkg with controllers can build valid eStargz blobs and parse them.
func CompressionTestSuite(t *testing.T, controllers ...TestingControllerFactory) { func CompressionTestSuite(t *TestRunner, controllers ...TestingControllerFactory) {
t.Run("testBuild", func(t *testing.T) { t.Parallel(); testBuild(t, controllers...) }) t.Run("testBuild", func(t *TestRunner) { t.Parallel(); testBuild(t, controllers...) })
t.Run("testDigestAndVerify", func(t *testing.T) { t.Parallel(); testDigestAndVerify(t, controllers...) }) t.Run("testDigestAndVerify", func(t *TestRunner) {
t.Run("testWriteAndOpen", func(t *testing.T) { t.Parallel(); testWriteAndOpen(t, controllers...) }) t.Parallel()
testDigestAndVerify(t, controllers...)
})
t.Run("testWriteAndOpen", func(t *TestRunner) { t.Parallel(); testWriteAndOpen(t, controllers...) })
} }
type TestingControllerFactory func() TestingController type TestingControllerFactory func() TestingController
@ -79,7 +110,7 @@ var allowedPrefix = [4]string{"", "./", "/", "../"}
// testBuild tests the resulting stargz blob built by this pkg has the same // testBuild tests the resulting stargz blob built by this pkg has the same
// contents as the normal stargz blob. // contents as the normal stargz blob.
func testBuild(t *testing.T, controllers ...TestingControllerFactory) { func testBuild(t *TestRunner, controllers ...TestingControllerFactory) {
tests := []struct { tests := []struct {
name string name string
chunkSize int chunkSize int
@ -165,7 +196,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
prefix := prefix prefix := prefix
for _, minChunkSize := range tt.minChunkSize { for _, minChunkSize := range tt.minChunkSize {
minChunkSize := minChunkSize minChunkSize := minChunkSize
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *testing.T) { t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s,minChunkSize=%d", newCL(), prefix, srcCompression, srcTarFormat, minChunkSize), func(t *TestRunner) {
tarBlob := buildTar(t, tt.in, prefix, srcTarFormat) tarBlob := buildTar(t, tt.in, prefix, srcTarFormat)
// Test divideEntries() // Test divideEntries()
entries, err := sortEntries(tarBlob, nil, nil) // identical order entries, err := sortEntries(tarBlob, nil, nil) // identical order
@ -265,7 +296,7 @@ func testBuild(t *testing.T, controllers ...TestingControllerFactory) {
} }
} }
func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool { func isSameTarGz(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
aGz, err := cla.Reader(bytes.NewReader(a)) aGz, err := cla.Reader(bytes.NewReader(a))
if err != nil { if err != nil {
t.Fatalf("failed to read A") t.Fatalf("failed to read A")
@ -325,7 +356,7 @@ func isSameTarGz(t *testing.T, cla TestingController, a []byte, clb TestingContr
return true return true
} }
func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingController, b []byte) bool { func isSameVersion(t TestingT, cla TestingController, a []byte, clb TestingController, b []byte) bool {
aJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(a), 0, int64(len(a))), cla) aJTOC, _, err := parseStargz(io.NewSectionReader(bytes.NewReader(a), 0, int64(len(a))), cla)
if err != nil { if err != nil {
t.Fatalf("failed to parse A: %v", err) t.Fatalf("failed to parse A: %v", err)
@ -339,7 +370,7 @@ func isSameVersion(t *testing.T, cla TestingController, a []byte, clb TestingCon
return aJTOC.Version == bJTOC.Version return aJTOC.Version == bJTOC.Version
} }
func isSameEntries(t *testing.T, a, b *Reader) bool { func isSameEntries(t TestingT, a, b *Reader) bool {
aroot, ok := a.Lookup("") aroot, ok := a.Lookup("")
if !ok { if !ok {
t.Fatalf("failed to get root of A") t.Fatalf("failed to get root of A")
@ -353,7 +384,7 @@ func isSameEntries(t *testing.T, a, b *Reader) bool {
return contains(t, aEntry, bEntry) && contains(t, bEntry, aEntry) return contains(t, aEntry, bEntry) && contains(t, bEntry, aEntry)
} }
func compressBlob(t *testing.T, src *io.SectionReader, srcCompression int) *io.SectionReader { func compressBlob(t TestingT, src *io.SectionReader, srcCompression int) *io.SectionReader {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
var w io.WriteCloser var w io.WriteCloser
var err error var err error
@ -387,7 +418,7 @@ type stargzEntry struct {
// contains checks if all child entries in "b" are also contained in "a". // contains checks if all child entries in "b" are also contained in "a".
// This function also checks if the files/chunks contain the same contents among "a" and "b". // This function also checks if the files/chunks contain the same contents among "a" and "b".
func contains(t *testing.T, a, b stargzEntry) bool { func contains(t TestingT, a, b stargzEntry) bool {
ae, ar := a.e, a.r ae, ar := a.e, a.r
be, br := b.e, b.r be, br := b.e, b.r
t.Logf("Comparing: %q vs %q", ae.Name, be.Name) t.Logf("Comparing: %q vs %q", ae.Name, be.Name)
@ -498,7 +529,7 @@ func equalEntry(a, b *TOCEntry) bool {
a.Digest == b.Digest a.Digest == b.Digest
} }
func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) { func readOffset(t TestingT, r *io.SectionReader, offset int64, e stargzEntry) ([]byte, int64, bool) {
ce, ok := e.r.ChunkEntryForOffset(e.e.Name, offset) ce, ok := e.r.ChunkEntryForOffset(e.e.Name, offset)
if !ok { if !ok {
return nil, 0, false return nil, 0, false
@ -517,7 +548,7 @@ func readOffset(t *testing.T, r *io.SectionReader, offset int64, e stargzEntry)
return data[:n], offset + ce.ChunkSize, true return data[:n], offset + ce.ChunkSize, true
} }
func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string { func dumpTOCJSON(t TestingT, tocJSON *JTOC) string {
jtocData, err := json.Marshal(*tocJSON) jtocData, err := json.Marshal(*tocJSON)
if err != nil { if err != nil {
t.Fatalf("failed to marshal TOC JSON: %v", err) t.Fatalf("failed to marshal TOC JSON: %v", err)
@ -531,20 +562,19 @@ func dumpTOCJSON(t *testing.T, tocJSON *JTOC) string {
const chunkSize = 3 const chunkSize = 3
// type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, compressionLevel int) type check func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
type check func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory)
// testDigestAndVerify runs specified checks against sample stargz blobs. // testDigestAndVerify runs specified checks against sample stargz blobs.
func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory) { func testDigestAndVerify(t *TestRunner, controllers ...TestingControllerFactory) {
tests := []struct { tests := []struct {
name string name string
tarInit func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) tarInit func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry)
checks []check checks []check
minChunkSize []int minChunkSize []int
}{ }{
{ {
name: "no-regfile", name: "no-regfile",
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) { tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf( return tarOf(
dir("test/"), dir("test/"),
) )
@ -559,7 +589,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
}, },
{ {
name: "small-files", name: "small-files",
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) { tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf( return tarOf(
regDigest(t, "baz.txt", "", dgstMap), regDigest(t, "baz.txt", "", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap), regDigest(t, "foo.txt", "a", dgstMap),
@ -583,7 +613,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
}, },
{ {
name: "big-files", name: "big-files",
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) { tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf( return tarOf(
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap), regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap), regDigest(t, "foo.txt", "a", dgstMap),
@ -607,7 +637,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
{ {
name: "with-non-regfiles", name: "with-non-regfiles",
minChunkSize: []int{0, 64000}, minChunkSize: []int{0, 64000},
tarInit: func(t *testing.T, dgstMap map[string]digest.Digest) (blob []tarEntry) { tarInit: func(t TestingT, dgstMap map[string]digest.Digest) (blob []tarEntry) {
return tarOf( return tarOf(
regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap), regDigest(t, "baz.txt", "bazbazbazbazbazbazbaz", dgstMap),
regDigest(t, "foo.txt", "a", dgstMap), regDigest(t, "foo.txt", "a", dgstMap),
@ -654,7 +684,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
srcTarFormat := srcTarFormat srcTarFormat := srcTarFormat
for _, minChunkSize := range tt.minChunkSize { for _, minChunkSize := range tt.minChunkSize {
minChunkSize := minChunkSize minChunkSize := minChunkSize
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *testing.T) { t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s,minChunkSize=%d", newCL(), prefix, srcTarFormat, minChunkSize), func(t *TestRunner) {
// Get original tar file and chunk digests // Get original tar file and chunk digests
dgstMap := make(map[string]digest.Digest) dgstMap := make(map[string]digest.Digest)
tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat) tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat)
@ -690,7 +720,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingControllerFactory)
// checkStargzTOC checks the TOC JSON of the passed stargz has the expected // checkStargzTOC checks the TOC JSON of the passed stargz has the expected
// digest and contains valid chunks. It walks all entries in the stargz and // digest and contains valid chunks. It walks all entries in the stargz and
// checks all chunk digests stored to the TOC JSON match the actual contents. // checks all chunk digests stored to the TOC JSON match the actual contents.
func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) { func checkStargzTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
sgz, err := Open( sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
WithDecompressors(controller), WithDecompressors(controller),
@ -801,7 +831,7 @@ func checkStargzTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
// checkVerifyTOC checks the verification works for the TOC JSON of the passed // checkVerifyTOC checks the verification works for the TOC JSON of the passed
// stargz. It walks all entries in the stargz and checks the verifications for // stargz. It walks all entries in the stargz and checks the verifications for
// all chunks work. // all chunks work.
func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) { func checkVerifyTOC(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
sgz, err := Open( sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
WithDecompressors(controller), WithDecompressors(controller),
@ -882,9 +912,9 @@ func checkVerifyTOC(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstM
// checkVerifyInvalidTOCEntryFail checks if misconfigured TOC JSON can be // checkVerifyInvalidTOCEntryFail checks if misconfigured TOC JSON can be
// detected during the verification and the verification returns an error. // detected during the verification and the verification returns an error.
func checkVerifyInvalidTOCEntryFail(filename string) check { func checkVerifyInvalidTOCEntryFail(filename string) check {
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) { return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
funcs := map[string]rewriteFunc{ funcs := map[string]rewriteFunc{
"lost digest in a entry": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) { "lost digest in a entry": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
var found bool var found bool
for _, e := range toc.Entries { for _, e := range toc.Entries {
if cleanEntryName(e.Name) == filename { if cleanEntryName(e.Name) == filename {
@ -902,7 +932,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
t.Fatalf("rewrite target not found") t.Fatalf("rewrite target not found")
} }
}, },
"duplicated entry offset": func(t *testing.T, toc *JTOC, sgz *io.SectionReader) { "duplicated entry offset": func(t TestingT, toc *JTOC, sgz *io.SectionReader) {
var ( var (
sampleEntry *TOCEntry sampleEntry *TOCEntry
targetEntry *TOCEntry targetEntry *TOCEntry
@ -929,7 +959,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
} }
for name, rFunc := range funcs { for name, rFunc := range funcs {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *TestRunner) {
newSgz, newTocDigest := rewriteTOCJSON(t, io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), rFunc, controller) newSgz, newTocDigest := rewriteTOCJSON(t, io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), rFunc, controller)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if _, err := io.Copy(buf, newSgz); err != nil { if _, err := io.Copy(buf, newSgz); err != nil {
@ -958,7 +988,7 @@ func checkVerifyInvalidTOCEntryFail(filename string) check {
// checkVerifyInvalidStargzFail checks if the verification detects that the // checkVerifyInvalidStargzFail checks if the verification detects that the
// given stargz file doesn't match to the expected digest and returns error. // given stargz file doesn't match to the expected digest and returns error.
func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check { func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) { return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
cl := newController() cl := newController()
rc, err := Build(invalid, WithChunkSize(chunkSize), WithCompression(cl)) rc, err := Build(invalid, WithChunkSize(chunkSize), WithCompression(cl))
if err != nil { if err != nil {
@ -990,7 +1020,7 @@ func checkVerifyInvalidStargzFail(invalid *io.SectionReader) check {
// checkVerifyBrokenContentFail checks if the verifier detects broken contents // checkVerifyBrokenContentFail checks if the verifier detects broken contents
// that doesn't match to the expected digest and returns error. // that doesn't match to the expected digest and returns error.
func checkVerifyBrokenContentFail(filename string) check { func checkVerifyBrokenContentFail(filename string) check {
return func(t *testing.T, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) { return func(t *TestRunner, sgzData []byte, tocDigest digest.Digest, dgstMap map[string]digest.Digest, controller TestingController, newController TestingControllerFactory) {
// Parse stargz file // Parse stargz file
sgz, err := Open( sgz, err := Open(
io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))), io.NewSectionReader(bytes.NewReader(sgzData), 0, int64(len(sgzData))),
@ -1047,9 +1077,9 @@ func chunkID(name string, offset, size int64) string {
return fmt.Sprintf("%s-%d-%d", cleanEntryName(name), offset, size) return fmt.Sprintf("%s-%d-%d", cleanEntryName(name), offset, size)
} }
type rewriteFunc func(t *testing.T, toc *JTOC, sgz *io.SectionReader) type rewriteFunc func(t TestingT, toc *JTOC, sgz *io.SectionReader)
func rewriteTOCJSON(t *testing.T, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) { func rewriteTOCJSON(t TestingT, sgz *io.SectionReader, rewrite rewriteFunc, controller TestingController) (newSgz io.Reader, tocDigest digest.Digest) {
decodedJTOC, jtocOffset, err := parseStargz(sgz, controller) decodedJTOC, jtocOffset, err := parseStargz(sgz, controller)
if err != nil { if err != nil {
t.Fatalf("failed to extract TOC JSON: %v", err) t.Fatalf("failed to extract TOC JSON: %v", err)
@ -1120,7 +1150,7 @@ func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJT
return decodedJTOC, tocOffset, nil return decodedJTOC, tocOffset, nil
} }
func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) { func testWriteAndOpen(t *TestRunner, controllers ...TestingControllerFactory) {
const content = "Some contents" const content = "Some contents"
invalidUtf8 := "\xff\xfe\xfd" invalidUtf8 := "\xff\xfe\xfd"
@ -1464,7 +1494,7 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingControllerFactory) {
for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} { for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
srcTarFormat := srcTarFormat srcTarFormat := srcTarFormat
for _, lossless := range []bool{true, false} { for _, lossless := range []bool{true, false} {
t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *testing.T) { t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", newCL(), prefix, lossless, srcTarFormat), func(t *TestRunner) {
var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat) var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat)
origTarDgstr := digest.Canonical.Digester() origTarDgstr := digest.Canonical.Digester()
tr = io.TeeReader(tr, origTarDgstr.Hash()) tr = io.TeeReader(tr, origTarDgstr.Hash())
@ -1628,7 +1658,7 @@ func digestFor(content string) string {
type numTOCEntries int type numTOCEntries int
func (n numTOCEntries) check(t *testing.T, r *Reader) { func (n numTOCEntries) check(t TestingT, r *Reader) {
if r.toc == nil { if r.toc == nil {
t.Fatal("nil TOC") t.Fatal("nil TOC")
} }
@ -1648,15 +1678,15 @@ func (n numTOCEntries) check(t *testing.T, r *Reader) {
func checks(s ...stargzCheck) []stargzCheck { return s } func checks(s ...stargzCheck) []stargzCheck { return s }
type stargzCheck interface { type stargzCheck interface {
check(t *testing.T, r *Reader) check(t TestingT, r *Reader)
} }
type stargzCheckFn func(*testing.T, *Reader) type stargzCheckFn func(TestingT, *Reader)
func (f stargzCheckFn) check(t *testing.T, r *Reader) { f(t, r) } func (f stargzCheckFn) check(t TestingT, r *Reader) { f(t, r) }
func maxDepth(max int) stargzCheck { func maxDepth(max int) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
e, ok := r.Lookup("") e, ok := r.Lookup("")
if !ok { if !ok {
t.Fatal("root directory not found") t.Fatal("root directory not found")
@ -1673,7 +1703,7 @@ func maxDepth(max int) stargzCheck {
}) })
} }
func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr error) { func getMaxDepth(t TestingT, e *TOCEntry, current, limit int) (max int, rErr error) {
if current > limit { if current > limit {
return -1, fmt.Errorf("walkMaxDepth: exceeds limit: current:%d > limit:%d", return -1, fmt.Errorf("walkMaxDepth: exceeds limit: current:%d > limit:%d",
current, limit) current, limit)
@ -1695,7 +1725,7 @@ func getMaxDepth(t *testing.T, e *TOCEntry, current, limit int) (max int, rErr e
} }
func hasFileLen(file string, wantLen int) stargzCheck { func hasFileLen(file string, wantLen int) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == file { if ent.Name == file {
if ent.Type != "reg" { if ent.Type != "reg" {
@ -1711,7 +1741,7 @@ func hasFileLen(file string, wantLen int) stargzCheck {
} }
func hasFileXattrs(file, name, value string) stargzCheck { func hasFileXattrs(file, name, value string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == file { if ent.Name == file {
if ent.Type != "reg" { if ent.Type != "reg" {
@ -1738,7 +1768,7 @@ func hasFileXattrs(file, name, value string) stargzCheck {
} }
func hasFileDigest(file string, digest string) stargzCheck { func hasFileDigest(file string, digest string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(file) ent, ok := r.Lookup(file)
if !ok { if !ok {
t.Fatalf("didn't find TOCEntry for file %q", file) t.Fatalf("didn't find TOCEntry for file %q", file)
@ -1750,7 +1780,7 @@ func hasFileDigest(file string, digest string) stargzCheck {
} }
func hasFileContentsWithPreRead(file string, offset int, want string, extra ...chunkInfo) stargzCheck { func hasFileContentsWithPreRead(file string, offset int, want string, extra ...chunkInfo) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
extraMap := make(map[string]chunkInfo) extraMap := make(map[string]chunkInfo)
for _, e := range extra { for _, e := range extra {
extraMap[e.name] = e extraMap[e.name] = e
@ -1797,7 +1827,7 @@ func hasFileContentsWithPreRead(file string, offset int, want string, extra ...c
} }
func hasFileContentsRange(file string, offset int, want string) stargzCheck { func hasFileContentsRange(file string, offset int, want string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
f, err := r.OpenFile(file) f, err := r.OpenFile(file)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -1814,7 +1844,7 @@ func hasFileContentsRange(file string, offset int, want string) stargzCheck {
} }
func hasChunkEntries(file string, wantChunks int) stargzCheck { func hasChunkEntries(file string, wantChunks int) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(file) ent, ok := r.Lookup(file)
if !ok { if !ok {
t.Fatalf("no file for %q", file) t.Fatalf("no file for %q", file)
@ -1858,7 +1888,7 @@ func hasChunkEntries(file string, wantChunks int) stargzCheck {
} }
func entryHasChildren(dir string, want ...string) stargzCheck { func entryHasChildren(dir string, want ...string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
want := append([]string(nil), want...) want := append([]string(nil), want...)
var got []string var got []string
ent, ok := r.Lookup(dir) ent, ok := r.Lookup(dir)
@ -1877,7 +1907,7 @@ func entryHasChildren(dir string, want ...string) stargzCheck {
} }
func hasDir(file string) stargzCheck { func hasDir(file string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) { if ent.Name == cleanEntryName(file) {
if ent.Type != "dir" { if ent.Type != "dir" {
@ -1891,7 +1921,7 @@ func hasDir(file string) stargzCheck {
} }
func hasDirLinkCount(file string, count int) stargzCheck { func hasDirLinkCount(file string, count int) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) { if ent.Name == cleanEntryName(file) {
if ent.Type != "dir" { if ent.Type != "dir" {
@ -1909,7 +1939,7 @@ func hasDirLinkCount(file string, count int) stargzCheck {
} }
func hasMode(file string, mode os.FileMode) stargzCheck { func hasMode(file string, mode os.FileMode) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == cleanEntryName(file) { if ent.Name == cleanEntryName(file) {
if ent.Stat().Mode() != mode { if ent.Stat().Mode() != mode {
@ -1924,7 +1954,7 @@ func hasMode(file string, mode os.FileMode) stargzCheck {
} }
func hasSymlink(file, target string) stargzCheck { func hasSymlink(file, target string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
for _, ent := range r.toc.Entries { for _, ent := range r.toc.Entries {
if ent.Name == file { if ent.Name == file {
if ent.Type != "symlink" { if ent.Type != "symlink" {
@ -1940,7 +1970,7 @@ func hasSymlink(file, target string) stargzCheck {
} }
func lookupMatch(name string, want *TOCEntry) stargzCheck { func lookupMatch(name string, want *TOCEntry) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
e, ok := r.Lookup(name) e, ok := r.Lookup(name)
if !ok { if !ok {
t.Fatalf("failed to Lookup entry %q", name) t.Fatalf("failed to Lookup entry %q", name)
@ -1953,7 +1983,7 @@ func lookupMatch(name string, want *TOCEntry) stargzCheck {
} }
func hasEntryOwner(entry string, owner owner) stargzCheck { func hasEntryOwner(entry string, owner owner) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
ent, ok := r.Lookup(strings.TrimSuffix(entry, "/")) ent, ok := r.Lookup(strings.TrimSuffix(entry, "/"))
if !ok { if !ok {
t.Errorf("entry %q not found", entry) t.Errorf("entry %q not found", entry)
@ -1967,7 +1997,7 @@ func hasEntryOwner(entry string, owner owner) stargzCheck {
} }
func mustSameEntry(files ...string) stargzCheck { func mustSameEntry(files ...string) stargzCheck {
return stargzCheckFn(func(t *testing.T, r *Reader) { return stargzCheckFn(func(t TestingT, r *Reader) {
var first *TOCEntry var first *TOCEntry
for _, f := range files { for _, f := range files {
if first == nil { if first == nil {
@ -2039,7 +2069,7 @@ func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string, format tar.Format
return f(tw, prefix, format) return f(tw, prefix, format)
} }
func buildTar(t *testing.T, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader { func buildTar(t TestingT, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
format := tar.FormatUnknown format := tar.FormatUnknown
for _, opt := range opts { for _, opt := range opts {
switch v := opt.(type) { switch v := opt.(type) {
@ -2248,7 +2278,7 @@ func noPrefetchLandmark() tarEntry {
}) })
} }
func regDigest(t *testing.T, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry { func regDigest(t TestingT, name string, contentStr string, digestMap map[string]digest.Digest) tarEntry {
if digestMap == nil { if digestMap == nil {
t.Fatalf("digest map mustn't be nil") t.Fatalf("digest map mustn't be nil")
} }
@ -2318,7 +2348,7 @@ func (f fileInfoOnlyMode) ModTime() time.Time { return time.Now() }
func (f fileInfoOnlyMode) IsDir() bool { return os.FileMode(f).IsDir() } func (f fileInfoOnlyMode) IsDir() bool { return os.FileMode(f).IsDir() }
func (f fileInfoOnlyMode) Sys() interface{} { return nil } func (f fileInfoOnlyMode) Sys() interface{} { return nil }
func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) { func CheckGzipHasStreams(t TestingT, b []byte, streams []int64) {
if len(streams) == 0 { if len(streams) == 0 {
return // nop return // nop
} }
@ -2356,7 +2386,7 @@ func CheckGzipHasStreams(t *testing.T, b []byte, streams []int64) {
} }
} }
func GzipDiffIDOf(t *testing.T, b []byte) string { func GzipDiffIDOf(t TestingT, b []byte) string {
h := sha256.New() h := sha256.New()
zr, err := gzip.NewReader(bytes.NewReader(b)) zr, err := gzip.NewReader(bytes.NewReader(b))
if err != nil { if err != nil {

View File

@ -30,7 +30,22 @@ import (
// TestZstdChunked tests zstd:chunked // TestZstdChunked tests zstd:chunked
func TestZstdChunked(t *testing.T) { func TestZstdChunked(t *testing.T) {
estargz.CompressionTestSuite(t, testRunner := &estargz.TestRunner{
TestingT: t,
Runner: func(testingT estargz.TestingT, name string, run func(t estargz.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
estargz.CompressionTestSuite(testRunner,
zstdControllerWithLevel(zstd.SpeedFastest), zstdControllerWithLevel(zstd.SpeedFastest),
zstdControllerWithLevel(zstd.SpeedDefault), zstdControllerWithLevel(zstd.SpeedDefault),
zstdControllerWithLevel(zstd.SpeedBetterCompression), zstdControllerWithLevel(zstd.SpeedBetterCompression),
@ -55,7 +70,7 @@ func (zc *zstdController) String() string {
// TestStream tests the passed zstdchunked blob contains the specified list of streams. // TestStream tests the passed zstdchunked blob contains the specified list of streams.
// The last entry of streams must be the offset of footer (len(b) - footerSize). // The last entry of streams must be the offset of footer (len(b) - footerSize).
func (zc *zstdController) TestStreams(t *testing.T, b []byte, streams []int64) { func (zc *zstdController) TestStreams(t estargz.TestingT, b []byte, streams []int64) {
t.Logf("got zstd streams (compressed size: %d):", len(b)) t.Logf("got zstd streams (compressed size: %d):", len(b))
if len(streams) == 0 { if len(streams) == 0 {
@ -122,7 +137,7 @@ func nextIndex(s1, sub []byte) int {
return -1 return -1
} }
func (zc *zstdController) DiffIDOf(t *testing.T, b []byte) string { func (zc *zstdController) DiffIDOf(t estargz.TestingT, b []byte) string {
h := sha256.New() h := sha256.New()
zr, err := zstd.NewReader(bytes.NewReader(b)) zr, err := zstd.NewReader(bytes.NewReader(b))
if err != nil { if err != nil {

View File

@ -139,6 +139,9 @@ type DirectoryCacheConfig struct {
// Direct disables on-memory data cache. Default is true for saving memory usage. // Direct disables on-memory data cache. Default is true for saving memory usage.
Direct bool `toml:"direct" default:"true" json:"direct"` Direct bool `toml:"direct" default:"true" json:"direct"`
// FadvDontNeed forcefully clean fscache pagecache for saving memory. Default is false.
FadvDontNeed bool `toml:"fadv_dontneed" json:"fadv_dontneed"`
} }
// FuseConfig is configuration for FUSE fs. // FuseConfig is configuration for FUSE fs.

View File

@ -235,11 +235,12 @@ func newCache(root string, cacheType string, cfg config.Config) (cache.BlobCache
return cache.NewDirectoryCache( return cache.NewDirectoryCache(
cachePath, cachePath,
cache.DirectoryCacheConfig{ cache.DirectoryCacheConfig{
SyncAdd: dcc.SyncAdd, SyncAdd: dcc.SyncAdd,
DataCache: dCache, DataCache: dCache,
FdCache: fCache, FdCache: fCache,
BufPool: bufPool, BufPool: bufPool,
Direct: dcc.Direct, Direct: dcc.Direct,
FadvDontNeed: dcc.FadvDontNeed,
}, },
) )
} }

View File

@ -30,7 +30,22 @@ import (
) )
func TestLayer(t *testing.T) { func TestLayer(t *testing.T) {
TestSuiteLayer(t, memorymetadata.NewReader) testRunner := &TestRunner{
TestingT: t,
Runner: func(testingT TestingT, name string, run func(t TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
TestSuiteLayer(testRunner, memorymetadata.NewReader)
} }
func TestWaiter(t *testing.T) { func TestWaiter(t *testing.T) {

View File

@ -39,7 +39,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"testing"
"time" "time"
"github.com/containerd/containerd/v2/pkg/reference" "github.com/containerd/containerd/v2/pkg/reference"
@ -76,7 +75,33 @@ type layerConfig struct {
passThroughConfig passThroughConfig passThroughConfig passThroughConfig
} }
func TestSuiteLayer(t *testing.T, store metadata.Store) { // TestingT is the minimal set of testing.T required to run the
// tests defined in TestSuiteLayer. This interface exists to prevent
// leaking the testing package from being exposed outside tests.
type TestingT interface {
Errorf(format string, args ...any)
Fatal(args ...any)
Fatalf(format string, args ...any)
Logf(format string, args ...any)
}
// Runner allows running subtests of TestingT. This exists instead of adding
// a Run method to TestingT interface because the Run implementation of
// testing.T would not satisfy the interface.
type Runner func(t TestingT, name string, fn func(t TestingT))
type TestRunner struct {
TestingT
Runner Runner
}
func (r *TestRunner) Run(name string, run func(*TestRunner)) {
r.Runner(r.TestingT, name, func(t TestingT) {
run(&TestRunner{TestingT: t, Runner: r.Runner})
})
}
func TestSuiteLayer(t *TestRunner, store metadata.Store) {
for _, lc := range []layerConfig{ for _, lc := range []layerConfig{
{ {
name: "default", name: "default",
@ -117,10 +142,14 @@ func TestSuiteLayer(t *testing.T, store metadata.Store) {
var testStateLayerDigest = digest.FromString("dummy") var testStateLayerDigest = digest.FromString("dummy")
func testPrefetch(t *testing.T, factory metadata.Store, lc layerConfig) { func testPrefetch(t *TestRunner, factory metadata.Store, lc layerConfig) {
data64KB := string(tutil.RandomBytes(t, 64000)) randomData, err := tutil.RandomBytes(64000)
if err != nil {
t.Fatalf("failed rand.Read: %v", err)
}
data64KB := string(randomData)
defaultPrefetchSize := int64(10000) defaultPrefetchSize := int64(10000)
landmarkPosition := func(t *testing.T, l *layer) int64 { landmarkPosition := func(t TestingT, l *layer) int64 {
if l.r == nil { if l.r == nil {
t.Fatalf("layer hasn't been verified yet") t.Fatalf("layer hasn't been verified yet")
} }
@ -140,7 +169,7 @@ func testPrefetch(t *testing.T, factory metadata.Store, lc layerConfig) {
in []tutil.TarEntry in []tutil.TarEntry
wantNum int // number of chunks wanted in the cache wantNum int // number of chunks wanted in the cache
wants []string // filenames to compare wants []string // filenames to compare
prefetchSize func(*testing.T, *layer) int64 prefetchSize func(TestingT, *layer) int64
prioritizedFiles []string prioritizedFiles []string
}{ }{
{ {
@ -218,7 +247,7 @@ func testPrefetch(t *testing.T, factory metadata.Store, lc layerConfig) {
for _, tt := range tests { for _, tt := range tests {
for srcCompressionName, srcCompression := range srcCompressions { for srcCompressionName, srcCompression := range srcCompressions {
cl := srcCompression() cl := srcCompression()
t.Run("testPrefetch-"+tt.name+"-"+srcCompressionName+"-"+lc.name, func(t *testing.T) { t.Run("testPrefetch-"+tt.name+"-"+srcCompressionName+"-"+lc.name, func(t *TestRunner) {
chunkSize := sampleChunkSize chunkSize := sampleChunkSize
if tt.chunkSize > 0 { if tt.chunkSize > 0 {
chunkSize = tt.chunkSize chunkSize = tt.chunkSize
@ -345,7 +374,7 @@ func isDup(a, b region) bool {
return b.end >= a.begin return b.end >= a.begin
} }
func newBlob(t *testing.T, sr *io.SectionReader) *sampleBlob { func newBlob(t TestingT, sr *io.SectionReader) *sampleBlob {
return &sampleBlob{ return &sampleBlob{
t: t, t: t,
r: sr, r: sr,
@ -353,7 +382,7 @@ func newBlob(t *testing.T, sr *io.SectionReader) *sampleBlob {
} }
type sampleBlob struct { type sampleBlob struct {
t *testing.T t TestingT
r *io.SectionReader r *io.SectionReader
readCalled bool readCalled bool
@ -418,7 +447,7 @@ const (
lastChunkOffset1 = sampleChunkSize * (int64(len(sampleData1)) / sampleChunkSize) lastChunkOffset1 = sampleChunkSize * (int64(len(sampleData1)) / sampleChunkSize)
) )
func testNodeRead(t *testing.T, factory metadata.Store, lc layerConfig) { func testNodeRead(t *TestRunner, factory metadata.Store, lc layerConfig) {
sizeCond := map[string]int64{ sizeCond := map[string]int64{
"single_chunk": sampleChunkSize - sampleMiddleOffset, "single_chunk": sampleChunkSize - sampleMiddleOffset,
"multi_chunks": sampleChunkSize + sampleMiddleOffset, "multi_chunks": sampleChunkSize + sampleMiddleOffset,
@ -443,7 +472,7 @@ func testNodeRead(t *testing.T, factory metadata.Store, lc layerConfig) {
for fn, filesize := range fileSizeCond { for fn, filesize := range fileSizeCond {
for _, srcCompression := range srcCompressions { for _, srcCompression := range srcCompressions {
cl := srcCompression() cl := srcCompression()
t.Run(fmt.Sprintf("reading_%s_%s_%s_%s_%s", sn, in, bo, fn, lc.name), func(t *testing.T) { t.Run(fmt.Sprintf("reading_%s_%s_%s_%s_%s", sn, in, bo, fn, lc.name), func(t *TestRunner) {
if filesize > int64(len(sampleData1)) { if filesize > int64(len(sampleData1)) {
t.Fatal("sample file size is larger than sample data") t.Fatal("sample file size is larger than sample data")
} }
@ -498,7 +527,7 @@ func testNodeRead(t *testing.T, factory metadata.Store, lc layerConfig) {
} }
} }
func makeNodeReader(t *testing.T, contents []byte, chunkSize int, factory metadata.Store, cl tutil.Compression, lc layerConfig) (_ *file, closeFn func() error) { func makeNodeReader(t TestingT, contents []byte, chunkSize int, factory metadata.Store, cl tutil.Compression, lc layerConfig) (_ *file, closeFn func() error) {
testName := "test" testName := "test"
sr, tocDgst, err := tutil.BuildEStargz( sr, tocDgst, err := tutil.BuildEStargz(
[]tutil.TarEntry{tutil.File(testName, string(contents))}, []tutil.TarEntry{tutil.File(testName, string(contents))},
@ -526,16 +555,20 @@ func makeNodeReader(t *testing.T, contents []byte, chunkSize int, factory metada
return f.(*file), r.Close return f.(*file), r.Close
} }
func testNodes(t *testing.T, factory metadata.Store, lc layerConfig) { func testNodes(t *TestRunner, factory metadata.Store, lc layerConfig) {
for _, o := range []OverlayOpaqueType{OverlayOpaqueAll, OverlayOpaqueTrusted, OverlayOpaqueUser} { for _, o := range []OverlayOpaqueType{OverlayOpaqueAll, OverlayOpaqueTrusted, OverlayOpaqueUser} {
testNodesWithOpaque(t, factory, o, lc) testNodesWithOpaque(t, factory, o, lc)
} }
} }
func testNodesWithOpaque(t *testing.T, factory metadata.Store, opaque OverlayOpaqueType, lc layerConfig) { func testNodesWithOpaque(t *TestRunner, factory metadata.Store, opaque OverlayOpaqueType, lc layerConfig) {
data64KB := string(tutil.RandomBytes(t, 64000)) randomData, err := tutil.RandomBytes(64000)
if err != nil {
t.Fatalf("failed rand.Read: %v", err)
}
data64KB := string(randomData)
hasOpaque := func(entry string) check { hasOpaque := func(entry string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
for _, k := range opaqueXattrs[opaque] { for _, k := range opaqueXattrs[opaque] {
hasNodeXattrs(entry, k, opaqueXattrValue)(t, root, cc, cr) hasNodeXattrs(entry, k, opaqueXattrValue)(t, root, cc, cr)
} }
@ -741,7 +774,7 @@ func testNodesWithOpaque(t *testing.T, factory metadata.Store, opaque OverlayOpa
for _, tt := range tests { for _, tt := range tests {
for _, srcCompression := range srcCompressions { for _, srcCompression := range srcCompressions {
cl := srcCompression() cl := srcCompression()
t.Run(tt.name+"-"+lc.name, func(t *testing.T) { t.Run(tt.name+"-"+lc.name, func(t *TestRunner) {
opts := []tutil.BuildEStargzOption{ opts := []tutil.BuildEStargzOption{
tutil.WithEStargzOptions(estargz.WithCompression(cl)), tutil.WithEStargzOptions(estargz.WithCompression(cl)),
} }
@ -772,7 +805,7 @@ func testNodesWithOpaque(t *testing.T, factory metadata.Store, opaque OverlayOpa
} }
} }
func getRootNode(t *testing.T, r metadata.Reader, opaque OverlayOpaqueType, tocDgst digest.Digest, cc cache.BlobCache, lc layerConfig) *node { func getRootNode(t TestingT, r metadata.Reader, opaque OverlayOpaqueType, tocDgst digest.Digest, cc cache.BlobCache, lc layerConfig) *node {
vr, err := reader.NewReader(r, cc, digest.FromString("")) vr, err := reader.NewReader(r, cc, digest.FromString(""))
if err != nil { if err != nil {
t.Fatalf("failed to create reader: %v", err) t.Fatalf("failed to create reader: %v", err)
@ -806,10 +839,10 @@ func (tb *testBlobState) Refresh(ctx context.Context, host source.RegistryHosts,
} }
func (tb *testBlobState) Close() error { return nil } func (tb *testBlobState) Close() error { return nil }
type check func(*testing.T, *node, cache.BlobCache, *calledReaderAt) type check func(TestingT, *node, cache.BlobCache, *calledReaderAt)
func fileNotExist(file string) check { func fileNotExist(file string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
if _, _, err := getDirentAndNode(t, root, file); err == nil { if _, _, err := getDirentAndNode(t, root, file); err == nil {
t.Errorf("Node %q exists", file) t.Errorf("Node %q exists", file)
} }
@ -817,7 +850,7 @@ func fileNotExist(file string) check {
} }
func hasFileDigest(filename string, digest string) check { func hasFileDigest(filename string, digest string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
_, n, err := getDirentAndNode(t, root, filename) _, n, err := getDirentAndNode(t, root, filename)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", filename, err) t.Fatalf("failed to get node %q: %v", filename, err)
@ -846,7 +879,7 @@ func hasFileDigest(filename string, digest string) check {
} }
func hasSize(name string, size int) check { func hasSize(name string, size int) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
_, n, err := getDirentAndNode(t, root, name) _, n, err := getDirentAndNode(t, root, name)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", name, err) t.Fatalf("failed to get node %q: %v", name, err)
@ -862,7 +895,7 @@ func hasSize(name string, size int) check {
} }
func hasExtraMode(name string, mode os.FileMode) check { func hasExtraMode(name string, mode os.FileMode) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
_, n, err := getDirentAndNode(t, root, name) _, n, err := getDirentAndNode(t, root, name)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", name, err) t.Fatalf("failed to get node %q: %v", name, err)
@ -881,7 +914,7 @@ func hasExtraMode(name string, mode os.FileMode) check {
} }
func hasValidWhiteout(name string) check { func hasValidWhiteout(name string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
ent, n, err := getDirentAndNode(t, root, name) ent, n, err := getDirentAndNode(t, root, name)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", name, err) t.Fatalf("failed to get node %q: %v", name, err)
@ -917,7 +950,7 @@ func hasValidWhiteout(name string) check {
} }
func hasNodeXattrs(entry, name, value string) check { func hasNodeXattrs(entry, name, value string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
_, n, err := getDirentAndNode(t, root, entry) _, n, err := getDirentAndNode(t, root, entry)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", entry, err) t.Fatalf("failed to get node %q: %v", entry, err)
@ -958,7 +991,7 @@ func hasNodeXattrs(entry, name, value string) check {
} }
} }
func hasEntry(t *testing.T, name string, ents fusefs.DirStream) (fuse.DirEntry, bool) { func hasEntry(t TestingT, name string, ents fusefs.DirStream) (fuse.DirEntry, bool) {
for ents.HasNext() { for ents.HasNext() {
de, errno := ents.Next() de, errno := ents.Next()
if errno != 0 { if errno != 0 {
@ -971,8 +1004,8 @@ func hasEntry(t *testing.T, name string, ents fusefs.DirStream) (fuse.DirEntry,
return fuse.DirEntry{}, false return fuse.DirEntry{}, false
} }
func hasStateFile(t *testing.T, id string) check { func hasStateFile(t TestingT, id string) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
// Check the state dir is hidden on OpenDir for "/" // Check the state dir is hidden on OpenDir for "/"
ents, errno := root.Readdir(context.Background()) ents, errno := root.Readdir(context.Background())
@ -1069,7 +1102,7 @@ func hasStateFile(t *testing.T, id string) check {
// getDirentAndNode gets dirent and node at the specified path at once and makes // getDirentAndNode gets dirent and node at the specified path at once and makes
// sure that the both of them exist. // sure that the both of them exist.
func getDirentAndNode(t *testing.T, root *node, path string) (ent fuse.DirEntry, n *fusefs.Inode, err error) { func getDirentAndNode(t TestingT, root *node, path string) (ent fuse.DirEntry, n *fusefs.Inode, err error) {
dir, base := filepath.Split(filepath.Clean(path)) dir, base := filepath.Split(filepath.Clean(path))
// get the target's parent directory. // get the target's parent directory.
@ -1145,7 +1178,7 @@ type chunkInfo struct {
} }
func hasFileContentsWithPreCached(name string, off int64, contents string, extra ...chunkInfo) check { func hasFileContentsWithPreCached(name string, off int64, contents string, extra ...chunkInfo) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
buf := readFile(t, root, name, int64(len(contents)), off) buf := readFile(t, root, name, int64(len(contents)), off)
if len(buf) != len(contents) { if len(buf) != len(contents) {
t.Fatalf("failed to read contents %q (off:%d, want:%q) got %q", name, off, longBytesView([]byte(contents)), longBytesView(buf)) t.Fatalf("failed to read contents %q (off:%d, want:%q) got %q", name, off, longBytesView([]byte(contents)), longBytesView(buf))
@ -1167,7 +1200,7 @@ func hasFileContentsWithPreCached(name string, off int64, contents string, extra
} }
func hasFileContentsOffset(name string, off int64, contents string, fromCache bool) check { func hasFileContentsOffset(name string, off int64, contents string, fromCache bool) check {
return func(t *testing.T, root *node, cc cache.BlobCache, cr *calledReaderAt) { return func(t TestingT, root *node, cc cache.BlobCache, cr *calledReaderAt) {
cr.called = nil // reset test cr.called = nil // reset test
buf := readFile(t, root, name, int64(len(contents)), off) buf := readFile(t, root, name, int64(len(contents)), off)
if len(buf) != len(contents) { if len(buf) != len(contents) {
@ -1189,7 +1222,7 @@ func hasFileContentsOffset(name string, off int64, contents string, fromCache bo
} }
} }
func readFile(t *testing.T, root *node, filename string, size, off int64) []byte { func readFile(t TestingT, root *node, filename string, size, off int64) []byte {
_, n, err := getDirentAndNode(t, root, filename) _, n, err := getDirentAndNode(t, root, filename)
if err != nil { if err != nil {
t.Fatalf("failed to get node %q: %v", filename, err) t.Fatalf("failed to get node %q: %v", filename, err)

View File

@ -29,5 +29,20 @@ import (
) )
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
TestSuiteReader(t, memorymetadata.NewReader) testRunner := &TestRunner{
TestingT: t,
Runner: func(testingT TestingT, name string, run func(t TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
TestSuiteReader(testRunner, memorymetadata.NewReader)
} }

View File

@ -32,7 +32,6 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
"testing"
"time" "time"
"github.com/containerd/stargz-snapshotter/cache" "github.com/containerd/stargz-snapshotter/cache"
@ -64,7 +63,34 @@ var (
MockReadAtOutput = 4194304 MockReadAtOutput = 4194304
) )
func TestSuiteReader(t *testing.T, store metadata.Store) { // TestingT is the minimal set of testing.T required to run the
// tests defined in TestSuiteReader. This interface exists to prevent
// leaking the testing package from being exposed outside tests.
type TestingT interface {
Cleanup(func())
Errorf(format string, args ...any)
Fatal(args ...any)
Fatalf(format string, args ...any)
Logf(format string, args ...any)
}
// Runner allows running subtests of TestingT. This exists instead of adding
// a Run method to TestingT interface because the Run implementation of
// testing.T would not satisfy the interface.
type Runner func(t TestingT, name string, fn func(t TestingT))
type TestRunner struct {
TestingT
Runner Runner
}
func (r *TestRunner) Run(name string, run func(*TestRunner)) {
r.Runner(r.TestingT, name, func(t TestingT) {
run(&TestRunner{TestingT: t, Runner: r.Runner})
})
}
func TestSuiteReader(t *TestRunner, store metadata.Store) {
testFileReadAt(t, store) testFileReadAt(t, store)
testCacheVerify(t, store) testCacheVerify(t, store)
testFailReader(t, store) testFailReader(t, store)
@ -72,7 +98,7 @@ func TestSuiteReader(t *testing.T, store metadata.Store) {
testProcessBatchChunks(t) testProcessBatchChunks(t)
} }
func testFileReadAt(t *testing.T, factory metadata.Store) { func testFileReadAt(t *TestRunner, factory metadata.Store) {
sizeCond := map[string]int64{ sizeCond := map[string]int64{
"single_chunk": sampleChunkSize - sampleMiddleOffset, "single_chunk": sampleChunkSize - sampleMiddleOffset,
"multi_chunks": sampleChunkSize + sampleMiddleOffset, "multi_chunks": sampleChunkSize + sampleMiddleOffset,
@ -109,7 +135,7 @@ func testFileReadAt(t *testing.T, factory metadata.Store) {
for cc, cacheExcept := range cacheCond { for cc, cacheExcept := range cacheCond {
for srcCompressionName, srcCompression := range srcCompressions { for srcCompressionName, srcCompression := range srcCompressions {
srcCompression := srcCompression() srcCompression := srcCompression()
t.Run(fmt.Sprintf("reading_%s_%s_%s_%s_%s_%s", sn, in, bo, fn, cc, srcCompressionName), func(t *testing.T) { t.Run(fmt.Sprintf("reading_%s_%s_%s_%s_%s_%s", sn, in, bo, fn, cc, srcCompressionName), func(t *TestRunner) {
if filesize > int64(len(sampleData1)) { if filesize > int64(len(sampleData1)) {
t.Fatal("sample file size is larger than sample data") t.Fatal("sample file size is larger than sample data")
} }
@ -199,7 +225,7 @@ func testFileReadAt(t *testing.T, factory metadata.Store) {
} }
} }
func newExceptFile(t *testing.T, fr metadata.File, except ...region) metadata.File { func newExceptFile(t TestingT, fr metadata.File, except ...region) metadata.File {
er := exceptFile{fr: fr, t: t} er := exceptFile{fr: fr, t: t}
er.except = map[region]bool{} er.except = map[region]bool{}
for _, reg := range except { for _, reg := range except {
@ -211,7 +237,7 @@ func newExceptFile(t *testing.T, fr metadata.File, except ...region) metadata.Fi
type exceptFile struct { type exceptFile struct {
fr metadata.File fr metadata.File
except map[region]bool except map[region]bool
t *testing.T t TestingT
} }
func (er *exceptFile) ReadAt(p []byte, offset int64) (int, error) { func (er *exceptFile) ReadAt(p []byte, offset int64) (int, error) {
@ -225,7 +251,7 @@ func (er *exceptFile) ChunkEntryForOffset(offset int64) (off int64, size int64,
return er.fr.ChunkEntryForOffset(offset) return er.fr.ChunkEntryForOffset(offset)
} }
func makeFile(t *testing.T, contents []byte, chunkSize int, factory metadata.Store, comp tutil.Compression) (*file, func() error) { func makeFile(t TestingT, contents []byte, chunkSize int, factory metadata.Store, comp tutil.Compression) (*file, func() error) {
testName := "test" testName := "test"
sr, dgst, err := tutil.BuildEStargz([]tutil.TarEntry{ sr, dgst, err := tutil.BuildEStargz([]tutil.TarEntry{
tutil.File(testName, string(contents)), tutil.File(testName, string(contents)),
@ -265,7 +291,7 @@ func makeFile(t *testing.T, contents []byte, chunkSize int, factory metadata.Sto
return f, vr.Close return f, vr.Close
} }
func testCacheVerify(t *testing.T, factory metadata.Store) { func testCacheVerify(t *TestRunner, factory metadata.Store) {
for _, skipVerify := range [2]bool{true, false} { for _, skipVerify := range [2]bool{true, false} {
for _, invalidChunkBeforeVerify := range [2]bool{true, false} { for _, invalidChunkBeforeVerify := range [2]bool{true, false} {
for _, invalidChunkAfterVerify := range [2]bool{true, false} { for _, invalidChunkAfterVerify := range [2]bool{true, false} {
@ -273,7 +299,7 @@ func testCacheVerify(t *testing.T, factory metadata.Store) {
srcCompression := srcCompression() srcCompression := srcCompression()
name := fmt.Sprintf("test_cache_verify_%v_%v_%v_%v", name := fmt.Sprintf("test_cache_verify_%v_%v_%v_%v",
skipVerify, invalidChunkBeforeVerify, invalidChunkAfterVerify, srcCompressionName) skipVerify, invalidChunkBeforeVerify, invalidChunkAfterVerify, srcCompressionName)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *TestRunner) {
sr, tocDgst, err := tutil.BuildEStargz([]tutil.TarEntry{ sr, tocDgst, err := tutil.BuildEStargz([]tutil.TarEntry{
tutil.File("a", sampleData1+"a"), tutil.File("a", sampleData1+"a"),
tutil.File("b", sampleData1+"b"), tutil.File("b", sampleData1+"b"),
@ -483,11 +509,11 @@ func prepareMap(mr metadata.Reader, id uint32, p string) (off2id map[int64]uint3
return off2id, id2path, nil return off2id, id2path, nil
} }
func testFailReader(t *testing.T, factory metadata.Store) { func testFailReader(t *TestRunner, factory metadata.Store) {
testFileName := "test" testFileName := "test"
for srcCompressionName, srcCompression := range srcCompressions { for srcCompressionName, srcCompression := range srcCompressions {
srcCompression := srcCompression() srcCompression := srcCompression()
t.Run(fmt.Sprintf("%v", srcCompressionName), func(t *testing.T) { t.Run(fmt.Sprintf("%v", srcCompressionName), func(t *TestRunner) {
for _, rs := range []bool{true, false} { for _, rs := range []bool{true, false} {
for _, vs := range []bool{true, false} { for _, vs := range []bool{true, false} {
stargzFile, tocDigest, err := tutil.BuildEStargz([]tutil.TarEntry{ stargzFile, tocDigest, err := tutil.BuildEStargz([]tutil.TarEntry{
@ -595,8 +621,12 @@ func (bev *testChunkVerifier) verifier(id uint32, chunkDigest string) (digest.Ve
return &testVerifier{bev.success}, nil return &testVerifier{bev.success}, nil
} }
func testPreReader(t *testing.T, factory metadata.Store) { func testPreReader(t *TestRunner, factory metadata.Store) {
data64KB := string(tutil.RandomBytes(t, 64000)) randomData, err := tutil.RandomBytes(64000)
if err != nil {
t.Fatalf("failed rand.Read: %v", err)
}
data64KB := string(randomData)
tests := []struct { tests := []struct {
name string name string
chunkSize int chunkSize int
@ -666,7 +696,7 @@ func testPreReader(t *testing.T, factory metadata.Store) {
for _, tt := range tests { for _, tt := range tests {
for srcCompresionName, srcCompression := range srcCompressions { for srcCompresionName, srcCompression := range srcCompressions {
srcCompression := srcCompression() srcCompression := srcCompression()
t.Run(tt.name+"-"+srcCompresionName, func(t *testing.T) { t.Run(tt.name+"-"+srcCompresionName, func(t *TestRunner) {
opts := []tutil.BuildEStargzOption{ opts := []tutil.BuildEStargzOption{
tutil.WithEStargzOptions(estargz.WithCompression(srcCompression)), tutil.WithEStargzOptions(estargz.WithCompression(srcCompression)),
} }
@ -705,7 +735,7 @@ func testPreReader(t *testing.T, factory metadata.Store) {
} }
} }
type check func(*testing.T, *reader, *calledReaderAt) type check func(TestingT, *reader, *calledReaderAt)
type chunkInfo struct { type chunkInfo struct {
name string name string
@ -715,7 +745,7 @@ type chunkInfo struct {
} }
func hasFileContentsOffset(name string, off int64, contents string, fromCache bool) check { func hasFileContentsOffset(name string, off int64, contents string, fromCache bool) check {
return func(t *testing.T, r *reader, cr *calledReaderAt) { return func(t TestingT, r *reader, cr *calledReaderAt) {
tid, err := lookup(r, name) tid, err := lookup(r, name)
if err != nil { if err != nil {
t.Fatalf("failed to lookup %q", name) t.Fatalf("failed to lookup %q", name)
@ -750,7 +780,7 @@ func hasFileContentsOffset(name string, off int64, contents string, fromCache bo
} }
func hasFileContentsWithPreCached(name string, off int64, contents string, extra ...chunkInfo) check { func hasFileContentsWithPreCached(name string, off int64, contents string, extra ...chunkInfo) check {
return func(t *testing.T, r *reader, cr *calledReaderAt) { return func(t TestingT, r *reader, cr *calledReaderAt) {
tid, err := lookup(r, name) tid, err := lookup(r, name)
if err != nil { if err != nil {
t.Fatalf("failed to lookup %q", name) t.Fatalf("failed to lookup %q", name)
@ -870,7 +900,7 @@ func (f *mockFile) ReadAt(p []byte, offset int64) (int, error) {
return MockReadAtOutput, nil return MockReadAtOutput, nil
} }
func testProcessBatchChunks(t *testing.T) { func testProcessBatchChunks(t *TestRunner) {
type testCase struct { type testCase struct {
name string name string
setupMock func() setupMock func()
@ -878,7 +908,7 @@ func testProcessBatchChunks(t *testing.T) {
expectErrorInHoles bool expectErrorInHoles bool
} }
runTest := func(t *testing.T, tc testCase) { runTest := func(t TestingT, tc testCase) {
if tc.setupMock != nil { if tc.setupMock != nil {
tc.setupMock() tc.setupMock()
} }
@ -1000,7 +1030,7 @@ func testProcessBatchChunks(t *testing.T) {
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *TestRunner) {
runTest(t, tc) runTest(t, tc)
}) })
} }

34
go.mod
View File

@ -6,7 +6,7 @@ toolchain go1.24.2
require ( require (
github.com/containerd/console v1.0.5 github.com/containerd/console v1.0.5
github.com/containerd/containerd/v2 v2.1.3 github.com/containerd/containerd/v2 v2.1.4
github.com/containerd/continuity v0.4.5 github.com/containerd/continuity v0.4.5
github.com/containerd/errdefs v1.0.0 github.com/containerd/errdefs v1.0.0
github.com/containerd/log v0.1.0 github.com/containerd/log v0.1.0
@ -14,7 +14,7 @@ require (
github.com/containerd/plugin v1.0.0 github.com/containerd/plugin v1.0.0
github.com/containerd/stargz-snapshotter/estargz v0.17.0 github.com/containerd/stargz-snapshotter/estargz v0.17.0
github.com/distribution/reference v0.6.0 github.com/distribution/reference v0.6.0
github.com/docker/cli v28.3.2+incompatible github.com/docker/cli v28.3.3+incompatible
github.com/docker/go-metrics v0.0.1 github.com/docker/go-metrics v0.0.1
github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.2
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
@ -25,13 +25,13 @@ require (
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1 github.com/opencontainers/image-spec v1.1.1
github.com/opencontainers/runtime-spec v1.2.1 github.com/opencontainers/runtime-spec v1.2.1
github.com/prometheus/client_golang v1.22.0 github.com/prometheus/client_golang v1.23.0
github.com/rs/xid v1.6.0 github.com/rs/xid v1.6.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
go.etcd.io/bbolt v1.4.2 go.etcd.io/bbolt v1.4.2
golang.org/x/sync v0.16.0 golang.org/x/sync v0.16.0
golang.org/x/sys v0.34.0 golang.org/x/sys v0.34.0
google.golang.org/grpc v1.73.0 google.golang.org/grpc v1.74.2
k8s.io/api v0.33.3 k8s.io/api v0.33.3
k8s.io/apimachinery v0.33.3 k8s.io/apimachinery v0.33.3
k8s.io/client-go v0.33.3 k8s.io/client-go v0.33.3
@ -47,7 +47,7 @@ require (
github.com/containerd/containerd/api v1.9.0 // indirect github.com/containerd/containerd/api v1.9.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/go-cni v1.1.12 // indirect github.com/containerd/go-cni v1.1.13 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/containernetworking/cni v1.3.0 // indirect github.com/containernetworking/cni v1.3.0 // indirect
@ -57,7 +57,7 @@ require (
github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect
@ -82,9 +82,9 @@ require (
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/pflag v1.0.6 // indirect
@ -96,15 +96,15 @@ require (
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/net v0.38.0 // indirect golang.org/x/net v0.40.0 // indirect
golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/term v0.30.0 // indirect golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.9.0 // indirect golang.org/x/time v0.9.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect

76
go.sum
View File

@ -23,8 +23,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q
github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0= github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI= github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
github.com/containerd/containerd/v2 v2.1.3 h1:eMD2SLcIQPdMlnlNF6fatlrlRLAeDaiGPGwmRKLZKNs= github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
github.com/containerd/containerd/v2 v2.1.3/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM= github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
@ -33,8 +33,8 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY=
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
github.com/containerd/go-cni v1.1.12 h1:wm/5VD/i255hjM4uIZjBRiEQ7y98W9ACy/mHeLi4+94= github.com/containerd/go-cni v1.1.13 h1:eFSGOKlhoYNxpJ51KRIMHZNlg5UgocXEIEBGkY7Hnis=
github.com/containerd/go-cni v1.1.12/go.mod h1:+jaqRBdtW5faJxj2Qwg1Of7GsV66xcvnCx4mSJtUlxU= github.com/containerd/go-cni v1.1.13/go.mod h1:nTieub0XDRmvCZ9VI/SBG6PyqT95N4FIhxsauF1vSBI=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E= github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
@ -55,8 +55,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v28.3.2+incompatible h1:mOt9fcLE7zaACbxW1GeS65RI67wIJrTnqS3hP2huFsY= github.com/docker/cli v28.3.3+incompatible h1:fp9ZHAr1WWPGdIWBM1b3zLtgCF+83gRdVMTJsUeiyAo=
github.com/docker/cli v28.3.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
@ -77,8 +77,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
@ -212,22 +212,22 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
@ -275,16 +275,16 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -308,11 +308,11 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -332,12 +332,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -359,15 +359,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@ -5,10 +5,10 @@ go 1.23.0
toolchain go1.24.1 toolchain go1.24.1
require ( require (
github.com/containerd/containerd/v2 v2.1.3 github.com/containerd/containerd/v2 v2.1.4
github.com/containerd/platforms v1.0.0-rc.1 github.com/containerd/platforms v1.0.0-rc.1
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/multiformats/go-multiaddr v0.16.0 github.com/multiformats/go-multiaddr v0.16.1
github.com/opencontainers/image-spec v1.1.1 github.com/opencontainers/image-spec v1.1.1
) )
@ -27,7 +27,7 @@ require (
github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/distribution/reference v0.6.0 // indirect github.com/distribution/reference v0.6.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@ -57,17 +57,17 @@ require (
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.38.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.38.0 // indirect golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.16.0 // indirect golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/grpc v1.73.0 // indirect google.golang.org/grpc v1.74.2 // indirect
google.golang.org/protobuf v1.36.6 // indirect google.golang.org/protobuf v1.36.6 // indirect
lukechampine.com/blake3 v1.2.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect
) )

View File

@ -13,8 +13,8 @@ github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJ
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0= github.com/containerd/containerd/api v1.9.0 h1:HZ/licowTRazus+wt9fM6r/9BQO7S0vD5lMcWspGIg0=
github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI= github.com/containerd/containerd/api v1.9.0/go.mod h1:GhghKFmTR3hNtyznBoQ0EMWr9ju5AqHjcZPsSpTKutI=
github.com/containerd/containerd/v2 v2.1.3 h1:eMD2SLcIQPdMlnlNF6fatlrlRLAeDaiGPGwmRKLZKNs= github.com/containerd/containerd/v2 v2.1.4 h1:/hXWjiSFd6ftrBOBGfAZ6T30LJcx1dBjdKEeI8xucKQ=
github.com/containerd/containerd/v2 v2.1.3/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM= github.com/containerd/containerd/v2 v2.1.4/go.mod h1:8C5QV9djwsYDNhxfTCFjWtTBZrqjditQ4/ghHSYjnHM=
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
@ -45,8 +45,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@ -114,8 +114,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= github.com/multiformats/go-multiaddr v0.16.1 h1:fgJ0Pitow+wWXzN9do+1b8Pyjmo8m5WhGfzpL82MpCw=
github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr v0.16.1/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
@ -162,22 +162,22 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
@ -195,8 +195,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -215,8 +215,8 @@ golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -234,15 +234,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@ -25,7 +25,21 @@ import (
) )
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
testutil.TestReader(t, readerFactory) testRunner := &testutil.TestRunner{
TestingT: t,
Runner: func(testingT testutil.TestingT, name string, run func(t testutil.TestingT)) {
tt, ok := testingT.(*testing.T)
if !ok {
testingT.Fatal("TestingT is not a *testing.T")
return
}
tt.Run(name, func(t *testing.T) {
run(t)
})
},
}
testutil.TestReader(testRunner, readerFactory)
} }
func readerFactory(sr *io.SectionReader, opts ...metadata.Option) (testutil.TestableReader, error) { func readerFactory(sr *io.SectionReader, opts ...metadata.Option) (testutil.TestableReader, error) {

View File

@ -26,7 +26,6 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"strings" "strings"
"testing"
"time" "time"
"github.com/containerd/stargz-snapshotter/estargz" "github.com/containerd/stargz-snapshotter/estargz"
@ -60,11 +59,41 @@ type TestableReader interface {
NumOfNodes() (i int, _ error) NumOfNodes() (i int, _ error)
} }
// TestingT is the minimal set of testing.T required to run the
// tests defined in TestReader. This interface exists to prevent
// leaking the testing package from being exposed outside tests.
type TestingT interface {
Errorf(format string, args ...any)
Fatal(args ...any)
Fatalf(format string, args ...any)
Logf(format string, args ...any)
}
// Runner allows running subtests of TestingT. This exists instead of adding
// a Run method to TestingT interface because the Run implementation of
// testing.T would not satisfy the interface.
type Runner func(t TestingT, name string, fn func(t TestingT))
type TestRunner struct {
TestingT
Runner Runner
}
func (r *TestRunner) Run(name string, run func(*TestRunner)) {
r.Runner(r.TestingT, name, func(t TestingT) {
run(&TestRunner{TestingT: t, Runner: r.Runner})
})
}
// TestReader tests Reader returns correct file metadata. // TestReader tests Reader returns correct file metadata.
func TestReader(t *testing.T, factory ReaderFactory) { func TestReader(t *TestRunner, factory ReaderFactory) {
sampleTime := time.Now().Truncate(time.Second) sampleTime := time.Now().Truncate(time.Second)
sampleText := "qwer" + "tyui" + "opas" + "dfgh" + "jk" sampleText := "qwer" + "tyui" + "opas" + "dfgh" + "jk"
data64KB := string(tutil.RandomBytes(t, 64000)) randomData, err := tutil.RandomBytes(64000)
if err != nil {
t.Fatalf("failed rand.Read: %v", err)
}
data64KB := string(randomData)
tests := []struct { tests := []struct {
name string name string
chunkSize int chunkSize int
@ -286,7 +315,8 @@ func TestReader(t *testing.T, factory ReaderFactory) {
prefix := prefix prefix := prefix
for srcCompresionName, srcCompression := range srcCompressions { for srcCompresionName, srcCompression := range srcCompressions {
srcCompression := srcCompression() srcCompression := srcCompression()
t.Run(tt.name+"-"+srcCompresionName, func(t *testing.T) {
t.Run(tt.name+"-"+srcCompresionName, func(t *TestRunner) {
opts := []tutil.BuildEStargzOption{ opts := []tutil.BuildEStargzOption{
tutil.WithBuildTarOptions(tutil.WithPrefix(prefix)), tutil.WithBuildTarOptions(tutil.WithPrefix(prefix)),
tutil.WithEStargzOptions(estargz.WithCompression(srcCompression)), tutil.WithEStargzOptions(estargz.WithCompression(srcCompression)),
@ -343,7 +373,7 @@ func TestReader(t *testing.T, factory ReaderFactory) {
} }
} }
t.Run("clone-id-stability", func(t *testing.T) { t.Run("clone-id-stability", func(t *TestRunner) {
var mapEntries func(r TestableReader, id uint32, m map[string]uint32) (map[string]uint32, error) var mapEntries func(r TestableReader, id uint32, m map[string]uint32) (map[string]uint32, error)
mapEntries = func(r TestableReader, id uint32, m map[string]uint32) (map[string]uint32, error) { mapEntries = func(r TestableReader, id uint32, m map[string]uint32) (map[string]uint32, error) {
if m == nil { if m == nil {
@ -426,7 +456,7 @@ func newCalledTelemetry() (telemetry *metadata.Telemetry, check func() error) {
} }
} }
func dumpNodes(t *testing.T, r TestableReader, id uint32, level int) { func dumpNodes(t TestingT, r TestableReader, id uint32, level int) {
if err := r.ForeachChild(id, func(name string, id uint32, mode os.FileMode) bool { if err := r.ForeachChild(id, func(name string, id uint32, mode os.FileMode) bool {
ind := "" ind := ""
for i := 0; i < level; i++ { for i := 0; i < level; i++ {
@ -440,10 +470,10 @@ func dumpNodes(t *testing.T, r TestableReader, id uint32, level int) {
} }
} }
type check func(*testing.T, TestableReader) type check func(TestingT, TestableReader)
func numOfNodes(want int) check { func numOfNodes(want int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
i, err := r.NumOfNodes() i, err := r.NumOfNodes()
if err != nil { if err != nil {
t.Errorf("num of nodes: %v", err) t.Errorf("num of nodes: %v", err)
@ -455,7 +485,7 @@ func numOfNodes(want int) check {
} }
func numOfChunks(name string, num int) check { func numOfChunks(name string, num int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
nr, ok := r.(interface { nr, ok := r.(interface {
NumOfChunks(id uint32) (i int, _ error) NumOfChunks(id uint32) (i int, _ error)
}) })
@ -479,7 +509,7 @@ func numOfChunks(name string, num int) check {
} }
func sameNodes(n string, nodes ...string) check { func sameNodes(n string, nodes ...string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, n) id, err := lookup(r, n)
if err != nil { if err != nil {
t.Errorf("failed to lookup %q: %v", n, err) t.Errorf("failed to lookup %q: %v", n, err)
@ -499,7 +529,7 @@ func sameNodes(n string, nodes ...string) check {
} }
func linkName(name string, linkName string) check { func linkName(name string, linkName string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("failed to lookup %q: %v", name, err) t.Errorf("failed to lookup %q: %v", name, err)
@ -522,7 +552,7 @@ func linkName(name string, linkName string) check {
} }
func hasNumLink(name string, numLink int) check { func hasNumLink(name string, numLink int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("failed to lookup %q: %v", name, err) t.Errorf("failed to lookup %q: %v", name, err)
@ -541,7 +571,7 @@ func hasNumLink(name string, numLink int) check {
} }
func hasDirChildren(name string, children ...string) check { func hasDirChildren(name string, children ...string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("failed to lookup %q: %v", name, err) t.Errorf("failed to lookup %q: %v", name, err)
@ -576,7 +606,7 @@ func hasDirChildren(name string, children ...string) check {
} }
func hasChardev(name string, maj, min int) check { func hasChardev(name string, maj, min int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find chardev %q: %v", name, err) t.Errorf("cannot find chardev %q: %v", name, err)
@ -599,7 +629,7 @@ func hasChardev(name string, maj, min int) check {
} }
func hasBlockdev(name string, maj, min int) check { func hasBlockdev(name string, maj, min int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find blockdev %q: %v", name, err) t.Errorf("cannot find blockdev %q: %v", name, err)
@ -622,7 +652,7 @@ func hasBlockdev(name string, maj, min int) check {
} }
func hasFifo(name string) check { func hasFifo(name string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find blockdev %q: %v", name, err) t.Errorf("cannot find blockdev %q: %v", name, err)
@ -641,7 +671,7 @@ func hasFifo(name string) check {
} }
func hasFile(name, content string, size int64) check { func hasFile(name, content string, size int64) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find file %q: %v", name, err) t.Errorf("cannot find file %q: %v", name, err)
@ -686,7 +716,7 @@ type chunkInfo struct {
} }
func hasFileContentsWithPreRead(name string, off int64, contents string, extra ...chunkInfo) check { func hasFileContentsWithPreRead(name string, off int64, contents string, extra ...chunkInfo) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
extraMap := make(map[uint32]chunkInfo) extraMap := make(map[uint32]chunkInfo)
for _, e := range extra { for _, e := range extra {
id, err := lookup(r, e.name) id, err := lookup(r, e.name)
@ -753,7 +783,7 @@ func hasFileContentsWithPreRead(name string, off int64, contents string, extra .
} }
func hasFileContentsOffset(name string, off int64, contents string) check { func hasFileContentsOffset(name string, off int64, contents string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("failed to lookup %q: %v", name, err) t.Errorf("failed to lookup %q: %v", name, err)
@ -782,7 +812,7 @@ func hasFileContentsOffset(name string, off int64, contents string) check {
} }
func hasMode(name string, mode os.FileMode) check { func hasMode(name string, mode os.FileMode) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find file %q: %v", name, err) t.Errorf("cannot find file %q: %v", name, err)
@ -801,7 +831,7 @@ func hasMode(name string, mode os.FileMode) check {
} }
func hasOwner(name string, uid, gid int) check { func hasOwner(name string, uid, gid int) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find file %q: %v", name, err) t.Errorf("cannot find file %q: %v", name, err)
@ -820,7 +850,7 @@ func hasOwner(name string, uid, gid int) check {
} }
func hasModTime(name string, modTime time.Time) check { func hasModTime(name string, modTime time.Time) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find file %q: %v", name, err) t.Errorf("cannot find file %q: %v", name, err)
@ -840,7 +870,7 @@ func hasModTime(name string, modTime time.Time) check {
} }
func hasXattrs(name string, xattrs map[string]string) check { func hasXattrs(name string, xattrs map[string]string) check {
return func(t *testing.T, r TestableReader) { return func(t TestingT, r TestableReader) {
id, err := lookup(r, name) id, err := lookup(r, name)
if err != nil { if err != nil {
t.Errorf("cannot find file %q: %v", name, err) t.Errorf("cannot find file %q: %v", name, err)

View File

@ -760,10 +760,13 @@ func (o *snapshotter) restoreRemoteSnapshot(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := os.Mkdir(filepath.Join(o.root, "snapshots", id), 0700); err != nil { if err := os.Mkdir(filepath.Join(o.root, "snapshots", id), 0700); err != nil && !os.IsExist(err) {
return err return err
} }
return os.Mkdir(o.upperPath(id), 0755) if err := os.Mkdir(o.upperPath(id), 0755); err != nil && !os.IsExist(err) {
return err
}
return nil
}(); err != nil { }(); err != nil {
return fmt.Errorf("failed to create remote snapshot directory: %s: %w", info.Name, err) return fmt.Errorf("failed to create remote snapshot directory: %s: %w", info.Name, err)
} }

View File

@ -18,14 +18,13 @@ package testutil
import ( import (
"crypto/rand" "crypto/rand"
"testing"
) )
// RandomBytes returns the specified number of random bytes // RandomBytes returns the specified number of random bytes
func RandomBytes(t *testing.T, n int) []byte { func RandomBytes(n int) ([]byte, error) {
b := make([]byte, n) b := make([]byte, n)
if _, err := rand.Read(b); err != nil { if _, err := rand.Read(b); err != nil {
t.Fatalf("failed rand.Read: %v", err) return nil, err
} }
return b return b, nil
} }