Showing preview only (2,492K chars total). Download the full file or copy to clipboard to get everything.
Repository: containerd/nydus-snapshotter
Branch: main
Commit: 389bddbab0da
Files: 271
Total size: 2.3 MB
Directory structure:
gitextract_bo46r8c0/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ ├── feature-request.yml
│ │ └── improvement-report.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── codecov.yml
│ └── workflows/
│ ├── ci.yml
│ ├── e2e.yml
│ ├── k8s-e2e-run.yml
│ ├── k8s-e2e.yml
│ ├── optimizer.yml
│ └── release.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── MAINTAINERS
├── Makefile
├── README.md
├── cmd/
│ ├── containerd-nydus-grpc/
│ │ ├── main.go
│ │ └── snapshotter.go
│ ├── converter/
│ │ └── main.go
│ ├── nydus-overlayfs/
│ │ ├── main.go
│ │ └── main_test.go
│ ├── optimizer-nri-plugin/
│ │ └── main.go
│ └── prefetchfiles-nri-plugin/
│ └── main.go
├── config/
│ ├── config.go
│ ├── config_test.go
│ ├── daemonconfig/
│ │ ├── daemonconfig.go
│ │ ├── daemonconfig_test.go
│ │ ├── fscache.go
│ │ ├── fuse.go
│ │ ├── mirror_select_test.go
│ │ ├── mirrors.go
│ │ └── mirrors_test.go
│ ├── default.go
│ └── global.go
├── docs/
│ ├── configure_nydus.md
│ ├── crictl_dry_run.md
│ ├── index_detection.md
│ ├── optimize_nydus_image.md
│ ├── registry_authentication.md
│ ├── run_nydus_in_kubernetes.md
│ ├── setup_snapshotter_by_daemonset.md
│ └── tarfs.md
├── export/
│ └── snapshotter/
│ └── snapshotter.go
├── go.mod
├── go.sum
├── integration/
│ ├── Dockerfile
│ └── entrypoint.sh
├── internal/
│ ├── constant/
│ │ └── values.go
│ ├── flags/
│ │ ├── flags.go
│ │ └── flags_test.go
│ └── logging/
│ ├── setup.go
│ └── setup_test.go
├── misc/
│ ├── example/
│ │ ├── 10-containerd-net.conflist
│ │ ├── README.md
│ │ ├── container.yaml
│ │ ├── containerd-config.toml
│ │ ├── containerd-test-config.toml
│ │ ├── crictl.yaml
│ │ ├── optimizer-nri-plugin.conf
│ │ └── pod.yaml
│ ├── nri-prefetch/
│ │ └── prefetchConfig.toml
│ ├── optimizer/
│ │ ├── containerd-config.toml
│ │ ├── crictl.yaml
│ │ ├── nginx.yaml
│ │ ├── sandbox.yaml
│ │ └── script/
│ │ ├── entrypoint.sh
│ │ └── file_list.txt
│ └── snapshotter/
│ ├── Dockerfile
│ ├── base/
│ │ ├── kustomization.yaml
│ │ └── nydus-snapshotter.yaml
│ ├── config-blockdev.toml
│ ├── config-proxy.toml
│ ├── config.toml
│ ├── nydus-snapshotter-rbac.yaml
│ ├── nydus-snapshotter.fscache.service
│ ├── nydus-snapshotter.fusedev.service
│ ├── nydus-snapshotter.service
│ ├── nydusd-config-localfs.json
│ ├── nydusd-config.fscache.json
│ ├── nydusd-config.fusedev.json
│ ├── overlays/
│ │ ├── k3s/
│ │ │ ├── kustomization.yaml
│ │ │ └── mount_k3s_conf.yaml
│ │ └── rke2/
│ │ ├── kustomization.yaml
│ │ └── mount_rke2_conf.yaml
│ └── snapshotter.sh
├── pkg/
│ ├── auth/
│ │ ├── cri.go
│ │ ├── cri_test.go
│ │ ├── docker.go
│ │ ├── docker_test.go
│ │ ├── keychain.go
│ │ ├── kubelet.go
│ │ ├── kubelet_test.go
│ │ ├── kubesecret.go
│ │ ├── kubesecret_test.go
│ │ ├── labels.go
│ │ ├── labels_test.go
│ │ ├── provider.go
│ │ ├── renewal.go
│ │ └── renewal_test.go
│ ├── backend/
│ │ ├── backend.go
│ │ ├── localfs.go
│ │ ├── oss.go
│ │ ├── s3.go
│ │ └── s3_test.go
│ ├── cache/
│ │ ├── manager.go
│ │ └── manager_test.go
│ ├── cgroup/
│ │ ├── cgroup.go
│ │ ├── manager.go
│ │ ├── v1/
│ │ │ └── v1.go
│ │ └── v2/
│ │ └── v2.go
│ ├── converter/
│ │ ├── constant.go
│ │ ├── convert_unix.go
│ │ ├── convert_windows.go
│ │ ├── cs_proxy_unix.go
│ │ ├── merge_unix_test.go
│ │ ├── reconvert_unix.go
│ │ ├── reconvert_unix_test.go
│ │ ├── tool/
│ │ │ ├── builder.go
│ │ │ ├── feature.go
│ │ │ └── feature_test.go
│ │ ├── types.go
│ │ └── utils.go
│ ├── daemon/
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── command/
│ │ │ ├── command.go
│ │ │ └── command_builder_test.go
│ │ ├── config.go
│ │ ├── daemon.go
│ │ ├── daemon_test.go
│ │ ├── idgen.go
│ │ └── types/
│ │ └── types.go
│ ├── encryption/
│ │ └── encryption.go
│ ├── errdefs/
│ │ └── errors.go
│ ├── fanotify/
│ │ ├── conn/
│ │ │ └── conn.go
│ │ └── fanotify.go
│ ├── filesystem/
│ │ ├── config.go
│ │ ├── fs.go
│ │ ├── index_adaptor.go
│ │ ├── referer_adaptor.go
│ │ ├── stargz_adaptor.go
│ │ └── tarfs_adaptor.go
│ ├── index/
│ │ ├── detector.go
│ │ ├── detector_test.go
│ │ ├── manager.go
│ │ └── manager_test.go
│ ├── label/
│ │ └── label.go
│ ├── layout/
│ │ └── layout.go
│ ├── manager/
│ │ ├── daemon_adaptor.go
│ │ ├── daemon_cache.go
│ │ ├── daemon_cache_test.go
│ │ ├── daemon_event.go
│ │ ├── manager.go
│ │ ├── monitor.go
│ │ ├── monitor_test.go
│ │ └── store.go
│ ├── metrics/
│ │ ├── collector/
│ │ │ ├── cache.go
│ │ │ ├── collector.go
│ │ │ ├── daemon.go
│ │ │ ├── fs.go
│ │ │ └── snapshotter.go
│ │ ├── data/
│ │ │ ├── auth.go
│ │ │ ├── cache.go
│ │ │ ├── daemon.go
│ │ │ ├── fs.go
│ │ │ ├── labels.go
│ │ │ └── snapshotter.go
│ │ ├── listener.go
│ │ ├── registry/
│ │ │ └── registry.go
│ │ ├── serve.go
│ │ ├── tool/
│ │ │ ├── common.go
│ │ │ ├── stat.go
│ │ │ └── stat_test.go
│ │ └── types/
│ │ ├── ttl/
│ │ │ ├── gauge.go
│ │ │ └── gauge_test.go
│ │ └── types.go
│ ├── pprof/
│ │ └── listener.go
│ ├── prefetch/
│ │ └── prefetch.go
│ ├── rafs/
│ │ └── rafs.go
│ ├── referrer/
│ │ ├── manager.go
│ │ └── referrer.go
│ ├── remote/
│ │ ├── remote.go
│ │ ├── remote_test.go
│ │ ├── remotes/
│ │ │ ├── docker/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── fetch.go
│ │ │ │ │ ├── fetch_test.go
│ │ │ │ │ ├── parse.go
│ │ │ │ │ └── parse_test.go
│ │ │ │ ├── authorizer.go
│ │ │ │ ├── config/
│ │ │ │ │ ├── config_unix.go
│ │ │ │ │ ├── config_windows.go
│ │ │ │ │ ├── docker_fuzzer_internal.go
│ │ │ │ │ ├── hosts.go
│ │ │ │ │ └── hosts_test.go
│ │ │ │ ├── converter.go
│ │ │ │ ├── converter_fuzz.go
│ │ │ │ ├── errcode.go
│ │ │ │ ├── errdesc.go
│ │ │ │ ├── fetcher.go
│ │ │ │ ├── fetcher_fuzz.go
│ │ │ │ ├── fetcher_test.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── handler_test.go
│ │ │ │ ├── httpreadseeker.go
│ │ │ │ ├── pusher.go
│ │ │ │ ├── pusher_test.go
│ │ │ │ ├── referrers.go
│ │ │ │ ├── registry.go
│ │ │ │ ├── registry_test.go
│ │ │ │ ├── resolver.go
│ │ │ │ ├── resolver_test.go
│ │ │ │ ├── schema1/
│ │ │ │ │ └── converter.go
│ │ │ │ ├── scope.go
│ │ │ │ ├── scope_test.go
│ │ │ │ └── status.go
│ │ │ ├── errors/
│ │ │ │ └── errors.go
│ │ │ ├── handlers.go
│ │ │ ├── handlers_test.go
│ │ │ └── resolver.go
│ │ └── unpack.go
│ ├── resolve/
│ │ └── resolver.go
│ ├── signature/
│ │ └── signature.go
│ ├── snapshot/
│ │ └── storage.go
│ ├── stargz/
│ │ ├── resolver.go
│ │ ├── resolver_test.go
│ │ └── testdata/
│ │ ├── config/
│ │ │ └── nydus.json
│ │ └── stargz.index.json
│ ├── store/
│ │ ├── daemonstore.go
│ │ ├── database.go
│ │ ├── database_compat.go
│ │ └── database_test.go
│ ├── supervisor/
│ │ ├── supervisor.go
│ │ └── supervisor_test.go
│ ├── system/
│ │ ├── system.go
│ │ └── system_test.go
│ ├── tarfs/
│ │ └── tarfs.go
│ └── utils/
│ ├── display/
│ │ └── display.go
│ ├── erofs/
│ │ └── erofs.go
│ ├── file/
│ │ └── file.go
│ ├── mount/
│ │ └── mount.go
│ ├── parser/
│ │ ├── parser.go
│ │ └── parser_test.go
│ ├── registry/
│ │ ├── registry.go
│ │ └── registry_test.go
│ ├── retry/
│ │ └── retry.go
│ ├── signals/
│ │ ├── signal.go
│ │ └── signal_test.go
│ ├── signer/
│ │ └── signer.go
│ ├── sysinfo/
│ │ └── sysinfo.go
│ └── transport/
│ ├── pool.go
│ └── pool_test.go
├── snapshot/
│ ├── mount_option.go
│ ├── mount_option_test.go
│ ├── process.go
│ ├── renewal.go
│ ├── renewal_test.go
│ ├── snapshot.go
│ ├── snapshot_test.go
│ └── utils.go
├── tests/
│ ├── converter_test.go
│ ├── e2e/
│ │ └── k8s/
│ │ ├── kind.yaml
│ │ ├── snapshotter-cri.yaml
│ │ ├── snapshotter-kubeconf.yaml
│ │ └── test-pod.yaml.tpl
│ ├── helpers/
│ │ ├── helpers.sh
│ │ ├── kind.sh
│ │ └── lib.sh
│ └── nydusd.go
├── tools/
│ └── optimizer-server/
│ ├── Cargo.toml
│ ├── Makefile
│ └── src/
│ └── main.rs
└── version/
└── version.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: Bug report
title: "[Bug] Bug title"
description: Problems and issues with code of nydus-snapshotter
labels: [ "bug"]
body:
- type: markdown
attributes:
value: >
Thank you for taking the time to report an issue. To help us resolve it quickly, please fill out the following
information.
- type: textarea
attributes:
label: Problem Description
description: A clear and concise description of the bug you've encountered.
placeholder: >
Please clearly and concisely describe the error you encountered.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: >
Explain the behavior you expected to see.
validations:
required: true
- type: textarea
attributes:
label: Actual Behavior
description: What actually happened? Please provide any relevant logs, stack traces, or screenshots.
placeholder: >
Describe the actual behavior. Include logs or screenshots if possible.
validations:
required: true
- type: textarea
attributes:
label: How to reproduce
description: Provide detailed steps to reproduce the issue.
placeholder: >
Please make sure you provide a reproducible step-by-step case of how to reproduce the problem
as minimally and precisely as possible.
value: |
1.
2.
3.
validations:
required: true
- type: textarea
id: environment-details
attributes:
label: Environment Details
description: |
Please provide your environment information.
value: |
- Nydus-snapshotter version:
- Nydus version:
- Container runtime:
- Operating System:
- Kernel version:
validations:
required: true
- type: textarea
attributes:
label: Additional Information
description: Any other context or details that could be helpful.
placeholder: >
If you have any other information that might help us diagnose the issue, please provide it here.
- type: checkboxes
attributes:
label: Are you willing to submit PR?
description: >
This is absolutely not required, but we are happy to guide you in the contribution process
especially if you already have a good understanding of how to implement the fix.
options:
- label: Yes I am willing to submit a PR!
- type: markdown
attributes:
value: "Thanks for completing our form!"
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: Feature request
description: Suggest an idea for nydus-snapshotter
title: "[Feature] Feature title"
labels: [ "feature"]
body:
- type: markdown
attributes:
value: |
Thank you for suggesting a new feature. Please provide a clear and detailed description.
- type: textarea
attributes:
label: Feature Description
description: A clear and concise description of the feature you would like to see.
placeholder: >
Describe the feature you are requesting.
validations:
required: true
- type: textarea
attributes:
label: Problem and Use Case
description: What problem does this feature solve? Why is it important to you or other users?
placeholder: >
Describe the problem and a specific use case.
validations:
required: true
- type: textarea
attributes:
label: Related issues
description: Is there currently another issue associated with this?
- type: checkboxes
attributes:
label: Are you willing to submit PR?
description: >
This is absolutely not required, but we are happy to guide you in the contribution process
especially if you already have a good understanding of how to implement the fix.
options:
- label: Yes I am willing to submit a PR!
- type: markdown
attributes:
value: "Thanks for completing our form!"
================================================
FILE: .github/ISSUE_TEMPLATE/improvement-report.yml
================================================
name: Improvement Report
description: Suggest an improvement to an existing feature or process.
title: "[Improvement] Improvement title"
labels: ["improvement"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thank you for helping us improve nydus-snapshotter! Please provide a clear and detailed description of your suggestion.
- type: textarea
id: problem-summary
attributes:
label: Problem Summary
description: A brief, high-level summary of the issue or inefficiency you've identified.
placeholder: Describe the problem you want to solve.
validations:
required: true
- type: textarea
id: proposed-improvement
attributes:
label: Proposed Improvement
description: A detailed description of your proposed change or improvement.
placeholder: Explain your proposed solution.
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context or references that would be helpful (e.g., links to discussions, related issues).
placeholder: Add any additional context here.
validations:
required: false
- type: checkboxes
attributes:
label: Are you willing to submit PR?
description: >
This is absolutely not required, but we are happy to guide you in the contribution process
especially if you already have a good understanding of how to implement the fix.
options:
- label: Yes I am willing to submit a PR!
- type: markdown
attributes:
value: "Thanks for completing our form!"
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Overview
_Please briefly describe the changes your pull request makes._
## Related Issues
_Please link to the relevant issue. For example: `Fix #123` or `Related #456`._
## Change Details
_Please describe your changes in detail:_
## Test Results
_If you have any relevant screenshots or videos that can help illustrate your changes, please add them here._
## Change Type
_Please select the type of change your pull request relates to:_
- [ ] Bug Fix
- [ ] Feature Addition
- [ ] Documentation Update
- [ ] Code Refactoring
- [ ] Performance Improvement
- [ ] Other (please describe)
## Self-Checklist
_Before submitting a pull request, please ensure you have completed the following:_
- [ ] I have run a code style check and addressed any warnings/errors.
- [ ] I have added appropriate comments to my code (if applicable).
- [ ] I have updated the documentation (if applicable).
- [ ] I have written appropriate unit tests.
================================================
FILE: .github/codecov.yml
================================================
coverage:
status:
patch: off
project:
default:
enabled: yes
target: auto # auto compares coverage to the previous base commit
# adjust accordingly based on how flaky your tests are
# this allows a 0.3% drop from the previous base commit coverage
threshold: 0.3%
comment:
layout: "reach, diff, flags, files"
behavior: default
require_changes: true # if true: only post the comment if coverage changes
codecov:
require_ci_to_pass: false
notify:
wait_for_ci: true
# When modifying this file, please validate using
# curl -X POST --data-binary @codecov.yml https://codecov.io/validate
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches: ["**", "stable/**"]
pull_request:
branches: ["**", "stable/**"]
env:
CARGO_TERM_COLOR: always
jobs:
security:
name: Security scan
timeout-minutes: 10
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
"$(go env GOPATH)/bin/govulncheck" ./...
- name: OSV-Scanner
run: |
go install github.com/google/osv-scanner/cmd/osv-scanner@v1
"$(go env GOPATH)/bin/osv-scanner" -r .
build:
name: Build and Lint
timeout-minutes: 10
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
# Prebuilt golangci-lint v2.1.x is built with Go 1.24; go.mod requires Go 1.25+.
install-mode: goinstall
version: v2.1.6
skip-cache: true
- name: Build
run: |
make
make test
build-optimizer:
name: Build optimizer
timeout-minutes: 10
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Build
run: |
rustup component add rustfmt clippy
make build-optimizer
smoke:
name: Smoke
timeout-minutes: 10
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Set up containerd
uses: crazy-max/ghaction-setup-containerd@v3
- name: Build
run: |
# Download nydus components
NYDUS_VER=v$(curl -fsSL --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name | sed 's/^v//')
wget -q https://github.com/dragonflyoss/nydus/releases/download/$NYDUS_VER/nydus-static-$NYDUS_VER-linux-amd64.tgz
tar xzvf nydus-static-$NYDUS_VER-linux-amd64.tgz
mkdir -p /usr/bin
sudo mv nydus-static/nydus-image nydus-static/nydusd nydus-static/nydusify /usr/bin/
export PATH=$PATH:$(go env GOPATH)/bin
make smoke
cross-build-test:
name: Cross Build Test
timeout-minutes: 10
runs-on: ubuntu-22.04
strategy:
matrix:
GOOS: ["linux", "windows", "darwin"]
GOARCH: ["amd64", "arm64"]
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Build
run: |
make -e GOOS=${{ matrix.GOOS }} GOARCH=${{ matrix.GOARCH }} converter
coverage:
name: Code coverage
timeout-minutes: 10
runs-on: ubuntu-22.04
needs: [build]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Run unit tests.
run: make cover
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
files: ./coverage.txt
================================================
FILE: .github/workflows/e2e.yml
================================================
name: integration test
on:
push:
branches:
- "main"
tags:
- v[0-9]+.[0-9]+.[0-9]+
pull_request:
branches:
- "main"
schedule:
# Trigger test every day at 00:03 clock UTC
- cron: "3 0 * * *"
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
jobs:
run-e2e-for-cgroups-v1:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Log in to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run e2e test
run: |
TAG=$GITHUB_REF_NAME
[ "$TAG" == "main" ] && TAG="latest"
[ "$GITHUB_EVENT_NAME" == "pull_request" ] && TAG="local"
make integration
run-e2e-for-cgroups-v2:
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Log in to container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run e2e test
run: |
TAG=$GITHUB_REF_NAME
[ "$TAG" == "main" ] && TAG="latest"
[ "$GITHUB_EVENT_NAME" == "pull_request" ] && TAG="local"
make integration
================================================
FILE: .github/workflows/k8s-e2e-run.yml
================================================
name: E2E Test With Kubernetes
on:
push:
branches:
- "main"
tags:
- v[0-9]+.[0-9]+.[0-9]+
pull_request:
branches: [main]
jobs:
cri_auth:
uses: ./.github/workflows/k8s-e2e.yml
with:
auth-type: cri
kubeconf_auth:
uses: ./.github/workflows/k8s-e2e.yml
with:
auth-type: kubeconf
index_detect:
uses: ./.github/workflows/k8s-e2e.yml
with:
auth-type: kubeconf
index-detect: true
================================================
FILE: .github/workflows/k8s-e2e.yml
================================================
name: E2E Test With Kubernetes Template
on:
workflow_call:
inputs:
auth-type:
required: true
type: string
index-detect:
required: false
type: boolean
env:
DOCKER_USER: testuser
DOCKER_PASSWORD: testpassword
NAMESPACE: nydus-system
jobs:
e2e_tests_k8s:
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: Test
env:
AUTH_TYPE: ${{ inputs.auth-type }}
INDEX_DETECT: ${{ inputs.index-detect }}
run: |
./tests/helpers/kind.sh
- name: Dump logs
if: failure()
continue-on-error: true
run: |
log_dir="/tmp/nydus-log"
mkdir -p $log_dir
for p in `kubectl --namespace "$NAMESPACE" get pods --no-headers -o custom-columns=NAME:metadata.name`; do
kubectl --namespace "$NAMESPACE" get pod $p -o yaml >> $log_dir/nydus-pods.conf
kubectl --namespace "$NAMESPACE" describe pod $p >> $log_dir/nydus-pods.conf
kubectl --namespace "$NAMESPACE" logs $p -c nydus-snapshotter >> $log_dir/nydus-snapshotter.log || echo "failed to get snapshotter log"
done
kubectl --namespace "$NAMESPACE" get secrets -o yaml >> $log_dir/nydus-secrets.log
docker exec kind-control-plane cat /etc/containerd/config.toml >> $log_dir/containerd-config.toml
docker exec kind-control-plane containerd config dump >> $log_dir/containerd-config-dump.toml
docker exec kind-control-plane journalctl --no-pager -u containerd >> $log_dir/containerd.log
docker exec kind-control-plane journalctl --no-pager -u kubelet >> $log_dir/kubelet.log
docker exec kind-control-plane ps -ef >> $log_dir/psef.log
kubectl get pod test-pod -o yaml >> $log_dir/test-pod.log || echo "test-pod may be deleted or not created"
cat ~/.docker/config.json > $log_dir/docker.config.json || echo "~/.docker/config.json not found"
- name: Upload Logs
uses: actions/upload-artifact@v4
if: failure()
with:
name: k8s-e2e-tests-logs
path: |
/tmp/nydus-log
overwrite: true
================================================
FILE: .github/workflows/optimizer.yml
================================================
name: optimizer test
on:
push:
branches:
- "main"
tags:
- v[0-9]+.[0-9]+.[0-9]+
pull_request:
branches:
- "main"
schedule:
# Trigger test every day at 00:03 clock UTC
- cron: "3 0 * * *"
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
run_optimizer:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
tools/optimizer-server/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('tools/optimizer-server/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo
- name: containerd runc and crictl
run: |
sudo wget -q https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.26.0/crictl-v1.26.0-linux-amd64.tar.gz
sudo tar zxvf ./crictl-v1.26.0-linux-amd64.tar.gz -C /usr/local/bin
sudo install -D -m 755 misc/optimizer/crictl.yaml /etc/crictl.yaml
sudo wget -q https://github.com/containerd/containerd/releases/download/v1.7.0/containerd-static-1.7.0-linux-amd64.tar.gz
sudo systemctl stop containerd
sudo tar -zxf ./containerd-static-1.7.0-linux-amd64.tar.gz -C /usr/
sudo install -D -m 755 misc/optimizer/containerd-config.toml /etc/containerd/config.toml
sudo systemctl restart containerd
sudo wget -q https://github.com/opencontainers/runc/releases/download/v1.1.5/runc.amd64 -O /usr/bin/runc
sudo chmod +x /usr/bin/runc
- name: Setup CNI
run: |
wget -q https://github.com/containernetworking/plugins/releases/download/v1.2.0/cni-plugins-linux-amd64-v1.2.0.tgz
sudo mkdir -p /opt/cni/bin
sudo tar xzf cni-plugins-linux-amd64-v1.2.0.tgz -C /opt/cni/bin/
sudo install -D -m 755 misc/example/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist
- name: Build and install optimizer
run: |
rustup component add rustfmt clippy
make optimizer
sudo chown -R $(id -un):$(id -gn) . ~/.cargo/
pwd
ls -lh bin/*optimizer*
sudo make install-optimizer
sudo install -D -m 755 misc/example/optimizer-nri-plugin.conf /etc/nri/conf.d/02-optimizer-nri-plugin.conf
sudo systemctl restart containerd
systemctl status containerd --no-pager -l
- name: Wait containerd ready
run: |
unset READY
for i in $(seq 30); do
if eval "timeout 180 ls /run/containerd/containerd.sock"; then
READY=true
break
fi
echo "Fail(${i}). Retrying..."
sleep 1
done
if [ "$READY" != "true" ];then
echo "containerd is not ready"
exit 1
fi
- name: Generate accessed files list
run: |
sed -i "s|host_path: script|host_path: $(pwd)/misc/optimizer/script|g" misc/optimizer/nginx.yaml
sudo crictl run misc/optimizer/nginx.yaml misc/optimizer/sandbox.yaml
sleep 20
sudo crictl rmp -f --all
tree /opt/nri/optimizer/results/
count=$(cat /opt/nri/optimizer/results/library/nginx:1.23.3 | wc -l)
expected=$(cat misc/optimizer/script/file_list.txt | wc -l)
echo "count: $count expected minimum value: $expected"
if [ $count -lt $expected ]; then
echo "failed to generate accessed files list for nginx:1.23.3"
cat misc/optimizer/script/file_list.txt
exit 1
fi
cat /opt/nri/optimizer/results/library/nginx:1.23.3.csv
- name: Dump logs
if: failure()
continue-on-error: true
run: |
systemctl status containerd --no-pager -l
journalctl -xeu containerd --no-pager
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+*
env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- build-os: linux
build-arch: amd64
build-linker: x86-64
- build-os: linux
build-arch: arm64
build-linker: aarch64
- build-os: linux
build-arch: s390x
build-linker: s390x
- build-os: linux
build-arch: ppc64le
build-linker: powerpc64le
- build-os: linux
build-arch: riscv64
build-linker: riscv64
- build-os: linux
build-arch: static
build-linker: static
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache-dependency-path: "go.sum"
- name: cache go mod
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ matrix.build-os }}-go-${{ hashFiles('go.sum') }}
restore-keys: |
${{ matrix.build-os }}-go
- name: cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
tools/optimizer-server/target/
key: ${{ matrix.build-os }}-cargo-${{ hashFiles('tools/optimizer-server/Cargo.lock') }}
restore-keys: |
${{ matrix.build-os }}-cargo
- name: install gnu gcc linker
run: |
if [ "${{ matrix.build-linker }}" != "static" ]; then
sudo apt-get update && sudo apt-get install -qq gcc-${{ matrix.build-linker }}-linux-gnu
fi
- name: build nydus-snapshotter and optimizer
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2
export PATH=$PATH:$(go env GOPATH)/bin
if [ "${{ matrix.build-arch }}" == "static" ]; then
make static-package
else
make package GOOS=${{ matrix.build-os }} GOARCH=${{ matrix.build-arch }}
fi
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-tars-${{ matrix.build-os }}-${{ matrix.build-arch }}
path: |
package/*.tar.gz*
overwrite: true
upload:
runs-on: ubuntu-22.04
needs: [build]
steps:
- uses: actions/checkout@v4
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: builds
- name: Release
uses: softprops/action-gh-release@v1
with:
name: "Nydus Snapshotter ${{ github.ref_name }} Release"
generate_release_notes: true
files: |
builds/release-tars-**/*
publish-image:
runs-on: ubuntu-22.04
needs: [build]
strategy:
matrix:
include:
- build-os: linux
build-arch: amd64
- build-os: linux
build-arch: arm64
- build-os: linux
build-arch: s390x
- build-os: linux
build-arch: ppc64le
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to the container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: download artifacts
uses: actions/download-artifact@v4
with:
name: release-tars-${{ matrix.build-os }}-${{ matrix.build-arch }}
path: misc/snapshotter
- name: unpack static release
run: |
cd misc/snapshotter && tar -zxf *.tar.gz && mv bin/* . && rm -rf bin
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Get the nydusd version
run: |
export NYDUS_STABLE_VER=$(curl -fsSL https://api.github.com/repos/dragonflyoss/nydus/releases/latest | jq -r .tag_name)
echo "NYDUS_STABLE_VER=$NYDUS_STABLE_VER" >> "$GITHUB_ENV"
printf 'nydus version is: %s\n' "$NYDUS_STABLE_VER"
- name: build and push nydus-snapshotter image
uses: docker/build-push-action@v5
with:
context: misc/snapshotter
file: misc/snapshotter/Dockerfile
push: true
platforms: ${{ matrix.build-os }}/${{ matrix.build-arch }}
provenance: false
tags: |
${{ fromJSON(steps.meta.outputs.json).tags[0] }}-${{ matrix.build-arch }}
${{ fromJSON(steps.meta.outputs.json).tags[1] }}-${{ matrix.build-arch }}
labels: ${{ steps.meta.outputs.labels }}
build-args: NYDUS_VER=${{ env.NYDUS_STABLE_VER }}
publish-manifest:
runs-on: ubuntu-22.04
needs: [publish-image]
steps:
- name: Log in to the container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Publish manifest for multi-arch image
run: |
IFS=',' read -ra tags <<< "$(echo "${{ steps.meta.outputs.tags }}" | tr '\n' ',')"
for tag in "${tags[@]}"; do
docker manifest create "${tag}" \
--amend "${tag}-amd64" \
--amend "${tag}-arm64" \
--amend "${tag}-s390x" \
--amend "${tag}-ppc64le"
docker manifest push "${tag}"
done
================================================
FILE: .gitignore
================================================
bin/
pkg/filesystem/stargz/testdata/db/
coverage.txt
.vscode/
tests/output/
smoke.tests
tools/optimizer-server/target
vendor/
.idea/
.DS_Store
================================================
FILE: .golangci.yml
================================================
# https://golangci-lint.run/usage/configuration#config-file
version: "2"
run:
concurrency: 4
timeout: 5m
issues-exit-code: 1
tests: true
linters:
default: none
enable:
- depguard # Checks for imports that shouldn't be used.
- staticcheck
- unconvert
- revive
- ineffassign
- govet
- unused
- misspell
- bodyclose
# - cyclop
- dogsled
- nilnil
- unparam
- nilerr
# - gosec
- gocritic
- prealloc
# - funlen
- exhaustive
- errcheck
exclusions:
paths:
- misc
# The package is ported from containerd project, let's skip it.
- pkg/remote/remotes
settings:
errcheck:
# Don't check errors for these functions (common cleanup patterns)
exclude-functions:
- (io.Closer).Close
- (*os.File).Close
- (net.Conn).Close
- (*net.UnixListener).Close
- (*net.UnixConn).Close
- (*http.Response).Body.Close
- (*io.PipeWriter).Close
- (*compress/gzip.Writer).Close
- os.RemoveAll
- os.Remove
- os.Setenv
- fmt.Fprintf
- fmt.Fprintln
- golang.org/x/sys/unix.Close
exhaustive:
# Allow default case to be considered exhaustive
default-signifies-exhaustive: true
revive:
rules:
# Disable exported comment requirements (too strict for this codebase)
- name: exported
disabled: true
- name: package-comments
disabled: true
depguard:
rules:
Main:
list-mode: lax
files:
- $all
deny:
- pkg: "github.com/containerd/containerd/errdefs"
desc: The containerd errdefs package was migrated to a separate module. Use github.com/containerd/errdefs instead.
- pkg: "github.com/containerd/containerd/log"
desc: The containerd log package was migrated to a separate module. Use github.com/containerd/log instead.
- pkg: "github.com/containerd/containerd/platforms"
desc: The containerd platforms package was migrated to a separate module. Use github.com/containerd/platforms instead.
- pkg: "github.com/containerd/containerd/reference/docker"
desc: The containerd reference package was migrated to a separate module. Use github.com/distribution/reference instead.
# govet:
# check-shadowing: true
# enable:
# - fieldalignment
funlen:
# Checks the number of lines in a function.
# If lower than 0, disable the check.
# Default: 60
lines: 100
# Checks the number of statements in a function.
# If lower than 0, disable the check.
# Default: 40
statements: 80
nilnil:
checked-types:
- ptr
- func
- iface
- map
- chan
formatters:
enable:
- gofmt
- goimports
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: MAINTAINERS
================================================
# nydus-snapshotter maintainers
#
# As a containerd sub-project, containerd maintainers are also included from https://github.com/containerd/project/blob/main/MAINTAINERS.
# See https://github.com/containerd/project/blob/main/GOVERNANCE.md for description of maintainer role
#
# COMMITTERS
# GitHub ID, Name, Email address
changweige, Changwei Ge, changweige@gmail.com
eryugey, Eryu Guan, eguan@linux.alibaba.com
imeoer, Yan Song, yansong.ys@antgroup.com
Fricounet, Baptiste Girard-Carrabin, baptiste.girardcarrabin@datadoghq.com
#
# REVIEWERS
# GitHub ID, Name, Email address
sctb512, Bin Tang, tangbin.bin@bytedance.com
BraveY, Kaiyong Yang, yangkaiyong.yky@antgroup.com
================================================
FILE: Makefile
================================================
all: clean build
optimizer: clean-optimizer build-optimizer
PKG = github.com/containerd/nydus-snapshotter
PACKAGES ?= $(shell go list ./... | grep -v /tests)
SUDO = $(shell which sudo)
GO_EXECUTABLE_PATH ?= $(shell which go)
NYDUS_BUILDER ?= /usr/bin/nydus-image
NYDUS_NYDUSD ?= /usr/bin/nydusd
GOOS ?= linux
GOARCH ?= $(shell go env GOARCH)
KERNEL_VER = $(shell uname -r)
# Used to populate variables in version package.
BUILD_TIMESTAMP=$(shell date '+%Y-%m-%dT%H:%M:%S')
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)
REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
RELEASE=nydus-snapshotter-v$(VERSION:v%=%)-${GOOS}-${GOARCH}
STATIC_RELEASE=nydus-snapshotter-v$(VERSION:v%=%)-${GOOS}-static
# Relpace test target images for e2e tests.
ifdef E2E_TEST_TARGET_IMAGES_FILE
ENV_TARGET_IMAGES_FILE = --env-file ${E2E_TEST_TARGET_IMAGES_FILE}
endif
ifdef E2E_DOWNLOADS_MIRROR
BUILD_ARG_E2E_DOWNLOADS_MIRROR = --build-arg DOWNLOADS_MIRROR=${E2E_DOWNLOADS_MIRROR}
endif
ifdef GOPROXY
PROXY := GOPROXY="${GOPROXY}"
endif
ifdef FS_CACHE
FS_DRIVER = fscache
else
FS_DRIVER = fusedev
endif
SNAPSHOTTER_CONFIG=/etc/nydus/config.toml
SOURCE_SNAPSHOTTER_CONFIG=misc/snapshotter/config.toml
NYDUSD_CONFIG=/etc/nydus/nydusd-config.${FS_DRIVER}.json
SOURCE_NYDUSD_CONFIG=misc/snapshotter/nydusd-config.${FS_DRIVER}.json
SNAPSHOTTER_SYSTEMD_UNIT_SERVICE=misc/snapshotter/nydus-snapshotter.${FS_DRIVER}.service
LDFLAGS = -s -w -X ${PKG}/version.Version=${VERSION} -X ${PKG}/version.Revision=$(REVISION) -X ${PKG}/version.BuildTimestamp=$(BUILD_TIMESTAMP)
DEBUG_LDFLAGS = -X ${PKG}/version.Version=${VERSION} -X ${PKG}/version.Revision=$(REVISION) -X ${PKG}/version.BuildTimestamp=$(BUILD_TIMESTAMP)
CARGO ?= $(shell which cargo)
OPTIMIZER_SERVER = tools/optimizer-server
OPTIMIZER_SERVER_TOML = ${OPTIMIZER_SERVER}/Cargo.toml
OPTIMIZER_SERVER_BIN = ${OPTIMIZER_SERVER}/bin/optimizer-server
.PHONY: build
build:
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs
.PHONY: static
static:
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs
debug:
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(DEBUG_LDFLAGS)" -gcflags "-N -l" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(DEBUG_LDFLAGS)" -gcflags "-N -l" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs
.PHONY: build-optimizer
build-optimizer:
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/optimizer-nri-plugin ./cmd/optimizer-nri-plugin
make -C tools/optimizer-server release OS=$(GOOS) ARCH=$(GOARCH) && cp ${OPTIMIZER_SERVER_BIN} ./bin
static-release:
CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc
CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs
CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/optimizer-nri-plugin ./cmd/optimizer-nri-plugin
make -C tools/optimizer-server static-release && cp ${OPTIMIZER_SERVER_BIN} ./bin
package/$(RELEASE).tar.gz: build build-optimizer
mkdir -p package
rm -rf package/$(RELEASE) package/$(RELEASE).tar.gz
tar -czf package/$(RELEASE).tar.gz bin
rm -rf package/$(RELEASE)
package/$(STATIC_RELEASE).tar.gz: static-release
@mkdir -p package
@rm -rf package/$(STATIC_RELEASE) package/$(STATIC_RELEASE).tar.gz
@tar -czf package/$(STATIC_RELEASE).tar.gz bin
@rm -rf package/$(STATIC_RELEASE)
package: package/$(RELEASE).tar.gz
cd package && sha256sum $(RELEASE).tar.gz >$(RELEASE).tar.gz.sha256sum
static-package: package/$(STATIC_RELEASE).tar.gz
@cd package && sha256sum $(STATIC_RELEASE).tar.gz >$(STATIC_RELEASE).tar.gz.sha256sum
# Majorly for cross build for converter package since it is imported by other projects
converter:
GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/converter ./cmd/converter
.PHONY: clean
clean:
rm -f bin/*
rm -rf _out
.PHONY: clean-optimizer
clean-optimizer:
rm -rf bin/optimizer-nri-plugin bin/optimizer-server
make -C tools/optimizer-server clean
.PHONY: install
install:
@echo "+ $@ bin/containerd-nydus-grpc"
@sudo install -D -m 755 bin/containerd-nydus-grpc /usr/local/bin/containerd-nydus-grpc
@echo "+ $@ bin/nydus-overlayfs"
@sudo install -D -m 755 bin/nydus-overlayfs /usr/local/bin/nydus-overlayfs
@if [ ! -e ${NYDUSD_CONFIG} ]; then echo "+ $@ SOURCE_NYDUSD_CONFIG"; sudo install -D -m 664 ${SOURCE_NYDUSD_CONFIG} ${NYDUSD_CONFIG}; fi
@if [ ! -e ${SNAPSHOTTER_CONFIG} ]; then echo "+ $@ ${SOURCE_SNAPSHOTTER_CONFIG}"; sudo install -D -m 664 ${SOURCE_SNAPSHOTTER_CONFIG} ${SNAPSHOTTER_CONFIG}; fi
@sudo ln -f -s /etc/nydus/nydusd-config.${FS_DRIVER}.json /etc/nydus/nydusd-config.json
@echo "+ $@ ${SNAPSHOTTER_SYSTEMD_UNIT_SERVICE}"
@sudo install -D -m 644 ${SNAPSHOTTER_SYSTEMD_UNIT_SERVICE} /etc/systemd/system/nydus-snapshotter.service
@sudo mkdir -p /etc/nydus/certs.d
@if which systemctl >/dev/null; then sudo systemctl enable /etc/systemd/system/nydus-snapshotter.service; sudo systemctl restart nydus-snapshotter; fi
install-optimizer:
sudo install -D -m 755 bin/optimizer-nri-plugin /opt/nri/plugins/02-optimizer-nri-plugin
sudo install -D -m 755 bin/optimizer-server /usr/local/bin/optimizer-server
sudo install -D -m 755 misc/example/optimizer-nri-plugin.conf /etc/nri/conf.d/02-optimizer-nri-plugin.conf
@sudo mkdir -p /opt/nri/optimizer/results
.PHONY: vet
vet:
go vet $(PACKAGES) ./tests
.PHONY: check
check: vet
golangci-lint run
.PHONY: test
test:
go test -race -v -mod=mod -cover ${PACKAGES}
.PHONY: cover
cover:
go test -v -covermode=atomic -coverprofile=coverage.txt $(PACKAGES)
go tool cover -func=coverage.txt
# make smoke TESTS=TestPack
smoke:
${GO_EXECUTABLE_PATH} test -o smoke.tests -c -race -v -cover ./tests
$(SUDO) -E NYDUS_BUILDER=${NYDUS_BUILDER} NYDUS_NYDUSD=${NYDUS_NYDUSD} ./smoke.tests -test.v -test.timeout 10m -test.parallel=8 -test.run=$(TESTS)
.PHONY: integration
integration:
CGO_ENABLED=1 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags '-X "${PKG}/version.Version=${VERSION}" -extldflags "-static"' -race -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc
CGO_ENABLED=1 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags '-X "${PKG}/version.Version=${VERSION}" -extldflags "-static"' -race -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs
$(SUDO) docker build ${BUILD_ARG_E2E_DOWNLOADS_MIRROR} -t nydus-snapshotter-e2e:0.1 -f integration/Dockerfile .
$(SUDO) docker run --cap-add SYS_ADMIN --security-opt seccomp=unconfined --cgroup-parent=system.slice --cgroupns private --name nydus-snapshotter_e2e --rm --privileged -v /root/.docker:/root/.docker -v `go env GOMODCACHE`:/go/pkg/mod \
-v `go env GOCACHE`:/root/.cache/go-build -v `pwd`:/nydus-snapshotter \
-v /usr/src/linux-headers-${KERNEL_VER}:/usr/src/linux-headers-${KERNEL_VER} \
${ENV_TARGET_IMAGES_FILE} \
nydus-snapshotter-e2e:0.1
================================================
FILE: README.md
================================================
[**[⬇️ Download]**](https://github.com/containerd/nydus-snapshotter/releases)
[**[📖 Website]**](https://nydus.dev/)
[**[☸ Quick Start (Kubernetes)**]](https://github.com/containerd/nydus-snapshotter/blob/main/docs/run_nydus_in_kubernetes.md)
[**[🤓 Quick Start (nerdctl)**]](https://github.com/containerd/nerdctl/blob/master/docs/nydus.md)
[**[❓ FAQs & Troubleshooting]**](https://github.com/dragonflyoss/nydus/wiki/FAQ)
# Nydus Snapshotter
<p><img src="https://github.com/dragonflyoss/nydus/blob/master/misc/logo.svg" width="170"></p>
[](https://github.com/containerd/nydus-snapshotter/releases)
[](https://github.com/containerd/nydus-snapshotter/blob/main/LICENSE)

[](https://goreportcard.com/report/github.com/containerd/nydus-snapshotter)
[](https://twitter.com/dragonfly_oss)
[](https://github.com/dragonflyoss/nydus)
Nydus-snapshotter is a **non-core** sub-project of containerd.
Nydus snapshotter is an external plugin of containerd for [Nydus image service](https://nydus.dev) which implements a chunk-based content-addressable filesystem on top of a called `RAFS (Registry Acceleration File System)` format that improves the current OCI image specification, in terms of container launching speed, image space, and network bandwidth efficiency, as well as data integrity with several runtime backends: FUSE, virtiofs and in-kernel [EROFS](https://www.kernel.org/doc/html/latest/filesystems/erofs.html).
Nydus supports lazy pulling feature since pulling image is one of the time-consuming steps in the container lifecycle. Lazy pulling here means a container can run even the image is partially available and necessary chunks of the image are fetched on-demand. Apart from that, Nydus also supports [(e)Stargz](https://github.com/containerd/stargz-snapshotter) and OCI (by using [zran](https://github.com/dragonflyoss/nydus/blob/master/docs/nydus-zran.md)) lazy pulling directly **WITHOUT** any explicit conversion.
For more details about how to build Nydus container image, please refer to [nydusify](https://github.com/dragonflyoss/nydus/blob/master/docs/nydusify.md) conversion tool and [acceld](https://github.com/goharbor/acceleration-service).
## Architecture
### Architecture Based on FUSE

### Architecture Based on Fscache/Erofs

## Building
Just invoke `make` and check out the output executable binary `./bin/containerd-nydus-grpc`
```bash
make
```
## Integrate Nydus-snapshotter into Containerd
The following document will describe how to manually configure containerd + Nydus snapshotter. If you want to run Nydus snapshotter in Kubernetes cluster, you can try to use helm or run nydus snapshotter as a container. You can refer to [this documentation](./docs/run_nydus_in_kubernetes.md).
Containerd provides a general mechanism to exploit different types of snapshotters. Please ensure your containerd's version is 1.4.0 or above.
Add Nydus as a proxy plugin into containerd's configuration file which may be located at `/etc/containerd/config.toml`.
```toml
# The `address` field specifies through which socket snapshotter and containerd communicate.
[proxy_plugins]
[proxy_plugins.nydus]
type = "snapshot"
address = "/run/containerd-nydus/containerd-nydus-grpc.sock"
```
Restart your containerd service making the change take effect. Assume that your node is systemd based, restart the service as below:
```bash
systemctl restart containerd
```
### Get Nydus Binaries
Get `nydusd` `nydus-image` and `nydusctl` binaries from [nydus releases page](https://github.com/dragonflyoss/nydus/releases).
It's suggested to install the binaries to your system path. `nydusd` is FUSE userspace daemon and a vhost-user-fs backend. Nydus-snapshotter
will fork a nydusd process when necessary.
### Configure Nydus
Please follow instructions to [configure nydus](./docs/configure_nydus.md) in order to make it work properly in your environment.
### Start Nydus Snapshotter
Nydus-snapshotter is implemented as a [proxy plugin](https://github.com/containerd/containerd/blob/04985039cede6aafbb7dfb3206c9c4d04e2f924d/PLUGINS.md#proxy-plugins) (`containerd-nydus-grpc`) for containerd.
Assume your server is systemd based, install nydus-snapshotter:
Note: `nydusd` and `nydus-image` should be found from $PATH.
```bash
make install
systemctl restart containerd
```
Or you can start nydus-snapshotter manually.
```bash
# `--nydusd` specifies the path to nydusd binary. If `nydusd` and `nydus-image` are installed, `--nydusd` and `--nydus-image`can be omitted.
# Otherwise, provide them in below command line.
# `address` is the domain socket that you configured in containerd configuration file
# `--nydusd-config` is the path to `nydusd` configuration file
# The default nydus-snapshotter work directory is located at `/var/lib/containerd/io.containerd.snapshotter.v1.nydus`
$ sudo ./containerd-nydus-grpc --config /etc/nydus/config.toml --nydusd-config /etc/nydus/nydusd-config.json --log-to-stdout
```
### Validate Nydus-snapshotter Setup
Utilize containerd's `ctr` CLI command to validate if nydus-snapshotter is set up successfully.
```bash
$ ctr -a /run/containerd/containerd.sock plugin ls
TYPE ID PLATFORMS STATUS
io.containerd.snapshotter.v1 nydus - ok
```
### Optimize Nydus Image as per Workload
Nydus usually prefetch image data to local filesystem before a real user on-demand read. It helps to improve the performance and availability. A containerd NRI plugin [container image optimizer](docs/optimize_nydus_image.md) can be used to generate nydus image building suggestions to optimize your nydus image making the nydusd runtime match your workload IO pattern. The optimized nydus image has
a better performance.
## Quickstart Container with Lazy Pulling
### Start Container on single Node
Start container using `nerdctl` (>=v0.22) which has native nydus support with `nydus-snapshotter`.
```bash
# Start container by `nerdctl`
nerdctl --snapshotter nydus run ghcr.io/dragonflyoss/image-service/nginx:nydus-latest
```
### Start Container in Kubernetes Cluster
Change containerd's CRI configuration:
```toml
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "nydus"
disable_snapshot_annotations = false
```
Use `crictl` to debug starting container via Kubernetes CRI. Dry run [steps](./docs/crictl_dry_run.md) of using `crictl` can be found in [documents](./docs).
### Setup with nydus-snapshotter image
We can also use the `nydus-snapshotter` container image when we want to put Nydus stuffs inside a container. See the [nydus-snapshotter example](./misc/example/README.md) for how to setup and use it.
## Integrate with Dragonfly to Distribute Images by P2P
Nydus is a sub-project of [Dragonfly](https://github.com/dragonflyoss/dragonfly). So it closely works with Dragonfly to distribute container images in a fast and efficient P2P fashion to reduce network latency and lower the pressure on a single-point of the registry.
### Quickstart Dragonfly & Nydus in Kubernetes
We recommend using the Dragonfly P2P data distribution system to further improve the runtime performance of Nydus images.
If you want to deploy Dragonfly and Nydus at the same time, please refer to this **[Quick Start](https://github.com/dragonflyoss/helm-charts/blob/main/INSTALL.md)**.
### Config Dragonfly mode
Dragonfly supports both **mirror** mode and HTTP **proxy** mode to boost the containers startup. It is suggested to use Dragonfly mirror mode. To integrate with Dragonfly in the mirror mode, please provide registry mirror in nydusd's json configuration file in section `device.backend.mirrors`
```json
{
"mirrors": [
{
"host": "http://127.0.0.1:65001",
"headers": "https://index.docker.io/v1/"
}
]
}
```
### Hot updating mirror configurations
`nydus-snapshotter` supports hot updating mirror configurations. You can set the configuration directory in nydus-snapshotter's toml configuration file with `remote.mirrors_config.dir`. The empty `remote.mirrors_config.dir` means disabling it.
```toml
[remote.mirrors_config]
dir = "/etc/nydus/certs.d"
```
Configuration file is compatible with containerd's configuration file in toml format.
```toml
[host]
[host."http://127.0.0.1:65001"]
# Optional: health check URL. If set, the mirror is only used when this URL returns HTTP 2xx.
# If not set, the mirror is used unconditionally.
ping_url = "http://127.0.0.1:65001/ping"
```
Before each mount, the snapshotter reads the mirror configuration for the target registry host and rewrites nydusd's backend `host` to the first reachable mirror. If a mirror has no `ping_url` it is selected immediately. If all mirrors fail their health check, the original registry host is used as fallback.
## Community
Nydus aims to form a **vendor-neutral opensource** image distribution solution to all communities.
Questions, bug reports, technical discussion, feature requests and contribution are always welcomed!
We're very pleased to hear your use cases any time.
Feel free to reach/join us via Slack and/or Dingtalk.
- **Slack:** [Nydus Workspace](https://join.slack.com/t/nydusimageservice/shared_invite/zt-pz4qvl4y-WIh4itPNILGhPS8JqdFm_w)
- **Twitter:** [@dragonfly_oss](https://twitter.com/dragonfly_oss)
- **Dingtalk:** [34971767](https://qr.dingtalk.com/action/joingroup?code=v1,k1,ioWGzuDZEIO10Bf+/ohz4RcQqAkW0MtOwoG1nbbMxQg=&_dt_no_comment=1&origin=11)
<img src="https://github.com/dragonflyoss/nydus/blob/master/misc/dingtalk.jpg" width="250" height="300"/>
- **Technical Meeting:** Every Wednesday at 06:00 UTC (Beijing, Shanghai 14:00), please see our [HackMD](https://hackmd.io/@Nydus/Bk8u2X0p9) page for more information.
## License
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fcontainerd%2Fnydus-snapshotter?ref=badge_large)
================================================
FILE: cmd/containerd-nydus-grpc/main.go
================================================
/*
* Copyright (c) 2020. Ant Group. All rights reserved.
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"os"
"github.com/containerd/log"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/containerd/nydus-snapshotter/config"
"github.com/containerd/nydus-snapshotter/internal/flags"
"github.com/containerd/nydus-snapshotter/internal/logging"
"github.com/containerd/nydus-snapshotter/pkg/errdefs"
"github.com/containerd/nydus-snapshotter/version"
)
func main() {
flags := flags.NewFlags()
app := &cli.App{
Name: "containerd-nydus-grpc",
Usage: "Nydus remote snapshotter for containerd",
Version: version.Version,
Flags: flags.F,
HideVersion: true,
Action: func(_ *cli.Context) error {
if flags.Args.PrintVersion {
fmt.Println("Version: ", version.Version)
fmt.Println("Revision: ", version.Revision)
fmt.Println("Go version: ", version.GoVersion)
fmt.Println("Build time: ", version.BuildTimestamp)
return nil
}
snapshotterConfigPath := flags.Args.SnapshotterConfigPath
var defaultSnapshotterConfig config.SnapshotterConfig
var snapshotterConfig config.SnapshotterConfig
if err := defaultSnapshotterConfig.FillUpWithDefaults(); err != nil {
return errors.New("failed to generate nydus default configuration")
}
// Once snapshotter's configuration file is provided, parse it and let command line parameters override it.
if snapshotterConfigPath != "" {
if c, err := config.LoadSnapshotterConfig(snapshotterConfigPath); err == nil {
// Command line parameters override the snapshotter's configurations for backwards compatibility
if err := config.ParseParameters(flags.Args, c); err != nil {
return errors.Wrap(err, "failed to parse commandline options")
}
snapshotterConfig = *c
} else {
return errors.Wrapf(err, "failed to load snapshotter configuration from %q", snapshotterConfigPath)
}
} else {
if err := config.ParseParameters(flags.Args, &snapshotterConfig); err != nil {
return errors.Wrap(err, "failed to parse commandline options")
}
}
if err := config.MergeConfig(&snapshotterConfig, &defaultSnapshotterConfig); err != nil {
return errors.Wrap(err, "failed to merge configurations")
}
if err := config.ValidateConfig(&snapshotterConfig); err != nil {
return errors.Wrapf(err, "failed to validate configurations")
}
config.PrepareLogDir(&snapshotterConfig)
ctx := logging.WithContext()
logConfig := &snapshotterConfig.LoggingConfig
logRotateArgs := &logging.RotateLogArgs{
RotateLogMaxSize: logConfig.RotateLogMaxSize,
RotateLogMaxBackups: logConfig.RotateLogMaxBackups,
RotateLogMaxAge: logConfig.RotateLogMaxAge,
RotateLogLocalTime: logConfig.RotateLogLocalTime,
RotateLogCompress: logConfig.RotateLogCompress,
}
if err := logging.SetUp(logConfig.LogLevel, logConfig.LogToStdout, logConfig.LogDir, logRotateArgs); err != nil {
return errors.Wrap(err, "failed to setup logger")
}
log.L.Infof("Logger successfully set up. Proceeding to process nydus-snapshotter configurations")
if err := config.ProcessConfigurations(&snapshotterConfig); err != nil {
return errors.Wrap(err, "failed to process configurations")
}
if err := config.SetUpEnvironment(&snapshotterConfig); err != nil {
return errors.Wrap(err, "failed to setup environment")
}
log.L.Infof("Start nydus-snapshotter. Version: %s, PID: %d, FsDriver: %s, DaemonMode: %s",
version.Version, os.Getpid(), config.GetFsDriver(), snapshotterConfig.DaemonMode)
return Start(ctx, &snapshotterConfig)
},
}
if err := app.Run(os.Args); err != nil {
if errdefs.IsConnectionClosed(err) {
log.L.Info("nydus-snapshotter exited")
} else {
log.L.WithError(err).Fatal("failed to start nydus-snapshotter")
}
}
}
================================================
FILE: cmd/containerd-nydus-grpc/snapshotter.go
================================================
/*
* Copyright (c) 2020. Ant Group. All rights reserved.
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"context"
"net"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/containerd/nydus-snapshotter/config"
"github.com/containerd/nydus-snapshotter/pkg/auth"
"github.com/containerd/nydus-snapshotter/pkg/utils/signals"
"github.com/containerd/nydus-snapshotter/snapshot"
api "github.com/containerd/containerd/api/services/snapshots/v1"
"github.com/containerd/containerd/v2/contrib/snapshotservice"
"github.com/containerd/containerd/v2/core/snapshots"
"github.com/containerd/log"
"google.golang.org/grpc"
)
func Start(ctx context.Context, cfg *config.SnapshotterConfig) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
rs, err := snapshot.NewSnapshotter(ctx, cfg)
if err != nil {
return errors.Wrap(err, "failed to initialize snapshotter")
}
stopSignal := signals.SetupSignalHandler()
opt := ServeOptions{
ListeningSocketPath: cfg.Address,
ListeningSocketUID: cfg.UID,
ListeningSocketGID: cfg.GID,
EnableCRIKeychain: cfg.RemoteConfig.AuthConfig.EnableCRIKeychain,
ImageServiceAddress: cfg.RemoteConfig.AuthConfig.ImageServiceAddress,
}
if cfg.RemoteConfig.AuthConfig.EnableKubeconfigKeychain {
if err := auth.InitKubeSecretListener(ctx, cfg.RemoteConfig.AuthConfig.KubeconfigPath); err != nil {
return err
}
}
if cfg.RemoteConfig.AuthConfig.EnableKubeletCredentialProviders {
if err := auth.InitKubeletProvider(
cfg.RemoteConfig.AuthConfig.CredentialProviderConfig,
cfg.RemoteConfig.AuthConfig.CredentialProviderBinDir,
); err != nil {
return errors.Wrap(err, "failed to initialize kubelet credential provider")
}
}
return Serve(ctx, rs, opt, stopSignal)
}
type ServeOptions struct {
ListeningSocketPath string
ListeningSocketUID int
ListeningSocketGID int
EnableCRIKeychain bool
ImageServiceAddress string
}
func Serve(ctx context.Context, sn snapshots.Snapshotter, options ServeOptions, stop <-chan struct{}) error {
err := ensureSocketNotExists(options.ListeningSocketPath)
if err != nil {
return err
}
rpc := grpc.NewServer()
if rpc == nil {
return errors.New("start gRPC server")
}
api.RegisterSnapshotsServer(rpc, snapshotservice.FromSnapshotter(sn))
listener, err := net.Listen("unix", options.ListeningSocketPath)
if err != nil {
return errors.Wrapf(err, "listen socket %q", options.ListeningSocketPath)
}
if err := os.Chown(options.ListeningSocketPath, options.ListeningSocketUID, options.ListeningSocketGID); err != nil {
return errors.Wrap(err, "chown socket")
}
if options.EnableCRIKeychain {
auth.AddImageProxy(ctx, rpc, options.ImageServiceAddress)
}
go func() {
<-stop
log.L.Infof("Shutting down nydus-snapshotter!")
if err := sn.Close(); err != nil {
log.L.WithError(err).Errorf("Closing snapshotter error")
}
if err := listener.Close(); err != nil {
log.L.Errorf("Failed to close listener %s, err: %v", options.ListeningSocketPath, err)
}
}()
return rpc.Serve(listener)
}
func ensureSocketNotExists(listeningSocketPath string) error {
if err := os.MkdirAll(filepath.Dir(listeningSocketPath), 0700); err != nil {
return errors.Wrapf(err, "failed to create directory %q", filepath.Dir(listeningSocketPath))
}
finfo, err := os.Stat(listeningSocketPath)
// err is nil means listening socket path exists, remove before serve
if err == nil {
if finfo.Mode()&os.ModeSocket == 0 {
return errors.Errorf("file %s is not a socket", listeningSocketPath)
}
err := os.Remove(listeningSocketPath)
if err != nil {
return err
}
}
return nil
}
================================================
FILE: cmd/converter/main.go
================================================
package main
// Import the converter package so that it can be compiled during
// `go build` to ensure cross-compilation compatibility.
import (
_ "github.com/containerd/nydus-snapshotter/pkg/converter"
)
func main() {
}
================================================
FILE: cmd/nydus-overlayfs/main.go
================================================
package main
import (
"fmt"
"log"
"os"
"path"
"strings"
"syscall"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"golang.org/x/sys/unix"
)
const (
// Extra mount option to pass Nydus specific information from snapshotter to runtime through containerd.
extraOptionKey = "extraoption="
// Kata virtual volume infmation passed from snapshotter to runtime through containerd, superset of `extraOptionKey`.
// Please refer to `KataVirtualVolume` in https://github.com/kata-containers/kata-containers/blob/main/src/libs/kata-types/src/mount.rs
kataVolumeOptionKey = "io.katacontainers.volume="
)
var (
Version = "v0.1"
BuildTime = "unknown"
pagesize = os.Getpagesize()
)
/*
containerd run fuse.mount format: nydus-overlayfs overlay /tmp/ctd-volume107067851
-o lowerdir=/foo/lower2:/foo/lower1,upperdir=/foo/upper,workdir=/foo/work,extraoption={...},dev,suid]
*/
type mountArgs struct {
fsType string
target string
options []string
}
func parseArgs(args []string) (*mountArgs, error) {
margs := &mountArgs{
fsType: args[0],
target: args[1],
}
if margs.fsType != "overlay" {
return nil, errors.Errorf("invalid filesystem type %s for overlayfs", margs.fsType)
}
if len(margs.target) == 0 {
return nil, errors.New("empty overlayfs mount target")
}
if args[2] == "-o" && len(args[3]) != 0 {
for _, opt := range strings.Split(args[3], ",") {
// filter Nydus specific options
if strings.HasPrefix(opt, extraOptionKey) || strings.HasPrefix(opt, kataVolumeOptionKey) {
continue
}
margs.options = append(margs.options, opt)
}
}
if len(margs.options) == 0 {
return nil, errors.New("empty overlayfs mount options")
}
return margs, nil
}
func parseOptions(options []string) (int, string) {
flagsTable := map[string]int{
"async": unix.MS_SYNCHRONOUS,
"atime": unix.MS_NOATIME,
"bind": unix.MS_BIND,
"defaults": 0,
"dev": unix.MS_NODEV,
"diratime": unix.MS_NODIRATIME,
"dirsync": unix.MS_DIRSYNC,
"exec": unix.MS_NOEXEC,
"mand": unix.MS_MANDLOCK,
"noatime": unix.MS_NOATIME,
"nodev": unix.MS_NODEV,
"nodiratime": unix.MS_NODIRATIME,
"noexec": unix.MS_NOEXEC,
"nomand": unix.MS_MANDLOCK,
"norelatime": unix.MS_RELATIME,
"nostrictatime": unix.MS_STRICTATIME,
"nosuid": unix.MS_NOSUID,
"rbind": unix.MS_BIND | unix.MS_REC,
"relatime": unix.MS_RELATIME,
"remount": unix.MS_REMOUNT,
"ro": unix.MS_RDONLY,
"rw": unix.MS_RDONLY,
"strictatime": unix.MS_STRICTATIME,
"suid": unix.MS_NOSUID,
"sync": unix.MS_SYNCHRONOUS,
}
var (
flags int
data []string
)
for _, o := range options {
if f, exist := flagsTable[o]; exist {
flags |= f
} else {
data = append(data, o)
}
}
return flags, strings.Join(data, ",")
}
// longestCommonPrefix finds the longest common prefix in the string slice.
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
} else if len(strs) == 1 {
return strs[0]
}
min, max := strs[0], strs[0]
for _, str := range strs[1:] {
if min > str {
min = str
}
if max < str {
max = str
}
}
for i := 0; i < len(min) && i < len(max); i++ {
if min[i] != max[i] {
return min[:i]
}
}
return min
}
// compactLowerdirOption shortens lowerdir paths by extracting the longest
// common directory prefix across all lowerdirs, upperdir, and workdir. The
// caller chdir's into that prefix before calling mount so the kernel receives
// shorter, relative paths that fit within the mount-data page-size limit.
// Ported from containerd's core/mount/mount_linux.go.
func compactLowerdirOption(options []string) (string, []string) {
var lowerdirIdx = -1
for i, opt := range options {
if strings.HasPrefix(opt, "lowerdir=") {
lowerdirIdx = i
break
}
}
if lowerdirIdx == -1 {
return "", options
}
dirs := strings.Split(options[lowerdirIdx][len("lowerdir="):], ":")
if len(dirs) <= 1 {
return "", options
}
// Collect all paths that participate in the overlay: lowerdirs + upperdir + workdir.
allPaths := make([]string, 0, len(dirs)+2)
allPaths = append(allPaths, dirs...)
for _, opt := range options {
if strings.HasPrefix(opt, "upperdir=") {
allPaths = append(allPaths, opt[len("upperdir="):])
} else if strings.HasPrefix(opt, "workdir=") {
allPaths = append(allPaths, opt[len("workdir="):])
}
}
commondir := longestCommonPrefix(allPaths)
if commondir == "" {
return "", options
}
// Back up to the parent directory to avoid partial snapshot-id matches.
commondir = path.Dir(commondir)
if commondir == "/" || commondir == "." {
return "", options
}
commondir += "/"
// Rebuild options with relative paths.
newopts := make([]string, 0, len(options))
for i, opt := range options {
switch {
case i == lowerdirIdx:
newdirs := make([]string, 0, len(dirs))
for _, dir := range dirs {
if len(dir) <= len(commondir) {
return "", options
}
newdirs = append(newdirs, dir[len(commondir):])
}
newopts = append(newopts, fmt.Sprintf("lowerdir=%s", strings.Join(newdirs, ":")))
case strings.HasPrefix(opt, "upperdir="):
p := opt[len("upperdir="):]
if len(p) <= len(commondir) {
return "", options
}
newopts = append(newopts, fmt.Sprintf("upperdir=%s", p[len(commondir):]))
case strings.HasPrefix(opt, "workdir="):
p := opt[len("workdir="):]
if len(p) <= len(commondir) {
return "", options
}
newopts = append(newopts, fmt.Sprintf("workdir=%s", p[len(commondir):]))
default:
newopts = append(newopts, opt)
}
}
return commondir, newopts
}
func run(args cli.Args) error {
margs, err := parseArgs(args.Slice())
if err != nil {
return errors.Wrap(err, "parse mount options")
}
flags, data := parseOptions(margs.options)
// When the mount data string exceeds the kernel's page-size limit, compact
// overlay paths by chdir'ing into their common prefix and using relative
// paths — the same approach containerd uses for direct overlay mounts.
var chdir string
if len(data) >= pagesize-512 {
chdir, margs.options = compactLowerdirOption(margs.options)
if chdir != "" {
_, data = parseOptions(margs.options)
}
}
if chdir != "" {
if err := os.Chdir(chdir); err != nil {
return errors.Wrapf(err, "chdir to common overlay dir %s", chdir)
}
}
err = syscall.Mount(margs.fsType, margs.target, margs.fsType, uintptr(flags), data)
if err != nil {
return errors.Wrapf(err, "mount overlayfs by syscall")
}
return nil
}
func main() {
app := &cli.App{
Name: "NydusOverlayfs",
Usage: "FUSE mount helper for containerd to filter out Nydus specific options",
Version: fmt.Sprintf("%s.%s", Version, BuildTime),
UsageText: "[Usage]: nydus-overlayfs overlay <target> -o <options>",
Action: func(c *cli.Context) error {
return run(c.Args())
},
Before: func(c *cli.Context) error {
if c.NArg() != 4 {
cli.ShowAppHelpAndExit(c, 1)
}
return nil
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
os.Exit(0)
}
================================================
FILE: cmd/nydus-overlayfs/main_test.go
================================================
/*
* Copyright (c) 2026. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLongestCommonPrefix(t *testing.T) {
tests := []struct {
name string
input []string
expected string
}{
{
name: "empty slice",
input: []string{},
expected: "",
},
{
name: "single element",
input: []string{"/var/lib/snapshots/1/fs"},
expected: "/var/lib/snapshots/1/fs",
},
{
name: "common prefix across snapshot ids",
input: []string{"/var/lib/snapshots/128/fs", "/var/lib/snapshots/21/fs", "/var/lib/snapshots/99/fs"},
expected: "/var/lib/snapshots/",
},
{
name: "no common prefix",
input: []string{"/foo/bar", "/baz/qux"},
expected: "/",
},
{
name: "identical strings",
input: []string{"/a/b/c", "/a/b/c"},
expected: "/a/b/c",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result := longestCommonPrefix(tc.input)
assert.Equal(t, tc.expected, result)
})
}
}
func TestCompactLowerdirOption(t *testing.T) {
tests := []struct {
name string
options []string
expectedChdir string
expectedOptions []string
}{
{
name: "no lowerdir option",
options: []string{"ro", "dev"},
expectedChdir: "",
expectedOptions: []string{"ro", "dev"},
},
{
name: "single lowerdir - no compaction needed",
options: []string{"lowerdir=/var/lib/snapshots/1/fs"},
expectedChdir: "",
expectedOptions: []string{"lowerdir=/var/lib/snapshots/1/fs"},
},
{
name: "two lowerdirs with common prefix",
options: []string{
"workdir=/var/lib/snapshots/3/work",
"upperdir=/var/lib/snapshots/3/fs",
"lowerdir=/var/lib/snapshots/2/fs:/var/lib/snapshots/1/fs",
},
expectedChdir: "/var/lib/snapshots/",
expectedOptions: []string{
"workdir=3/work",
"upperdir=3/fs",
"lowerdir=2/fs:1/fs",
},
},
{
name: "many lowerdirs simulating real nydus case",
options: func() []string {
lowerdirs := make([]string, 0, 108)
for i := 128; i >= 21; i-- {
lowerdirs = append(lowerdirs, fmt.Sprintf("/var/lib/nydus-snapshotter/snapshots/%d/fs", i))
}
return []string{
"workdir=/var/lib/nydus-snapshotter/snapshots/129/work",
"upperdir=/var/lib/nydus-snapshotter/snapshots/129/fs",
fmt.Sprintf("lowerdir=%s", strings.Join(lowerdirs, ":")),
"ro",
}
}(),
expectedChdir: "/var/lib/nydus-snapshotter/snapshots/",
expectedOptions: func() []string {
lowerdirs := make([]string, 0, 108)
for i := 128; i >= 21; i-- {
lowerdirs = append(lowerdirs, fmt.Sprintf("%d/fs", i))
}
return []string{
"workdir=129/work",
"upperdir=129/fs",
fmt.Sprintf("lowerdir=%s", strings.Join(lowerdirs, ":")),
"ro",
}
}(),
},
{
name: "disjoint paths - no compaction possible",
options: []string{
"workdir=/tmp/work",
"upperdir=/tmp/upper",
"lowerdir=/var/lib/snapshots/2/fs:/var/lib/snapshots/1/fs",
},
expectedChdir: "",
expectedOptions: nil, // same as input
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
chdir, newopts := compactLowerdirOption(tc.options)
assert.Equal(t, tc.expectedChdir, chdir)
if tc.expectedOptions != nil {
assert.Equal(t, tc.expectedOptions, newopts)
}
if chdir != "" {
_, newdata := parseOptions(newopts)
assert.Less(t, len(newdata), len(strings.Join(tc.options, ",")),
"compacted options should be shorter than original")
}
})
}
}
func TestCompactLowerdirOption_RealWorldSizeSavings(t *testing.T) {
lowerdirs := make([]string, 0, 108)
for i := 128; i >= 21; i-- {
lowerdirs = append(lowerdirs, fmt.Sprintf("/var/lib/nydus-snapshotter/snapshots/%d/fs", i))
}
options := []string{
"workdir=/var/lib/nydus-snapshotter/snapshots/129/work",
"upperdir=/var/lib/nydus-snapshotter/snapshots/129/fs",
fmt.Sprintf("lowerdir=%s", strings.Join(lowerdirs, ":")),
}
_, origdata := parseOptions(options)
chdir, newopts := compactLowerdirOption(options)
require.NotEmpty(t, chdir)
_, compactdata := parseOptions(newopts)
assert.Greater(t, len(origdata), 4096, "original data should exceed page size")
assert.Less(t, len(compactdata), 4096, "compacted data should fit within page size")
}
func TestParseArgs(t *testing.T) {
tests := []struct {
name string
args []string
expectedType string
expectedTarget string
expectedOptions []string
expectErr bool
}{
{
name: "basic overlay",
args: []string{"overlay", "/tmp/merged", "-o", "lowerdir=/a:/b,upperdir=/c,workdir=/d"},
expectedType: "overlay",
expectedTarget: "/tmp/merged",
expectedOptions: []string{"lowerdir=/a:/b", "upperdir=/c", "workdir=/d"},
},
{
name: "filters extraoption",
args: []string{"overlay", "/tmp/merged", "-o", "lowerdir=/a:/b,extraoption=abc123,ro"},
expectedType: "overlay",
expectedTarget: "/tmp/merged",
expectedOptions: []string{"lowerdir=/a:/b", "ro"},
},
{
name: "filters kata volume option",
args: []string{"overlay", "/tmp/merged", "-o", "lowerdir=/a:/b,io.katacontainers.volume=abc123,ro"},
expectedType: "overlay",
expectedTarget: "/tmp/merged",
expectedOptions: []string{"lowerdir=/a:/b", "ro"},
},
{
name: "invalid fs type",
args: []string{"ext4", "/tmp/merged", "-o", "lowerdir=/a"},
expectErr: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
margs, err := parseArgs(tc.args)
if tc.expectErr {
assert.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tc.expectedType, margs.fsType)
assert.Equal(t, tc.expectedTarget, margs.target)
assert.Equal(t, tc.expectedOptions, margs.options)
})
}
}
================================================
FILE: cmd/optimizer-nri-plugin/main.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"context"
"fmt"
"io"
"log/syslog"
"os"
"path/filepath"
"strings"
"time"
"github.com/containerd/log"
distribution "github.com/distribution/reference"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/containerd/nri/pkg/api"
"github.com/containerd/nri/pkg/stub"
"github.com/containerd/nydus-snapshotter/pkg/errdefs"
"github.com/containerd/nydus-snapshotter/pkg/fanotify"
"github.com/containerd/nydus-snapshotter/version"
"github.com/pelletier/go-toml"
)
const (
defaultEvents = "StartContainer,StopContainer"
defaultServerPath = "/usr/local/bin/optimizer-server"
defaultPersistDir = "/opt/nri/optimizer/results"
)
type PluginConfig struct {
Events []string `toml:"events"`
ServerPath string `toml:"server_path"`
PersistDir string `toml:"persist_dir"`
Readable bool `toml:"readable"`
Timeout int `toml:"timeout"`
Overwrite bool `toml:"overwrite"`
}
type PluginArgs struct {
PluginName string
PluginIdx string
PluginEvents string
Config PluginConfig
}
type Flags struct {
Args *PluginArgs
F []cli.Flag
}
func buildFlags(args *PluginArgs) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "plugin name to register to NRI",
Destination: &args.PluginName,
},
&cli.StringFlag{
Name: "idx",
Usage: "plugin index to register to NRI",
Destination: &args.PluginIdx,
},
&cli.StringFlag{
Name: "events",
Value: defaultEvents,
Usage: "the events that containerd subscribes to. DO NOT CHANGE THIS.",
Destination: &args.PluginEvents,
},
&cli.StringFlag{
Name: "server-path",
Value: defaultServerPath,
Usage: "the path of optimizer server binary",
Destination: &args.Config.ServerPath,
},
&cli.StringFlag{
Name: "persist-dir",
Value: defaultPersistDir,
Usage: "the directory to persist accessed files list for container",
Destination: &args.Config.PersistDir,
},
&cli.BoolFlag{
Name: "readable",
Value: false,
Usage: "whether to make the csv file human readable",
Destination: &args.Config.Readable,
},
&cli.IntFlag{
Name: "timeout",
Value: 0,
Usage: "the timeout to kill optimizer server, 0 to disable it",
Destination: &args.Config.Timeout,
},
&cli.BoolFlag{
Name: "overwrite",
Usage: "whether to overwrite the existed persistent files",
Destination: &args.Config.Overwrite,
},
}
}
func NewPluginFlags() *Flags {
var args PluginArgs
return &Flags{
Args: &args,
F: buildFlags(&args),
}
}
type plugin struct {
stub stub.Stub
mask stub.EventMask
}
var (
cfg PluginConfig
logWriter *syslog.Writer
globalFanotifyServer = make(map[string]*fanotify.Server)
_ = stub.ConfigureInterface(&plugin{})
_ = stub.StartContainerInterface(&plugin{})
_ = stub.StopContainerInterface(&plugin{})
)
const (
imageNameLabel = "io.kubernetes.cri.image-name"
)
func (p *plugin) Configure(ctx context.Context, config, runtime, version string) (stub.EventMask, error) {
log.G(ctx).Infof("got configuration data: %q from runtime %s %s", config, runtime, version)
if config == "" {
return p.mask, nil
}
tree, err := toml.Load(config)
if err != nil {
return 0, errors.Wrap(err, "parse TOML")
}
if err := tree.Unmarshal(&cfg); err != nil {
return 0, err
}
p.mask, err = api.ParseEventMask(cfg.Events...)
if err != nil {
return 0, errors.Wrap(err, "parse events in configuration")
}
log.G(ctx).Infof("configuration: %#v", cfg)
return p.mask, nil
}
func (p *plugin) StartContainer(_ context.Context, _ *api.PodSandbox, container *api.Container) error {
dir, imageName, err := GetImageName(container.Annotations)
if err != nil {
return err
}
persistDir := filepath.Join(cfg.PersistDir, dir)
if err := os.MkdirAll(persistDir, os.ModePerm); err != nil {
return err
}
persistFile := filepath.Join(persistDir, imageName)
if cfg.Timeout > 0 {
persistFile = fmt.Sprintf("%s.timeout%ds", persistFile, cfg.Timeout)
}
fanotifyServer := fanotify.NewServer(cfg.ServerPath, container.Pid, imageName, persistFile, cfg.Readable, cfg.Overwrite, time.Duration(cfg.Timeout)*time.Second, logWriter)
if err := fanotifyServer.RunServer(); err != nil {
return err
}
globalFanotifyServer[imageName] = fanotifyServer
return nil
}
func (p *plugin) StopContainer(_ context.Context, _ *api.PodSandbox, container *api.Container) ([]*api.ContainerUpdate, error) {
var update = []*api.ContainerUpdate{}
_, imageName, err := GetImageName(container.Annotations)
if err != nil {
return update, err
}
if fanotifyServer, ok := globalFanotifyServer[imageName]; ok {
fanotifyServer.StopServer()
} else {
return nil, errors.New("can not find fanotify server for container image " + imageName)
}
return update, nil
}
func GetImageName(annotations map[string]string) (string, string, error) {
named, err := distribution.ParseDockerRef(annotations[imageNameLabel])
if err != nil {
return "", "", err
}
nameTagged := named.(distribution.NamedTagged)
repo := distribution.Path(nameTagged)
dir := filepath.Dir(repo)
image := filepath.Base(repo)
imageName := image + ":" + nameTagged.Tag()
return dir, imageName, nil
}
func (p *plugin) onClose() {
for _, fanotifyServer := range globalFanotifyServer {
fanotifyServer.StopServer()
}
os.Exit(0)
}
func main() {
flags := NewPluginFlags()
app := &cli.App{
Name: "optimizer-nri-plugin",
Usage: "Optimizer client for NRI plugin to manage optimizer server",
Version: version.Version,
Flags: flags.F,
HideVersion: true,
Action: func(_ *cli.Context) error {
var (
opts []stub.Option
err error
)
cfg = flags.Args.Config
// FIXME(thaJeztah): ucontainerd's log does not set "PadLevelText: true"
_ = log.SetFormat(log.TextFormat)
ctx := log.WithLogger(context.Background(), log.L)
logWriter, err = syslog.New(syslog.LOG_INFO, "optimizer-nri-plugin")
if err == nil {
log.G(ctx).Logger.SetOutput(io.MultiWriter(os.Stdout, logWriter))
}
if flags.Args.PluginName != "" {
opts = append(opts, stub.WithPluginName(flags.Args.PluginName))
}
if flags.Args.PluginIdx != "" {
opts = append(opts, stub.WithPluginIdx(flags.Args.PluginIdx))
}
p := &plugin{}
if p.mask, err = api.ParseEventMask(flags.Args.PluginEvents); err != nil {
log.G(ctx).Fatalf("failed to parse events: %v", err)
}
cfg.Events = strings.Split(flags.Args.PluginEvents, ",")
if p.stub, err = stub.New(p, append(opts, stub.WithOnClose(p.onClose))...); err != nil {
log.G(ctx).Fatalf("failed to create plugin stub: %v", err)
}
err = p.stub.Run(context.Background())
if err != nil {
log.G(ctx).Errorf("plugin exited with error %v", err)
os.Exit(1)
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
if errdefs.IsConnectionClosed(err) {
log.L.Info("optimizer NRI plugin exited")
} else {
log.L.WithError(err).Fatal("failed to start optimizer NRI plugin")
}
}
}
================================================
FILE: cmd/prefetchfiles-nri-plugin/main.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"context"
"fmt"
"io"
"log/syslog"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/containerd/log"
"github.com/containerd/nri/pkg/api"
"github.com/containerd/nri/pkg/stub"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/containerd/nydus-snapshotter/pkg/errdefs"
"github.com/containerd/nydus-snapshotter/version"
)
const (
endpointPrefetch = "/api/v1/prefetch"
defaultEvents = "RunPodSandbox"
defaultSystemControllerAddress = "/run/containerd-nydus/system.sock"
defaultPrefetchConfigDir = "/etc/nydus"
nydusPrefetchAnnotation = "containerd.io/nydus-prefetch"
)
type PluginArgs struct {
PluginName string
PluginIdx string
SocketAddress string
}
type Flags struct {
Args *PluginArgs
Flag []cli.Flag
}
func buildFlags(args *PluginArgs) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "plugin name to register to NRI",
Destination: &args.PluginName,
},
&cli.StringFlag{
Name: "idx",
Usage: "plugin index to register to NRI",
Destination: &args.PluginIdx,
},
&cli.StringFlag{
Name: "socket-addr",
Value: defaultSystemControllerAddress,
Usage: "unix domain socket address. If defined in the configuration file, there is no need to add ",
Destination: &args.SocketAddress,
},
}
}
func NewPluginFlags() *Flags {
var args PluginArgs
return &Flags{
Args: &args,
Flag: buildFlags(&args),
}
}
type plugin struct {
stub stub.Stub
mask stub.EventMask
}
var (
globalSocket string
logWriter *syslog.Writer
_ = stub.RunPodInterface(&plugin{})
)
// sendDataOverHTTP sends the prefetch data to the specified endpoint over HTTP using a Unix socket.
func sendDataOverHTTP(data string, endpoint, sock string) error {
url := fmt.Sprintf("http://unix%s", endpoint)
req, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data))
if err != nil {
return err
}
client := &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", sock)
},
},
}
resp, err := client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to send data, status code: %d", resp.StatusCode)
}
resp.Body.Close()
return nil
}
func (p *plugin) RunPodSandbox(ctx context.Context, pod *api.PodSandbox) error {
prefetchList, ok := pod.Annotations[nydusPrefetchAnnotation]
if !ok {
return nil
}
err := sendDataOverHTTP(prefetchList, endpointPrefetch, globalSocket)
if err != nil {
log.G(ctx).Errorf("failed to send data: %v", err)
return err
}
return nil
}
func main() {
flags := NewPluginFlags()
app := &cli.App{
Name: "prefetch-nri-plugin",
Usage: "NRI plugin for obtaining and transmitting prefetch files path",
Version: version.Version,
Flags: flags.Flag,
HideVersion: true,
Action: func(_ *cli.Context) error {
var (
opts []stub.Option
err error
)
// FIXME(thaJeztah): ucontainerd's log does not set "PadLevelText: true"
_ = log.SetFormat(log.TextFormat)
ctx := log.WithLogger(context.Background(), log.L)
configFileName := "prefetchConfig.toml"
configDir := defaultPrefetchConfigDir
configFilePath := filepath.Join(configDir, configFileName)
config, err := toml.LoadFile(configFilePath)
if err != nil {
log.G(ctx).Warnf("failed to read config file: %v", err)
}
configSocketAddrRaw := config.Get("file_prefetch.socket_address")
if configSocketAddrRaw != nil {
if configSocketAddr, ok := configSocketAddrRaw.(string); ok {
globalSocket = configSocketAddr
} else {
log.G(ctx).Warnf("failed to read config: 'file_prefetch.socket_address' is not a string")
}
} else {
globalSocket = flags.Args.SocketAddress
}
logWriter, err = syslog.New(syslog.LOG_INFO, "prefetch-nri-plugin")
if err == nil {
log.G(ctx).Logger.SetOutput(io.MultiWriter(os.Stdout, logWriter))
}
if flags.Args.PluginName != "" {
opts = append(opts, stub.WithPluginName(flags.Args.PluginName))
}
if flags.Args.PluginIdx != "" {
opts = append(opts, stub.WithPluginIdx(flags.Args.PluginIdx))
}
p := &plugin{}
if p.mask, err = api.ParseEventMask(defaultEvents); err != nil {
log.G(ctx).Fatalf("failed to parse events: %v", err)
}
if p.stub, err = stub.New(p, opts...); err != nil {
log.G(ctx).Fatalf("failed to create plugin stub: %v", err)
}
err = p.stub.Run(context.Background())
if err != nil {
return errors.Wrap(err, "plugin exited")
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
if errdefs.IsConnectionClosed(err) {
log.L.Info("prefetch NRI plugin exited")
} else {
log.L.WithError(err).Fatal("failed to start prefetch NRI plugin")
}
}
}
================================================
FILE: config/config.go
================================================
/*
* Copyright (c) 2020. Ant Group. All rights reserved.
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package config
import (
"os"
"time"
"dario.cat/mergo"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
"github.com/containerd/nydus-snapshotter/internal/constant"
"github.com/containerd/nydus-snapshotter/internal/flags"
"github.com/containerd/nydus-snapshotter/pkg/cgroup"
"github.com/containerd/nydus-snapshotter/pkg/errdefs"
"github.com/containerd/nydus-snapshotter/pkg/utils/file"
"github.com/containerd/nydus-snapshotter/pkg/utils/parser"
"github.com/containerd/nydus-snapshotter/pkg/utils/sysinfo"
)
func init() {
recoverPolicyParser = map[string]DaemonRecoverPolicy{
RecoverPolicyNone.String(): RecoverPolicyNone,
RecoverPolicyRestart.String(): RecoverPolicyRestart,
RecoverPolicyFailover.String(): RecoverPolicyFailover}
}
// Define a policy how to fork nydusd daemon and attach file system instances to serve.
type DaemonMode string
const (
// Spawn a dedicated nydusd for each RAFS instance.
DaemonModeMultiple DaemonMode = DaemonMode(constant.DaemonModeMultiple)
// Spawn a dedicated nydusd for each RAFS instance.
DaemonModeDedicated DaemonMode = DaemonMode(constant.DaemonModeDedicated)
// Share a global nydusd to serve all RAFS instances.
DaemonModeShared DaemonMode = DaemonMode(constant.DaemonModeShared)
// Do not spawn nydusd for RAFS instances.
//
// For tarfs and rund, there's no need to create nydusd to serve RAFS instances,
// the snapshotter just returns mount slices with additional information for runC/runD
// to manage those snapshots.
DaemonModeNone DaemonMode = DaemonMode(constant.DaemonModeNone)
DaemonModeInvalid DaemonMode = DaemonMode(constant.DaemonModeInvalid)
// MaxRootPathLen defines the maximum allowed length of the root portion of a Unix domain socket path.
//
// This value is calculated based on the hard length limit of `sun_path` on Linux systems (108 bytes).
// Nydusd's socket path format is "${rootPath}/socket/${xid}/api?.sock".
// - The length of the fixed part "/socket/${xid}/api?.sock" is 38 bytes.
//
// Since the maximum upper limit of the total path length is 108 bytes, in order to avoid exceeding the limit, the maximum allowed length of rootPath is:
// 108 - len("/socket/${xid}/api?.sock") = 108 - 38 = 70.
// Therefore, we must set the effective maximum length of the root path to 70 bytes.
MaxRootPathLen = 70
)
func parseDaemonMode(m string) (DaemonMode, error) {
switch m {
case string(DaemonModeMultiple):
return DaemonModeDedicated, nil
case string(DaemonModeDedicated):
return DaemonModeDedicated, nil
case string(DaemonModeShared):
return DaemonModeShared, nil
case string(DaemonModeNone):
return DaemonModeNone, nil
default:
return DaemonModeInvalid, errors.Errorf("invalid daemon mode %q", m)
}
}
type DaemonRecoverPolicy int
const (
RecoverPolicyInvalid DaemonRecoverPolicy = iota
RecoverPolicyNone
RecoverPolicyRestart
RecoverPolicyFailover
)
func (p DaemonRecoverPolicy) String() string {
switch p {
case RecoverPolicyNone:
return "none"
case RecoverPolicyRestart:
return "restart"
case RecoverPolicyFailover:
return "failover"
case RecoverPolicyInvalid:
fallthrough
default:
return ""
}
}
var recoverPolicyParser map[string]DaemonRecoverPolicy
func ParseRecoverPolicy(p string) (DaemonRecoverPolicy, error) {
policy, ok := recoverPolicyParser[p]
if !ok {
return RecoverPolicyInvalid, errors.Errorf("invalid recover policy %q", p)
}
return policy, nil
}
const (
FsDriverBlockdev string = constant.FsDriverBlockdev
FsDriverFusedev string = constant.FsDriverFusedev
FsDriverFscache string = constant.FsDriverFscache
FsDriverNodev string = constant.FsDriverNodev
FsDriverProxy string = constant.FsDriverProxy
)
const (
FailoverPolicyNone string = constant.FailoverPolicyNone
FailoverPolicyResend string = constant.FailoverPolicyResend
FailoverPolicyFlush string = constant.FailoverPolicyFlush
)
type Experimental struct {
EnableStargz bool `toml:"enable_stargz"`
EnableReferrerDetect bool `toml:"enable_referrer_detect"`
EnableIndexDetect bool `toml:"enable_index_detect"`
TarfsConfig TarfsConfig `toml:"tarfs"`
EnableBackendSource bool `toml:"enable_backend_source"`
}
type TarfsConfig struct {
EnableTarfs bool `toml:"enable_tarfs"`
MountTarfsOnHost bool `toml:"mount_tarfs_on_host"`
TarfsHint bool `toml:"tarfs_hint"`
MaxConcurrentProc int `toml:"max_concurrent_proc"`
ExportMode string `toml:"export_mode"`
}
type CgroupConfig struct {
Enable bool `toml:"enable"`
MemoryLimit string `toml:"memory_limit"`
}
// Configure how to start and recover nydusd daemons
type DaemonConfig struct {
NydusdPath string `toml:"nydusd_path"`
NydusdConfigPath string `toml:"nydusd_config"`
NydusImagePath string `toml:"nydusimage_path"`
RecoverPolicy string `toml:"recover_policy"`
FsDriver string `toml:"fs_driver"`
ThreadsNumber int `toml:"threads_number"`
LogRotationSize int `toml:"log_rotation_size"`
FailoverPolicy string `toml:"failover_policy"`
}
type LoggingConfig struct {
LogToStdout bool `toml:"log_to_stdout"`
LogLevel string `toml:"level"`
LogDir string `toml:"dir"`
RotateLogMaxSize int `toml:"log_rotation_max_size"`
RotateLogMaxBackups int `toml:"log_rotation_max_backups"`
RotateLogMaxAge int `toml:"log_rotation_max_age"`
RotateLogLocalTime bool `toml:"log_rotation_local_time"`
RotateLogCompress bool `toml:"log_rotation_compress"`
}
// Nydus image layers additional process
type ImageConfig struct {
PublicKeyFile string `toml:"public_key_file"`
ValidateSignature bool `toml:"validate_signature"`
}
// Configure containerd snapshots interfaces and how to process the snapshots
// requests from containerd
type SnapshotConfig struct {
EnableNydusOverlayFS bool `toml:"enable_nydus_overlayfs"`
NydusOverlayFSPath string `toml:"nydus_overlayfs_path"`
EnableKataVolume bool `toml:"enable_kata_volume"`
SyncRemove bool `toml:"sync_remove"`
// EnableOverlayfsVolatile globally enables the "volatile" overlayfs mount option
// on all writable snapshots. This skips sync on the upper layer, improving
// write performance for ephemeral container filesystems at the cost of crash consistency.
EnableOverlayfsVolatile bool `toml:"enable_overlayfs_volatile"`
}
// Configure cache manager that manages the cache files lifecycle
type CacheManagerConfig struct {
Disable bool `toml:"disable"`
// Trigger GC gc_period after the specified period.
// Example format: 24h, 120min
GCPeriod time.Duration `toml:"gc_period"`
CacheDir string `toml:"cache_dir"`
}
// Configure how nydus-snapshotter receive auth information
type AuthConfig struct {
// based on kubeconfig or ServiceAccount
EnableKubeconfigKeychain bool `toml:"enable_kubeconfig_keychain"`
KubeconfigPath string `toml:"kubeconfig_path"`
// CRI proxy mode
EnableCRIKeychain bool `toml:"enable_cri_keychain"`
ImageServiceAddress string `toml:"image_service_address"`
// Kubelet credential provider plugins
EnableKubeletCredentialProviders bool `toml:"enable_kubelet_credential_providers"`
CredentialProviderConfig string `toml:"credential_provider_config"`
CredentialProviderBinDir string `toml:"credential_provider_bin_dir"`
// Periodic credential renewal interval. When set to a positive duration,
// the snapshotter caches credentials from configured renewable providers and
// refreshes them at this interval. Set to 0 (default) to disable.
CredentialRenewalInterval time.Duration `toml:"credential_renewal_interval"`
}
// Configure remote storage like container registry
type RemoteConfig struct {
AuthConfig AuthConfig `toml:"auth"`
ConvertVpcRegistry bool `toml:"convert_vpc_registry"`
SkipSSLVerify bool `toml:"skip_ssl_verify"`
MirrorsConfig MirrorsConfig `toml:"mirrors_config"`
}
type MirrorsConfig struct {
Dir string `toml:"dir"`
}
type MetricsConfig struct {
// Address is the network address for the metrics server. Empty indicates the server is disabled.
Address string `toml:"address"`
// HungIOInterval defines the timeout for a single I/O operation to be considered "hung".
HungIOInterval time.Duration `toml:"hung_io_interval"`
// CollectInterval defines how often metrics are collected and reported.
CollectInterval time.Duration `toml:"collect_interval"`
}
type DebugConfig struct {
ProfileDuration int64 `toml:"daemon_cpu_profile_duration_secs"`
PprofAddress string `toml:"pprof_address"`
}
type SystemControllerConfig struct {
Enable bool `toml:"enable"`
Address string `toml:"address"`
// UID to set on the system controller socket
UID int `toml:"uid"`
// GID to set on the system controller socket
GID int `toml:"gid"`
DebugConfig DebugConfig `toml:"debug"`
}
type SnapshotterConfig struct {
// Configuration format version
Version int `toml:"version"`
// Snapshotter's root work directory
Root string `toml:"root"`
Address string `toml:"address"`
// UID to set on the snapshotter socket
UID int `toml:"uid"`
// GID to set on the snapshotter socket
GID int `toml:"gid"`
DaemonMode string `toml:"daemon_mode"`
// Clean up all the resources when snapshotter is closed
CleanupOnClose bool `toml:"cleanup_on_close"`
SystemControllerConfig SystemControllerConfig `toml:"system"`
MetricsConfig MetricsConfig `toml:"metrics"`
DaemonConfig DaemonConfig `toml:"daemon"`
SnapshotsConfig SnapshotConfig `toml:"snapshot"`
RemoteConfig RemoteConfig `toml:"remote"`
ImageConfig ImageConfig `toml:"image"`
CacheManagerConfig CacheManagerConfig `toml:"cache_manager"`
LoggingConfig LoggingConfig `toml:"log"`
CgroupConfig CgroupConfig `toml:"cgroup"`
Experimental Experimental `toml:"experimental"`
}
func LoadSnapshotterConfig(path string) (*SnapshotterConfig, error) {
var config SnapshotterConfig
// get nydus-snapshotter configuration from specified path of toml file
if path == "" {
return nil, errors.New("snapshotter configuration path cannot be empty")
}
tree, err := toml.LoadFile(path)
if err != nil {
return nil, errors.Wrapf(err, "load toml configuration from file %q", path)
}
if err = tree.Unmarshal(&config); err != nil {
return nil, errors.Wrap(err, "unmarshal snapshotter configuration")
}
if config.Version != 1 {
return nil, errors.Errorf("unsupported configuration version %d", config.Version)
}
return &config, nil
}
func MergeConfig(to, from *SnapshotterConfig) error {
err := mergo.Merge(to, from)
if err != nil {
return err
}
return nil
}
func ValidateConfig(c *SnapshotterConfig) error {
if c == nil {
return errors.Wrapf(errdefs.ErrInvalidArgument, "configuration is none")
}
if c.ImageConfig.ValidateSignature {
if c.ImageConfig.PublicKeyFile == "" {
return errors.New("public key file for signature validation is not provided")
} else if _, err := os.Stat(c.ImageConfig.PublicKeyFile); err != nil {
return errors.Wrapf(err, "check publicKey file %q", c.ImageConfig.PublicKeyFile)
}
}
rootPathLen := len(c.Root)
if rootPathLen == 0 {
return errors.New("empty root directory")
}
if rootPathLen > MaxRootPathLen {
return errors.Errorf("root directory path is too long: %d bytes, max is %d bytes", rootPathLen, MaxRootPathLen)
}
if c.DaemonConfig.FsDriver != FsDriverFscache && c.DaemonConfig.FsDriver != FsDriverFusedev &&
c.DaemonConfig.FsDriver != FsDriverBlockdev && c.DaemonConfig.FsDriver != FsDriverNodev &&
c.DaemonConfig.FsDriver != FsDriverProxy {
return errors.Errorf("invalid filesystem driver %q", c.DaemonConfig.FsDriver)
}
if _, err := ParseRecoverPolicy(c.DaemonConfig.RecoverPolicy); err != nil {
return err
}
if c.DaemonConfig.ThreadsNumber > 1024 {
return errors.Errorf("nydusd worker thread number %d is too big, max 1024", c.DaemonConfig.ThreadsNumber)
}
if c.DaemonConfig.FailoverPolicy != FailoverPolicyNone &&
c.DaemonConfig.FailoverPolicy != FailoverPolicyResend &&
c.DaemonConfig.FailoverPolicy != FailoverPolicyFlush {
return errors.Errorf("invalid failover policy %q", c.DaemonConfig.FailoverPolicy)
}
if c.RemoteConfig.AuthConfig.EnableCRIKeychain && c.RemoteConfig.AuthConfig.EnableKubeconfigKeychain {
return errors.Wrapf(errdefs.ErrInvalidArgument,
"\"enable_cri_keychain\" and \"enable_kubeconfig_keychain\" can't be set at the same time")
}
if c.RemoteConfig.MirrorsConfig.Dir != "" {
dirExisted, err := file.IsDirExisted(c.RemoteConfig.MirrorsConfig.Dir)
if err != nil {
return err
}
if !dirExisted {
return errors.Errorf("mirrors config directory %s does not exist", c.RemoteConfig.MirrorsConfig.Dir)
}
}
return nil
}
// Parse command line arguments and fill the nydus-snapshotter configuration
// Always let options from CLI override those from configuration file.
func ParseParameters(args *flags.Args, cfg *SnapshotterConfig) error {
// --- essential configuration
if args.Address != "" {
cfg.Address = args.Address
}
if args.RootDir != "" {
cfg.Root = args.RootDir
}
// Give --shared-daemon higher priority
if args.DaemonMode != "" {
cfg.DaemonMode = args.DaemonMode
}
// --- image processor configuration
// empty
// --- daemon configuration
daemonConfig := &cfg.DaemonConfig
if args.NydusdConfigPath != "" {
daemonConfig.NydusdConfigPath = args.NydusdConfigPath
}
if args.NydusdPath != "" {
daemonConfig.NydusdPath = args.NydusdPath
}
if args.NydusImagePath != "" {
daemonConfig.NydusImagePath = args.NydusImagePath
}
if args.FsDriver != "" {
daemonConfig.FsDriver = args.FsDriver
}
// --- cache manager configuration
// empty
// --- logging configuration
logConfig := &cfg.LoggingConfig
if args.LogLevel != "" {
logConfig.LogLevel = args.LogLevel
}
if args.LogToStdoutCount > 0 {
logConfig.LogToStdout = args.LogToStdout
}
// --- remote storage configuration
// empty
// --- snapshot configuration
if args.NydusOverlayFSPath != "" {
cfg.SnapshotsConfig.NydusOverlayFSPath = args.NydusOverlayFSPath
}
// --- metrics configuration
// empty
return nil
}
func ParseCgroupConfig(config CgroupConfig) (cgroup.Config, error) {
totalMemory, err := sysinfo.GetTotalMemoryBytes()
if err != nil {
return cgroup.Config{}, errors.Wrap(err, "Failed to get total memory bytes")
}
memoryLimitInBytes, err := parser.MemoryConfigToBytes(config.MemoryLimit, totalMemory)
if err != nil {
return cgroup.Config{}, err
}
return cgroup.Config{
MemoryLimitInBytes: memoryLimitInBytes,
}, nil
}
================================================
FILE: config/config_test.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package config
import (
"path/filepath"
"testing"
"github.com/containerd/nydus-snapshotter/internal/constant"
"github.com/containerd/nydus-snapshotter/internal/flags"
"github.com/stretchr/testify/assert"
)
func TestLoadSnapshotterTOMLConfig(t *testing.T) {
A := assert.New(t)
cfg, err := LoadSnapshotterConfig("../misc/snapshotter/config.toml")
A.NoError(err)
exampleConfig := SnapshotterConfig{
Version: 1,
Root: "/var/lib/containerd/io.containerd.snapshotter.v1.nydus",
Address: "/run/containerd-nydus/containerd-nydus-grpc.sock",
UID: 0,
GID: 0,
DaemonMode: "dedicated",
Experimental: Experimental{
EnableStargz: false,
EnableReferrerDetect: false,
EnableIndexDetect: false,
},
CleanupOnClose: false,
SystemControllerConfig: SystemControllerConfig{
Enable: true,
Address: "/run/containerd-nydus/system.sock",
UID: 0,
GID: 0,
DebugConfig: DebugConfig{
ProfileDuration: 5,
PprofAddress: "",
},
},
DaemonConfig: DaemonConfig{
NydusdPath: "/usr/local/bin/nydusd",
NydusImagePath: "/usr/local/bin/nydus-image",
FsDriver: "fusedev",
RecoverPolicy: "failover",
NydusdConfigPath: "/etc/nydus/nydusd-config.fusedev.json",
ThreadsNumber: 4,
LogRotationSize: 100,
FailoverPolicy: "resend",
},
SnapshotsConfig: SnapshotConfig{
EnableNydusOverlayFS: false,
NydusOverlayFSPath: "nydus-overlayfs",
SyncRemove: false,
},
RemoteConfig: RemoteConfig{
ConvertVpcRegistry: false,
AuthConfig: AuthConfig{
EnableKubeconfigKeychain: false,
KubeconfigPath: "",
},
MirrorsConfig: MirrorsConfig{
Dir: "",
},
},
ImageConfig: ImageConfig{
PublicKeyFile: "",
ValidateSignature: false,
},
CacheManagerConfig: CacheManagerConfig{
Disable: false,
GCPeriod: constant.DefaultGCPeriod,
CacheDir: "",
},
LoggingConfig: LoggingConfig{
LogLevel: "info",
RotateLogCompress: true,
RotateLogLocalTime: true,
RotateLogMaxAge: 7,
RotateLogMaxBackups: 5,
RotateLogMaxSize: 100,
LogToStdout: false,
},
MetricsConfig: MetricsConfig{
Address: ":9110",
HungIOInterval: constant.DefaultHungIOInterval,
CollectInterval: constant.DefaultCollectInterval,
},
CgroupConfig: CgroupConfig{
Enable: true,
MemoryLimit: "",
},
}
A.EqualValues(cfg, &exampleConfig)
args := flags.Args{}
args.RootDir = "/var/lib/containerd/nydus"
exampleConfig.Root = "/var/lib/containerd/nydus"
err = ParseParameters(&args, cfg)
A.NoError(err)
A.EqualValues(cfg, &exampleConfig)
A.EqualValues(cfg.LoggingConfig.LogToStdout, false)
args.LogToStdout = true
args.LogToStdoutCount = 1
err = ParseParameters(&args, cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, true)
err = ProcessConfigurations(cfg)
A.NoError(err)
A.Equal(cfg.CacheManagerConfig.GCPeriod, constant.DefaultGCPeriod)
A.Equal(cfg.MetricsConfig.HungIOInterval, constant.DefaultHungIOInterval)
A.Equal(cfg.MetricsConfig.CollectInterval, constant.DefaultCollectInterval)
}
func TestSnapshotterConfig(t *testing.T) {
A := assert.New(t)
var cfg SnapshotterConfig
var args flags.Args
// The log_to_stdout is false in toml file without --log-to-stdout flag.
// Expected false.
cfg.LoggingConfig.LogToStdout = false
args.LogToStdoutCount = 0
err := ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, false)
// The log_to_stdout is true in toml file without --log-to-stdout flag.
// Expected true.
// This case is failed.
cfg.LoggingConfig.LogToStdout = true
args.LogToStdoutCount = 0
err = ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, true)
// The log_to_stdout is false in toml file with --log-to-stdout=true.
// Expected true (command flag has higher priority).
args.LogToStdout = true
args.LogToStdoutCount = 1
cfg.LoggingConfig.LogToStdout = false
err = ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, true)
// The log_to_stdout is true in toml file with --log-to-stdout=true.
// Expected true (command flag has higher priority).
args.LogToStdout = true
args.LogToStdoutCount = 1
cfg.LoggingConfig.LogToStdout = true
err = ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, true)
// The log_to_stdout is false in toml file with --log-to-stdout=false.
// Expected false (command flag has higher priority).
args.LogToStdout = false
args.LogToStdoutCount = 1
cfg.LoggingConfig.LogToStdout = false
err = ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, false)
// The log_to_stdout is true in toml file with --log-to-stdout=false.
// Expected false (command flag has higher priority).
args.LogToStdout = false
args.LogToStdoutCount = 1
cfg.LoggingConfig.LogToStdout = true
err = ParseParameters(&args, &cfg)
A.NoError(err)
A.EqualValues(cfg.LoggingConfig.LogToStdout, false)
}
func TestMergeConfig(t *testing.T) {
A := assert.New(t)
var defaultSnapshotterConfig SnapshotterConfig
var snapshotterConfig1 SnapshotterConfig
err := defaultSnapshotterConfig.FillUpWithDefaults()
A.NoError(err)
err = MergeConfig(&snapshotterConfig1, &defaultSnapshotterConfig)
A.NoError(err)
A.Equal(snapshotterConfig1.Root, constant.DefaultRootDir)
A.Equal(snapshotterConfig1.LoggingConfig.LogDir, "")
A.Equal(snapshotterConfig1.CacheManagerConfig.CacheDir, "")
A.Equal(snapshotterConfig1.DaemonMode, constant.DefaultDaemonMode)
A.Equal(snapshotterConfig1.SystemControllerConfig.Address, constant.DefaultSystemControllerAddress)
A.Equal(snapshotterConfig1.LoggingConfig.LogLevel, constant.DefaultLogLevel)
A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxSize, constant.DefaultRotateLogMaxSize)
A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxBackups, constant.DefaultRotateLogMaxBackups)
A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxAge, constant.DefaultRotateLogMaxAge)
A.Equal(snapshotterConfig1.LoggingConfig.RotateLogCompress, constant.DefaultRotateLogCompress)
A.Equal(snapshotterConfig1.DaemonConfig.NydusdConfigPath, constant.DefaultNydusDaemonConfigPath)
A.Equal(snapshotterConfig1.DaemonConfig.RecoverPolicy, RecoverPolicyRestart.String())
A.Equal(snapshotterConfig1.CacheManagerConfig.GCPeriod, constant.DefaultGCPeriod)
A.Equal(snapshotterConfig1.MetricsConfig.HungIOInterval, constant.DefaultHungIOInterval)
A.Equal(snapshotterConfig1.MetricsConfig.CollectInterval, constant.DefaultCollectInterval)
var snapshotterConfig2 SnapshotterConfig
snapshotterConfig2.Root = "/snapshotter/root"
err = MergeConfig(&snapshotterConfig2, &defaultSnapshotterConfig)
A.NoError(err)
A.Equal(snapshotterConfig2.Root, "/snapshotter/root")
A.Equal(snapshotterConfig2.LoggingConfig.LogDir, "")
A.Equal(snapshotterConfig2.CacheManagerConfig.CacheDir, "")
}
func TestProcessConfigurations(t *testing.T) {
A := assert.New(t)
var defaultSnapshotterConfig SnapshotterConfig
var snapshotterConfig1 SnapshotterConfig
err := defaultSnapshotterConfig.FillUpWithDefaults()
A.NoError(err)
err = MergeConfig(&snapshotterConfig1, &defaultSnapshotterConfig)
A.NoError(err)
err = ValidateConfig(&snapshotterConfig1)
A.NoError(err)
PrepareLogDir(&snapshotterConfig1)
err = ProcessConfigurations(&snapshotterConfig1)
A.NoError(err)
A.Equal(snapshotterConfig1.LoggingConfig.LogDir, filepath.Join(snapshotterConfig1.Root, "logs"))
A.Equal(snapshotterConfig1.CacheManagerConfig.CacheDir, filepath.Join(snapshotterConfig1.Root, "cache"))
var snapshotterConfig2 SnapshotterConfig
snapshotterConfig2.Root = "/snapshotter/root"
err = MergeConfig(&snapshotterConfig2, &defaultSnapshotterConfig)
A.NoError(err)
err = ValidateConfig(&snapshotterConfig2)
A.NoError(err)
PrepareLogDir(&snapshotterConfig2)
err = ProcessConfigurations(&snapshotterConfig2)
A.NoError(err)
A.Equal(snapshotterConfig2.LoggingConfig.LogDir, filepath.Join(snapshotterConfig2.Root, "logs"))
A.Equal(snapshotterConfig2.CacheManagerConfig.CacheDir, filepath.Join(snapshotterConfig2.Root, "cache"))
var snapshotterConfig3 SnapshotterConfig
snapshotterConfig3.Root = "./snapshotter/root"
err = MergeConfig(&snapshotterConfig3, &defaultSnapshotterConfig)
A.NoError(err)
err = ValidateConfig(&snapshotterConfig3)
A.NoError(err)
err = ProcessConfigurations(&snapshotterConfig3)
A.NoError(err)
var snapshotterConfig4 SnapshotterConfig
oversizedPath := "/path/to/very/long/root/directory/that/exceed/the/max/nydus-snapshotter"
A.Equal(MaxRootPathLen+1, len(oversizedPath))
snapshotterConfig4.Root = oversizedPath
err = MergeConfig(&snapshotterConfig4, &defaultSnapshotterConfig)
A.NoError(err)
err = ValidateConfig(&snapshotterConfig4)
A.Error(err)
}
================================================
FILE: config/daemonconfig/daemonconfig.go
================================================
/*
* Copyright (c) 2020. Ant Group. All rights reserved.
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"encoding/json"
"io"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"time"
"github.com/containerd/log"
"github.com/pkg/errors"
"github.com/containerd/nydus-snapshotter/config"
"github.com/containerd/nydus-snapshotter/pkg/auth"
"github.com/containerd/nydus-snapshotter/pkg/utils/registry"
)
type StorageBackendType = string
const (
backendTypeLocalfs StorageBackendType = "localfs"
backendTypeOss StorageBackendType = "oss"
backendTypeRegistry StorageBackendType = "registry"
backendTypeS3 StorageBackendType = "s3"
)
type DaemonConfig interface {
// Provide stuffs relevant to accessing registry apart from auth
Supplement(host, repo, snapshotID string, params map[string]string)
// Provide auth
FillAuth(kc *auth.PassKeyChain)
StorageBackend() (StorageBackendType, *BackendConfig)
DumpString() (string, error)
DumpFile(path string) error
}
// Daemon configurations factory
func NewDaemonConfig(fsDriver, path string) (DaemonConfig, error) {
switch fsDriver {
case config.FsDriverFscache:
cfg, err := LoadFscacheConfig(path)
if err != nil {
return nil, err
}
return cfg, nil
case config.FsDriverFusedev:
cfg, err := LoadFuseConfig(path)
if err != nil {
return nil, err
}
return cfg, nil
default:
return nil, errors.Errorf("unsupported, fs driver %q", fsDriver)
}
}
type BackendConfig struct {
// Localfs backend configs
BlobFile string `json:"blob_file,omitempty"`
Dir string `json:"dir,omitempty"`
ReadAhead bool `json:"readahead"`
ReadAheadSec int `json:"readahead_sec,omitempty"`
// Registry backend configs
Host string `json:"host,omitempty"`
Repo string `json:"repo,omitempty"`
Auth string `json:"auth,omitempty" secret:"true"`
RegistryToken string `json:"registry_token,omitempty" secret:"true"`
BlobURLScheme string `json:"blob_url_scheme,omitempty"`
BlobRedirectedHost string `json:"blob_redirected_host,omitempty"`
// Shared by oss and s3 backend configs
EndPoint string `json:"endpoint,omitempty"`
AccessKeyID string `json:"access_key_id,omitempty" secret:"true"`
AccessKeySecret string `json:"access_key_secret,omitempty" secret:"true"`
BucketName string `json:"bucket_name,omitempty"`
ObjectPrefix string `json:"object_prefix,omitempty"`
// S3-specific config
Region string `json:"region,omitempty"`
// Shared by registry, oss, and s3
Scheme string `json:"scheme,omitempty"`
SkipVerify bool `json:"skip_verify,omitempty"`
CACertFiles []string `json:"ca_cert_files,omitempty"`
// Below configs are common configs shared by all backends
Proxy struct {
URL string `json:"url,omitempty"`
Fallback bool `json:"fallback"`
PingURL string `json:"ping_url,omitempty"`
CheckInterval int `json:"check_interval,omitempty"`
UseHTTP bool `json:"use_http,omitempty"`
} `json:"proxy,omitempty"`
Timeout int `json:"timeout,omitempty"`
ConnectTimeout int `json:"connect_timeout,omitempty"`
RetryLimit int `json:"retry_limit,omitempty"`
}
type DeviceConfig struct {
ID string `json:"id,omitempty"`
Backend struct {
BackendType string `json:"type"`
Config BackendConfig `json:"config"`
} `json:"backend"`
Cache struct {
CacheType string `json:"type"`
Compressed bool `json:"compressed,omitempty"`
Config struct {
WorkDir string `json:"work_dir"`
DisableIndexedMap bool `json:"disable_indexed_map"`
} `json:"config"`
} `json:"cache"`
}
// For nydusd as FUSE daemon. Serialize Daemon info and persist to a json file
// We don't have to persist configuration file for fscache since its configuration
// is passed through HTTP API.
func DumpConfigFile(c interface{}, path string) error {
if config.IsBackendSourceEnabled() {
c = serializeWithSecretFilter(c)
}
b, err := json.Marshal(c)
if err != nil {
return errors.Wrapf(err, "marshal config")
}
return os.WriteFile(path, b, 0600)
}
func DumpConfigString(c interface{}) (string, error) {
b, err := json.Marshal(c)
return string(b), err
}
// Achieve a daemon configuration from template or snapshotter's configuration
func SupplementDaemonConfig(c DaemonConfig, imageID, snapshotID string,
vpcRegistry bool, labels map[string]string, params map[string]string) error {
image, err := registry.ParseImage(imageID)
if err != nil {
return errors.Wrapf(err, "parse image %s", imageID)
}
backendType, _ := c.StorageBackend()
switch backendType {
case backendTypeRegistry:
registryHost := image.Host
if vpcRegistry {
registryHost = registry.ConvertToVPCHost(registryHost)
} else if registryHost == "docker.io" {
// For docker.io images, we should use index.docker.io
registryHost = "index.docker.io"
}
effectiveScheme, effectiveHost, caCerts := selectMirrorHost(config.GetMirrorsConfigDir(), registryHost)
// No mirror configured use the original registry host
if effectiveHost == "" {
effectiveHost = registryHost
}
// If no auth is provided, don't touch auth from provided nydusd configuration file.
// We don't validate the original nydusd auth from configuration file since it can be empty
// when repository is public.
keyChain := auth.GetRegistryKeyChain(imageID, labels)
c.Supplement(effectiveHost, image.Repo, snapshotID, params)
c.FillAuth(keyChain)
_, bc := c.StorageBackend()
if len(caCerts) > 0 {
bc.CACertFiles = caCerts
}
if effectiveScheme != "" {
bc.Scheme = effectiveScheme
}
// For Localfs, OSS, and S3 backends, only the WorkDir needs to be supplemented.
case backendTypeLocalfs, backendTypeOss, backendTypeS3:
c.Supplement("", "", snapshotID, params)
default:
return errors.Errorf("unknown backend type %s", backendType)
}
return nil
}
// selectMirrorHost loads mirror configs for the given registry host and returns the host and
// scheme of the first reachable mirror. If a mirror has no PingURL it is used unconditionally.
// Falls back to (registryHost, "") when no mirror is configured or reachable.
func selectMirrorHost(mirrorsConfigDir, registryHost string) (scheme string, host string, caCerts []string) {
mirrors, caCerts, err := LoadMirrorsConfig(mirrorsConfigDir, registryHost)
if err != nil {
log.L.Warnf("Failed to load mirrors config for %s: %v, falling back to origin", registryHost, err)
return "", registryHost, nil
}
client := &http.Client{Timeout: 3 * time.Second}
for _, mirror := range mirrors {
scheme, host, err = splitMirrorURL(mirror.Host)
if err != nil {
log.L.Warnf("Skipping due to Failing to split mirror host %s: %v", mirror.Host, err)
continue
}
if mirror.PingURL == "" {
return scheme, host, caCerts
}
resp, pingErr := client.Get(mirror.PingURL)
if pingErr == nil {
resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return scheme, host, caCerts
}
}
if resp != nil {
pingBody, _ := io.ReadAll(resp.Body)
log.L.Warnf("Mirror %s ping URL %s check failed with error %v, statusCode %d, response '%s', trying next mirror",
mirror.Host,
mirror.PingURL,
err,
resp.StatusCode,
string(pingBody),
)
} else {
log.L.Warnf("Mirror %s ping URL %s check failed with error %v, trying next mirror",
mirror.Host,
mirror.PingURL,
err,
)
}
}
return "", registryHost, nil
}
// splitMirrorURL splits a mirror host URL (e.g. "http://mirror:5000") into scheme and bare host.
// Scheme is forced to be https if not present.
func splitMirrorURL(mirrorHost string) (scheme, host string, err error) {
// url.Parse requires a scheme to properly works even if it doesn't returns an error
if !strings.HasPrefix(mirrorHost, "http://") && !strings.HasPrefix(mirrorHost, "https://") {
mirrorHost = "https://" + mirrorHost
}
value, err := url.Parse(mirrorHost)
if err != nil {
return "", "", err
}
return value.Scheme, value.Host, nil
}
func serializeWithSecretFilter(obj interface{}) map[string]interface{} {
result := make(map[string]interface{})
value := reflect.ValueOf(obj)
typeOfObj := reflect.TypeOf(obj)
if value.Kind() == reflect.Ptr {
value = value.Elem()
typeOfObj = typeOfObj.Elem()
}
for i := 0; i < value.NumField(); i++ {
field := value.Field(i)
fieldType := typeOfObj.Field(i)
secretTag := fieldType.Tag.Get("secret")
jsonTags := strings.Split(fieldType.Tag.Get("json"), ",")
omitemptyTag := false
for _, tag := range jsonTags {
if tag == "omitempty" {
omitemptyTag = true
break
}
}
if secretTag == "true" {
continue
}
if field.Kind() == reflect.Ptr && field.IsNil() {
continue
}
if omitemptyTag && reflect.DeepEqual(reflect.Zero(field.Type()).Interface(), field.Interface()) {
continue
}
//nolint:exhaustive
switch fieldType.Type.Kind() {
case reflect.Struct:
result[jsonTags[0]] = serializeWithSecretFilter(field.Interface())
case reflect.Ptr:
if fieldType.Type.Elem().Kind() == reflect.Struct {
result[jsonTags[0]] = serializeWithSecretFilter(field.Elem().Interface())
} else {
result[jsonTags[0]] = field.Elem().Interface()
}
default:
result[jsonTags[0]] = field.Interface()
}
}
return result
}
================================================
FILE: config/daemonconfig/daemonconfig_test.go
================================================
/*
* Copyright (c) 2020. Ant Group. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestLoadConfig(t *testing.T) {
buf := []byte(`{
"device": {
"backend": {
"type": "registry",
"config": {
"skip_verify": true,
"host": "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com",
"repo": "test/myserver",
"auth": "",
"blob_url_scheme": "http",
"proxy": {
"url": "http://p2p-proxy:65001",
"fallback": true,
"ping_url": "http://p2p-proxy:40901/server/ping",
"check_interval": 5
},
"timeout": 5,
"connect_timeout": 5,
"retry_limit": 0
}
},
"cache": {
"type": "blobcache",
"config": {
"work_dir": "/cache"
}
}
},
"mode": "direct",
"digest_validate": true,
"iostats_files": true,
"enable_xattr": true,
"amplify_io": 1048576,
"fs_prefetch": {
"enable": true,
"threads_count": 10,
"merging_size": 131072
}
}`)
var cfg FuseDaemonConfig
err := json.Unmarshal(buf, &cfg)
require.Nil(t, err)
require.Equal(t, cfg.Enable, true)
require.Equal(t, cfg.MergingSize, 131072)
require.Equal(t, cfg.ThreadsCount, 10)
require.Equal(t, cfg.Device.Backend.Config.BlobURLScheme, "http")
require.Equal(t, cfg.Device.Backend.Config.SkipVerify, true)
require.Equal(t, cfg.Device.Backend.Config.Proxy.CheckInterval, 5)
}
func TestAmplifyIo(t *testing.T) {
// Test non-zero value
input1 := []byte(`{"amplify_io": 1048576}`)
var cfg1 FuseDaemonConfig
err1 := json.Unmarshal(input1, &cfg1)
require.Nil(t, err1)
require.Equal(t, *cfg1.AmplifyIo, 1048576)
output1, _ := json.Marshal(cfg1)
require.Contains(t, string(output1), `"amplify_io":1048576`)
// Test zero value
input2 := []byte(`{"amplify_io": 0}`)
var cfg2 FuseDaemonConfig
err2 := json.Unmarshal(input2, &cfg2)
require.Nil(t, err2)
require.Equal(t, *cfg2.AmplifyIo, 0)
output2, _ := json.Marshal(cfg2)
require.Contains(t, string(output2), `"amplify_io":0`)
// Test nil value
input3 := []byte(`{}`)
var cfg3 FuseDaemonConfig
err3 := json.Unmarshal(input3, &cfg3)
require.Nil(t, err3)
require.Nil(t, cfg3.AmplifyIo)
output3, _ := json.Marshal(cfg3)
require.NotContains(t, string(output3), `amplify_io`)
}
func TestSerializeWithSecretFilter(t *testing.T) {
buf := []byte(`{
"device": {
"backend": {
"type": "registry",
"config": {
"skip_verify": true,
"host": "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com",
"repo": "test/myserver",
"auth": "token_token",
"blob_url_scheme": "http",
"proxy": {
"url": "http://p2p-proxy:65001",
"fallback": true,
"ping_url": "http://p2p-proxy:40901/server/ping",
"check_interval": 5
},
"timeout": 5,
"connect_timeout": 5,
"retry_limit": 0
}
},
"cache": {
"type": "blobcache",
"config": {
"work_dir": "/cache"
}
}
},
"mode": "direct",
"digest_validate": true,
"iostats_files": true,
"enable_xattr": true,
"amplify_io": 1048576,
"fs_prefetch": {
"enable": true,
"threads_count": 10,
"merging_size": 131072
}
}`)
var cfg FuseDaemonConfig
_ = json.Unmarshal(buf, &cfg)
filter := serializeWithSecretFilter(&cfg)
jsonData, err := json.Marshal(filter)
require.Nil(t, err)
var newCfg FuseDaemonConfig
err = json.Unmarshal(jsonData, &newCfg)
require.Nil(t, err)
require.Equal(t, newCfg.FSPrefetch, cfg.FSPrefetch)
require.Equal(t, newCfg.Device.Cache.CacheType, cfg.Device.Cache.CacheType)
require.Equal(t, newCfg.Device.Cache.Config, cfg.Device.Cache.Config)
require.Equal(t, newCfg.Mode, cfg.Mode)
require.Equal(t, newCfg.DigestValidate, cfg.DigestValidate)
require.Equal(t, newCfg.IOStatsFiles, cfg.IOStatsFiles)
require.Equal(t, newCfg.Device.Backend.Config.Host, cfg.Device.Backend.Config.Host)
require.Equal(t, newCfg.Device.Backend.Config.Repo, cfg.Device.Backend.Config.Repo)
require.Equal(t, newCfg.Device.Backend.Config.Proxy, cfg.Device.Backend.Config.Proxy)
require.Equal(t, newCfg.Device.Backend.Config.BlobURLScheme, cfg.Device.Backend.Config.BlobURLScheme)
require.Equal(t, newCfg.Device.Backend.Config.Auth, "")
require.NotEqual(t, newCfg.Device.Backend.Config.Auth, cfg.Device.Backend.Config.Auth)
require.NotNil(t, newCfg.AmplifyIo)
require.Equal(t, *newCfg.AmplifyIo, *cfg.AmplifyIo)
}
================================================
FILE: config/daemonconfig/fscache.go
================================================
/*
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"encoding/json"
"os"
"path"
"github.com/containerd/log"
"github.com/containerd/nydus-snapshotter/pkg/auth"
"github.com/containerd/nydus-snapshotter/pkg/utils/erofs"
"github.com/pkg/errors"
)
const (
WorkDir string = "workdir"
Bootstrap string = "bootstrap"
)
type BlobPrefetchConfig struct {
Enable bool `json:"enable"`
ThreadsCount int `json:"threads_count"`
MergingSize int `json:"merging_size"`
BandwidthRate int `json:"bandwidth_rate"`
PrefetchAll bool `json:"prefetch_all"`
}
type FscacheDaemonConfig struct {
// These fields is only for fscache daemon.
Type string `json:"type"`
// Snapshotter fills
ID string `json:"id"`
DomainID string `json:"domain_id"`
Config *struct {
ID string `json:"id"`
BackendType string `json:"backend_type"`
BackendConfig BackendConfig `json:"backend_config"`
CacheType string `json:"cache_type"`
// Snapshotter fills
CacheConfig struct {
WorkDir string `json:"work_dir"`
} `json:"cache_config"`
BlobPrefetchConfig BlobPrefetchConfig `json:"prefetch_config"`
MetadataPath string `json:"metadata_path"`
} `json:"config"`
}
// Load Fscache configuration template file
func LoadFscacheConfig(p string) (*FscacheDaemonConfig, error) {
var cfg FscacheDaemonConfig
b, err := os.ReadFile(p)
if err != nil {
return nil, errors.Wrapf(err, "read fscache configuration file %s", p)
}
if err = json.Unmarshal(b, &cfg); err != nil {
return nil, errors.Wrapf(err, "unmarshal")
}
if cfg.Config == nil {
return nil, errors.New("invalid fscache configuration")
}
return &cfg, nil
}
func (c *FscacheDaemonConfig) StorageBackend() (string, *BackendConfig) {
return c.Config.BackendType, &c.Config.BackendConfig
}
// Each fscache/erofs has a configuration with different fscache ID built from snapshot ID.
func (c *FscacheDaemonConfig) Supplement(host, repo, snapshotID string, params map[string]string) {
if host != "" {
c.Config.BackendConfig.Host = host
}
if repo != "" {
c.Config.BackendConfig.Repo = repo
}
fscacheID := erofs.FscacheID(snapshotID)
c.ID = fscacheID
if c.DomainID != "" {
log.L.Warnf("Linux Kernel Shared Domain feature in use. make sure your kernel version >= 6.1")
} else {
c.DomainID = fscacheID
}
c.Config.ID = fscacheID
if WorkDir, ok := params[WorkDir]; ok {
c.Config.CacheConfig.WorkDir = WorkDir
}
if bootstrap, ok := params[Bootstrap]; ok {
c.Config.MetadataPath = bootstrap
}
}
func (c *FscacheDaemonConfig) FillAuth(kc *auth.PassKeyChain) {
if kc != nil {
if kc.TokenBase() {
c.Config.BackendConfig.RegistryToken = kc.Password
} else {
c.Config.BackendConfig.Auth = kc.ToBase64()
}
}
}
func (c *FscacheDaemonConfig) DumpString() (string, error) {
return DumpConfigString(c)
}
func (c *FscacheDaemonConfig) DumpFile(f string) error {
if err := os.MkdirAll(path.Dir(f), 0755); err != nil {
return err
}
return DumpConfigFile(c, f)
}
================================================
FILE: config/daemonconfig/fuse.go
================================================
/*
* Copyright (c) 2022. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"encoding/json"
"os"
"path"
"github.com/pkg/errors"
"github.com/containerd/nydus-snapshotter/pkg/auth"
)
const CacheDir string = "cachedir"
// Used when nydusd works as a FUSE daemon or vhost-user-fs backend
type FuseDaemonConfig struct {
Device *DeviceConfig `json:"device"`
Mode string `json:"mode"`
DigestValidate bool `json:"digest_validate"`
IOStatsFiles bool `json:"iostats_files,omitempty"`
EnableXattr bool `json:"enable_xattr,omitempty"`
AccessPattern bool `json:"access_pattern,omitempty"`
LatestReadFiles bool `json:"latest_read_files,omitempty"`
AmplifyIo *int `json:"amplify_io,omitempty"`
FSPrefetch `json:"fs_prefetch,omitempty"`
// (experimental) The nydus daemon could cache more data to increase hit ratio when enabled the warmup feature.
Warmup uint64 `json:"warmup,omitempty"`
}
// Control how to perform prefetch from file system layer
type FSPrefetch struct {
Enable bool `json:"enable"`
PrefetchAll bool `json:"prefetch_all"`
ThreadsCount int `json:"threads_count,omitempty"`
MergingSize int `json:"merging_size,omitempty"`
BandwidthRate int `json:"bandwidth_rate,omitempty"`
}
// Load fuse daemon configuration from template file
func LoadFuseConfig(p string) (*FuseDaemonConfig, error) {
b, err := os.ReadFile(p)
if err != nil {
return nil, errors.Wrapf(err, "read FUSE configuration file %s", p)
}
var cfg FuseDaemonConfig
if err := json.Unmarshal(b, &cfg); err != nil {
return nil, errors.Wrapf(err, "unmarshal %s", p)
}
if cfg.Device == nil {
return nil, errors.New("invalid fuse daemon configuration")
}
return &cfg, nil
}
func (c *FuseDaemonConfig) Supplement(host, repo, snapshotID string, params map[string]string) {
if host != "" {
c.Device.Backend.Config.Host = host
}
if repo != "" {
c.Device.Backend.Config.Repo = repo
}
// Temporary fix while https://github.com/containerd/nydus-snapshotter/issues/712 is being addressed
if snapshotID != "" {
c.Device.ID = "/" + snapshotID
}
c.Device.Cache.Config.WorkDir = params[CacheDir]
}
func (c *FuseDaemonConfig) FillAuth(kc *auth.PassKeyChain) {
if kc != nil {
if kc.TokenBase() {
c.Device.Backend.Config.RegistryToken = kc.Password
} else {
c.Device.Backend.Config.Auth = kc.ToBase64()
}
}
}
func (c *FuseDaemonConfig) StorageBackend() (string, *BackendConfig) {
return c.Device.Backend.BackendType, &c.Device.Backend.Config
}
func (c *FuseDaemonConfig) DumpString() (string, error) {
return DumpConfigString(c)
}
func (c *FuseDaemonConfig) DumpFile(f string) error {
if err := os.MkdirAll(path.Dir(f), 0755); err != nil {
return err
}
return DumpConfigFile(c, f)
}
================================================
FILE: config/daemonconfig/mirror_select_test.go
================================================
/*
* Copyright (c) 2026. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
var testRegistryHost = "fake-test.registry.com"
func writeMirrorHostsToml(t *testing.T, dir, content string) {
t.Helper()
hostDir := filepath.Join(dir, testRegistryHost)
require.NoError(t, os.MkdirAll(hostDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(hostDir, "hosts.toml"), []byte(content), 0600))
}
func TestSplitMirrorURL(t *testing.T) {
cases := []struct {
name string
input string
expectedScheme string
expectedHost string
expectErr bool
}{
{
name: "http with port",
input: "http://mirror:5000",
expectedScheme: "http",
expectedHost: "mirror:5000",
},
{
name: "https without port",
input: "https://mirror.example.com",
expectedScheme: "https",
expectedHost: "mirror.example.com",
},
{
name: "no scheme, host only",
input: "mirror.example.com",
expectedScheme: "https",
expectedHost: "mirror.example.com",
},
{
name: "no scheme, host with port",
input: "mirror:5000",
expectedScheme: "https",
expectedHost: "mirror:5000",
},
{
name: "https with port",
input: "https://mirror.example.com:5000",
expectedScheme: "https",
expectedHost: "mirror.example.com:5000",
},
{
name: "http with path",
input: "http://mirror.example.com/v2",
expectedScheme: "http",
expectedHost: "mirror.example.com",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
scheme, host, err := splitMirrorURL(tc.input)
if tc.expectErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectedScheme, scheme, "scheme for %s", tc.input)
require.Equal(t, tc.expectedHost, host, "host for %s", tc.input)
})
}
}
func TestSelectMirrorHost_NoConfig(t *testing.T) {
scheme, host, _ := selectMirrorHost("", testRegistryHost)
require.Equal(t, testRegistryHost, host)
require.Equal(t, "", scheme)
}
func TestSelectMirrorHost_EmptyDir(t *testing.T) {
tmpDir := t.TempDir()
scheme, host, _ := selectMirrorHost(tmpDir, testRegistryHost)
require.Equal(t, testRegistryHost, host)
require.Equal(t, "", scheme)
}
func TestSelectMirrorHost_MirrorNoPingURL(t *testing.T) {
tmpDir := t.TempDir()
writeMirrorHostsToml(t, tmpDir, `
[host]
[host."http://mirror1:5000"]
`)
scheme, host, _ := selectMirrorHost(tmpDir, testRegistryHost)
require.Equal(t, "mirror1:5000", host)
require.Equal(t, "http", scheme)
}
func TestSelectMirrorHost_MirrorPingSucceeds(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
tmpDir := t.TempDir()
writeMirrorHostsToml(t, tmpDir, `
[host]
[host."http://mirror1:5000"]
ping_url = "`+srv.URL+`"
`)
scheme, host, _ := selectMirrorHost(tmpDir, testRegistryHost)
require.Equal(t, "mirror1:5000", host)
require.Equal(t, "http", scheme)
}
func TestSelectMirrorHost_MirrorPingFails_FallbackToOrigin(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
}))
defer srv.Close()
tmpDir := t.TempDir()
writeMirrorHostsToml(t, tmpDir, `
[host]
[host."http://mirror1:5000"]
ping_url = "`+srv.URL+`"
`)
scheme, host, _ := selectMirrorHost(tmpDir, testRegistryHost)
require.Equal(t, testRegistryHost, host)
require.Equal(t, "", scheme)
}
func TestSelectMirrorHost_FirstMirrorFails_SecondMirrorNoPing(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
}))
defer srv.Close()
tmpDir := t.TempDir()
writeMirrorHostsToml(t, tmpDir, `
[host]
[host."http://mirror1:5000"]
ping_url = "`+srv.URL+`"
[host."https://mirror2.example.com"]
`)
scheme, host, _ := selectMirrorHost(tmpDir, testRegistryHost)
require.Equal(t, "mirror2.example.com", host)
require.Equal(t, "https", scheme)
}
================================================
FILE: config/daemonconfig/mirrors.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"fmt"
"net/http"
"net/url"
"os"
"path/filepath"
"sort"
"strings"
"github.com/containerd/log"
"github.com/pelletier/go-toml"
"github.com/pkg/errors"
)
type MirrorConfig struct {
Host string
Headers map[string]string
HealthCheckInterval int
FailureLimit uint8
PingURL string
}
// Copied from containerd, for compatibility with containerd's toml configuration file.
type HostFileConfig struct {
Capabilities []string `toml:"capabilities"`
CACert interface{} `toml:"ca"`
Client interface{} `toml:"client"`
SkipVerify *bool `toml:"skip_verify"`
Header map[string]interface{} `toml:"header"`
OverridePath bool `toml:"override_path"`
// The following configuration items are specific to nydus.
HealthCheckInterval int `toml:"health_check_interval,omitempty"`
FailureLimit uint8 `toml:"failure_limit,omitempty"`
PingURL string `toml:"ping_url,omitempty"`
}
type hostConfig struct {
Scheme string
Host string
Header http.Header
CACerts []string
HealthCheckInterval int
FailureLimit uint8
PingURL string
}
func makeStringSlice(slice []interface{}, cb func(string) string) ([]string, error) {
out := make([]string, len(slice))
for i, value := range slice {
str, ok := value.(string)
if !ok {
return nil, fmt.Errorf("unable to cast %v to string", value)
}
if cb != nil {
out[i] = cb(str)
} else {
out[i] = str
}
}
return out, nil
}
func parseMirrorsConfig(hosts []hostConfig) []MirrorConfig {
var parsedMirrors = make([]MirrorConfig, len(hosts))
for i, host := range hosts {
parsedMirrors[i].Host = fmt.Sprintf("%s://%s", host.Scheme, host.Host)
parsedMirrors[i].HealthCheckInterval = host.HealthCheckInterval
parsedMirrors[i].FailureLimit = host.FailureLimit
parsedMirrors[i].PingURL = host.PingURL
if len(host.Header) > 0 {
mirrorHeader := make(map[string]string, len(host.Header))
for key, value := range host.Header {
if len(value) > 1 {
log.L.Warnf("some values of the header[%q] are omitted: %#v", key, value[1:])
}
mirrorHeader[key] = host.Header.Get(key)
}
parsedMirrors[i].Headers = mirrorHeader
}
}
return parsedMirrors
}
// hostDirectory converts ":port" to "_port_" in directory names
func hostDirectory(host string) string {
idx := strings.LastIndex(host, ":")
if idx > 0 {
return host[:idx] + "_" + host[idx+1:] + "_"
}
return host
}
func hostPaths(root, host string) []string {
var hosts []string
ch := hostDirectory(host)
if ch != host {
hosts = append(hosts, filepath.Join(root, ch))
}
return append(hosts,
filepath.Join(root, host),
filepath.Join(root, "_default"),
)
}
func hostDirFromRoot(root, host string) (string, error) {
for _, p := range hostPaths(root, host) {
if _, err := os.Stat(p); err == nil {
return p, nil
} else if !os.IsNotExist(err) {
return "", err
}
}
return "", nil
}
// getSortedHosts returns the list of hosts as they defined in the file.
func getSortedHosts(root *toml.Tree) ([]string, error) {
iter, ok := root.Get("host").(*toml.Tree)
if !ok {
return nil, errors.New("invalid `host` tree")
}
list := append([]string{}, iter.Keys()...)
// go-toml stores TOML sections in the map object, so no order guaranteed.
// We retrieve line number for each key and sort the keys by position.
sort.Slice(list, func(i, j int) bool {
h1 := iter.GetPath([]string{list[i]}).(*toml.Tree)
h2 := iter.GetPath([]string{list[j]}).(*toml.Tree)
return h1.Position().Line < h2.Position().Line
})
return list, nil
}
// parseHostConfig returns the parsed host configuration, make sure the server is not null.
func parseHostConfig(server string, config HostFileConfig) (hostConfig, error) {
var (
result = hostConfig{}
err error
)
if !strings.HasPrefix(server, "http") {
server = "https://" + server
}
u, err := url.Parse(server)
if err != nil {
return hostConfig{}, fmt.Errorf("unable to parse server %v: %w", server, err)
}
result.Scheme = u.Scheme
result.Host = u.Host
if config.Header != nil {
header := http.Header{}
for key, ty := range config.Header {
switch value := ty.(type) {
case string:
header[key] = []string{value}
case []interface{}:
header[key], err = makeStringSlice(value, nil)
if err != nil {
return hostConfig{}, err
}
default:
return hostConfig{}, fmt.Errorf("invalid type %v for header %q", ty, key)
}
}
result.Header = header
}
if config.CACert != nil {
switch cert := config.CACert.(type) {
case string:
result.CACerts = []string{cert}
case []interface{}:
certs, err := makeStringSlice(cert, nil)
if err != nil {
return hostConfig{}, fmt.Errorf("invalid type for ca: %w", err)
}
result.CACerts = certs
default:
return hostConfig{}, fmt.Errorf("invalid type %v for ca", config.CACert)
}
}
result.HealthCheckInterval = config.HealthCheckInterval
result.FailureLimit = config.FailureLimit
result.PingURL = config.PingURL
return result, nil
}
func parseHostsFile(b []byte) ([]hostConfig, error) {
tree, err := toml.LoadBytes(b)
if err != nil {
return nil, fmt.Errorf("failed to parse TOML: %w", err)
}
c := struct {
// HostConfigs store the per-host configuration
HostConfigs map[string]HostFileConfig `toml:"host"`
}{}
orderedHosts, err := getSortedHosts(tree)
if err != nil {
return nil, err
}
var (
hosts []hostConfig
)
if err := tree.Unmarshal(&c); err != nil {
return nil, err
}
// Parse hosts array
for _, host := range orderedHosts {
if host != "" {
config := c.HostConfigs[host]
parsed, err := parseHostConfig(host, config)
if err != nil {
return nil, err
}
hosts = append(hosts, parsed)
}
}
return hosts, nil
}
func loadHostDir(hostsDir string) ([]hostConfig, error) {
b, err := os.ReadFile(filepath.Join(hostsDir, "hosts.toml"))
if err != nil {
if !os.IsNotExist(err) {
return nil, err
}
return []hostConfig{}, nil
}
hosts, err := parseHostsFile(b)
if err != nil {
return nil, err
}
return hosts, nil
}
func LoadMirrorsConfig(mirrorsConfigDir, registryHost string) ([]MirrorConfig, []string, error) {
if mirrorsConfigDir == "" {
return nil, nil, nil
}
hostDir, err := hostDirFromRoot(mirrorsConfigDir, registryHost)
if err != nil {
return nil, nil, err
}
if hostDir == "" {
return nil, nil, nil
}
hosts, err := loadHostDir(hostDir)
if err != nil {
return nil, nil, err
}
// Collect CA certs from all host entries and deduplicate.
seen := make(map[string]struct{})
var caCerts []string
for _, h := range hosts {
for _, ca := range h.CACerts {
if _, ok := seen[ca]; !ok {
seen[ca] = struct{}{}
caCerts = append(caCerts, ca)
}
}
}
return parseMirrorsConfig(hosts), caCerts, nil
}
================================================
FILE: config/daemonconfig/mirrors_test.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package daemonconfig
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLoadMirrorConfigCACerts(t *testing.T) {
registryHost := "registry.example.com"
t.Run("single CA cert as absolute path", func(t *testing.T) {
tmpDir := t.TempDir()
hostDir := filepath.Join(tmpDir, "certs.d", registryHost)
require.NoError(t, os.MkdirAll(hostDir, os.ModePerm))
caPath := filepath.Join(tmpDir, "my-ca.pem")
require.NoError(t, os.WriteFile(caPath, []byte(""), 0600))
hosts := fmt.Sprintf(`
[host."https://mirror.example.com"]
ca = %q
`, caPath)
require.NoError(t, os.WriteFile(filepath.Join(hostDir, "hosts.toml"), []byte(hosts), 0600))
_, caCerts, err := LoadMirrorsConfig(filepath.Join(tmpDir, "certs.d"), registryHost)
require.NoError(t, err)
require.Equal(t, []string{caPath}, caCerts)
})
t.Run("multiple CA certs as array", func(t *testing.T) {
tmpDir := t.TempDir()
hostDir := filepath.Join(tmpDir, "certs.d", registryHost)
require.NoError(t, os.MkdirAll(hostDir, os.ModePerm))
ca1 := filepath.Join(tmpDir, "ca1.pem")
ca2 := filepath.Join(tmpDir, "ca2.pem")
hosts := fmt.Sprintf(`
[host."https://mirror.example.com"]
ca = [%q, %q]
`, ca1, ca2)
require.NoError(t, os.WriteFile(filepath.Join(hostDir, "hosts.toml"), []byte(hosts), 0600))
_, caCerts, err := LoadMirrorsConfig(filepath.Join(tmpDir, "certs.d"), registryHost)
require.NoError(t, err)
require.Equal(t, []string{ca1, ca2}, caCerts)
})
t.Run("CA certs deduplicated across multiple hosts", func(t *testing.T) {
tmpDir := t.TempDir()
hostDir := filepath.Join(tmpDir, "certs.d", registryHost)
require.NoError(t, os.MkdirAll(hostDir, os.ModePerm))
ca1 := filepath.Join(tmpDir, "ca1.pem")
ca2 := filepath.Join(tmpDir, "ca2.pem")
hosts := fmt.Sprintf(`
[host."https://mirror1.example.com"]
ca = %q
[host."https://mirror2.example.com"]
ca = [%q, %q]
`, ca1, ca1, ca2)
require.NoError(t, os.WriteFile(filepath.Join(hostDir, "hosts.toml"), []byte(hosts), 0600))
_, caCerts, err := LoadMirrorsConfig(filepath.Join(tmpDir, "certs.d"), registryHost)
require.NoError(t, err)
require.Equal(t, []string{ca1, ca2}, caCerts)
})
t.Run("no CA cert field returns nil caCerts", func(t *testing.T) {
tmpDir := t.TempDir()
hostDir := filepath.Join(tmpDir, "certs.d", registryHost)
require.NoError(t, os.MkdirAll(hostDir, os.ModePerm))
hosts := `
[host."https://mirror.example.com"]
`
require.NoError(t, os.WriteFile(filepath.Join(hostDir, "hosts.toml"), []byte(hosts), 0600))
_, caCerts, err := LoadMirrorsConfig(filepath.Join(tmpDir, "certs.d"), registryHost)
require.NoError(t, err)
require.Nil(t, caCerts)
})
}
func TestLoadMirrorConfig(t *testing.T) {
tmpDir := t.TempDir()
defer os.RemoveAll(tmpDir)
registryHost := "registry.docker.io"
mirrorsConfigDir := filepath.Join(tmpDir, "certs.d")
registryHostConfigDir := filepath.Join(mirrorsConfigDir, registryHost)
defaultHostConfigDir := filepath.Join(mirrorsConfigDir, "_default")
mirrors, _, err := LoadMirrorsConfig("", registryHost)
require.NoError(t, err)
require.Nil(t, mirrors)
mirrors, _, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost)
require.NoError(t, err)
require.Nil(t, mirrors)
err = os.MkdirAll(defaultHostConfigDir, os.ModePerm)
assert.NoError(t, err)
mirrors, _, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost)
require.NoError(t, err)
require.Equal(t, len(mirrors), 0)
buf1 := []byte(`server = "https://default-docker.hub.com"
[host]
[host."http://default-p2p-mirror1:65001"]
[host."http://default-p2p-mirror1:65001".header]
X-Dragonfly-Registry = ["https://default-docker.hub.com"]
`)
err = os.WriteFile(filepath.Join(defaultHostConfigDir, "hosts.toml"), buf1, 0600)
assert.NoError(t, err)
mirrors, _, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost)
require.NoError(t, err)
require.Equal(t, len(mirrors), 1)
require.Equal(t, mirrors[0].Host, "http://default-p2p-mirror1:65001")
require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://default-docker.hub.com")
err = os.MkdirAll(registryHostConfigDir, os.ModePerm)
assert.NoError(t, err)
buf2 := []byte(`server = "https://docker.hub.com"
[host]
[host."http://p2p-mirror1:65001"]
[host."http://p2p-mirror1:65001".header]
X-Dragonfly-Registry = ["https://docker.hub.com"]
`)
err = os.WriteFile(filepath.Join(registryHostConfigDir, "hosts.toml"), buf2, 0600)
assert.NoError(t, err)
mirrors, _, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost)
require.NoError(t, err)
require.Equal(t, len(mirrors), 1)
require.Equal(t, mirrors[0].Host, "http://p2p-mirror1:65001")
require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://docker.hub.com")
buf3 := []byte(`
[host."http://p2p-mirror2:65001"]
[host."http://p2p-mirror2:65001".header]
X-Dragonfly-Registry = ["https://docker.hub.com"]
`)
err = os.WriteFile(filepath.Join(registryHostConfigDir, "hosts.toml"), buf3, 0600)
assert.NoError(t, err)
mirrors, _, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost)
require.NoError(t, err)
require.Equal(t, len(mirrors), 1)
require.Equal(t, mirrors[0].Host, "http://p2p-mirror2:65001")
require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://docker.hub.com")
}
================================================
FILE: config/default.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package config
import (
"os/exec"
"github.com/containerd/nydus-snapshotter/internal/constant"
)
func (c *SnapshotterConfig) FillUpWithDefaults() error {
c.Version = 1
c.Root = constant.DefaultRootDir
c.Address = constant.DefaultAddress
// essential configuration
if c.DaemonMode == "" {
c.DaemonMode = constant.DefaultDaemonMode
}
// system controller configuration
c.SystemControllerConfig.Address = constant.DefaultSystemControllerAddress
// logging configuration
logConfig := &c.LoggingConfig
if logConfig.LogLevel == "" {
logConfig.LogLevel = constant.DefaultLogLevel
}
logConfig.RotateLogMaxSize = constant.DefaultRotateLogMaxSize
logConfig.RotateLogMaxBackups = constant.DefaultRotateLogMaxBackups
logConfig.RotateLogMaxAge = constant.DefaultRotateLogMaxAge
logConfig.RotateLogLocalTime = constant.DefaultRotateLogLocalTime
logConfig.RotateLogCompress = constant.DefaultRotateLogCompress
// daemon configuration
daemonConfig := &c.DaemonConfig
if daemonConfig.NydusdConfigPath == "" {
daemonConfig.NydusdConfigPath = constant.DefaultNydusDaemonConfigPath
}
daemonConfig.RecoverPolicy = RecoverPolicyRestart.String()
daemonConfig.FsDriver = constant.DefaultFsDriver
daemonConfig.LogRotationSize = constant.DefaultDaemonRotateLogMaxSize
daemonConfig.FailoverPolicy = constant.DefaultFailoverPolicy
// cache configuration
cacheConfig := &c.CacheManagerConfig
cacheConfig.GCPeriod = constant.DefaultGCPeriod
// metrics configuration
metricsConfig := &c.MetricsConfig
metricsConfig.HungIOInterval = constant.DefaultHungIOInterval
metricsConfig.CollectInterval = constant.DefaultCollectInterval
return c.SetupNydusBinaryPaths()
}
func (c *SnapshotterConfig) SetupNydusBinaryPaths() error {
// resolve nydusd path
if path, err := exec.LookPath(constant.NydusdBinaryName); err == nil {
c.DaemonConfig.NydusdPath = path
}
// resolve nydus-image path
if path, err := exec.LookPath(constant.NydusImageBinaryName); err == nil {
c.DaemonConfig.NydusImagePath = path
}
return nil
}
================================================
FILE: config/global.go
================================================
/*
* Copyright (c) 2023. Nydus Developers. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
// Expose configurations across nydus-snapshotter, the configurations is parsed
// and extracted from nydus-snapshotter toml based configuration file or command line
package config
import (
"os"
"path/filepath"
"github.com/containerd/log"
"github.com/containerd/nydus-snapshotter/internal/logging"
"github.com/containerd/nydus-snapshotter/pkg/utils/mount"
"github.com/pkg/errors"
)
var (
globalConfig GlobalConfig
)
// Global cached configuration information to help:
// - access configuration information without passing a configuration object
// - avoid frequent generation of information from configuration information
type GlobalConfig struct {
origin *SnapshotterConfig
SnapshotsDir string
DaemonMode DaemonMode
SocketRoot string
ConfigRoot string
RootMountpoint string
DaemonThreadsNum int
MirrorsConfig MirrorsConfig
}
func IsFusedevSharedModeEnabled() bool {
return globalConfig.DaemonMode == DaemonModeShared
}
func GetDaemonMode() DaemonMode {
return globalConfig.DaemonMode
}
func GetSnapshotsRootDir() string {
return globalConfig.SnapshotsDir
}
func GetRootMountpoint() string {
return globalConfig.RootMountpoint
}
func GetSocketRoot() string {
return globalConfig.SocketRoot
}
func GetConfigRoot() string {
return globalConfig.ConfigRoot
}
func GetMirrorsConfigDir() string {
return globalConfig.MirrorsConfig.Dir
}
func GetFsDriver() string {
return globalConfig.origin.DaemonConfig.FsDriver
}
func GetLogDir() string {
return globalConfig.origin.LoggingConfig.LogDir
}
func GetLogLevel() string {
return globalConfig.origin.LoggingConfig.LogLevel
}
func GetDaemonLogRotationSize() int {
return globalConfig.origin.DaemonConfig.LogRotationSize
}
func GetDaemonThreadsNumber() int {
return globalConfig.origin.DaemonConfig.ThreadsNumber
}
func GetDaemonFailoverPolicy() string {
return globalConfig.origin.DaemonConfig.FailoverPolicy
}
func GetLogToStdout() bool {
return globalConfig.origin.LoggingConfig.LogToStdout
}
func IsBackendSourceEnabled() bool {
return globalConfig.origin.Experimental.EnableBackendSource && globalConfig.origin.SystemControllerConfig.Enable
}
func IsSystemControllerEnabled() bool {
return globalConfig.origin.SystemControllerConfig.Enable
}
func SystemControllerAddress() string {
return globalConfig.origin.SystemControllerConfig.Address
}
func SystemControllerPprofAddress() string {
return globalConfig.origin.SystemControllerConfig.DebugConfig.PprofAddress
}
func GetDaemonProfileCPUDuration() int64 {
return globalConfig.origin.SystemControllerConfig.DebugConfig.ProfileDuration
}
func GetSkipSSLVerify() bool {
return globalConfig.origin.RemoteConfig.SkipSSLVerify
}
const (
TarfsLayerVerityOnly string = "layer_verity_only"
TarfsImageVerityOnly string = "image_verity_only"
TarfsLayerBlockDevice string = "layer_block"
TarfsImageBlockDevice string = "image_block"
TarfsLayerBlockWithVerity string = "layer_block_with_verity"
TarfsImageBlockWithVerity string = "image_block_with_verity"
)
func GetTarfsMountOnHost() bool {
return globalConfig.origin.Experimental.TarfsConfig.MountTarfsOnHost
}
func GetTarfsExportEnabled() bool {
switch globalConfig.origin.Experimental.TarfsConfig.ExportMode {
case TarfsLayerVerityOnly, TarfsLayerBlockDevice, TarfsLayerBlockWithVerity:
return true
case TarfsImageVerityOnly, TarfsImageBlockDevice, TarfsImageBlockWithVerity:
return true
default:
return false
}
}
// Returns (wholeImage, generateBlockImage, withVerityInfo)
// wholeImage: generate tarfs for the whole image instead of of a specific layer.
// generateBlockImage: generate a block image file.
// withVerityInfo: generate disk verity information.
func GetTarfsExportFlags() (bool, bool, bool) {
switch globalConfig.origin.Experimental.TarfsConfig.ExportMode {
case "layer_verity_only":
return false, false, true
case "image_verity_only":
return true, false, true
case "layer_block":
return false, true, false
case "image_block":
return true, true, false
case "layer_block_with_verity":
return false, true, true
case "image_block_with_verity":
return true, true, true
default:
return false, false, false
}
}
func ProcessConfigurations(c *SnapshotterConfig) error {
if c.CacheManagerConfig.CacheDir == "" {
c.CacheManagerConfig.CacheDir = filepath.Join(c.Root, "cache")
}
globalConfig.origin = c
globalConfig.SnapshotsDir = filepath.Join(c.Root, "snapshots")
globalConfig.ConfigRoot = filepath.Join(c.Root, "config")
globalConfig.SocketRoot = filepath.Join(c.Root, "socket")
globalConfig.RootMountpoint = filepath.Join(c.Root, "mnt")
globalConfig.MirrorsConfig = c.RemoteConfig.MirrorsConfig
m, err := parseDaemonMode(c.DaemonMode)
if err != nil {
return err
}
if c.DaemonConfig.FsDriver == FsDriverFscache && m != DaemonModeShared {
log.L.Infof("fscache driver only supports 'shared' mode, override daemon mode from '%s' to 'shared'", m)
m = DaemonModeShared
}
globalConfig.DaemonMode = m
return nil
}
func PrepareLogDir(c *SnapshotterConfig) {
if c.LoggingConfig.LogDir == "" {
c.LoggingConfig.LogDir = filepath.Join(c.Root, logging.DefaultLogDirName)
}
}
func SetUpEnvironment(c *SnapshotterConfig) error {
if err := os.MkdirAll(c.Root, 0700); err != nil {
return errors.Wrapf(err, "create root dir %s", c.Root)
}
realPath, err := mount.NormalizePath(c.Root)
if err != nil {
return errors.Wrapf(err, "invalid root path")
}
c.Root = realPath
return nil
}
================================================
FILE: docs/configure_nydus.md
================================================
# Configure Nydus-snapshotter
Nydus-snapshotter can receive a toml file as its configurations to start providing image service through CLI parameter `--config`. An example configuration file can be found [here](../misc/snapshotter/config.toml). Besides nydus-snapshotter's configuration, `nydusd`'s configuration has to be provided to nydus-snapshotter too. Nydusd is started by nydus-snapshotter and it is configured by the provided json configuration file. A minimal configuration file can be found [here](../misc/snapshotter/nydusd-config.fusedev.json)
## Authentication
See [Registry Authentication](registry_authentication.md) for the full reference covering Docker config, CRI, kubeconfig, kubelet credential providers, and automatic credential renewal.
## Metrics
Nydusd records metrics in its own format. The metrics are exported via a HTTP server on top of unix domain socket. Nydus-snapshotter fetches the metrics and convert them in to Prometheus format which is exported via a network address. Nydus-snapshotter by default does not fetch metrics from nydusd. You can enable the nydusd metrics download by assigning a network address to `metrics.address` in nydus-snapshotter's toml [configuration file](../misc/snapshotter/config.toml).
Once this entry is enabled, not only nydusd metrics, but also some information about the nydus-snapshotter
runtime and snapshot related events are exported in Prometheus format as well.
## Diagnose
A system controller can be ran insides nydus-snapshotter.
By setting `system.enable` to `true`, nydus-snapshotter will start a simple HTTP server on unix domain socket `system.address` path and exports some internal working status to users. The address defaults to `/var/run/containerd-nydus/system.sock`
================================================
FILE: docs/crictl_dry_run.md
================================================
# Start Container by crictl
## Create crictl Config
The runtime endpoint can be set in the config file. Please refer to [crictl](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md) document for more details.
Compose your `crictl` configuration file named as `crictl.yaml`:
```yml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: true
```
Compose a pod configuration which can be named as `pod.yaml`
```yml
metadata:
attempt: 1
name: nydus-sandbox
namespace: default
uid: hdishd83djaidwnduwk28bcsb
log_directory: /tmp
linux:
security_context:
namespace_options:
network: 2
```
Compose a container configuration which can be named as `container.yaml`
```yml
metadata:
name: nydus-container
image:
image: <nydus-image>
command:
- /bin/sleep
args:
- 600
log_path: container.1.log
```
Start a container based on nydus image.
```bash
# auth is base64 encoded string from "username:password"
$ crictl --config ./crictl.yaml run --auth <base64 of registry auth> ./container.yaml ./pod.yaml
```
================================================
FILE: docs/index_detection.md
================================================
# Index Detection
## Overview
Index Detection is a feature that automatically discovers Nydus alternative manifests within OCI index manifests. This enables transparent fallback to optimized Nydus images when available while keeping the original index manifest OCI compliant, allowing non-Nydus clients to pull regular OCI images.
## Motivation
The Index Detection feature addresses several limitations of the existing Referrer API-based detection:
- **Registry Support**: Not all registries support the Referrer API
- **Supply Chain Security**: Referrer API relies on external changes to the manifest, creating potential supply chain risks
- **Universal Compatibility**: Index detection works with all OCI-compliant registries
Unlike referrer-based detection, Index Detection packages everything into a single manifest, eliminating supply chain concerns while maintaining universal registry support.
## How It Works
### Detection Process
1. **Index Manifest Parsing**: When a manifest digest is encountered, the system fetches and parses the original OCI index manifest
2. **Platform Matching**: The system finds the original manifest descriptor within the index
3. **Nydus Alternative Search**: It searches for platform-compatible manifests that contain:
- `platform.os.features` containing `nydus.remoteimage.v1`, or
- `artifactType` set to `application/vnd.nydus.image.manifest.v1+json`
4. **Validation**: The found manifest is validated to ensure it's a valid Nydus manifest with metadata layers
5. **Caching**: Results are cached to avoid repeated API calls for the same digest
Both `platform.os.features` and `artifactType` are looked at because index manifests built using `merge-platform` before acceleration-service: v0.2.19 or nydus: v2.3.5 will have `platform.os.features` configured while images built after will have `artifactType` configured.
### Detection Priority
When both Index Detection and Referrer Detection are available, Index Detection takes priority due to its superior supply chain security properties.
## Configuration
Index Detection is controlled by the `EnableIndexDetect` configuration option in the experimental features section:
```toml
[experimental]
enable_index_detect = true
```
## Building Compatible Images
To create images compatible with Index Detection, use the `nydusify convert` command with the `--merge-platform` flag:
```bash
nydusify convert --merge-platform <source-image> <target-image>
```
This creates an OCI index manifest containing both the original image and the Nydus alternative:
```json
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:a63dfddecc661e4ad05896418b2f3774022269c3bf5b7e01baaa6e851a3a4a23",
"size": 2320,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:bb82dd8ee111bfe5fdf12145b6ed553da9c15de17f54b1f658d95ff26a65a01c",
"size": 3229,
"platform": {
"architecture": "amd64",
"os": "linux"
},
"artifactType": "application/vnd.nydus.image.manifest.v1+json"
}
]
}
```
## Comparison with Referrer Detection
| Aspect | Index Detection | Referrer Detection |
|--------|----------------|-------------------|
| Registry Support | Universal | Limited |
| Supply Chain Security | Secure (single manifest) | Potential risks (external refs) |
| OCI Compliance | Full compliance | Requires Referrer API |
| Cache Behavior | Immutable (digest-based) | May require invalidation |
| Detection Priority | Higher | Lower |
================================================
FILE: docs/optimize_nydus_image.md
================================================
# Optimize a nydus image
To improve the prefetch hit rate, we can specify a prefetch table when converting an OCI image to a nydus image. The prefetch table is workload related and we should generate the list of accessed files in order when the workload is running. Nydus-snapshotter has implemented an optimizer with Containerd NRI plugin to optimize the nydus image. The optimizer is image format independent and requires NRI 2.0, which is available in containerd (>=v1.7.0). The optimizer subscribes container events to watch what files are opened and read, etc. during container application is starting up. This enables nydus image build tools to optimize the nydus image making it put the necessary and prioritized files into a special region of nydus image with extra image metadata. So nydus runtime can pull this files into local disk in top priority, thus to boost the performance further.
## Requirements
- [NRI 2.0](https://github.com/containerd/nri): Which has been integrated into containerd since [v1.7.0](https://github.com/containerd/containerd/tree/v1.7.0-beta.1).
## Workflow

1. Run the optimizer as a NRI plugin to run optimizer server when the StartContainer event occurs.
2. Optimizer server joins container mount namespace and starts fanotify server.
3. Optimizer server detects fanotify event and sends the accessed file descriptor to client.
4. Optimizer client converts file descriptor to path.
5. Generate list of accessed files on local disk.
6. Convert OCI images with accessed files list to nydus image.
## Generate an accessed files list
To install the optimizer and optimizer-server, invoke below command:
```console
make optimizer && make install-optimizer
```
This command installs the optimizer's default toml configuration file in `/etc/nri/conf.d/02-optimizer-nri-plugin.conf`. Here is an example:
```toml
# The directory to persist accessed files list for container.
persist_dir = "/opt/nri/optimizer/results"
# Whether to make the csv file human readable.
readable = false
# The path of optimizer server binary.
server_path = "/usr/local/bin/optimizer-server"
# The timeout to kill optimizer server, 0 to disable it.
timeout = 0
# Whether to overwrite the existed persistent files.
overwrite = false
# The events that containerd subscribes to.
# Do not change this element.
events = [ "StartContainer", "StopContainer" ]
```
Modify containerd's toml configuration file to enable NRI.
```console
sudo tee -a /etc/containerd/config.toml <<- EOF
[plugins."io.containerd.nri.v1.nri"]
config_file = "/etc/nri/nri.conf"
disable = false
plugin_path = "/opt/nri/plugins"
socket_path = "/var/run/nri.sock"
EOF
```
Containerd will load all NRI plugins in the `plugin_path` directory on startup. If you want to start a NRI plugin manually, please add the following configuration to allow other NRI plugins to connect via `socket_path`.
```console
sudo tee /etc/nri/nri.conf <<- EOF
disableConnections: false
EOF
```
Restart the containerd service.
```console
sudo systemctl restart containerd
```
Now, just run a container workload in sandbox and you will get the list of accessed files in `persist_dir`.
Note that NRI plugin can only be called from containerd/CRI. So start a container using `crictl` as below.
```console
sudo tee nginx.yaml <<- EOF
metadata:
name: nginx
image:
image: nginx:latest
log_path: nginx.0.log
linux: {}
EOF
sudo tee pod.yaml <<- EOF
metadata:
name: nginx-sandbox
namespace: default
attempt: 1
uid: hdishd83djaidwnduwk28bcsb
log_directory: /tmp
linux: {}
EOF
crictl run nginx.yaml pod.yaml
```
The result file for the nginx image is `/opt/nri/optimizer/results/library/nginx:latest`.
## Build Nydus Image with Optimizer's Suggestions
Nydus provides a [nydusify](https://github.com/dragonflyoss/nydus/blob/master/docs/nydusify.md) CLI tool to convert OCI images from the source registry or local file system to nydus format and push them to the target registry.
We can install the `nydusify` cli tool from the nydus package.
```console
VERSION=v2.3.0
wget https://github.com/dragonflyoss/nydus/releases/download/$VERSION/nydus-static-$VERSION-linux-amd64.tgz
tar -zxvf nydus-static-$VERSION-linux-amd64.tgz
sudo install -D -m 755 nydus-static/nydusify /usr/local/bin/nydusify
sudo install -D -m 755 nydus-static/nydus-image /usr/local/bin/nydus-image
```
A simple example converts the OCI image nginx to nydus format in RAFS V6.
```console
sudo nydusify convert --source nginx --target sctb512/nginx:nydusv6 --fs-version 6
```
With the `--prefetch-patterns` argument, we can specify the list of files to be written in the front of the nydus image and be prefetched in order when starting a container.
```console
sudo nydusify convert --source nginx --target sctb512/nginx:optimized-nydusv6 --fs-version 6 --prefetch-patterns < /opt/nri/optimizer/results/library/nginx:latest
```
On a host with nydus-snapshotter installed and configured properly, start a container with an optimized nydus image.
```console
sudo nerdctl --snapshotter nydus run --rm --net host -it sctb512/nginx:optimized-nydusv6
```
================================================
FILE: docs/registry_authentication.md
================================================
# Registry Authentication
As [containerd#3731](https://github.com/containerd/containerd/issues/3731) discussed, containerd doesn't share credentials with third-party snapshotters. Like [stargz snapshotter](https://github.com/containerd/stargz-snapshotter/blob/main/docs/overview.md#authentication), nydus-snapshotter supports multiple ways to access private registries with custom configurations.
Credentials are looked up in the following priority order:
1. Snapshot labels (username and password)
2. CRI request interception
3. Docker config (enabled by default)
4. Kubelet credential provider plugins
5. Kubernetes docker config secrets
## Docker config
By default, the snapshotter reads credentials from `$DOCKER_CONFIG` or `~/.docker/config.json`.
```console
# docker login
(Enter username and password)
# crictl pull --creds USERNAME[:PASSWORD] docker.io/<your-repository>/ubuntu:22.04
(Here the credential is only used by containerd)
```
## CRI-based authentication
The following configuration enables nydus-snapshotter to pull private images via CRI requests.
```toml
[remote.auth]
# Fetch the private registry auth as CRI image service proxy
enable_cri_keychain = true
image_service_address = "/run/containerd/containerd.sock"
```
The snapshotter acts as a proxy of the CRI Image Service, exposing the CRI Image Service API on the snapshotter's unix socket (i.e. `/run/containerd/containerd-nydus-grpc.sock`). It acquires registry credentials by scanning requests. `image_service_address` defaults to `/run/containerd/containerd.sock` if omitted.
You **must** specify `--image-service-endpoint=unix:///run/containerd-nydus/containerd-nydus-grpc.sock` to kubelet when using Kubernetes, or set `image-endpoint: "unix:////run/containerd-nydus/containerd-nydus-grpc.sock"` in `crictl.yaml` when using `crictl`.
## Kubeconfig-based authentication
Nydus snapshotter can watch Kubernetes secrets (type `kubernetes.io/dockerconfigjson`) for private registry credentials.
### Using a kubeconfig file
```toml
[remote.auth]
enable_kubeconfig_keychain = true
kubeconfig_path = "/path/to/.kubeconfig"
```
If `kubeconfig_path` is omitted, the snapshotter searches `$KUBECONFIG` or `~/.kube/config`.
> **Note:** This requires additional privilege (a kubeconfig with permission to list/watch secrets) on the node. It does not work if kubelet retrieves credentials outside the API server (e.g. via a [credential provider](https://kubernetes.io/docs/tasks/kubelet-credential-provider/kubelet-credential-provider/)). For that use case, see the [kubelet credential provider](#kubelet-credential-provider) section.
### Using a ServiceAccount
If nydus-snapshotter runs inside a Kubernetes cluster you can use a ServiceAccount instead of a kubeconfig:
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nydus-snapshotter-sa
namespace: nydus-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nydus-snapshotter-role
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nydus-snapshotter-role-binding
roleRef:
kind: ClusterRole
name: nydus-snapshotter-role
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: nydus-snapshotter-sa
namespace: nydus-system
```
Then reference the ServiceAccount in the nydus-snapshotter Pod spec:
```yaml
spec:
serviceAccountName: nydus-snapshotter-sa
```
### Creating secrets
If you have logged into a private registry, create a secret from the local config file:
```bash
kubectl create --namespace nydus-system secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson
```
The snapshotter will pick up the secret and use it for subsequent image pulls from the matched registry.
## Kubelet credential provider
Nydus snapshotter supports [Kubernetes kubelet credential provider plugins](https://kubernetes.io/docs/tasks/kubelet-credential-provider/kubelet-credential-provider/), which allow dynamic credential retrieval from external sources such as cloud provider identity services or secrets managers.
> **Note:** This implementation supports **exec-based credential provider plugins** (GA since [Kubernetes v1.26](https://kubernetes.io/blog/2022/12/22/kubelet-credential-providers/)) but does **not** support the [service account token integration](https://kubernetes.io/blog/2025/05/07/kubernetes-v1-33-wi-for-image-pulls/) introduced in Kubernetes v1.33+. Plugins must retrieve credentials via other means (instance metadata, environment variables, local credential files, etc.).
This authentication method is well-suited for:
- Frequently rotated credentials managed by external systems
- Cloud provider-managed registries (ECR, GCR, ACR) using instance or workload identity
- Enterprise secrets management integrations
### Configuration
```toml
[remote.auth]
enable_kubelet_credential_providers = true
credential_provider_config = "/etc/nydus/credential-provider-config.yaml"
credential_provider_bin_dir = "/usr/local/bin/credential-providers"
```
| Parameter | Description |
|---|---|
| `enable_kubelet_credential_providers` | Enable kubelet credential provider support (default: `false`) |
| `credential_provider_config` | Path to the credential provider configuration file |
| `credential_provider_bin_dir` | Directory containing credential provider plugin binaries |
### Credential provider configuration file
Follow the [Kubernetes spec](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1/#kubelet-config-k8s-io-v1-CredentialProviderConfig):
```yaml
apiVersion: kubelet.config.k8s.io/v1
kind: CredentialProviderConfig
providers:
- name: ecr-credential-provider
apiVersion: credentialprovider.kubelet.k8s.io/v1
matchImages:
- "*.dkr.ecr.*.amazonaws.com"
defaultCacheDuration: "12h"
args:
- get-credentials
- name: gcr-credential-provider
apiVersion: credentialprovider.kubelet.k8s.io/v1
matchImages:
- "gcr.io"
- "*.gcr.io"
defaultCacheDuration: "1h"
```
### Plugin installation
1. Place credential provider binaries in the `credential_provider_bin_dir` directory and ensure they are executable.
2. Configure `matchImages` patterns to match your registry URLs. Wildcards are supported (e.g. `*.dkr.ecr.*.amazonaws.com`).
For AWS ECR, use the official [ECR credential provider](https://github.com/kubernetes/cloud-provider-aws/tree/master/cmd/ecr-credential-provider):
```bash
mkdir -p /usr/local/bin/credential-providers
wget https://artifacts.k8s.io/binaries/cloud-provider-aws/v1.30.0/linux/amd64/ecr-credential-provider
chmod +x ecr-credential-provider
mv ecr-credential-provider /usr/local/bin/credential-providers/
```
### Plugin protocol
Plugins communicate via stdin/stdout using JSON.
**Request:**
```json
{
"kind": "CredentialProviderRequest",
"apiVersion": "credentialprovider.kubelet.k8s.io/v1",
"image": "123456789.dkr.ecr.us-east-1.amazonaws.com/my-image:latest"
}
```
**Response:**
```json
{
"kind": "CredentialProviderResponse",
"apiVersion": "credentialprovider.kubelet.k8s.io/v1",
"cacheKeyType": "Image",
"cacheDuration": "12h",
"auth": {
"123456789.dkr.ecr.us-east-1.amazonaws.com": {
"username": "AWS",
"password": "<token>"
}
}
}
```
Set `auth` to `null` if no credentials are available for the requested image.
### Troubleshooting
- Plugin execution failures are logged but don't halt the authentication chain — the snapshotter tries the next provider.
- Check logs for: `level=warning msg="failed to execute credential provider plugin"`
- Test plugins manually by sending a JSON request on stdin to verify output.
## Credential renewal
For providers that issue short-lived tokens (such as the kubelet credential provider with cloud IAM backends), nydus-snapshotter can automatically renew credentials in the background before they expire.
When enabled, a background goroutine periodically reconciles the set of active RAFS instances against an in-memory credential store, renewing credentials for images currently in use and evicting entries for images that are no longer mounted. On each renewal tick the goroutine re-queries the renewable providers (Docker config, kubelet credential providers, Kubernetes secrets) in priority order.
Only providers that support renewal participate: Docker config, kubelet credential providers, and Kubernetes secret-based providers. CRI-based and label-based credentials are not renewed. The kubelet provider being
expiration aware, it will only renew tokens when they are about to expire.
Entries are evicted when the corresponding RAFS instance is no longer mounted; the credential store itself does not expire entries.
### Configuration
```toml
[remote.auth]
# How often to renew credentials. Set to 0 (the default) to disable.
credential_renewal_interval = "30m"
```
Set `credential_renewal_interval` to at most one third of your token lifetime. This ensures at least two renewal attempts before a token expires, so a single transient failure (network blip, metadata service hiccup) does not cause an auth outage. For example, if ECR tokens are valid for 12 hours, use an interval of 4 hours or less.
> **Future improvement:** The current configuration conflates two concerns into a single interval: how frequently the renewal loop runs, and how early before expiry a token should be renewed. A future version may separate these into a `credential_renewal_check_interval` (the loop cadence, kept short) and a `credential_renewal_lead_time` (how far before expiry to trigger renewal, e.g. 2 hours before a 12-hour token expires). This would allow fine-grained control without the lifetime/3 approximation.
### Metrics
When credential renewal is enabled, the following Prometheus metrics are exported:
| Metric | Type | Description |
|---|---|---|
| `snapshotter_credential_renewals_total` | Counter | Renewal attempts, labeled by `image_ref` and `result` (`success` or `failure`) |
| `snapshotter_credential_store_entries` | Gauge | Number of credentials tracked per `image_ref` |
A rising `failure` count in `snapshotter_credential_renewals_total` indicates that a provider is failing to renew credentials and warrants investigation before the current tokens expire.
================================================
FILE: docs/run_nydus_in_kubernetes.md
================================================
# Run Dragonfly & Nydus in Kubernetes
We recommend using the Dragonfly P2P data distribution system to further improve the runtime performance of Nydus images.
If you want to deploy Dragonfly and Nydus at the same time through Helm, please refer to the **[Quick Start](https://github.com/dragonflyoss/helm-charts/blob/main/INSTALL.md)**.
# Run Nydus snapshotter in Kubernetes
This document will introduce how to run Nydus snapshotter in Kubernetes cluster, you can use helm to deploy Nydus snapshotter container.
**NOTE:** This document is mainly to allow everyone to quickly deploy and experience Nydus snapshotter in the Kubernetes cluster. You cannot use it as a deployment and configuration solution for the production environment.
## Setup Kubernetes using kind
[kind](https://kind.sigs.k8s.io/) is a tool for running local Kubernetes clusters using Docker container “nodes”.
kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI.
First, we need to prepare a configuration file(`kind-config.yaml`) for kind to specify the devices and files we need to mount to the kind node.
```yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
ipFamily: dual
nodes:
- role: control-plane
image: kindest/node:v1.30.2
extraMounts:
- hostPath: ./containerd-config.toml
containerPath: /etc/containerd/config.toml
- hostPath: /dev/fuse
containerPath: /dev/fuse
```
Next, we also need a config for containerd(`containerd-config.toml`).
**NOTE:** It may be necessary to explain here why `disable_snapshot_annotations` and `discard_unpacked_layers` need to be configured in containerd.
- `disable_snapshot_annotations`: This variable disables to pass additional annotations (image related information) to snapshotters in containerd (default value is `true`). In nydus snapshotter, we need these annotations to pull images. Therefore, we need to set it to `false`.
- `discard_unpacked_layers`: This variable allows GC to remove layers from the content store after successfully unpacking these layers to the snapshotter in containerd (default value is `true`). In nydus snapshotter, we need to preserve layers for demand pulling and sharing even after they are unpacked. Therefore, we need to set it to `false`.
```toml
version = 2
[debug]
level = "debug"
[plugins."io.containerd.grpc.v1.cri".containerd]
discard_unpacked_layers = false
disable_snapshot_annotations = false
snapshotter = "overlayfs"
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.6"
```
With these two configuration files, we can create a kind cluster.
```bash
$ kind create cluster --config=kind-config.yaml
```
If everything is fine, kind should have prepared the configuration for us, and we can run the `kubectl` command directly on the host machine, such as:
```bash
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane,master 19m v1.23.4
```
## Use helm to install Nydus snapshotter
Before proceeding, you need to make sure [`helm` is installed](https://helm.sh/docs/intro/quickstart/#install-helm).
First, you need to create a `config-nydus.yaml` for helm to install Nydus-snapshotter.
```yaml
name: nydus-snapshotter
pullPolicy: Always
hostNetwork: true
dragonfly:
enable: false
containerRuntime:
containerd:
enable: true
```
Then clone the Nydus snapshotter helm chart.
```bash
$ git clone https://github.com/dragonflyoss/helm-charts.git
```
Last run helm to create Nydus snapshotter.
```bash
$ cd helm-charts
$ helm install --wait --timeout 10m --dependency-update \
--create-namespace --namespace nydus-system \
-f config-nydus.yaml \
nydus-snapshotter charts/nydus-snapshotter
```
## Run Nydus containers
We can then create a Pod(`nydus-pod.yaml`) config file that runs Nydus image.
```yaml
apiVersion: v1
kind: Pod
metadata:
name: nydus-pod
spec:
containers:
- name: nginx
image: ghcr.io/dragonflyoss/image-service/nginx:nydus-latest
imagePullPolicy: Always
command: ["sh", "-c"]
args:
- tail -f /dev/null
```
Use `kubectl` to create the Pod.
```bash
$ kubectl create -f nydus-pod.yaml
$ kubectl get pods -w
```
The `-w` options will block the console and wait for the changes of the status of the pod. If everything is normal, you can see that the pod will become `Running` after a while.
```bash
NAME READY STATUS RESTARTS AGE
nydus-pod 1/1 Running 0 51s
```
================================================
FILE: docs/setup_snapshotter_by_daemonset.md
================================================
# Setup Nydus Snapshotter by DaemonSet
This document will guide you through the simple steps of setting up and cleaning up the nydus snapshotter in a kubernetes cluster that runs on the host.
## Steps for Setting up Nydus Snapshotter
To begin, let's clone the Nydus Snapshotter repository.
```bash
git clone https://github.com/containerd/nydus-snapshotter
cd nydus-snapshotter
```
We can build the docker image locally. (optional)
```bash
$ export NYDUS_VER=$(curl -s "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name)
$ make # build snapshotter binaries
$ cp bin/* misc/snapshotter/
$ pushd misc/snapshotter/
$ docker build --build-arg NYDUS_VER="${NYDUS_VER}" -t ghcr.io/containerd/nydus-snapshotter:latest .
$ popd
```
**NOTE:** By default, the nydus snapshotter would use the latest release nydus version. If you want to use a specific version, you can set `NYDUS_VER` on your side.
Next, we can configure access control for nydus snapshotter.
```bash
kubectl apply -f misc/snapshotter/nydus-snapshotter-rbac.yaml
```
Afterward, we can deploy a DaemonSet for nydus snapshotter, according to the kubernetes flavour you're using.
```bash
# Vanilla kubernetes
kubectl apply -f misc/snapshotter/base/nydus-snapshotter.yaml
```
```bash
# k3s
kubectl apply -k misc/snapshotter/overlays/k3s/
```
```bash
# rke2
kubectl apply -k misc/snapshotter/overlays/rke2/
```
Then, we can confirm that nydus snapshotter is running through the DaemonSet.
```bash
$ kubectl get pods -n nydus-system
NAME READY STATUS RESTARTS AGE
nydus-snapshotter-26rf7 1/1 Running 0 18s
```
Finally, we can view the logs in the pod.
```bash
$ kubectl logs nydus-snapshotter-26rf7 -n nydus-system
install nydus snapshotter artifacts
there is no proxy plugin!
Created symlink /etc/systemd/system/multi-user.target.wants/nydus-snapshotter.service → /etc/systemd/system/nydus-snapshotter.service.
```
And we can see the nydus snapshotter service on the host.
```bash
$ systemctl status nydus-snapshotter
● nydus-snapshotter.service - nydus snapshotter
Loaded: loaded (/etc/systemd/system/nydus-snapshotter.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/nydus-snapshotter.service.d
└─proxy.conf
Active: active (running) since Wed 2024-01-17 16:14:22 UTC; 56s ago
Main PID: 1100169 (containerd-nydu)
Tasks: 11 (limit: 96376)
Memory: 8.6M
CPU: 35ms
CGroup: /system.slice/nydus-snapshotter.service
└─1100169 /opt/nydus/bin/containerd-nydus-grpc --config /etc/nydus/config.toml
Jan 17 16:14:22 worker systemd[1]: Started nydus snapshotter.
Jan 17 16:14:22 worker containerd-nydus-grpc[1100169]: time="2024-01-17T16:14:22.998798369Z" level=info msg="Start nydus-snapshotter. Version: v0.7.0-308-g106a6cb, PID: 1100169, FsDriver: fusedev, DaemonMode: dedicated"
Jan 17 16:14:23 worker containerd-nydus-grpc[1100169]: time="2024-01-17T16:14:23.000186538Z" level=info msg="Run daemons monitor..."
```
**NOTE:** By default, the nydus snapshotter operates as a systemd service. If you prefer to run nydus snapshotter as a standalone process, you can set `ENABLE_SYSTEMD_SERVICE` to `false` in `nydus-snapshotter.yaml`.
## Steps for Cleaning up Nydus Snapshotter
We use `preStop`` hook in the DaemonSet to uninstall nydus snapshotter and roll back the containerd configuration.
```bash
# Vanilla kubernetes
$ kubectl delete -f misc/snapshotter/base/nydus-snapshotter.yaml
```
```bash
# k3s
$ kubectl delete -k misc/snapshotter/overlays/k3s/
```
```bash
# rke2
$ kubectl delete -k misc/snapshotter/overlays/rke2/
```
```bash
$ kubectl delete -f misc/snapshotter/nydus-snapshotter-rbac.yaml
$ systemd restart containerd.service
```
## Customized Setup
As we know, nydus snapshotter supports four filesystem drivers (fs_driver): `fusedev`, `fscache`, `blockdev`, `proxy`. Within the container image, we have included configurations for these snapshotter drivers, as well as the corresponding nydusd configurations. By default, the fusedev driver is enabled in the nydus snapshotter, using the snapshotter configuration [`config-fusedev.toml`](../misc/snapshotter/config-fusedev.toml) and the nydusd configuration [`nydusd-config.fusedev.json`](../misc/snapshotter/nydusd-config.fusedev.json).
### Other filesystem driver with related default configuration
If we want to setup the nydus snapshotter with the default configuration for different fs_driver (such as `proxy`), we can modify the values in the `Configmap` in `nydus-snapshotter.yaml`:
```yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nydus-snapshotter-configs
labels:
app: nydus-snapshotter
namespace: nydus-snapshotter
data:
FS_DRIVER: "proxy"
NYDUSD_DAEMON_MODE: "none"
```
Then we can run the nydus snapshotter enabling `proxy` `fs_driver` with the snapshotter configuration [`config-proxy.toml`](../misc/snapshotter/config-proxy.toml).
**NOTE:** The fs_driver (`blockdev` and `proxy`) do not need nydusd, so they do not need nydusd config.
### Same filesystem with different snapshotter configuration and different nydusd configuration
If we want to setup the nydus snapshotter for the same fs_driver (such as `fusedev`) with different snapshotter configuration and different nydusd configuration, we can enable `ENABLE_CONFIG_FROM_VOLUME` and add the snapshotter configuration [`config.toml`](../misc/snapshotter/config.toml) and nydusd configuration [`nydusd-config.json`](../misc/snapshotter/nydusd-config.fusedev.json) in the `Configmap` in `nydus-snapshotter.yaml`:
```yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nydus-snapshotter-configs
labels:
app: nydus-snapshotter
namespace: nydus-snapshotter
data:
ENABLE_CONFIG_FROM_VOLUME: "true"
config.toml: |-
# The snapshotter config c
gitextract_bo46r8c0/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.yml
│ │ ├── feature-request.yml
│ │ └── improvement-report.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── codecov.yml
│ └── workflows/
│ ├── ci.yml
│ ├── e2e.yml
│ ├── k8s-e2e-run.yml
│ ├── k8s-e2e.yml
│ ├── optimizer.yml
│ └── release.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── MAINTAINERS
├── Makefile
├── README.md
├── cmd/
│ ├── containerd-nydus-grpc/
│ │ ├── main.go
│ │ └── snapshotter.go
│ ├── converter/
│ │ └── main.go
│ ├── nydus-overlayfs/
│ │ ├── main.go
│ │ └── main_test.go
│ ├── optimizer-nri-plugin/
│ │ └── main.go
│ └── prefetchfiles-nri-plugin/
│ └── main.go
├── config/
│ ├── config.go
│ ├── config_test.go
│ ├── daemonconfig/
│ │ ├── daemonconfig.go
│ │ ├── daemonconfig_test.go
│ │ ├── fscache.go
│ │ ├── fuse.go
│ │ ├── mirror_select_test.go
│ │ ├── mirrors.go
│ │ └── mirrors_test.go
│ ├── default.go
│ └── global.go
├── docs/
│ ├── configure_nydus.md
│ ├── crictl_dry_run.md
│ ├── index_detection.md
│ ├── optimize_nydus_image.md
│ ├── registry_authentication.md
│ ├── run_nydus_in_kubernetes.md
│ ├── setup_snapshotter_by_daemonset.md
│ └── tarfs.md
├── export/
│ └── snapshotter/
│ └── snapshotter.go
├── go.mod
├── go.sum
├── integration/
│ ├── Dockerfile
│ └── entrypoint.sh
├── internal/
│ ├── constant/
│ │ └── values.go
│ ├── flags/
│ │ ├── flags.go
│ │ └── flags_test.go
│ └── logging/
│ ├── setup.go
│ └── setup_test.go
├── misc/
│ ├── example/
│ │ ├── 10-containerd-net.conflist
│ │ ├── README.md
│ │ ├── container.yaml
│ │ ├── containerd-config.toml
│ │ ├── containerd-test-config.toml
│ │ ├── crictl.yaml
│ │ ├── optimizer-nri-plugin.conf
│ │ └── pod.yaml
│ ├── nri-prefetch/
│ │ └── prefetchConfig.toml
│ ├── optimizer/
│ │ ├── containerd-config.toml
│ │ ├── crictl.yaml
│ │ ├── nginx.yaml
│ │ ├── sandbox.yaml
│ │ └── script/
│ │ ├── entrypoint.sh
│ │ └── file_list.txt
│ └── snapshotter/
│ ├── Dockerfile
│ ├── base/
│ │ ├── kustomization.yaml
│ │ └── nydus-snapshotter.yaml
│ ├── config-blockdev.toml
│ ├── config-proxy.toml
│ ├── config.toml
│ ├── nydus-snapshotter-rbac.yaml
│ ├── nydus-snapshotter.fscache.service
│ ├── nydus-snapshotter.fusedev.service
│ ├── nydus-snapshotter.service
│ ├── nydusd-config-localfs.json
│ ├── nydusd-config.fscache.json
│ ├── nydusd-config.fusedev.json
│ ├── overlays/
│ │ ├── k3s/
│ │ │ ├── kustomization.yaml
│ │ │ └── mount_k3s_conf.yaml
│ │ └── rke2/
│ │ ├── kustomization.yaml
│ │ └── mount_rke2_conf.yaml
│ └── snapshotter.sh
├── pkg/
│ ├── auth/
│ │ ├── cri.go
│ │ ├── cri_test.go
│ │ ├── docker.go
│ │ ├── docker_test.go
│ │ ├── keychain.go
│ │ ├── kubelet.go
│ │ ├── kubelet_test.go
│ │ ├── kubesecret.go
│ │ ├── kubesecret_test.go
│ │ ├── labels.go
│ │ ├── labels_test.go
│ │ ├── provider.go
│ │ ├── renewal.go
│ │ └── renewal_test.go
│ ├── backend/
│ │ ├── backend.go
│ │ ├── localfs.go
│ │ ├── oss.go
│ │ ├── s3.go
│ │ └── s3_test.go
│ ├── cache/
│ │ ├── manager.go
│ │ └── manager_test.go
│ ├── cgroup/
│ │ ├── cgroup.go
│ │ ├── manager.go
│ │ ├── v1/
│ │ │ └── v1.go
│ │ └── v2/
│ │ └── v2.go
│ ├── converter/
│ │ ├── constant.go
│ │ ├── convert_unix.go
│ │ ├── convert_windows.go
│ │ ├── cs_proxy_unix.go
│ │ ├── merge_unix_test.go
│ │ ├── reconvert_unix.go
│ │ ├── reconvert_unix_test.go
│ │ ├── tool/
│ │ │ ├── builder.go
│ │ │ ├── feature.go
│ │ │ └── feature_test.go
│ │ ├── types.go
│ │ └── utils.go
│ ├── daemon/
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── command/
│ │ │ ├── command.go
│ │ │ └── command_builder_test.go
│ │ ├── config.go
│ │ ├── daemon.go
│ │ ├── daemon_test.go
│ │ ├── idgen.go
│ │ └── types/
│ │ └── types.go
│ ├── encryption/
│ │ └── encryption.go
│ ├── errdefs/
│ │ └── errors.go
│ ├── fanotify/
│ │ ├── conn/
│ │ │ └── conn.go
│ │ └── fanotify.go
│ ├── filesystem/
│ │ ├── config.go
│ │ ├── fs.go
│ │ ├── index_adaptor.go
│ │ ├── referer_adaptor.go
│ │ ├── stargz_adaptor.go
│ │ └── tarfs_adaptor.go
│ ├── index/
│ │ ├── detector.go
│ │ ├── detector_test.go
│ │ ├── manager.go
│ │ └── manager_test.go
│ ├── label/
│ │ └── label.go
│ ├── layout/
│ │ └── layout.go
│ ├── manager/
│ │ ├── daemon_adaptor.go
│ │ ├── daemon_cache.go
│ │ ├── daemon_cache_test.go
│ │ ├── daemon_event.go
│ │ ├── manager.go
│ │ ├── monitor.go
│ │ ├── monitor_test.go
│ │ └── store.go
│ ├── metrics/
│ │ ├── collector/
│ │ │ ├── cache.go
│ │ │ ├── collector.go
│ │ │ ├── daemon.go
│ │ │ ├── fs.go
│ │ │ └── snapshotter.go
│ │ ├── data/
│ │ │ ├── auth.go
│ │ │ ├── cache.go
│ │ │ ├── daemon.go
│ │ │ ├── fs.go
│ │ │ ├── labels.go
│ │ │ └── snapshotter.go
│ │ ├── listener.go
│ │ ├── registry/
│ │ │ └── registry.go
│ │ ├── serve.go
│ │ ├── tool/
│ │ │ ├── common.go
│ │ │ ├── stat.go
│ │ │ └── stat_test.go
│ │ └── types/
│ │ ├── ttl/
│ │ │ ├── gauge.go
│ │ │ └── gauge_test.go
│ │ └── types.go
│ ├── pprof/
│ │ └── listener.go
│ ├── prefetch/
│ │ └── prefetch.go
│ ├── rafs/
│ │ └── rafs.go
│ ├── referrer/
│ │ ├── manager.go
│ │ └── referrer.go
│ ├── remote/
│ │ ├── remote.go
│ │ ├── remote_test.go
│ │ ├── remotes/
│ │ │ ├── docker/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── fetch.go
│ │ │ │ │ ├── fetch_test.go
│ │ │ │ │ ├── parse.go
│ │ │ │ │ └── parse_test.go
│ │ │ │ ├── authorizer.go
│ │ │ │ ├── config/
│ │ │ │ │ ├── config_unix.go
│ │ │ │ │ ├── config_windows.go
│ │ │ │ │ ├── docker_fuzzer_internal.go
│ │ │ │ │ ├── hosts.go
│ │ │ │ │ └── hosts_test.go
│ │ │ │ ├── converter.go
│ │ │ │ ├── converter_fuzz.go
│ │ │ │ ├── errcode.go
│ │ │ │ ├── errdesc.go
│ │ │ │ ├── fetcher.go
│ │ │ │ ├── fetcher_fuzz.go
│ │ │ │ ├── fetcher_test.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── handler_test.go
│ │ │ │ ├── httpreadseeker.go
│ │ │ │ ├── pusher.go
│ │ │ │ ├── pusher_test.go
│ │ │ │ ├── referrers.go
│ │ │ │ ├── registry.go
│ │ │ │ ├── registry_test.go
│ │ │ │ ├── resolver.go
│ │ │ │ ├── resolver_test.go
│ │ │ │ ├── schema1/
│ │ │ │ │ └── converter.go
│ │ │ │ ├── scope.go
│ │ │ │ ├── scope_test.go
│ │ │ │ └── status.go
│ │ │ ├── errors/
│ │ │ │ └── errors.go
│ │ │ ├── handlers.go
│ │ │ ├── handlers_test.go
│ │ │ └── resolver.go
│ │ └── unpack.go
│ ├── resolve/
│ │ └── resolver.go
│ ├── signature/
│ │ └── signature.go
│ ├── snapshot/
│ │ └── storage.go
│ ├── stargz/
│ │ ├── resolver.go
│ │ ├── resolver_test.go
│ │ └── testdata/
│ │ ├── config/
│ │ │ └── nydus.json
│ │ └── stargz.index.json
│ ├── store/
│ │ ├── daemonstore.go
│ │ ├── database.go
│ │ ├── database_compat.go
│ │ └── database_test.go
│ ├── supervisor/
│ │ ├── supervisor.go
│ │ └── supervisor_test.go
│ ├── system/
│ │ ├── system.go
│ │ └── system_test.go
│ ├── tarfs/
│ │ └── tarfs.go
│ └── utils/
│ ├── display/
│ │ └── display.go
│ ├── erofs/
│ │ └── erofs.go
│ ├── file/
│ │ └── file.go
│ ├── mount/
│ │ └── mount.go
│ ├── parser/
│ │ ├── parser.go
│ │ └── parser_test.go
│ ├── registry/
│ │ ├── registry.go
│ │ └── registry_test.go
│ ├── retry/
│ │ └── retry.go
│ ├── signals/
│ │ ├── signal.go
│ │ └── signal_test.go
│ ├── signer/
│ │ └── signer.go
│ ├── sysinfo/
│ │ └── sysinfo.go
│ └── transport/
│ ├── pool.go
│ └── pool_test.go
├── snapshot/
│ ├── mount_option.go
│ ├── mount_option_test.go
│ ├── process.go
│ ├── renewal.go
│ ├── renewal_test.go
│ ├── snapshot.go
│ ├── snapshot_test.go
│ └── utils.go
├── tests/
│ ├── converter_test.go
│ ├── e2e/
│ │ └── k8s/
│ │ ├── kind.yaml
│ │ ├── snapshotter-cri.yaml
│ │ ├── snapshotter-kubeconf.yaml
│ │ └── test-pod.yaml.tpl
│ ├── helpers/
│ │ ├── helpers.sh
│ │ ├── kind.sh
│ │ └── lib.sh
│ └── nydusd.go
├── tools/
│ └── optimizer-server/
│ ├── Cargo.toml
│ ├── Makefile
│ └── src/
│ └── main.rs
└── version/
└── version.go
SYMBOL INDEX (1789 symbols across 192 files)
FILE: cmd/containerd-nydus-grpc/main.go
function main (line 25) | func main() {
FILE: cmd/containerd-nydus-grpc/snapshotter.go
function Start (line 30) | func Start(ctx context.Context, cfg *config.SnapshotterConfig) error {
type ServeOptions (line 65) | type ServeOptions struct
function Serve (line 73) | func Serve(ctx context.Context, sn snapshots.Snapshotter, options ServeO...
function ensureSocketNotExists (line 113) | func ensureSocketNotExists(listeningSocketPath string) error {
FILE: cmd/converter/main.go
function main (line 9) | func main() {
FILE: cmd/nydus-overlayfs/main.go
constant extraOptionKey (line 18) | extraOptionKey = "extraoption="
constant kataVolumeOptionKey (line 21) | kataVolumeOptionKey = "io.katacontainers.volume="
type mountArgs (line 34) | type mountArgs struct
function parseArgs (line 40) | func parseArgs(args []string) (*mountArgs, error) {
function parseOptions (line 68) | func parseOptions(options []string) (int, string) {
function longestCommonPrefix (line 112) | func longestCommonPrefix(strs []string) string {
function compactLowerdirOption (line 142) | func compactLowerdirOption(options []string) (string, []string) {
function run (line 214) | func run(args cli.Args) error {
function main (line 246) | func main() {
FILE: cmd/nydus-overlayfs/main_test.go
function TestLongestCommonPrefix (line 18) | func TestLongestCommonPrefix(t *testing.T) {
function TestCompactLowerdirOption (line 59) | func TestCompactLowerdirOption(t *testing.T) {
function TestCompactLowerdirOption_RealWorldSizeSavings (line 149) | func TestCompactLowerdirOption_RealWorldSizeSavings(t *testing.T) {
function TestParseArgs (line 170) | func TestParseArgs(t *testing.T) {
FILE: cmd/optimizer-nri-plugin/main.go
constant defaultEvents (line 33) | defaultEvents = "StartContainer,StopContainer"
constant defaultServerPath (line 34) | defaultServerPath = "/usr/local/bin/optimizer-server"
constant defaultPersistDir (line 35) | defaultPersistDir = "/opt/nri/optimizer/results"
type PluginConfig (line 38) | type PluginConfig struct
type PluginArgs (line 48) | type PluginArgs struct
type Flags (line 55) | type Flags struct
function buildFlags (line 60) | func buildFlags(args *PluginArgs) []cli.Flag {
function NewPluginFlags (line 110) | func NewPluginFlags() *Flags {
type plugin (line 118) | type plugin struct
method Configure (line 137) | func (p *plugin) Configure(ctx context.Context, config, runtime, versi...
method StartContainer (line 161) | func (p *plugin) StartContainer(_ context.Context, _ *api.PodSandbox, ...
method StopContainer (line 188) | func (p *plugin) StopContainer(_ context.Context, _ *api.PodSandbox, c...
method onClose (line 219) | func (p *plugin) onClose() {
constant imageNameLabel (line 134) | imageNameLabel = "io.kubernetes.cri.image-name"
function GetImageName (line 203) | func GetImageName(annotations map[string]string) (string, string, error) {
function main (line 226) | func main() {
FILE: cmd/prefetchfiles-nri-plugin/main.go
constant endpointPrefetch (line 32) | endpointPrefetch = "/api/v1/prefetch"
constant defaultEvents (line 33) | defaultEvents = "RunPodSandbox"
constant defaultSystemControllerAddress (line 34) | defaultSystemControllerAddress = "/run/containerd-nydus/system.sock"
constant defaultPrefetchConfigDir (line 35) | defaultPrefetchConfigDir = "/etc/nydus"
constant nydusPrefetchAnnotation (line 36) | nydusPrefetchAnnotation = "containerd.io/nydus-prefetch"
type PluginArgs (line 39) | type PluginArgs struct
type Flags (line 45) | type Flags struct
function buildFlags (line 50) | func buildFlags(args *PluginArgs) []cli.Flag {
function NewPluginFlags (line 71) | func NewPluginFlags() *Flags {
type plugin (line 79) | type plugin struct
method RunPodSandbox (line 119) | func (p *plugin) RunPodSandbox(ctx context.Context, pod *api.PodSandbo...
function sendDataOverHTTP (line 92) | func sendDataOverHTTP(data string, endpoint, sock string) error {
function main (line 134) | func main() {
FILE: config/config.go
function init (line 27) | func init() {
type DaemonMode (line 35) | type DaemonMode
constant DaemonModeMultiple (line 39) | DaemonModeMultiple DaemonMode = DaemonMode(constant.DaemonModeMultiple)
constant DaemonModeDedicated (line 41) | DaemonModeDedicated DaemonMode = DaemonMode(constant.DaemonModeDedicated)
constant DaemonModeShared (line 43) | DaemonModeShared DaemonMode = DaemonMode(constant.DaemonModeShared)
constant DaemonModeNone (line 49) | DaemonModeNone DaemonMode = DaemonMode(constant.DaemonModeNone)
constant DaemonModeInvalid (line 50) | DaemonModeInvalid DaemonMode = DaemonMode(constant.DaemonModeInvalid)
constant MaxRootPathLen (line 60) | MaxRootPathLen = 70
function parseDaemonMode (line 63) | func parseDaemonMode(m string) (DaemonMode, error) {
type DaemonRecoverPolicy (line 78) | type DaemonRecoverPolicy
method String (line 87) | func (p DaemonRecoverPolicy) String() string {
constant RecoverPolicyInvalid (line 81) | RecoverPolicyInvalid DaemonRecoverPolicy = iota
constant RecoverPolicyNone (line 82) | RecoverPolicyNone
constant RecoverPolicyRestart (line 83) | RecoverPolicyRestart
constant RecoverPolicyFailover (line 84) | RecoverPolicyFailover
function ParseRecoverPolicy (line 104) | func ParseRecoverPolicy(p string) (DaemonRecoverPolicy, error) {
constant FsDriverBlockdev (line 114) | FsDriverBlockdev string = constant.FsDriverBlockdev
constant FsDriverFusedev (line 115) | FsDriverFusedev string = constant.FsDriverFusedev
constant FsDriverFscache (line 116) | FsDriverFscache string = constant.FsDriverFscache
constant FsDriverNodev (line 117) | FsDriverNodev string = constant.FsDriverNodev
constant FsDriverProxy (line 118) | FsDriverProxy string = constant.FsDriverProxy
constant FailoverPolicyNone (line 122) | FailoverPolicyNone string = constant.FailoverPolicyNone
constant FailoverPolicyResend (line 123) | FailoverPolicyResend string = constant.FailoverPolicyResend
constant FailoverPolicyFlush (line 124) | FailoverPolicyFlush string = constant.FailoverPolicyFlush
type Experimental (line 127) | type Experimental struct
type TarfsConfig (line 135) | type TarfsConfig struct
type CgroupConfig (line 143) | type CgroupConfig struct
type DaemonConfig (line 149) | type DaemonConfig struct
type LoggingConfig (line 160) | type LoggingConfig struct
type ImageConfig (line 172) | type ImageConfig struct
type SnapshotConfig (line 179) | type SnapshotConfig struct
type CacheManagerConfig (line 191) | type CacheManagerConfig struct
type AuthConfig (line 200) | type AuthConfig struct
type RemoteConfig (line 218) | type RemoteConfig struct
type MirrorsConfig (line 225) | type MirrorsConfig struct
type MetricsConfig (line 229) | type MetricsConfig struct
type DebugConfig (line 238) | type DebugConfig struct
type SystemControllerConfig (line 243) | type SystemControllerConfig struct
type SnapshotterConfig (line 253) | type SnapshotterConfig struct
function LoadSnapshotterConfig (line 279) | func LoadSnapshotterConfig(path string) (*SnapshotterConfig, error) {
function MergeConfig (line 299) | func MergeConfig(to, from *SnapshotterConfig) error {
function ValidateConfig (line 308) | func ValidateConfig(c *SnapshotterConfig) error {
function ParseParameters (line 366) | func ParseParameters(args *flags.Args, cfg *SnapshotterConfig) error {
function ParseCgroupConfig (line 424) | func ParseCgroupConfig(config CgroupConfig) (cgroup.Config, error) {
FILE: config/config_test.go
function TestLoadSnapshotterTOMLConfig (line 18) | func TestLoadSnapshotterTOMLConfig(t *testing.T) {
function TestSnapshotterConfig (line 129) | func TestSnapshotterConfig(t *testing.T) {
function TestMergeConfig (line 189) | func TestMergeConfig(t *testing.T) {
function TestProcessConfigurations (line 228) | func TestProcessConfigurations(t *testing.T) {
FILE: config/daemonconfig/daemonconfig.go
constant backendTypeLocalfs (line 31) | backendTypeLocalfs StorageBackendType = "localfs"
constant backendTypeOss (line 32) | backendTypeOss StorageBackendType = "oss"
constant backendTypeRegistry (line 33) | backendTypeRegistry StorageBackendType = "registry"
constant backendTypeS3 (line 34) | backendTypeS3 StorageBackendType = "s3"
type DaemonConfig (line 37) | type DaemonConfig interface
function NewDaemonConfig (line 48) | func NewDaemonConfig(fsDriver, path string) (DaemonConfig, error) {
type BackendConfig (line 67) | type BackendConfig struct
type DeviceConfig (line 110) | type DeviceConfig struct
function DumpConfigFile (line 129) | func DumpConfigFile(c interface{}, path string) error {
function DumpConfigString (line 141) | func DumpConfigString(c interface{}) (string, error) {
function SupplementDaemonConfig (line 147) | func SupplementDaemonConfig(c DaemonConfig, imageID, snapshotID string,
function selectMirrorHost (line 199) | func selectMirrorHost(mirrorsConfigDir, registryHost string) (scheme str...
function splitMirrorURL (line 247) | func splitMirrorURL(mirrorHost string) (scheme, host string, err error) {
function serializeWithSecretFilter (line 259) | func serializeWithSecretFilter(obj interface{}) map[string]interface{} {
FILE: config/daemonconfig/daemonconfig_test.go
function TestLoadConfig (line 16) | func TestLoadConfig(t *testing.T) {
function TestAmplifyIo (line 67) | func TestAmplifyIo(t *testing.T) {
function TestSerializeWithSecretFilter (line 96) | func TestSerializeWithSecretFilter(t *testing.T) {
FILE: config/daemonconfig/fscache.go
constant WorkDir (line 22) | WorkDir string = "workdir"
constant Bootstrap (line 23) | Bootstrap string = "bootstrap"
type BlobPrefetchConfig (line 26) | type BlobPrefetchConfig struct
type FscacheDaemonConfig (line 34) | type FscacheDaemonConfig struct
method StorageBackend (line 72) | func (c *FscacheDaemonConfig) StorageBackend() (string, *BackendConfig) {
method Supplement (line 77) | func (c *FscacheDaemonConfig) Supplement(host, repo, snapshotID string...
method FillAuth (line 105) | func (c *FscacheDaemonConfig) FillAuth(kc *auth.PassKeyChain) {
method DumpString (line 115) | func (c *FscacheDaemonConfig) DumpString() (string, error) {
method DumpFile (line 119) | func (c *FscacheDaemonConfig) DumpFile(f string) error {
function LoadFscacheConfig (line 55) | func LoadFscacheConfig(p string) (*FscacheDaemonConfig, error) {
FILE: config/daemonconfig/fuse.go
constant CacheDir (line 19) | CacheDir string = "cachedir"
type FuseDaemonConfig (line 22) | type FuseDaemonConfig struct
method Supplement (line 63) | func (c *FuseDaemonConfig) Supplement(host, repo, snapshotID string, p...
method FillAuth (line 77) | func (c *FuseDaemonConfig) FillAuth(kc *auth.PassKeyChain) {
method StorageBackend (line 87) | func (c *FuseDaemonConfig) StorageBackend() (string, *BackendConfig) {
method DumpString (line 91) | func (c *FuseDaemonConfig) DumpString() (string, error) {
method DumpFile (line 95) | func (c *FuseDaemonConfig) DumpFile(f string) error {
type FSPrefetch (line 37) | type FSPrefetch struct
function LoadFuseConfig (line 46) | func LoadFuseConfig(p string) (*FuseDaemonConfig, error) {
FILE: config/daemonconfig/mirror_select_test.go
function writeMirrorHostsToml (line 21) | func writeMirrorHostsToml(t *testing.T, dir, content string) {
function TestSplitMirrorURL (line 28) | func TestSplitMirrorURL(t *testing.T) {
function TestSelectMirrorHost_NoConfig (line 87) | func TestSelectMirrorHost_NoConfig(t *testing.T) {
function TestSelectMirrorHost_EmptyDir (line 93) | func TestSelectMirrorHost_EmptyDir(t *testing.T) {
function TestSelectMirrorHost_MirrorNoPingURL (line 100) | func TestSelectMirrorHost_MirrorNoPingURL(t *testing.T) {
function TestSelectMirrorHost_MirrorPingSucceeds (line 111) | func TestSelectMirrorHost_MirrorPingSucceeds(t *testing.T) {
function TestSelectMirrorHost_MirrorPingFails_FallbackToOrigin (line 128) | func TestSelectMirrorHost_MirrorPingFails_FallbackToOrigin(t *testing.T) {
function TestSelectMirrorHost_FirstMirrorFails_SecondMirrorNoPing (line 145) | func TestSelectMirrorHost_FirstMirrorFails_SecondMirrorNoPing(t *testing...
FILE: config/daemonconfig/mirrors.go
type MirrorConfig (line 23) | type MirrorConfig struct
type HostFileConfig (line 32) | type HostFileConfig struct
type hostConfig (line 46) | type hostConfig struct
function makeStringSlice (line 57) | func makeStringSlice(slice []interface{}, cb func(string) string) ([]str...
function parseMirrorsConfig (line 74) | func parseMirrorsConfig(hosts []hostConfig) []MirrorConfig {
function hostDirectory (line 99) | func hostDirectory(host string) string {
function hostPaths (line 107) | func hostPaths(root, host string) []string {
function hostDirFromRoot (line 119) | func hostDirFromRoot(root, host string) (string, error) {
function getSortedHosts (line 131) | func getSortedHosts(root *toml.Tree) ([]string, error) {
function parseHostConfig (line 151) | func parseHostConfig(server string, config HostFileConfig) (hostConfig, ...
function parseHostsFile (line 207) | func parseHostsFile(b []byte) ([]hostConfig, error) {
function loadHostDir (line 245) | func loadHostDir(hostsDir string) ([]hostConfig, error) {
function LoadMirrorsConfig (line 262) | func LoadMirrorsConfig(mirrorsConfigDir, registryHost string) ([]MirrorC...
FILE: config/daemonconfig/mirrors_test.go
function TestLoadMirrorConfigCACerts (line 19) | func TestLoadMirrorConfigCACerts(t *testing.T) {
function TestLoadMirrorConfig (line 98) | func TestLoadMirrorConfig(t *testing.T) {
FILE: config/default.go
method FillUpWithDefaults (line 15) | func (c *SnapshotterConfig) FillUpWithDefaults() error {
method SetupNydusBinaryPaths (line 61) | func (c *SnapshotterConfig) SetupNydusBinaryPaths() error {
FILE: config/global.go
type GlobalConfig (line 29) | type GlobalConfig struct
function IsFusedevSharedModeEnabled (line 40) | func IsFusedevSharedModeEnabled() bool {
function GetDaemonMode (line 44) | func GetDaemonMode() DaemonMode {
function GetSnapshotsRootDir (line 48) | func GetSnapshotsRootDir() string {
function GetRootMountpoint (line 52) | func GetRootMountpoint() string {
function GetSocketRoot (line 56) | func GetSocketRoot() string {
function GetConfigRoot (line 60) | func GetConfigRoot() string {
function GetMirrorsConfigDir (line 64) | func GetMirrorsConfigDir() string {
function GetFsDriver (line 68) | func GetFsDriver() string {
function GetLogDir (line 72) | func GetLogDir() string {
function GetLogLevel (line 76) | func GetLogLevel() string {
function GetDaemonLogRotationSize (line 80) | func GetDaemonLogRotationSize() int {
function GetDaemonThreadsNumber (line 84) | func GetDaemonThreadsNumber() int {
function GetDaemonFailoverPolicy (line 88) | func GetDaemonFailoverPolicy() string {
function GetLogToStdout (line 92) | func GetLogToStdout() bool {
function IsBackendSourceEnabled (line 96) | func IsBackendSourceEnabled() bool {
function IsSystemControllerEnabled (line 100) | func IsSystemControllerEnabled() bool {
function SystemControllerAddress (line 104) | func SystemControllerAddress() string {
function SystemControllerPprofAddress (line 108) | func SystemControllerPprofAddress() string {
function GetDaemonProfileCPUDuration (line 112) | func GetDaemonProfileCPUDuration() int64 {
function GetSkipSSLVerify (line 116) | func GetSkipSSLVerify() bool {
constant TarfsLayerVerityOnly (line 121) | TarfsLayerVerityOnly string = "layer_verity_only"
constant TarfsImageVerityOnly (line 122) | TarfsImageVerityOnly string = "image_verity_only"
constant TarfsLayerBlockDevice (line 123) | TarfsLayerBlockDevice string = "layer_block"
constant TarfsImageBlockDevice (line 124) | TarfsImageBlockDevice string = "image_block"
constant TarfsLayerBlockWithVerity (line 125) | TarfsLayerBlockWithVerity string = "layer_block_with_verity"
constant TarfsImageBlockWithVerity (line 126) | TarfsImageBlockWithVerity string = "image_block_with_verity"
function GetTarfsMountOnHost (line 129) | func GetTarfsMountOnHost() bool {
function GetTarfsExportEnabled (line 133) | func GetTarfsExportEnabled() bool {
function GetTarfsExportFlags (line 148) | func GetTarfsExportFlags() (bool, bool, bool) {
function ProcessConfigurations (line 167) | func ProcessConfigurations(c *SnapshotterConfig) error {
function PrepareLogDir (line 196) | func PrepareLogDir(c *SnapshotterConfig) {
function SetUpEnvironment (line 202) | func SetUpEnvironment(c *SnapshotterConfig) error {
FILE: export/snapshotter/snapshotter.go
function init (line 14) | func init() {
FILE: internal/constant/values.go
constant DaemonModeMultiple (line 14) | DaemonModeMultiple string = "multiple"
constant DaemonModeDedicated (line 15) | DaemonModeDedicated string = "dedicated"
constant DaemonModeShared (line 16) | DaemonModeShared string = "shared"
constant DaemonModeNone (line 17) | DaemonModeNone string = "none"
constant DaemonModeInvalid (line 18) | DaemonModeInvalid string = ""
constant FsDriverBlockdev (line 23) | FsDriverBlockdev string = "blockdev"
constant FsDriverFusedev (line 25) | FsDriverFusedev string = "fusedev"
constant FsDriverFscache (line 27) | FsDriverFscache string = "fscache"
constant FsDriverNodev (line 29) | FsDriverNodev string = "nodev"
constant FsDriverProxy (line 31) | FsDriverProxy string = "proxy"
constant DefaultDaemonMode (line 35) | DefaultDaemonMode = DaemonModeMultiple
constant DefaultFsDriver (line 37) | DefaultFsDriver = FsDriverFusedev
constant DefaultLogLevel (line 39) | DefaultLogLevel string = "info"
constant DefaultGCPeriod (line 40) | DefaultGCPeriod = 24 * time.Hour
constant DefaultNydusDaemonConfigPath (line 42) | DefaultNydusDaemonConfigPath string = "/etc/nydus/nydusd-config.json"
constant NydusdBinaryName (line 43) | NydusdBinaryName string = "nydusd"
constant NydusImageBinaryName (line 44) | NydusImageBinaryName string = "nydus-image"
constant DefaultRootDir (line 46) | DefaultRootDir = "/var/lib/containerd/io.containerd.snap...
constant DefaultAddress (line 47) | DefaultAddress = "/run/containerd-nydus/containerd-nydus...
constant DefaultSystemControllerAddress (line 48) | DefaultSystemControllerAddress = "/run/containerd-nydus/system.sock"
constant DefaultDaemonRotateLogMaxSize (line 51) | DefaultDaemonRotateLogMaxSize = 100
constant DefaultRotateLogMaxSize (line 52) | DefaultRotateLogMaxSize = 200
constant DefaultRotateLogMaxBackups (line 53) | DefaultRotateLogMaxBackups = 5
constant DefaultRotateLogMaxAge (line 54) | DefaultRotateLogMaxAge = 0
constant DefaultRotateLogLocalTime (line 55) | DefaultRotateLogLocalTime = true
constant DefaultRotateLogCompress (line 56) | DefaultRotateLogCompress = true
constant DefaultHungIOInterval (line 59) | DefaultHungIOInterval = 10 * time.Second
constant DefaultCollectInterval (line 60) | DefaultCollectInterval = 1 * time.Minute
constant FailoverPolicyNone (line 64) | FailoverPolicyNone string = "none"
constant FailoverPolicyResend (line 65) | FailoverPolicyResend string = "resend"
constant FailoverPolicyFlush (line 66) | FailoverPolicyFlush string = "flush"
constant DefaultFailoverPolicy (line 67) | DefaultFailoverPolicy string = FailoverPolicyResend
FILE: internal/flags/flags.go
type Args (line 15) | type Args struct
type Flags (line 31) | type Flags struct
function buildFlags (line 36) | func buildFlags(args *Args) []cli.Flag {
function NewFlags (line 109) | func NewFlags() *Flags {
FILE: internal/flags/flags_test.go
function TestNewFlags (line 16) | func TestNewFlags(t *testing.T) {
FILE: internal/logging/setup.go
constant DefaultLogDirName (line 22) | DefaultLogDirName = "logs"
constant defaultLogFileName (line 23) | defaultLogFileName = "nydus-snapshotter.log"
type RotateLogArgs (line 26) | type RotateLogArgs struct
function SetUp (line 34) | func SetUp(logLevel string, logToStdout bool, logDir string, logRotateAr...
function WithContext (line 71) | func WithContext() context.Context {
FILE: internal/logging/setup_test.go
constant TestLogDirName (line 22) | TestLogDirName = "test-rotate-logs"
constant TestRootDirName (line 23) | TestRootDirName = "test-root"
function GetRotateLogFileNumbers (line 26) | func GetRotateLogFileNumbers(testLogDir string, suffix string) int {
function TestSetUp (line 40) | func TestSetUp(t *testing.T) {
FILE: pkg/auth/cri.go
constant DefaultImageServiceAddress (line 26) | DefaultImageServiceAddress = "/run/containerd/containerd.sock"
type CRIProvider (line 33) | type CRIProvider struct
method String (line 40) | func (p *CRIProvider) String() string {
method GetCredentials (line 44) | func (p *CRIProvider) GetCredentials(req *AuthRequest) (*PassKeyChain,...
function NewCRIProvider (line 36) | func NewCRIProvider() *CRIProvider {
function newCRIConn (line 82) | func newCRIConn(criAddr string) (*grpc.ClientConn, error) {
function AddImageProxy (line 102) | func AddImageProxy(ctx context.Context, rpc *grpc.Server, imageServiceAd...
FILE: pkg/auth/cri_test.go
type MockImageService (line 22) | type MockImageService struct
method PullImage (line 26) | func (*MockImageService) PullImage(_ context.Context, _ *runtime.PullI...
function TestFromImagePull (line 30) | func TestFromImagePull(t *testing.T) {
FILE: pkg/auth/docker.go
constant dockerHost (line 19) | dockerHost = "https://index.docker.io/v1/"
constant convertedDockerHost (line 20) | convertedDockerHost = "registry-1.docker.io"
type DockerProvider (line 24) | type DockerProvider struct
method CanRenew (line 37) | func (p *DockerProvider) CanRenew() bool { return true }
method String (line 39) | func (p *DockerProvider) String() string {
method GetCredentials (line 45) | func (p *DockerProvider) GetCredentials(req *AuthRequest) (*PassKeyCha...
function NewDockerProvider (line 29) | func NewDockerProvider() *DockerProvider {
FILE: pkg/auth/docker_test.go
constant testConfigFmt (line 20) | testConfigFmt = `
constant dockerUser (line 32) | dockerUser = "dockeruserfoobar"
constant dockerPass (line 33) | dockerPass = "dockerpassfoobar"
constant extraHost (line 34) | extraHost = "reg.docker.alibaba-cloud.com"
constant extraUser (line 35) | extraUser = "extrauserfoobar"
constant extraPass (line 36) | extraPass = "extrapassfoobar"
constant configFile (line 38) | configFile = "config.json"
function setupDockerConfig (line 43) | func setupDockerConfig() (string, error) {
function TestDockerCred (line 62) | func TestDockerCred(t *testing.T) {
FILE: pkg/auth/keychain.go
constant sep (line 22) | sep = ":"
type PassKeyChain (line 30) | type PassKeyChain struct
method ToBase64 (line 50) | func (kc PassKeyChain) ToBase64() string {
method TokenBase (line 59) | func (kc PassKeyChain) TokenBase() bool {
method Resolve (line 153) | func (kc PassKeyChain) Resolve(_ authn.Resource) (authn.Authenticator,...
method toAuthConfig (line 159) | func (kc PassKeyChain) toAuthConfig() authn.AuthConfig {
function FromBase64 (line 35) | func FromBase64(str string) (PassKeyChain, error) {
function GetRegistryKeyChain (line 95) | func GetRegistryKeyChain(ref string, labels map[string]string) *PassKeyC...
function getRegistryKeyChainFromProviders (line 100) | func getRegistryKeyChainFromProviders(ref string, labels map[string]stri...
function fetchFromProviders (line 119) | func fetchFromProviders(req *AuthRequest, providers []AuthProvider) *Pas...
function GetKeyChainByRef (line 147) | func GetKeyChainByRef(ref string, labels map[string]string) (*PassKeyCha...
FILE: pkg/auth/kubelet.go
constant pluginExecTimeout (line 34) | pluginExecTimeout = 1 * time.Minute
constant globalCacheKey (line 37) | globalCacheKey = "<global>"
type KubeletProvider (line 46) | type KubeletProvider struct
method CanRenew (line 189) | func (p *KubeletProvider) CanRenew() bool { return true }
method String (line 191) | func (p *KubeletProvider) String() string {
method GetCredentials (line 200) | func (p *KubeletProvider) GetCredentials(req *AuthRequest) (*PassKeyCh...
method evictExpired (line 309) | func (p *KubeletProvider) evictExpired() {
method getCachedCredential (line 323) | func (p *KubeletProvider) getCachedCredential(image string, validUntil...
method execPlugin (line 421) | func (p *KubeletProvider) execPlugin(ctx context.Context, plugin *kube...
type kubeletCredential (line 54) | type kubeletCredential struct
function InitKubeletProvider (line 61) | func InitKubeletProvider(configPath, binDir string) error {
function NewKubeletProvider (line 80) | func NewKubeletProvider(configPath, binDir string) (*KubeletProvider, er...
function validateCredentialProvider (line 133) | func validateCredentialProvider(p *kubeletconfigv1.CredentialProvider) e...
function bestKeychainMatch (line 346) | func bestKeychainMatch(keychains map[string]*PassKeyChain, image string)...
function computeCacheKey (line 370) | func computeCacheKey(cacheKeyType credentialproviderv1.PluginCacheKeyTyp...
function parseRegistry (line 385) | func parseRegistry(image string) string {
function resolveCacheDuration (line 393) | func resolveCacheDuration(resp *credentialproviderv1.CredentialProviderR...
function isImageAllowed (line 402) | func isImageAllowed(plugin *kubeletconfigv1.CredentialProvider, image st...
function parseSchemelessURL (line 487) | func parseSchemelessURL(schemelessURL string) (*url.URL, error) {
function splitURL (line 499) | func splitURL(url *url.URL) (parts []string, port string) {
function urlsMatchStr (line 510) | func urlsMatchStr(glob string, target string) (bool, error) {
function urlsMatch (line 532) | func urlsMatch(globURL *url.URL, targetURL *url.URL) (bool, error) {
FILE: pkg/auth/kubelet_test.go
constant testUser (line 26) | testUser = "test-user"
constant testPass (line 27) | testPass = "test-pass"
type credentialMap (line 30) | type credentialMap
function setupKubeletProvider (line 34) | func setupKubeletProvider(t *testing.T) (configPath, binDir string) {
function buildAuthSection (line 50) | func buildAuthSection(registries credentialMap) string {
function createMockPlugin (line 70) | func createMockPlugin(t *testing.T, binDir, pluginName string, registrie...
function createMockPluginWithTTL (line 77) | func createMockPluginWithTTL(t *testing.T, binDir, pluginName string, re...
function createMockPluginFull (line 84) | func createMockPluginFull(t *testing.T, binDir, pluginName string, regis...
function createMockCredentialProvider (line 100) | func createMockCredentialProvider(name string, matchImages []string) kub...
function createMockCredentialProviderWithTTL (line 106) | func createMockCredentialProviderWithTTL(name string, matchImages []stri...
function createMockProviderConfig (line 116) | func createMockProviderConfig(t *testing.T, configPath string, providers...
function setupMockProvider (line 135) | func setupMockProvider(t *testing.T, binDir, pluginName, configPath stri...
function TestNewKubeletProvider (line 143) | func TestNewKubeletProvider(t *testing.T) {
function TestValidateCredentialProvider (line 252) | func TestValidateCredentialProvider(t *testing.T) {
function TestKubeletProviderGetCredentials (line 413) | func TestKubeletProviderGetCredentials(t *testing.T) {
function TestInitKubeletProvider (line 631) | func TestInitKubeletProvider(t *testing.T) {
function TestURLsMatch (line 703) | func TestURLsMatch(t *testing.T) {
function TestKubeletProviderEvictExpired (line 798) | func TestKubeletProviderEvictExpired(t *testing.T) {
function TestKubeletProviderValidUntil (line 819) | func TestKubeletProviderValidUntil(t *testing.T) {
function TestKubeletProviderRegistryCache (line 869) | func TestKubeletProviderRegistryCache(t *testing.T) {
function TestKubeletProviderCacheKeyType (line 952) | func TestKubeletProviderCacheKeyType(t *testing.T) {
function TestComputeCacheKey (line 1045) | func TestComputeCacheKey(t *testing.T) {
function TestParseRegistry (line 1088) | func TestParseRegistry(t *testing.T) {
FILE: pkg/auth/kubesecret.go
type KubeSecretProvider (line 29) | type KubeSecretProvider struct
method CanRenew (line 38) | func (p *KubeSecretProvider) CanRenew() bool { return true }
method String (line 40) | func (p *KubeSecretProvider) String() string {
method GetCredentials (line 46) | func (p *KubeSecretProvider) GetCredentials(req *AuthRequest) (*PassKe...
function NewKubeSecretProvider (line 32) | func NewKubeSecretProvider() *KubeSecretProvider {
type KubeSecretListener (line 68) | type KubeSecretListener struct
method addDockerConfig (line 116) | func (kubelistener *KubeSecretListener) addDockerConfig(key string, ob...
method deleteDockerConfig (line 131) | func (kubelistener *KubeSecretListener) deleteDockerConfig(key string) {
method SyncKubeSecrets (line 137) | func (kubelistener *KubeSecretListener) SyncKubeSecrets(ctx context.Co...
method GetCredentialsStore (line 197) | func (kubelistener *KubeSecretListener) GetCredentialsStore(host strin...
function InitKubeSecretListener (line 73) | func InitKubeSecretListener(ctx context.Context, kubeconfigPath string) ...
FILE: pkg/auth/kubesecret_test.go
constant testDockerConfigJSONFmt (line 14) | testDockerConfigJSONFmt = `
constant dockerConfigKey (line 26) | dockerConfigKey = "testKey"
constant registryUser (line 27) | registryUser = "dockeruserfoobar"
constant registryPass (line 28) | registryPass = "dockerpassfoobar"
constant registryEmail (line 29) | registryEmail = "test@alibaba.com"
function TestGetCredentialsStore (line 32) | func TestGetCredentialsStore(t *testing.T) {
FILE: pkg/auth/labels.go
type LabelsProvider (line 15) | type LabelsProvider struct
method String (line 22) | func (p *LabelsProvider) String() string {
method GetCredentials (line 28) | func (p *LabelsProvider) GetCredentials(req *AuthRequest) (*PassKeyCha...
function NewLabelsProvider (line 18) | func NewLabelsProvider() *LabelsProvider {
FILE: pkg/auth/labels_test.go
function TestFromLabels (line 17) | func TestFromLabels(t *testing.T) {
FILE: pkg/auth/provider.go
type AuthRequest (line 18) | type AuthRequest struct
type AuthProvider (line 30) | type AuthProvider interface
type RenewableProvider (line 39) | type RenewableProvider interface
function parseReference (line 46) | func parseReference(ref string) (refSpec reference.Spec, host string, er...
FILE: pkg/auth/renewal.go
function InitCredentialStore (line 24) | func InitCredentialStore(interval time.Duration) {
function GetStoredCredential (line 30) | func GetStoredCredential(ref string) *PassKeyChain {
function RenewCredential (line 40) | func RenewCredential(ref string) *PassKeyChain {
function EvictStaleCredentials (line 60) | func EvictStaleCredentials(liveRefs map[string]struct{}) {
type credentialEntry (line 76) | type credentialEntry struct
type credentialStore (line 86) | type credentialStore struct
method Add (line 100) | func (s *credentialStore) Add(ref string, kc *PassKeyChain) {
method Get (line 114) | func (s *credentialStore) Get(ref string) *PassKeyChain {
method Remove (line 126) | func (s *credentialStore) Remove(ref string) {
method Entries (line 138) | func (s *credentialStore) Entries() []credentialEntry {
function newCredentialStore (line 92) | func newCredentialStore(renewInterval time.Duration) *credentialStore {
FILE: pkg/auth/renewal_test.go
type mockProvider (line 23) | type mockProvider struct
method GetCredentials (line 28) | func (m *mockProvider) GetCredentials(_ *AuthRequest) (*PassKeyChain, ...
method CanRenew (line 32) | func (m *mockProvider) CanRenew() bool { return true }
method String (line 34) | func (m *mockProvider) String() string { return "mockProvider" }
type mockNonRenewableProvider (line 37) | type mockNonRenewableProvider struct
method GetCredentials (line 42) | func (m *mockNonRenewableProvider) GetCredentials(_ *AuthRequest) (*Pa...
method String (line 46) | func (m *mockNonRenewableProvider) String() string { return "mockNonRe...
type trackingProvider (line 49) | type trackingProvider struct
method GetCredentials (line 55) | func (p *trackingProvider) GetCredentials(_ *AuthRequest) (*PassKeyCha...
method CanRenew (line 69) | func (p *trackingProvider) CanRenew() bool { return true }
method String (line 71) | func (p *trackingProvider) String() string { return "trackingProvider" }
function TestRenewableProviderTypeAssertion (line 75) | func TestRenewableProviderTypeAssertion(t *testing.T) {
function TestCredentialStoreGet (line 103) | func TestCredentialStoreGet(t *testing.T) {
function TestCredentialStoreRemove (line 136) | func TestCredentialStoreRemove(t *testing.T) {
function TestCredentialStoreAdd_Upsert (line 166) | func TestCredentialStoreAdd_Upsert(t *testing.T) {
function TestCredentialStoreEntries (line 180) | func TestCredentialStoreEntries(t *testing.T) {
function TestCredentialStoreConcurrency (line 189) | func TestCredentialStoreConcurrency(t *testing.T) {
function TestRenewCredential (line 210) | func TestRenewCredential(t *testing.T) {
function TestEvictStaleCredentials (line 264) | func TestEvictStaleCredentials(t *testing.T) {
function TestEvictStaleCredentials_GracePeriod (line 315) | func TestEvictStaleCredentials_GracePeriod(t *testing.T) {
function TestGetStoredCredential (line 329) | func TestGetStoredCredential(t *testing.T) {
function TestEvictStaleCredentials_NilStore (line 379) | func TestEvictStaleCredentials_NilStore(t *testing.T) {
function TestGetRegistryKeyChainFromProviders (line 390) | func TestGetRegistryKeyChainFromProviders(t *testing.T) {
FILE: pkg/backend/backend.go
constant BackendTypeOSS (line 19) | BackendTypeOSS = "oss"
constant BackendTypeS3 (line 20) | BackendTypeS3 = "s3"
constant BackendTypeLocalFS (line 21) | BackendTypeLocalFS = "localfs"
type Backend (line 31) | type Backend interface
function NewBackend (line 46) | func NewBackend(_type string, config []byte, forcePush bool) (Backend, e...
FILE: pkg/backend/localfs.go
type LocalFSBackend (line 24) | type LocalFSBackend struct
method dstPath (line 46) | func (b *LocalFSBackend) dstPath(blobID string) string {
method Push (line 50) | func (b *LocalFSBackend) Push(ctx context.Context, cs content.Store, d...
method Check (line 82) | func (b *LocalFSBackend) Check(blobDigest digest.Digest) (string, erro...
method Type (line 100) | func (b *LocalFSBackend) Type() string {
function newLocalFSBackend (line 29) | func newLocalFSBackend(rawConfig []byte, forcePush bool) (*LocalFSBacken...
FILE: pkg/backend/oss.go
type OSSBackend (line 25) | type OSSBackend struct
method push (line 99) | func (b *OSSBackend) push(ctx context.Context, cs content.Store, desc ...
method Push (line 159) | func (b *OSSBackend) Push(ctx context.Context, cs content.Store, desc ...
method Check (line 180) | func (b *OSSBackend) Check(blobDigest digest.Digest) (string, error) {
method Type (line 191) | func (b *OSSBackend) Type() string {
function newOSSBackend (line 33) | func newOSSBackend(rawConfig []byte, forcePush bool) (*OSSBackend, error) {
function splitFileByPartSize (line 69) | func splitFileByPartSize(blobSize, chunkSize int64) ([]oss.FileChunk, er...
FILE: pkg/backend/s3.go
type S3Backend (line 30) | type S3Backend struct
method client (line 101) | func (b *S3Backend) client() (*s3.Client, error) {
method existObject (line 119) | func (b *S3Backend) existObject(ctx context.Context, objectKey string)...
method Push (line 138) | func (b *S3Backend) Push(ctx context.Context, cs content.Store, desc o...
method Check (line 175) | func (b *S3Backend) Check(blobDigest digest.Digest) (string, error) {
method Type (line 186) | func (b *S3Backend) Type() string {
type S3Config (line 45) | type S3Config struct
function newS3Backend (line 56) | func newS3Backend(rawConfig []byte, forcePush bool) (*S3Backend, error) {
FILE: pkg/backend/s3_test.go
function Test_newS3Backend (line 16) | func Test_newS3Backend(t *testing.T) {
FILE: pkg/cache/manager.go
constant imageDiskFileSuffix (line 25) | imageDiskFileSuffix = ".image.disk"
constant layerDiskFileSuffix (line 26) | layerDiskFileSuffix = ".layer.disk"
constant chunkMapFileSuffix (line 27) | chunkMapFileSuffix = ".chunk_map"
constant metaFileSuffix (line 28) | metaFileSuffix = ".blob.meta"
constant dataFileSuffix (line 30) | dataFileSuffix = ".blob.data"
type Manager (line 34) | type Manager struct
method CacheDir (line 63) | func (m *Manager) CacheDir() string {
method CacheUsage (line 71) | func (m *Manager) CacheUsage(ctx context.Context, blobID string) (snap...
method RemoveBlobCache (line 100) | func (m *Manager) RemoveBlobCache(blobID string) error {
type Opt (line 40) | type Opt struct
function NewManager (line 47) | func NewManager(opt Opt) (*Manager, error) {
function ExtractBlobIDFromFilename (line 133) | func ExtractBlobIDFromFilename(filename string) string {
FILE: pkg/cache/manager_test.go
function TestExtractBlobIDFromFilename (line 15) | func TestExtractBlobIDFromFilename(t *testing.T) {
FILE: pkg/cgroup/cgroup.go
constant defaultSlice (line 18) | defaultSlice = "system.slice"
type Config (line 25) | type Config struct
type DaemonCgroup (line 29) | type DaemonCgroup interface
function createCgroup (line 36) | func createCgroup(name string, config Config) (DaemonCgroup, error) {
function supported (line 44) | func supported() bool {
function displayMode (line 48) | func displayMode() string {
FILE: pkg/cgroup/manager.go
type Manager (line 13) | type Manager struct
method AddProc (line 44) | func (m *Manager) AddProc(pid int) error {
method Delete (line 49) | func (m *Manager) Delete() error {
type Opt (line 19) | type Opt struct
function NewManager (line 24) | func NewManager(opt Opt) (*Manager, error) {
FILE: pkg/cgroup/v1/v1.go
type Cgroup (line 16) | type Cgroup struct
method Delete (line 67) | func (cg Cgroup) Delete() error {
method AddProc (line 78) | func (cg Cgroup) AddProc(pid int) error {
function generateHierarchy (line 20) | func generateHierarchy() cgroup1.Hierarchy {
function NewCgroup (line 24) | func NewCgroup(slice, name string, memoryLimitInBytes int64) (Cgroup, er...
FILE: pkg/cgroup/v2/v2.go
constant defaultRoot (line 22) | defaultRoot = "/sys/fs/cgroup"
type Cgroup (line 29) | type Cgroup struct
method Delete (line 79) | func (cg Cgroup) Delete() error {
method AddProc (line 85) | func (cg Cgroup) AddProc(pid int) error {
function readSubtreeControllers (line 33) | func readSubtreeControllers(dir string) ([]string, error) {
function NewCgroup (line 41) | func NewCgroup(slice, name string, memoryLimitInBytes int64) (Cgroup, er...
FILE: pkg/converter/constant.go
constant ManifestOSFeatureNydus (line 10) | ManifestOSFeatureNydus = "nydus.remoteimage.v1"
constant ManifestConfigNydus (line 11) | ManifestConfigNydus = "application/vnd.nydus.image.config.v1+json"
constant ManifestArtifactTypeNydus (line 12) | ManifestArtifactTypeNydus = "application/vnd.nydus.image.manifest.v1+json"
constant MediaTypeNydusBlob (line 13) | MediaTypeNydusBlob = "application/vnd.oci.image.layer.nydus.blob.v1"
constant BootstrapFileNameInLayer (line 14) | BootstrapFileNameInLayer = "image/image.boot"
constant ManifestNydusCache (line 16) | ManifestNydusCache = "containerd.io/snapshot/nydus-cache"
constant LayerAnnotationFSVersion (line 18) | LayerAnnotationFSVersion = "containerd.io/snapshot/nydus-fs-ver...
constant LayerAnnotationNydusBlob (line 19) | LayerAnnotationNydusBlob = "containerd.io/snapshot/nydus-blob"
constant LayerAnnotationNydusBlobDigest (line 20) | LayerAnnotationNydusBlobDigest = "containerd.io/snapshot/nydus-blob-d...
constant LayerAnnotationNydusBlobSize (line 21) | LayerAnnotationNydusBlobSize = "containerd.io/snapshot/nydus-blob-s...
constant LayerAnnotationNydusBootstrap (line 22) | LayerAnnotationNydusBootstrap = "containerd.io/snapshot/nydus-bootst...
constant LayerAnnotationNydusSourceChainID (line 23) | LayerAnnotationNydusSourceChainID = "containerd.io/snapshot/nydus-source...
constant LayerAnnotationNydusEncryptedBlob (line 24) | LayerAnnotationNydusEncryptedBlob = "containerd.io/snapshot/nydus-encryp...
constant LayerAnnotationNydusSourceDigest (line 25) | LayerAnnotationNydusSourceDigest = "containerd.io/snapshot/nydus-source...
constant LayerAnnotationNydusTargetDigest (line 26) | LayerAnnotationNydusTargetDigest = "containerd.io/snapshot/nydus-target...
constant LayerAnnotationNydusReferenceBlobIDs (line 28) | LayerAnnotationNydusReferenceBlobIDs = "containerd.io/snapshot/nydus-ref...
constant LayerAnnotationUncompressed (line 30) | LayerAnnotationUncompressed = "containerd.io/uncompressed"
FILE: pkg/converter/convert_unix.go
constant EntryBlob (line 46) | EntryBlob = "image.blob"
constant EntryBootstrap (line 47) | EntryBootstrap = "image.boot"
constant EntryBlobMeta (line 48) | EntryBlobMeta = "blob.meta"
constant EntryBlobMetaHeader (line 49) | EntryBlobMetaHeader = "blob.meta.header"
constant EntryTOC (line 50) | EntryTOC = "rafs.blob.toc"
constant envNydusBuilder (line 52) | envNydusBuilder = "NYDUS_BUILDER"
constant envNydusWorkDir (line 53) | envNydusWorkDir = "NYDUS_WORKDIR"
constant configGCLabelKey (line 55) | configGCLabelKey = "containerd.io/gc.ref.content.config"
function getBuilder (line 64) | func getBuilder(specifiedPath string) string {
function ensureWorkDir (line 77) | func ensureWorkDir(specifiedBasePath string) (string, error) {
function unpackOciTar (line 102) | func unpackOciTar(ctx context.Context, dst string, reader io.Reader) err...
function unpackNydusBlob (line 132) | func unpackNydusBlob(bootDst, blobDst string, ra content.ReaderAt, unpac...
function seekFileByTarHeader (line 163) | func seekFileByTarHeader(ra content.ReaderAt, targetName string, maxSize...
function seekFileByTOC (line 221) | func seekFileByTOC(ra content.ReaderAt, targetName string, handle func(i...
function UnpackEntry (line 287) | func UnpackEntry(ra content.ReaderAt, targetName string, target io.Write...
function seekFile (line 300) | func seekFile(ra content.ReaderAt, targetName string, handle func(io.Rea...
function Pack (line 326) | func Pack(ctx context.Context, dest io.Writer, opt PackOption) (io.Write...
function packFromDirectory (line 365) | func packFromDirectory(ctx context.Context, dest io.Writer, opt PackOpti...
function packFromTar (line 444) | func packFromTar(ctx context.Context, dest io.Writer, opt PackOption) (i...
function calcBlobTOCDigest (line 542) | func calcBlobTOCDigest(ra content.ReaderAt) (*digest.Digest, error) {
function Merge (line 561) | func Merge(ctx context.Context, layers []Layer, dest io.Writer, opt Merg...
function Unpack (line 774) | func Unpack(ctx context.Context, ra content.ReaderAt, dest io.Writer, op...
function IsNydusBlobAndExists (line 842) | func IsNydusBlobAndExists(ctx context.Context, cs content.Store, desc oc...
function IsNydusBlob (line 852) | func IsNydusBlob(desc ocispec.Descriptor) bool {
function IsNydusBootstrap (line 862) | func IsNydusBootstrap(desc ocispec.Descriptor) bool {
function isNydusImage (line 873) | func isNydusImage(manifest *ocispec.Manifest) bool {
function makeBlobDesc (line 885) | func makeBlobDesc(ctx context.Context, cs content.Store, opt PackOption,...
function LayerConvertFunc (line 927) | func LayerConvertFunc(opt PackOption) converter.ConvertFunc {
function ConvertHookFunc (line 1038) | func ConvertHookFunc(opt MergeOption) converter.ConvertHookFunc {
function convertIndex (line 1056) | func convertIndex(ctx context.Context, cs content.Store, newDesc *ocispe...
function convertManifest (line 1074) | func convertManifest(ctx context.Context, cs content.Store, oldDesc ocis...
function mergeManifestBlobDigests (line 1187) | func mergeManifestBlobDigests(nydusBlobDigests, originalBlobDigests []di...
function MergeLayers (line 1203) | func MergeLayers(ctx context.Context, cs content.Store, descs []ocispec....
FILE: pkg/converter/convert_windows.go
function Pack (line 22) | func Pack(ctx context.Context, dest io.Writer, opt PackOption) (io.Write...
function Merge (line 26) | func Merge(ctx context.Context, layers []Layer, dest io.Writer, opt Merg...
function Unpack (line 30) | func Unpack(ctx context.Context, ra content.ReaderAt, dest io.Writer, op...
function IsNydusBlobAndExists (line 34) | func IsNydusBlobAndExists(ctx context.Context, cs content.Store, desc oc...
function IsNydusBlob (line 38) | func IsNydusBlob(desc ocispec.Descriptor) bool {
function IsNydusBootstrap (line 42) | func IsNydusBootstrap(desc ocispec.Descriptor) bool {
function LayerConvertFunc (line 46) | func LayerConvertFunc(opt PackOption) converter.ConvertFunc {
function ConvertHookFunc (line 50) | func ConvertHookFunc(opt MergeOption) converter.ConvertHookFunc {
function MergeLayers (line 54) | func MergeLayers(ctx context.Context, cs content.Store, descs []ocispec....
FILE: pkg/converter/cs_proxy_unix.go
type contentStoreProxy (line 28) | type contentStoreProxy struct
method close (line 62) | func (p *contentStoreProxy) close() error {
function setupContentStoreProxy (line 33) | func setupContentStoreProxy(workDir string, ra content.ReaderAt) (*conte...
function parseRangeHeader (line 70) | func parseRangeHeader(rangeStr string, totalLen int64) (start, wantedLen...
function contentProxyHandler (line 95) | func contentProxyHandler(ra content.ReaderAt) http.Handler {
FILE: pkg/converter/merge_unix_test.go
function d (line 20) | func d(c byte) digest.Digest {
function repeat (line 24) | func repeat(c byte, n int) []byte {
function TestMergeManifestBlobDigests (line 34) | func TestMergeManifestBlobDigests(t *testing.T) {
FILE: pkg/converter/reconvert_unix.go
function DefaultIndexConvertFunc (line 38) | func DefaultIndexConvertFunc(layerConvertFunc converter.ConvertFunc, doc...
function collectNydusBlobDigests (line 62) | func collectNydusBlobDigests(ctx context.Context, cs content.Store, desc...
function collectFromManifest (line 84) | func collectFromManifest(ctx context.Context, cs content.Store, desc oci...
type wrappedStore (line 102) | type wrappedStore struct
method Info (line 107) | func (s *wrappedStore) Info(ctx context.Context, dgst digest.Digest) (...
function ReconvertHookFunc (line 127) | func ReconvertHookFunc() converter.ConvertHookFunc {
function LayerReconvertFunc (line 196) | func LayerReconvertFunc(opt UnpackOption) converter.ConvertFunc {
function makeOCIBlobDesc (line 298) | func makeOCIBlobDesc(ctx context.Context, cs content.Store, uncompressed...
FILE: pkg/converter/reconvert_unix_test.go
type mockContentStore (line 25) | type mockContentStore struct
method Info (line 38) | func (m *mockContentStore) Info(_ context.Context, dgst digest.Digest)...
method addBlob (line 45) | func (m *mockContentStore) addBlob(dgst digest.Digest, data []byte, la...
method ReaderAt (line 54) | func (m *mockContentStore) ReaderAt(_ context.Context, desc ocispec.De...
function newMockContentStore (line 31) | func newMockContentStore() *mockContentStore {
type mockReaderAt (line 61) | type mockReaderAt struct
method ReadAt (line 65) | func (r *mockReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
method Size (line 73) | func (r *mockReaderAt) Size() int64 {
method Close (line 77) | func (r *mockReaderAt) Close() error {
function TestCollectNydusBlobDigests (line 81) | func TestCollectNydusBlobDigests(t *testing.T) {
function TestCollectFromManifest (line 226) | func TestCollectFromManifest(t *testing.T) {
function TestWrappedStore_Info (line 320) | func TestWrappedStore_Info(t *testing.T) {
function TestWrappedStore_Info_Error (line 393) | func TestWrappedStore_Info_Error(t *testing.T) {
function TestMakeOCIBlobDesc (line 407) | func TestMakeOCIBlobDesc(t *testing.T) {
function TestReconvertHookFunc_NilDescriptor (line 484) | func TestReconvertHookFunc_NilDescriptor(t *testing.T) {
function TestReconvertHookFunc_NonManifestType (line 495) | func TestReconvertHookFunc_NonManifestType(t *testing.T) {
FILE: pkg/converter/tool/builder.go
function isSignalKilled (line 25) | func isSignalKilled(err error) bool {
type PackOption (line 29) | type PackOption struct
type MergeOption (line 49) | type MergeOption struct
type UnpackOption (line 65) | type UnpackOption struct
type outputJSON (line 74) | type outputJSON struct
function buildPackArgs (line 78) | func buildPackArgs(option PackOption) []string {
function Pack (line 148) | func Pack(option PackOption) error {
function packRef (line 180) | func packRef(option PackOption) error {
function Merge (line 220) | func Merge(option MergeOption) ([]digest.Digest, error) {
function Unpack (line 296) | func Unpack(option UnpackOption) error {
FILE: pkg/converter/tool/feature.go
type Feature (line 20) | type Feature
type Features (line 21) | type Features
method Add (line 51) | func (features *Features) Add(items ...Feature) {
method Remove (line 57) | func (features *Features) Remove(items ...Feature) {
method Contains (line 63) | func (features *Features) Contains(feature Feature) bool {
method Equals (line 68) | func (features *Features) Equals(other Features) bool {
constant envNydusDisableTar2Rafs (line 23) | envNydusDisableTar2Rafs string = "NYDUS_DISABLE_TAR2RAFS"
constant FeatureTar2Rafs (line 30) | FeatureTar2Rafs Feature = "--type tar-rafs"
constant FeatureBatchSize (line 34) | FeatureBatchSize Feature = "--batch-size"
constant FeatureEncrypt (line 37) | FeatureEncrypt Feature = "--encrypt"
function NewFeatures (line 45) | func NewFeatures(items ...Feature) Features {
function GetHelp (line 83) | func GetHelp(builder string) []byte {
function detectFeature (line 94) | func detectFeature(msg []byte, feature Feature) bool {
function DetectFeatures (line 116) | func DetectFeatures(builder string, required Features, getHelp func(stri...
FILE: pkg/converter/tool/feature_test.go
function TestFeature (line 16) | func TestFeature(t *testing.T) {
function TestDetectFeature (line 184) | func TestDetectFeature(t *testing.T) {
function TestDetectFeatures (line 702) | func TestDetectFeatures(t *testing.T) {
FILE: pkg/converter/types.go
constant CompressorNone (line 27) | CompressorNone Compressor = 0x0000_0001
constant CompressorZstd (line 28) | CompressorZstd Compressor = 0x0000_0002
constant CompressorLz4Block (line 29) | CompressorLz4Block Compressor = 0x0000_0004
constant CompressorMask (line 30) | CompressorMask Compressor = 0x0000_000f
type Layer (line 37) | type Layer struct
type Backend (line 47) | type Backend interface
type PackOption (line 58) | type PackOption struct
type MergeOption (line 92) | type MergeOption struct
type UnpackOption (line 135) | type UnpackOption struct
type TOCEntry (line 153) | type TOCEntry struct
method GetCompressor (line 170) | func (entry *TOCEntry) GetCompressor() (Compressor, error) {
method GetName (line 182) | func (entry *TOCEntry) GetName() string {
method GetUncompressedDigest (line 194) | func (entry *TOCEntry) GetUncompressedDigest() string {
method GetCompressedOffset (line 198) | func (entry *TOCEntry) GetCompressedOffset() uint64 {
method GetCompressedSize (line 202) | func (entry *TOCEntry) GetCompressedSize() uint64 {
method GetUncompressedSize (line 206) | func (entry *TOCEntry) GetUncompressedSize() uint64 {
FILE: pkg/converter/utils.go
type File (line 24) | type File struct
type writeCloser (line 30) | type writeCloser struct
method Close (line 36) | func (c *writeCloser) Close() error {
function newWriteCloser (line 53) | func newWriteCloser(wc io.WriteCloser, action func() error) *writeCloser {
type seekReader (line 60) | type seekReader struct
method Read (line 65) | func (ra *seekReader) Read(p []byte) (int, error) {
method Seek (line 71) | func (ra *seekReader) Seek(offset int64, whence int) (int64, error) {
function newSeekReader (line 84) | func newSeekReader(ra io.ReaderAt) *seekReader {
function packToTar (line 92) | func packToTar(files []File, compress bool) io.ReadCloser {
function readJSON (line 161) | func readJSON(ctx context.Context, cs content.Store, x interface{}, desc...
function writeJSON (line 182) | func writeJSON(ctx context.Context, cs content.Store, x interface{}, old...
FILE: pkg/daemon/client.go
constant endpointDaemonInfo (line 33) | endpointDaemonInfo = "/api/v1/daemon"
constant endpointMount (line 35) | endpointMount = "/api/v1/mount"
constant endpointMetrics (line 37) | endpointMetrics = "/api/v1/metrics"
constant endpointCacheMetrics (line 39) | endpointCacheMetrics = "/api/v1/metrics/blobcache"
constant endpointInflightMetrics (line 41) | endpointInflightMetrics = "/api/v1/metrics/inflight"
constant endpointTakeOver (line 43) | endpointTakeOver = "/api/v1/daemon/fuse/takeover"
constant endpointSendFd (line 45) | endpointSendFd = "/api/v1/daemon/fuse/sendfd"
constant endpointStart (line 47) | endpointStart = "/api/v1/daemon/start"
constant endpointExit (line 49) | endpointExit = "/api/v1/daemon/exit"
constant endpointConfig (line 51) | endpointConfig = "/api/v1/config"
constant endpointBlobs (line 55) | endpointBlobs = "/api/v2/blobs"
constant defaultHTTPClientTimeout (line 57) | defaultHTTPClientTimeout = 30 * time.Second
constant jsonContentType (line 59) | jsonContentType = "application/json"
type NydusdClient (line 64) | type NydusdClient interface
type nydusdClient (line 87) | type nydusdClient struct
method url (line 93) | func (c *nydusdClient) url(path string, query query) (url string) {
method request (line 105) | func (c *nydusdClient) request(method string, url string,
method GetDaemonInfo (line 216) | func (c *nydusdClient) GetDaemonInfo() (*types.DaemonInfo, error) {
method Mount (line 234) | func (c *nydusdClient) Mount(mp, bootstrap, mountConfig string) error {
method Umount (line 247) | func (c *nydusdClient) Umount(mp string) error {
method BindBlob (line 254) | func (c *nydusdClient) BindBlob(daemonConfig string) error {
method UnbindBlob (line 264) | func (c *nydusdClient) UnbindBlob(domainID, blobID string) error {
method GetFsMetrics (line 280) | func (c *nydusdClient) GetFsMetrics(sid string) (*types.FsMetrics, err...
method GetInflightMetrics (line 297) | func (c *nydusdClient) GetInflightMetrics() (*types.InflightMetrics, e...
method GetCacheMetrics (line 312) | func (c *nydusdClient) GetCacheMetrics(sid string) (*types.CacheMetric...
method UpdateConfig (line 329) | func (c *nydusdClient) UpdateConfig(id string, params map[string]strin...
method TakeOver (line 342) | func (c *nydusdClient) TakeOver() error {
method SendFd (line 347) | func (c *nydusdClient) SendFd() error {
method Start (line 352) | func (c *nydusdClient) Start() error {
method Exit (line 357) | func (c *nydusdClient) Exit() error {
function succeeded (line 135) | func succeeded(resp *http.Response) bool {
function decode (line 139) | func decode(resp *http.Response, v any) error {
function parseErrorMessage (line 149) | func parseErrorMessage(resp *http.Response) error {
function buildTransport (line 160) | func buildTransport(sock string) http.RoundTripper {
function WaitUntilSocketExisted (line 175) | func WaitUntilSocketExisted(sock string, pid int) error {
function NewNydusClient (line 206) | func NewNydusClient(sock string) (NydusdClient, error) {
FILE: pkg/daemon/client_test.go
function prepareNydusServer (line 32) | func prepareNydusServer(t *testing.T) (string, func()) {
function TestNydusClient_CheckStatus (line 61) | func TestNydusClient_CheckStatus(t *testing.T) {
function TestUpdateConfig (line 73) | func TestUpdateConfig(t *testing.T) {
FILE: pkg/daemon/command/command.go
type DaemonCommand (line 20) | type DaemonCommand struct
function BuildCommand (line 44) | func BuildCommand(opts []Opt) ([]string, error) {
function WithMode (line 105) | func WithMode(m string) Opt {
function WithPrefetchFiles (line 111) | func WithPrefetchFiles(p string) Opt {
function WithFscacheDriver (line 117) | func WithFscacheDriver(w string) Opt {
function WithFscacheThreads (line 123) | func WithFscacheThreads(num int) Opt {
function WithThreadNum (line 129) | func WithThreadNum(num int) Opt {
function WithConfig (line 135) | func WithConfig(config string) Opt {
function WithBootstrap (line 141) | func WithBootstrap(b string) Opt {
function WithMountpoint (line 147) | func WithMountpoint(m string) Opt {
function WithAPISock (line 153) | func WithAPISock(api string) Opt {
function WithLogFile (line 159) | func WithLogFile(l string) Opt {
function WithLogLevel (line 165) | func WithLogLevel(l string) Opt {
function WithLogRotationSize (line 171) | func WithLogRotationSize(l int) Opt {
function WithSupervisor (line 177) | func WithSupervisor(s string) Opt {
function WithID (line 183) | func WithID(id string) Opt {
function WithUpgrade (line 189) | func WithUpgrade() Opt {
function WithBackendSource (line 195) | func WithBackendSource(source string) Opt {
function WithFailoverPolicy (line 201) | func WithFailoverPolicy(policy string) Opt {
FILE: pkg/daemon/command/command_builder_test.go
function TestBuildCommand (line 16) | func TestBuildCommand(t *testing.T) {
function BenchmarkBuildCommand (line 44) | func BenchmarkBuildCommand(b *testing.B) {
FILE: pkg/daemon/config.go
function WithSocketDir (line 22) | func WithSocketDir(dir string) NewDaemonOpt {
function WithRef (line 34) | func WithRef(ref int32) NewDaemonOpt {
function WithLogDir (line 41) | func WithLogDir(dir string) NewDaemonOpt {
function WithLogToStdout (line 51) | func WithLogToStdout(logToStdout bool) NewDaemonOpt {
function WithLogLevel (line 58) | func WithLogLevel(logLevel string) NewDaemonOpt {
function WithLogRotationSize (line 69) | func WithLogRotationSize(logRotationSize int) NewDaemonOpt {
function WithConfigDir (line 76) | func WithConfigDir(dir string) NewDaemonOpt {
function WithMountpoint (line 88) | func WithMountpoint(mountpoint string) NewDaemonOpt {
function WithNydusdThreadNum (line 95) | func WithNydusdThreadNum(nydusdThreadNum int) NewDaemonOpt {
function WithFsDriver (line 102) | func WithFsDriver(fsDriver string) NewDaemonOpt {
function WithFailoverPolicy (line 109) | func WithFailoverPolicy(failoverPolicy string) NewDaemonOpt {
function WithDaemonMode (line 116) | func WithDaemonMode(daemonMode config.DaemonMode) NewDaemonOpt {
FILE: pkg/daemon/daemon.go
constant APISocketFileName (line 40) | APISocketFileName = "api.sock"
constant SharedNydusDaemonID (line 41) | SharedNydusDaemonID = "shared_daemon"
type NewDaemonOpt (line 44) | type NewDaemonOpt
type ConfigState (line 47) | type ConfigState struct
type Daemon (line 67) | type Daemon struct
method Lock (line 96) | func (d *Daemon) Lock() {
method Unlock (line 100) | func (d *Daemon) Unlock() {
method ID (line 104) | func (d *Daemon) ID() string {
method Pid (line 108) | func (d *Daemon) Pid() int {
method IncRef (line 112) | func (d *Daemon) IncRef() {
method DecRef (line 116) | func (d *Daemon) DecRef() int32 {
method GetRef (line 120) | func (d *Daemon) GetRef() int32 {
method HostMountpoint (line 124) | func (d *Daemon) HostMountpoint() (mnt string) {
method ConfigFile (line 130) | func (d *Daemon) ConfigFile(instanceID string) string {
method NydusdThreadNum (line 138) | func (d *Daemon) NydusdThreadNum() int {
method GetAPISock (line 142) | func (d *Daemon) GetAPISock() string {
method LogFile (line 146) | func (d *Daemon) LogFile() string {
method AddRafsInstance (line 150) | func (d *Daemon) AddRafsInstance(r *rafs.Rafs) {
method UpdateRafsInstance (line 157) | func (d *Daemon) UpdateRafsInstance(r *rafs.Rafs) {
method RemoveRafsInstance (line 161) | func (d *Daemon) RemoveRafsInstance(snapshotID string) {
method GetState (line 173) | func (d *Daemon) GetState() (types.DaemonState, error) {
method State (line 194) | func (d *Daemon) State() types.DaemonState {
method ResetState (line 201) | func (d *Daemon) ResetState() {
method WaitUntilState (line 208) | func (d *Daemon) WaitUntilState(expected types.DaemonState) error {
method IsSharedDaemon (line 232) | func (d *Daemon) IsSharedDaemon() bool {
method SharedMount (line 240) | func (d *Daemon) SharedMount(rafs *rafs.Rafs) error {
method sharedFusedevMount (line 256) | func (d *Daemon) sharedFusedevMount(rafs *rafs.Rafs) error {
method sharedErofsMount (line 286) | func (d *Daemon) sharedErofsMount(ra *rafs.Rafs) error {
method SharedUmount (line 337) | func (d *Daemon) SharedUmount(rafs *rafs.Rafs) error {
method sharedErofsUmount (line 357) | func (d *Daemon) sharedErofsUmount(ra *rafs.Rafs) error {
method UmountRafsInstance (line 383) | func (d *Daemon) UmountRafsInstance(r *rafs.Rafs) error {
method UmountRafsInstances (line 393) | func (d *Daemon) UmountRafsInstances() error {
method SendStates (line 410) | func (d *Daemon) SendStates() {
method doSendStates (line 428) | func (d *Daemon) doSendStates() error {
method TakeOver (line 441) | func (d *Daemon) TakeOver() error {
method Start (line 454) | func (d *Daemon) Start() error {
method Exit (line 467) | func (d *Daemon) Exit() error {
method GetDaemonInfo (line 480) | func (d *Daemon) GetDaemonInfo() (*types.DaemonInfo, error) {
method GetFsMetrics (line 489) | func (d *Daemon) GetFsMetrics(sid string) (*types.FsMetrics, error) {
method GetInflightMetrics (line 498) | func (d *Daemon) GetInflightMetrics() (*types.InflightMetrics, error) {
method UpdateAuthConfig (line 512) | func (d *Daemon) UpdateAuthConfig(snapshotID string, kc *auth.PassKeyC...
method GetCacheMetrics (line 543) | func (d *Daemon) GetCacheMetrics(sid string) (*types.CacheMetrics, err...
method GetClient (line 551) | func (d *Daemon) GetClient() (NydusdClient, error) {
method ResetClient (line 572) | func (d *Daemon) ResetClient() {
method Terminate (line 578) | func (d *Daemon) Terminate() error {
method Wait (line 597) | func (d *Daemon) Wait() error {
method ClearVestige (line 626) | func (d *Daemon) ClearVestige() {
method CloneRafsInstances (line 654) | func (d *Daemon) CloneRafsInstances(src *Daemon) {
method RecoverRafsInstances (line 665) | func (d *Daemon) RecoverRafsInstances() error {
function NewDaemon (line 693) | func NewDaemon(opt ...NewDaemonOpt) (*Daemon, error) {
function GetDaemonGitCommit (line 709) | func GetDaemonGitCommit(nydusdPath string) (string, error) {
FILE: pkg/daemon/daemon_test.go
function TestMain (line 26) | func TestMain(m *testing.M) {
function minimalFuseConfig (line 35) | func minimalFuseConfig() []byte {
function TestUpdateAuthConfig (line 45) | func TestUpdateAuthConfig(t *testing.T) {
FILE: pkg/daemon/idgen.go
function newID (line 13) | func newID() string {
FILE: pkg/daemon/types/types.go
type BuildTimeInfo (line 10) | type BuildTimeInfo struct
type DaemonState (line 18) | type DaemonState
constant DaemonStateUnknown (line 21) | DaemonStateUnknown DaemonState = "UNKNOWN"
constant DaemonStateInit (line 22) | DaemonStateInit DaemonState = "INIT"
constant DaemonStateReady (line 23) | DaemonStateReady DaemonState = "READY"
constant DaemonStateRunning (line 24) | DaemonStateRunning DaemonState = "RUNNING"
constant DaemonStateDied (line 25) | DaemonStateDied DaemonState = "DIED"
constant DaemonStateDestroyed (line 26) | DaemonStateDestroyed DaemonState = "DESTROYED"
type DaemonInfo (line 29) | type DaemonInfo struct
method DaemonState (line 35) | func (info *DaemonInfo) DaemonState() DaemonState {
method DaemonVersion (line 39) | func (info *DaemonInfo) DaemonVersion() BuildTimeInfo {
type ErrorMessage (line 43) | type ErrorMessage struct
type MountRequest (line 48) | type MountRequest struct
function NewMountRequest (line 54) | func NewMountRequest(source, config string) MountRequest {
type FsMetrics (line 62) | type FsMetrics struct
type InflightMetrics (line 76) | type InflightMetrics struct
type CacheMetrics (line 85) | type CacheMetrics struct
FILE: pkg/encryption/encryption.go
function encryptLayer (line 32) | func encryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderA...
function decryptLayer (line 90) | func decryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderA...
function ingestReader (line 117) | func ingestReader(ctx context.Context, cs content.Ingester, ref string, ...
function EncryptNydusBootstrap (line 143) | func EncryptNydusBootstrap(ctx context.Context, cs content.Store, desc o...
function DeryptNydusBootstrap (line 206) | func DeryptNydusBootstrap(ctx context.Context, cs content.Store, desc oc...
FILE: pkg/errdefs/errors.go
function IsAlreadyExists (line 28) | func IsAlreadyExists(err error) bool {
function IsNotFound (line 33) | func IsNotFound(err error) bool {
function IsConnectionClosed (line 39) | func IsConnectionClosed(err error) bool {
function IsErofsMounted (line 48) | func IsErofsMounted(err error) bool {
FILE: pkg/fanotify/conn/conn.go
type Client (line 14) | type Client struct
method GetEventInfo (line 24) | func (c *Client) GetEventInfo() (*EventInfo, error) {
type EventInfo (line 18) | type EventInfo struct
FILE: pkg/fanotify/fanotify.go
type Server (line 26) | type Server struct
method RunServer (line 52) | func (fserver *Server) RunServer() error {
method RunReceiver (line 103) | func (fserver *Server) RunReceiver() error {
method StopServer (line 152) | func (fserver *Server) StopServer() {
function NewServer (line 39) | func NewServer(binaryPath string, containerPid uint32, imageName string,...
FILE: pkg/filesystem/config.go
type NewFSOpt (line 21) | type NewFSOpt
function WithNydusdBinaryPath (line 23) | func WithNydusdBinaryPath(p string) NewFSOpt {
function WithManagers (line 30) | func WithManagers(managers []*manager.Manager) NewFSOpt {
function WithCacheManager (line 42) | func WithCacheManager(cm *cache.Manager) NewFSOpt {
function WithReferrerManager (line 53) | func WithReferrerManager(rm *referrer.Manager) NewFSOpt {
function WithIndexManager (line 64) | func WithIndexManager(im *index.Manager) NewFSOpt {
function WithTarfsManager (line 75) | func WithTarfsManager(tm *tarfs.Manager) NewFSOpt {
function WithVerifier (line 85) | func WithVerifier(verifier *signature.Verifier) NewFSOpt {
function WithRootMountpoint (line 92) | func WithRootMountpoint(mountpoint string) NewFSOpt {
function WithEnableStargz (line 99) | func WithEnableStargz(enable bool) NewFSOpt {
FILE: pkg/filesystem/fs.go
type Filesystem (line 47) | type Filesystem struct
method TryRetainSharedDaemon (line 207) | func (fs *Filesystem) TryRetainSharedDaemon(d *daemon.Daemon) {
method TryStopSharedDaemon (line 224) | func (fs *Filesystem) TryStopSharedDaemon() {
method WaitUntilReady (line 251) | func (fs *Filesystem) WaitUntilReady(snapshotID string) error {
method Mount (line 319) | func (fs *Filesystem) Mount(ctx context.Context, snapshotID string, la...
method getSnapshotMutex (line 491) | func (fs *Filesystem) getSnapshotMutex(snapshotID string) *sync.Mutex {
method copyBlobMetaFiles (line 496) | func (fs *Filesystem) copyBlobMetaFiles(bootstrap, cacheDir string) er...
method copyFile (line 522) | func (fs *Filesystem) copyFile(src, dst string) error {
method Umount (line 539) | func (fs *Filesystem) Umount(_ context.Context, snapshotID string) err...
method CacheUsage (line 599) | func (fs *Filesystem) CacheUsage(ctx context.Context, blobDigest strin...
method RemoveCache (line 610) | func (fs *Filesystem) RemoveCache(blobDigest string) error {
method WalkManagers (line 638) | func (fs *Filesystem) WalkManagers(fn func(*manager.Manager) error) er...
method GetCacheDir (line 648) | func (fs *Filesystem) GetCacheDir() (string, error) {
method Teardown (line 657) | func (fs *Filesystem) Teardown(ctx context.Context) error {
method MountPoint (line 676) | func (fs *Filesystem) MountPoint(snapshotID string) (string, error) {
method BootstrapFile (line 685) | func (fs *Filesystem) BootstrapFile(id string) (string, error) {
method mountRemote (line 695) | func (fs *Filesystem) mountRemote(fsManager *manager.Manager, useShare...
method decideDaemonMountpoint (line 718) | func (fs *Filesystem) decideDaemonMountpoint(fsDriver string, isShared...
method initSharedDaemon (line 738) | func (fs *Filesystem) initSharedDaemon(fsManager *manager.Manager) (er...
method createDaemon (line 789) | func (fs *Filesystem) createDaemon(fsManager *manager.Manager, daemonM...
method getManager (line 835) | func (fs *Filesystem) getManager(fsDriver string) (*manager.Manager, e...
method getSharedDaemon (line 843) | func (fs *Filesystem) getSharedDaemon(fsDriver string) (*daemon.Daemon...
method getDaemonByRafs (line 858) | func (fs *Filesystem) getDaemonByRafs(rafs *racache.Rafs) (*daemon.Dae...
method GetDaemonByID (line 871) | func (fs *Filesystem) GetDaemonByID(id string) (*daemon.Daemon, error) {
function NewFileSystem (line 64) | func NewFileSystem(ctx context.Context, opt ...NewFSOpt) (*Filesystem, e...
FILE: pkg/filesystem/index_adaptor.go
method IndexDetectEnabled (line 21) | func (fs *Filesystem) IndexDetectEnabled() bool {
method CheckIndexAlternative (line 26) | func (fs *Filesystem) CheckIndexAlternative(ctx context.Context, labels ...
method TryFetchMetadataFromIndex (line 60) | func (fs *Filesystem) TryFetchMetadataFromIndex(ctx context.Context, lab...
FILE: pkg/filesystem/referer_adaptor.go
method ReferrerDetectEnabled (line 18) | func (fs *Filesystem) ReferrerDetectEnabled() bool {
method CheckReferrer (line 22) | func (fs *Filesystem) CheckReferrer(ctx context.Context, labels map[stri...
method TryFetchMetadata (line 44) | func (fs *Filesystem) TryFetchMetadata(ctx context.Context, labels map[s...
FILE: pkg/filesystem/stargz_adaptor.go
method UpperPath (line 31) | func (fs *Filesystem) UpperPath(id string) string {
method StargzEnabled (line 35) | func (fs *Filesystem) StargzEnabled() bool {
method IsStargzDataLayer (line 41) | func (fs *Filesystem) IsStargzDataLayer(labels map[string]string) (bool,...
method MergeStargzMetaLayer (line 73) | func (fs *Filesystem) MergeStargzMetaLayer(ctx context.Context, s storag...
method PrepareStargzMetaLayer (line 165) | func (fs *Filesystem) PrepareStargzMetaLayer(blob *stargz.Blob, storageP...
method StargzLayer (line 262) | func (fs *Filesystem) StargzLayer(labels map[string]string) bool {
FILE: pkg/filesystem/tarfs_adaptor.go
method TarfsEnabled (line 20) | func (fs *Filesystem) TarfsEnabled() bool {
method PrepareTarfsLayer (line 24) | func (fs *Filesystem) PrepareTarfsLayer(ctx context.Context, labels map[...
method MergeTarfsLayers (line 66) | func (fs *Filesystem) MergeTarfsLayers(s storage.Snapshot, storageLocate...
method DetachTarfsLayer (line 70) | func (fs *Filesystem) DetachTarfsLayer(snapshotID string) error {
method ExportBlockData (line 74) | func (fs *Filesystem) ExportBlockData(s storage.Snapshot, perLayer bool,...
method GetTarfsImageDiskFilePath (line 79) | func (fs *Filesystem) GetTarfsImageDiskFilePath(id string) (string, erro...
method GetTarfsLayerDiskFilePath (line 86) | func (fs *Filesystem) GetTarfsLayerDiskFilePath(id string) (string, erro...
FILE: pkg/index/detector.go
constant maxManifestIndexSize (line 29) | maxManifestIndexSize = 0x800000
type detector (line 31) | type detector struct
method checkIndexAlternative (line 43) | func (d *detector) checkIndexAlternative(ctx context.Context, ref stri...
method findNydusManifestInIndex (line 113) | func (d *detector) findNydusManifestInIndex(index ocispec.Index, origi...
method hasNydusFeatures (line 137) | func (d *detector) hasNydusFeatures(platform *ocispec.Platform) bool {
method hasNydusArtifactType (line 146) | func (d *detector) hasNydusArtifactType(desc *ocispec.Descriptor) bool {
method fetchMetadata (line 154) | func (d *detector) fetchMetadata(ctx context.Context, ref string, desc...
function newDetector (line 35) | func newDetector(keyChain *auth.PassKeyChain, insecure bool) *detector {
FILE: pkg/index/detector_test.go
function TestHasNydusFeatures (line 17) | func TestHasNydusFeatures(t *testing.T) {
function TestFindNydusManifestInIndex (line 75) | func TestFindNydusManifestInIndex(t *testing.T) {
FILE: pkg/index/manager.go
type Manager (line 24) | type Manager struct
method CheckIndexAlternative (line 42) | func (manager *Manager) CheckIndexAlternative(ctx context.Context, ref...
method TryFetchMetadata (line 87) | func (manager *Manager) TryFetchMetadata(ctx context.Context, ref stri...
function NewManager (line 30) | func NewManager(insecure bool) *Manager {
FILE: pkg/index/manager_test.go
function TestCheckIndexAlternative (line 18) | func TestCheckIndexAlternative(t *testing.T) {
FILE: pkg/label/label.go
constant CRIImageRef (line 18) | CRIImageRef = snpkg.TargetRefLabel
constant CRIImageLayers (line 19) | CRIImageLayers = snpkg.TargetImageLayersLabel
constant CRILayerDigest (line 20) | CRILayerDigest = snpkg.TargetLayerDigestLabel
constant CRIManifestDigest (line 21) | CRIManifestDigest = snpkg.TargetManifestDigestLabel
constant TargetSnapshotRef (line 29) | TargetSnapshotRef = "containerd.io/snapshot.ref"
constant NydusDataLayer (line 32) | NydusDataLayer = "containerd.io/snapshot/nydus-blob"
constant NydusMetaLayer (line 34) | NydusMetaLayer = "containerd.io/snapshot/nydus-bootstrap"
constant NydusRefLayer (line 36) | NydusRefLayer = "containerd.io/snapshot/nydus-ref"
constant NydusTarfsLayer (line 38) | NydusTarfsLayer = "containerd.io/snapshot/nydus-tarfs"
constant NydusImageBlockInfo (line 40) | NydusImageBlockInfo = "containerd.io/snapshot/nydus-image-block"
constant NydusLayerBlockInfo (line 42) | NydusLayerBlockInfo = "containerd.io/snapshot/nydus-layer-block"
constant NydusImagePullSecret (line 44) | NydusImagePullSecret = "containerd.io/snapshot/pullsecret"
constant NydusImagePullUsername (line 46) | NydusImagePullUsername = "containerd.io/snapshot/pullusername"
constant NydusProxyMode (line 48) | NydusProxyMode = "containerd.io/snapshot/nydus-proxy-mode"
constant NydusSignature (line 50) | NydusSignature = "containerd.io/snapshot/nydus-signature"
constant StargzLayer (line 53) | StargzLayer = "containerd.io/snapshot/stargz"
constant OverlayfsVolatileOpt (line 58) | OverlayfsVolatileOpt = "containerd.io/snapshot/overlay.volatile"
constant TarfsHint (line 62) | TarfsHint = "containerd.io/snapshot/tarfs-hint"
constant NydusIndexAlternative (line 65) | NydusIndexAlternative = "containerd.io/snapshot/nydus-index-alternative"
function IsNydusDataLayer (line 68) | func IsNydusDataLayer(labels map[string]string) bool {
function IsNydusMetaLayer (line 73) | func IsNydusMetaLayer(labels map[string]string) bool {
function IsTarfsDataLayer (line 78) | func IsTarfsDataLayer(labels map[string]string) bool {
function IsNydusProxyMode (line 83) | func IsNydusProxyMode(labels map[string]string) bool {
function HasTarfsHint (line 88) | func HasTarfsHint(labels map[string]string) bool {
FILE: pkg/layout/layout.go
constant MaxSuperBlockSize (line 18) | MaxSuperBlockSize = 8 * 1024
constant RafsV5 (line 20) | RafsV5 string = "v5"
constant RafsV6 (line 21) | RafsV6 string = "v6"
constant RafsV5SuperVersion (line 22) | RafsV5SuperVersion uint32 = 0x500
constant RafsV5SuperMagic (line 23) | RafsV5SuperMagic uint32 = 0x5241_4653
constant RafsV6SuperMagic (line 24) | RafsV6SuperMagic uint32 = 0xE0F5_E1E2
constant RafsV6SuperBlockSize (line 25) | RafsV6SuperBlockSize uint32 = 1024 + 128 + 256
constant RafsV6SuperBlockOffset (line 26) | RafsV6SuperBlockOffset uint32 = 1024
constant RafsV6ChunkInfoOffset (line 27) | RafsV6ChunkInfoOffset uint32 = 1024 + 128 + 24
constant BootstrapFile (line 28) | BootstrapFile string = "image/image.boot"
constant LegacyBootstrapFile (line 29) | LegacyBootstrapFile string = "image.boot"
constant DummyMountpoint (line 30) | DummyMountpoint string = "/dummy"
type ImageMode (line 35) | type ImageMode
constant OnDemand (line 38) | OnDemand ImageMode = iota
constant PreLoad (line 39) | PreLoad
function init (line 42) | func init() {
function isRafsV6 (line 56) | func isRafsV6(buf []byte) bool {
function DetectFsVersion (line 60) | func DetectFsVersion(header []byte) (string, error) {
FILE: pkg/manager/daemon_adaptor.go
constant endpointGetBackend (line 29) | endpointGetBackend string = "/api/v1/daemons/%s/backend"
method StartDaemon (line 38) | func (m *Manager) StartDaemon(d *daemon.Daemon) error {
method BuildDaemonCommand (line 123) | func (m *Manager) BuildDaemonCommand(d *daemon.Daemon, bin string, upgra...
FILE: pkg/manager/daemon_cache.go
type DaemonCache (line 18) | type DaemonCache struct
method Add (line 32) | func (s *DaemonCache) Add(daemon *daemon.Daemon) *daemon.Daemon {
method removeLocked (line 41) | func (s *DaemonCache) removeLocked(d *daemon.Daemon) *daemon.Daemon {
method Remove (line 47) | func (s *DaemonCache) Remove(d *daemon.Daemon) *daemon.Daemon {
method RemoveByDaemonID (line 55) | func (s *DaemonCache) RemoveByDaemonID(id string) *daemon.Daemon {
method Update (line 60) | func (s *DaemonCache) Update(d *daemon.Daemon) {
method GetByDaemonID (line 69) | func (s *DaemonCache) GetByDaemonID(id string, op func(d *daemon.Daemo...
method List (line 82) | func (s *DaemonCache) List() []*daemon.Daemon {
method Size (line 98) | func (s *DaemonCache) Size() int {
function newDaemonCache (line 23) | func newDaemonCache() *DaemonCache {
FILE: pkg/manager/daemon_cache_test.go
function TestDaemonStatesCache (line 26) | func TestDaemonStatesCache(t *testing.T) {
FILE: pkg/manager/daemon_event.go
method SubscribeDaemonEvent (line 26) | func (m *Manager) SubscribeDaemonEvent(d *daemon.Daemon) error {
method UnsubscribeDaemonEvent (line 34) | func (m *Manager) UnsubscribeDaemonEvent(d *daemon.Daemon) error {
method handleDaemonDeathEvent (line 43) | func (m *Manager) handleDaemonDeathEvent() {
method doDaemonFailover (line 73) | func (m *Manager) doDaemonFailover(d *daemon.Daemon) {
method doDaemonRestart (line 112) | func (m *Manager) doDaemonRestart(d *daemon.Daemon) {
method DoDaemonUpgrade (line 144) | func (m *Manager) DoDaemonUpgrade(d *daemon.Daemon, nydusdPath string, m...
function buildNextAPISocket (line 225) | func buildNextAPISocket(cur string) (string, error) {
FILE: pkg/manager/manager.go
type Manager (line 33) | type Manager struct
method Lock (line 106) | func (m *Manager) Lock() {
method Unlock (line 110) | func (m *Manager) Unlock() {
method CacheDir (line 114) | func (m *Manager) CacheDir() string {
method Recover (line 124) | func (m *Manager) Recover(ctx context.Context,
method AddRafsInstance (line 135) | func (m *Manager) AddRafsInstance(r *rafs.Rafs) error {
method UpdateRafsInstance (line 149) | func (m *Manager) UpdateRafsInstance(r *rafs.Rafs) error {
method RemoveRafsInstance (line 153) | func (m *Manager) RemoveRafsInstance(snapshotID string) error {
method recoverRafsInstances (line 157) | func (m *Manager) recoverRafsInstances(ctx context.Context,
method AddDaemon (line 190) | func (m *Manager) AddDaemon(daemon *daemon.Daemon) error {
method UpdateDaemon (line 204) | func (m *Manager) UpdateDaemon(daemon *daemon.Daemon) error {
method UpdateDaemonLocked (line 212) | func (m *Manager) UpdateDaemonLocked(daemon *daemon.Daemon) error {
method DeleteDaemon (line 223) | func (m *Manager) DeleteDaemon(daemon *daemon.Daemon) error {
method GetByDaemonID (line 238) | func (m *Manager) GetByDaemonID(id string) *daemon.Daemon {
method ListDaemons (line 242) | func (m *Manager) ListDaemons() []*daemon.Daemon {
method DestroyDaemon (line 248) | func (m *Manager) DestroyDaemon(d *daemon.Daemon) error {
method cleanUpDaemonResources (line 295) | func (m *Manager) cleanUpDaemonResources(d *daemon.Daemon) {
method recoverDaemons (line 312) | func (m *Manager) recoverDaemons(ctx context.Context,
type Opt (line 54) | type Opt struct
function NewManager (line 65) | func NewManager(opt Opt) (*Manager, error) {
FILE: pkg/manager/monitor.go
type LivenessMonitor (line 26) | type LivenessMonitor interface
type target (line 38) | type target struct
type livenessMonitor (line 50) | type livenessMonitor struct
method Subscribe (line 81) | func (m *livenessMonitor) Subscribe(id string, path string, notifier c...
method Unsubscribe (line 151) | func (m *livenessMonitor) Unsubscribe(id string) (err error) {
method unsubscribe (line 158) | func (m *livenessMonitor) unsubscribe(id string) (err error) {
method Run (line 191) | func (m *livenessMonitor) Run() {
method Destroy (line 231) | func (m *livenessMonitor) Destroy() {
type deathEvent (line 60) | type deathEvent struct
function newMonitor (line 65) | func newMonitor() (_ *livenessMonitor, err error) {
FILE: pkg/manager/monitor_test.go
function startUnixServer (line 20) | func startUnixServer(ctx context.Context, sock string) {
function TestLivenessMonitor (line 47) | func TestLivenessMonitor(t *testing.T) {
FILE: pkg/manager/store.go
type Store (line 19) | type Store interface
FILE: pkg/metrics/collector/cache.go
type CacheMetricsCollector (line 15) | type CacheMetricsCollector struct
method Collect (line 25) | func (c *CacheMetricsCollector) Collect() {
type CacheMetricsVecCollector (line 21) | type CacheMetricsVecCollector struct
method Collect (line 49) | func (c *CacheMetricsVecCollector) Collect() {
FILE: pkg/metrics/collector/collector.go
type Collector (line 21) | type Collector interface
function NewDaemonEventCollector (line 26) | func NewDaemonEventCollector(ev types.DaemonState) *DaemonEventCollector {
function NewFsMetricsCollector (line 30) | func NewFsMetricsCollector(m *types.FsMetrics, imageRef string) *FsMetri...
function NewFsMetricsVecCollector (line 34) | func NewFsMetricsVecCollector() *FsMetricsVecCollector {
function NewInflightMetricsVecCollector (line 38) | func NewInflightMetricsVecCollector(hungIOInterval time.Duration) *Infli...
function NewDaemonInfoCollector (line 44) | func NewDaemonInfoCollector(version *types.BuildTimeInfo, value float64)...
function NewDaemonImageCollector (line 48) | func NewDaemonImageCollector(daemonID, imageRef string) *DaemonImageColl...
function NewSnapshotterMetricsCollector (line 52) | func NewSnapshotterMetricsCollector(ctx context.Context, cacheDir string...
function NewSnapshotMetricsTimer (line 60) | func NewSnapshotMetricsTimer(method SnapshotMethod) *prometheus.Timer {
function NewCacheMetricsCollector (line 64) | func NewCacheMetricsCollector(m *types.CacheMetrics, imageRef, daemonID ...
function NewCacheMetricsVecCollector (line 68) | func NewCacheMetricsVecCollector() *CacheMetricsVecCollector {
FILE: pkg/metrics/collector/daemon.go
type DaemonEventCollector (line 15) | type DaemonEventCollector struct
method Collect (line 34) | func (d *DaemonEventCollector) Collect() {
type DaemonInfoCollector (line 19) | type DaemonInfoCollector struct
method Collect (line 38) | func (d *DaemonInfoCollector) Collect() {
type DaemonResourceCollector (line 24) | type DaemonResourceCollector struct
method Collect (line 46) | func (d *DaemonResourceCollector) Collect() {
type DaemonImageCollector (line 29) | type DaemonImageCollector struct
method Collect (line 50) | func (d *DaemonImageCollector) Collect() {
method Delete (line 54) | func (d *DaemonImageCollector) Delete() {
FILE: pkg/metrics/collector/fs.go
type FsMetricsCollector (line 22) | type FsMetricsCollector struct
method Collect (line 36) | func (f *FsMetricsCollector) Collect() {
type FsMetricsVecCollector (line 27) | type FsMetricsVecCollector struct
method Clear (line 79) | func (f *FsMetricsVecCollector) Clear() {
method Collect (line 85) | func (f *FsMetricsVecCollector) Collect() {
type InflightMetricsVecCollector (line 31) | type InflightMetricsVecCollector struct
method Collect (line 55) | func (i *InflightMetricsVecCollector) Collect() {
FILE: pkg/metrics/collector/snapshotter.go
type SnapshotterMetricsCollector (line 19) | type SnapshotterMetricsCollector struct
method CollectCacheUsage (line 36) | func (s *SnapshotterMetricsCollector) CollectCacheUsage() {
method CollectResourceUsage (line 45) | func (s *SnapshotterMetricsCollector) CollectResourceUsage() {
method Collect (line 80) | func (s *SnapshotterMetricsCollector) Collect() {
type SnapshotMethod (line 26) | type SnapshotMethod
constant SnapshotMethodUnknown (line 29) | SnapshotMethodUnknown SnapshotMethod = "UNKNOWN"
constant SnapshotMethodPrepare (line 30) | SnapshotMethodPrepare SnapshotMethod = "PREPARE"
constant SnapshotMethodMount (line 31) | SnapshotMethodMount SnapshotMethod = "MOUNTS"
constant SnapshotMethodCleanup (line 32) | SnapshotMethodCleanup SnapshotMethod = "CLEANUP"
constant SnapshotMethodRemove (line 33) | SnapshotMethodRemove SnapshotMethod = "REMOVE"
function CollectSnapshotMetricsTimer (line 85) | func CollectSnapshotMetricsTimer(h *prometheus.HistogramVec, event Snaps...
FILE: pkg/metrics/data/labels.go
constant imageRefLabel (line 4) | imageRefLabel = "image_ref"
constant nydusdEventLabel (line 5) | nydusdEventLabel = "nydusd_event"
constant nydusdVersionLabel (line 6) | nydusdVersionLabel = "version"
constant daemonIDLabel (line 7) | daemonIDLabel = "daemon_id"
constant snapshotEventLabel (line 8) | snapshotEventLabel = "snapshot_operation"
constant credentialResultLabel (line 9) | credentialResultLabel = "result"
FILE: pkg/metrics/listener.go
function trapClosedConnErr (line 24) | func trapClosedConnErr(err error) error {
function NewMetricsHTTPListenerServer (line 32) | func NewMetricsHTTPListenerServer(addr string) error {
FILE: pkg/metrics/registry/registry.go
function init (line 18) | func init() {
FILE: pkg/metrics/serve.go
type ServerOpt (line 26) | type ServerOpt
type Server (line 28) | type Server struct
method CollectDaemonResourceMetrics (line 87) | func (s *Server) CollectDaemonResourceMetrics(_ context.Context) {
method CollectFsMetrics (line 105) | func (s *Server) CollectFsMetrics(ctx context.Context) {
method CollectCacheMetrics (line 150) | func (s *Server) CollectCacheMetrics(ctx context.Context) {
method CollectInflightMetrics (line 191) | func (s *Server) CollectInflightMetrics(ctx context.Context) {
method StartCollectMetrics (line 222) | func (s *Server) StartCollectMetrics(ctx context.Context) error {
function WithProcessManagers (line 38) | func WithProcessManagers(managers []*manager.Manager) ServerOpt {
function WithCollectInterval (line 45) | func WithCollectInterval(interval time.Duration) ServerOpt {
function WithHungIOInterval (line 55) | func WithHungIOInterval(hungIOInterval time.Duration) ServerOpt {
function NewServer (line 65) | func NewServer(ctx context.Context, opts ...ServerOpt) (*Server, error) {
FILE: pkg/metrics/tool/common.go
constant defaultClkTck (line 21) | defaultClkTck = 100
function FormatFloat64 (line 24) | func FormatFloat64(f float64, point int) float64 {
function ParseFloat64 (line 39) | func ParseFloat64(val string) float64 {
function GetClkTck (line 44) | func GetClkTck() float64 {
function GetPageSize (line 58) | func GetPageSize() float64 {
FILE: pkg/metrics/tool/stat.go
type Stat (line 20) | type Stat struct
function CalculateCPUUtilization (line 37) | func CalculateCPUUtilization(begin *Stat, now *Stat) (float64, error) {
function GetProcessMemoryRSSKiloBytes (line 53) | func GetProcessMemoryRSSKiloBytes(pid int) (float64, error) {
function GetProcessStat (line 62) | func GetProcessStat(pid int) (*Stat, error) {
function GetProcessRunningState (line 98) | func GetProcessRunningState(pid int) (string, error) {
function IsZombieProcess (line 109) | func IsZombieProcess(pid int) (bool, error) {
FILE: pkg/metrics/tool/stat_test.go
function TestFindZombie (line 15) | func TestFindZombie(t *testing.T) {
FILE: pkg/metrics/types/ttl/gauge.go
type LabelWithValue (line 22) | type LabelWithValue struct
type GaugeVec (line 27) | type GaugeVec struct
method cleanUpExpired (line 53) | func (gv *GaugeVec) cleanUpExpired() {
method WithLabelValues (line 68) | func (gv *GaugeVec) WithLabelValues(val ...string) *GaugeWithTTL {
type GaugeWithTTL (line 35) | type GaugeWithTTL struct
method Set (line 77) | func (gwt *GaugeWithTTL) Set(val float64) {
function NewGaugeVecWithTTL (line 41) | func NewGaugeVecWithTTL(opts prometheus.GaugeOpts, labelNames []string, ...
FILE: pkg/metrics/types/ttl/gauge_test.go
function TestNewGaugeVecWithTTL (line 19) | func TestNewGaugeVecWithTTL(t *testing.T) {
FILE: pkg/metrics/types/types.go
type Fop (line 16) | type Fop
constant Getattr (line 19) | Getattr = iota
constant Readlink (line 20) | Readlink
constant Open (line 21) | Open
constant Release (line 22) | Release
constant Read (line 23) | Read
constant Statfs (line 24) | Statfs
constant Getxattr (line 25) | Getxattr
constant Listxattr (line 26) | Listxattr
constant Opendir (line 27) | Opendir
constant Lookup (line 28) | Lookup
constant Readdir (line 29) | Readdir
constant Readdirplus (line 30) | Readdirplus
constant Access (line 31) | Access
constant Forget (line 32) | Forget
constant BatchForget (line 33) | BatchForget
constant MaxFops (line 35) | MaxFops
function GetMaxFops (line 38) | func GetMaxFops() uint {
function MakeFopBuckets (line 42) | func MakeFopBuckets() []uint64 {
type GetCountersFn (line 51) | type GetCountersFn
type MetricHistogram (line 53) | type MetricHistogram struct
method ToConstHistogram (line 62) | func (h *MetricHistogram) ToConstHistogram(m *types.FsMetrics, imageRe...
method Clear (line 85) | func (h *MetricHistogram) Clear() {
method Save (line 89) | func (h *MetricHistogram) Save(m prometheus.Metric) {
method Describe (line 94) | func (h *MetricHistogram) Describe(ch chan<- *prometheus.Desc) {
method Collect (line 100) | func (h *MetricHistogram) Collect(ch chan<- prometheus.Metric) {
FILE: pkg/pprof/listener.go
function NewPprofHTTPListener (line 18) | func NewPprofHTTPListener(addr string) error {
FILE: pkg/prefetch/prefetch.go
type prefetchInfo (line 16) | type prefetchInfo struct
method SetPrefetchFiles (line 23) | func (p *prefetchInfo) SetPrefetchFiles(body []byte) error {
method GetPrefetchInfo (line 45) | func (p *prefetchInfo) GetPrefetchInfo(image string) string {
method DeleteFromPrefetchMap (line 55) | func (p *prefetchInfo) DeleteFromPrefetchMap(image string) {
FILE: pkg/rafs/rafs.go
constant AnnoFsCacheDomainID (line 24) | AnnoFsCacheDomainID string = "fscache.domainid"
constant AnnoFsCacheID (line 25) | AnnoFsCacheID string = "fscache.id"
type NewRafsOpt (line 28) | type NewRafsOpt
function init (line 30) | func init() {
type Cache (line 39) | type Cache struct
method Lock (line 48) | func (rs *Cache) Lock() {
method Unlock (line 52) | func (rs *Cache) Unlock() {
method Add (line 56) | func (rs *Cache) Add(r *Rafs) {
method Remove (line 62) | func (rs *Cache) Remove(snapshotID string) {
method Get (line 68) | func (rs *Cache) Get(snapshotID string) *Rafs {
method Len (line 75) | func (rs *Cache) Len() int {
method Head (line 82) | func (rs *Cache) Head() *Rafs {
method List (line 92) | func (rs *Cache) List() map[string]*Rafs {
method ListLocked (line 101) | func (rs *Cache) ListLocked() map[string]*Rafs {
method SetIntances (line 105) | func (rs *Cache) SetIntances(instances map[string]*Rafs) {
function NewRafsCache (line 44) | func NewRafsCache() Cache {
type Rafs (line 112) | type Rafs struct
method AddAnnotation (line 146) | func (r *Rafs) AddAnnotation(k, v string) {
method GetSnapshotDir (line 150) | func (r *Rafs) GetSnapshotDir() string {
method GetFsDriver (line 154) | func (r *Rafs) GetFsDriver() string {
method FscacheWorkDir (line 163) | func (r *Rafs) FscacheWorkDir() string {
method SetMountpoint (line 167) | func (r *Rafs) SetMountpoint(mp string) {
method GetMountpoint (line 177) | func (r *Rafs) GetMountpoint() string {
method RelaMountpoint (line 185) | func (r *Rafs) RelaMountpoint() string {
method BootstrapFile (line 189) | func (r *Rafs) BootstrapFile() (string, error) {
function NewRafs (line 126) | func NewRafs(snapshotID, imageID, fsDriver string) (*Rafs, error) {
FILE: pkg/referrer/manager.go
type Manager (line 21) | type Manager struct
method CheckReferrer (line 39) | func (manager *Manager) CheckReferrer(ctx context.Context, ref string,...
method TryFetchMetadata (line 75) | func (manager *Manager) TryFetchMetadata(ctx context.Context, ref stri...
function NewManager (line 27) | func NewManager(insecure bool) *Manager {
FILE: pkg/referrer/referrer.go
constant maxManifestIndexSize (line 28) | maxManifestIndexSize = 0x800000
type referrer (line 30) | type referrer struct
method checkReferrer (line 43) | func (r *referrer) checkReferrer(ctx context.Context, ref string, mani...
method fetchMetadata (line 107) | func (r *referrer) fetchMetadata(ctx context.Context, ref string, desc...
function newReferrer (line 34) | func newReferrer(keyChain *auth.PassKeyChain, insecure bool) *referrer {
FILE: pkg/remote/remote.go
function isErrHTTPResponseToHTTPSClient (line 26) | func isErrHTTPResponseToHTTPSClient(err error) bool {
function isErrConnectionRefused (line 35) | func isErrConnectionRefused(err error) bool {
type Remote (line 40) | type Remote struct
method RetryWithPlainHTTP (line 101) | func (remote *Remote) RetryWithPlainHTTP(ref string, err error) bool {
method Resolve (line 125) | func (remote *Remote) Resolve(_ context.Context, _ string) remotes.Res...
method Fetcher (line 129) | func (remote *Remote) Fetcher(ctx context.Context, ref string) (remote...
function New (line 56) | func New(keyChain *auth.PassKeyChain, insecure bool) *Remote {
FILE: pkg/remote/remote_test.go
function TestRetryWithPlainHTTP (line 16) | func TestRetryWithPlainHTTP(t *testing.T) {
FILE: pkg/remote/remotes/docker/auth/fetch.go
function GenerateTokenOptions (line 41) | func GenerateTokenOptions(ctx context.Context, host, username, secret st...
type TokenOptions (line 70) | type TokenOptions struct
type OAuthTokenResponse (line 88) | type OAuthTokenResponse struct
function FetchTokenWithOAuth (line 97) | func FetchTokenWithOAuth(ctx context.Context, client *http.Client, heade...
type FetchTokenResponse (line 154) | type FetchTokenResponse struct
function FetchToken (line 163) | func FetchToken(ctx context.Context, client *http.Client, headers http.H...
FILE: pkg/remote/remotes/docker/auth/fetch_test.go
function TestGenerateTokenOptions (line 26) | func TestGenerateTokenOptions(t *testing.T) {
FILE: pkg/remote/remotes/docker/auth/parse.go
type AuthenticationScheme (line 26) | type AuthenticationScheme
constant BasicAuth (line 30) | BasicAuth AuthenticationScheme = 1 << iota
constant DigestAuth (line 32) | DigestAuth
constant BearerAuth (line 34) | BearerAuth
type Challenge (line 39) | type Challenge struct
type byScheme (line 47) | type byScheme
method Len (line 49) | func (bs byScheme) Len() int { return len(bs) }
method Swap (line 50) | func (bs byScheme) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] }
method Less (line 53) | func (bs byScheme) Less(i, j int) bool { return bs[i].Scheme > bs[j].S...
type octetType (line 56) | type octetType
constant isToken (line 61) | isToken octetType = 1 << iota
constant isSpace (line 62) | isSpace
function init (line 65) | func init() {
function ParseAuthHeader (line 98) | func ParseAuthHeader(header http.Header) []Challenge {
function parseValueAndParams (line 119) | func parseValueAndParams(header string) (value string, params map[string...
function skipSpace (line 147) | func skipSpace(s string) (rest string) {
function expectToken (line 157) | func expectToken(s string) (token, rest string) {
function expectTokenOrQuoted (line 167) | func expectTokenOrQuoted(s string) (value string, rest string) {
FILE: pkg/remote/remotes/docker/auth/parse_test.go
function TestParseAuthHeaderBearer (line 28) | func TestParseAuthHeaderBearer(t *testing.T) {
function TestParseAuthHeader (line 75) | func TestParseAuthHeader(t *testing.T) {
function FuzzParseAuthHeader (line 89) | func FuzzParseAuthHeader(f *testing.F) {
FILE: pkg/remote/remotes/docker/authorizer.go
type dockerAuthorizer (line 34) | type dockerAuthorizer struct
method Authorize (line 111) | func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Re...
method getAuthHandler (line 136) | func (a *dockerAuthorizer) getAuthHandler(host string) *authHandler {
method AddResponses (line 143) | func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses...
type authorizerConfig (line 47) | type authorizerConfig struct
type AuthorizerOpt (line 55) | type AuthorizerOpt
function WithAuthClient (line 58) | func WithAuthClient(client *http.Client) AuthorizerOpt {
function WithAuthCreds (line 65) | func WithAuthCreds(creds func(string) (string, string, error)) Authorize...
function WithAuthHeader (line 72) | func WithAuthHeader(hdr http.Header) AuthorizerOpt {
type OnFetchRefreshToken (line 79) | type OnFetchRefreshToken
function WithFetchRefreshToken (line 82) | func WithFetchRefreshToken(f OnFetchRefreshToken) AuthorizerOpt {
function NewDockerAuthorizer (line 91) | func NewDockerAuthorizer(opts ...AuthorizerOpt) Authorizer {
type authResult (line 204) | type authResult struct
type authHandler (line 212) | type authHandler struct
method authorize (line 240) | func (ah *authHandler) authorize(ctx context.Context) (string, string,...
method doBasicAuth (line 251) | func (ah *authHandler) doBasicAuth(ctx context.Context) (string, strin...
method doBearerAuth (line 262) | func (ah *authHandler) doBearerAuth(ctx context.Context) (token, refre...
function newAuthHandler (line 230) | func newAuthHandler(client *http.Client, hdr http.Header, scheme auth.Au...
function invalidAuthorization (line 331) | func invalidAuthorization(c auth.Challenge, responses []*http.Response) ...
function sameRequest (line 345) | func sameRequest(r1, r2 *http.Request) bool {
FILE: pkg/remote/remotes/docker/config/config_unix.go
function hostPaths (line 26) | func hostPaths(root, host string) (hosts []string) {
function rootSystemPool (line 40) | func rootSystemPool() (*x509.CertPool, error) {
FILE: pkg/remote/remotes/docker/config/config_windows.go
function hostPaths (line 25) | func hostPaths(root, host string) (hosts []string) {
function rootSystemPool (line 39) | func rootSystemPool() (*x509.CertPool, error) {
FILE: pkg/remote/remotes/docker/config/docker_fuzzer_internal.go
function FuzzParseHostsFile (line 27) | func FuzzParseHostsFile(data []byte) int {
FILE: pkg/remote/remotes/docker/config/hosts.go
type UpdateClientFunc (line 42) | type UpdateClientFunc
type hostConfig (line 44) | type hostConfig struct
type HostOptions (line 61) | type HostOptions struct
function ConfigureHosts (line 75) | func ConfigureHosts(ctx context.Context, options HostOptions) docker.Reg...
function HostDirFromRoot (line 244) | func HostDirFromRoot(root string) func(string) (string, error) {
function hostDirectory (line 258) | func hostDirectory(host string) string {
function loadHostDir (line 266) | func loadHostDir(ctx context.Context, hostsDir string) ([]hostConfig, er...
type hostFileConfig (line 289) | type hostFileConfig struct
function parseHostsFile (line 327) | func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) {
function parseHostConfig (line 381) | func parseHostConfig(server string, baseDir string, config hostFileConfi...
function getSortedHosts (line 498) | func getSortedHosts(root *toml.Tree) ([]string, error) {
function makeStringSlice (line 519) | func makeStringSlice(slice []interface{}, cb func(string) string) ([]str...
function makeAbsPath (line 536) | func makeAbsPath(p string, base string) string {
function loadCertFiles (line 552) | func loadCertFiles(ctx context.Context, certsDir string) ([]hostConfig, ...
FILE: pkg/remote/remotes/docker/config/hosts_test.go
constant allCaps (line 32) | allCaps = docker.HostCapabilityPull | docker.HostCapabilityResolve | doc...
function TestDefaultHosts (line 34) | func TestDefaultHosts(t *testing.T) {
function TestParseHostFile (line 75) | func TestParseHostFile(t *testing.T) {
function TestLoadCertFiles (line 210) | func TestLoadCertFiles(t *testing.T) {
function compareRegistryHost (line 287) | func compareRegistryHost(j, k docker.RegistryHost) bool {
function compareHostConfig (line 304) | func compareHostConfig(j, k hostConfig) bool {
function printHostConfig (line 362) | func printHostConfig(hc []hostConfig) string {
FILE: pkg/remote/remotes/docker/converter.go
constant LegacyConfigMediaType (line 36) | LegacyConfigMediaType = "application/octet-stream"
function ConvertManifest (line 43) | func ConvertManifest(ctx context.Context, store content.Store, desc ocis...
FILE: pkg/remote/remotes/docker/converter_fuzz.go
function FuzzConvertManifest (line 32) | func FuzzConvertManifest(data []byte) int {
FILE: pkg/remote/remotes/docker/errcode.go
type ErrorCoder (line 27) | type ErrorCoder interface
type ErrorCode (line 33) | type ErrorCode
method ErrorCode (line 38) | func (ec ErrorCode) ErrorCode() ErrorCode {
method Error (line 43) | func (ec ErrorCode) Error() string {
method Descriptor (line 49) | func (ec ErrorCode) Descriptor() ErrorDescriptor {
method String (line 60) | func (ec ErrorCode) String() string {
method Message (line 65) | func (ec ErrorCode) Message() string {
method MarshalText (line 71) | func (ec ErrorCode) MarshalText() (text []byte, err error) {
method UnmarshalText (line 76) | func (ec *ErrorCode) UnmarshalText(text []byte) error {
method WithMessage (line 90) | func (ec ErrorCode) WithMessage(message string) Error {
method WithDetail (line 99) | func (ec ErrorCode) WithDetail(detail interface{}) Error {
method WithArgs (line 107) | func (ec ErrorCode) WithArgs(args ...interface{}) Error {
type Error (line 115) | type Error struct
method ErrorCode (line 127) | func (e Error) ErrorCode() ErrorCode {
method Error (line 132) | func (e Error) Error() string {
method WithDetail (line 138) | func (e Error) WithDetail(detail interface{}) Error {
method WithArgs (line 148) | func (e Error) WithArgs(args ...interface{}) Error {
type ErrorDescriptor (line 157) | type ErrorDescriptor struct
function ParseErrorCode (line 181) | func ParseErrorCode(value string) ErrorCode {
type Errors (line 192) | type Errors
method Error (line 196) | func (errs Errors) Error() string {
method Len (line 212) | func (errs Errors) Len() int {
method MarshalJSON (line 218) | func (errs Errors) MarshalJSON() ([]byte, error) {
method UnmarshalJSON (line 255) | func (errs *Errors) UnmarshalJSON(data []byte) error {
FILE: pkg/remote/remotes/docker/errdesc.go
function Register (line 99) | func Register(group string, descriptor ErrorDescriptor) ErrorCode {
type byValue (line 120) | type byValue
method Len (line 122) | func (a byValue) Len() int { return len(a) }
method Swap (line 123) | func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
method Less (line 124) | func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
function GetGroupNames (line 127) | func GetGroupNames() []string {
function GetErrorCodeGroup (line 138) | func GetErrorCodeGroup(name string) []ErrorDescriptor {
function GetErrorAllDescriptors (line 146) | func GetErrorAllDescriptors() []ErrorDescriptor {
FILE: pkg/remote/remotes/docker/fetcher.go
type dockerFetcher (line 36) | type dockerFetcher struct
method Fetch (line 40) | func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descrip...
method createGetReq (line 154) | func (r dockerFetcher) createGetReq(ctx context.Context, host Registry...
method FetchByDigest (line 183) | func (r dockerFetcher) FetchByDigest(ctx context.Context, dgst digest....
method open (line 262) | func (r dockerFetcher) open(ctx context.Context, req *request, mediaty...
FILE: pkg/remote/remotes/docker/fetcher_fuzz.go
function FuzzFetcher (line 32) | func FuzzFetcher(data []byte) int {
function FuzzParseDockerRef (line 78) | func FuzzParseDockerRef(data []byte) int {
FILE: pkg/remote/remotes/docker/fetcher_test.go
function TestFetcherOpen (line 33) | func TestFetcherOpen(t *testing.T) {
function TestDockerFetcherOpen (line 121) | func TestDockerFetcherOpen(t *testing.T) {
FILE: pkg/remote/remotes/docker/handler.go
function AppendDistributionSourceLabel (line 34) | func AppendDistributionSourceLabel(manager content.Manager, ref string) ...
function appendDistributionSourceLabel (line 79) | func appendDistributionSourceLabel(originLabel, repo string) string {
function distributionSourceLabelKey (line 105) | func distributionSourceLabelKey(source string) string {
function selectRepositoryMountCandidate (line 111) | func selectRepositoryMountCandidate(refspec reference.Spec, sources map[...
function commonPrefixComponents (line 139) | func commonPrefixComponents(components []string, target string) int {
FILE: pkg/remote/remotes/docker/handler_test.go
function TestAppendDistributionLabel (line 27) | func TestAppendDistributionLabel(t *testing.T) {
function TestDistributionSourceLabelKey (line 72) | func TestDistributionSourceLabelKey(t *testing.T) {
function TestCommonPrefixComponents (line 79) | func TestCommonPrefixComponents(t *testing.T) {
function TestSelectRepositoryMountCandidate (line 107) | func TestSelectRepositoryMountCandidate(t *testing.T) {
FILE: pkg/remote/remotes/docker/httpreadseeker.go
constant maxRetry (line 28) | maxRetry = 3
type httpReadSeeker (line 30) | type httpReadSeeker struct
method Read (line 47) | func (hrs *httpReadSeeker) Read(p []byte) (n int, err error) {
method Close (line 83) | func (hrs *httpReadSeeker) Close() error {
method Seek (line 95) | func (hrs *httpReadSeeker) Seek(offset int64, whence int) (int64, erro...
method reader (line 134) | func (hrs *httpReadSeeker) reader() (io.Reader, error) {
function newHTTPReadSeeker (line 40) | func newHTTPReadSeeker(size int64, open func(offset int64) (io.ReadClose...
FILE: pkg/remote/remotes/docker/pusher.go
type dockerPusher (line 40) | type dockerPusher struct
method Writer (line 52) | func (p dockerPusher) Writer(ctx context.Context, opts ...content.Writ...
method Push (line 65) | func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descripto...
method push (line 69) | func (p dockerPusher) push(ctx context.Context, desc ocispec.Descripto...
function getManifestPath (line 299) | func getManifestPath(object string, dgst digest.Digest) []string {
type pushWriter (line 318) | type pushWriter struct
method setPipe (line 349) | func (pw *pushWriter) setPipe(p *io.PipeWriter) {
method setError (line 353) | func (pw *pushWriter) setError(err error) {
method setResponse (line 356) | func (pw *pushWriter) setResponse(resp *http.Response) {
method Write (line 360) | func (pw *pushWriter) Write(p []byte) (n int, err error) {
method Close (line 407) | func (pw *pushWriter) Close() error {
method Status (line 425) | func (pw *pushWriter) Status() (content.Status, error) {
method Digest (line 434) | func (pw *pushWriter) Digest() digest.Digest {
method Commit (line 439) | func (pw *pushWriter) Commit(ctx context.Context, size int64, expected...
method Truncate (line 514) | func (pw *pushWriter) Truncate(size int64) error {
function newPushWriter (line 335) | func newPushWriter(db *dockerBase, ref string, expected digest.Digest, t...
function requestWithMountFrom (line 520) | func requestWithMountFrom(req *request, mount, from string) *request {
FILE: pkg/remote/remotes/docker/pusher_test.go
function TestGetManifestPath (line 40) | func TestGetManifestPath(t *testing.T) {
function TestPusherErrClosedRetry (line 69) | func TestPusherErrClosedRetry(t *testing.T) {
function TestPusherErrReset (line 90) | func TestPusherErrReset(t *testing.T) {
function tryUpload (line 135) | func tryUpload(ctx context.Context, t *testing.T, p dockerPusher, layerC...
function samplePusher (line 152) | func samplePusher(t *testing.T) (dockerPusher, *uploadableMockRegistry, ...
type uploadableMockRegistry (line 183) | type uploadableMockRegistry struct
method ServeHTTP (line 189) | func (u *uploadableMockRegistry) ServeHTTP(w http.ResponseWriter, r *h...
method defaultHandler (line 199) | func (u *uploadableMockRegistry) defaultHandler(w http.ResponseWriter,...
method isContentAlreadyExist (line 254) | func (u *uploadableMockRegistry) isContentAlreadyExist(c string) bool {
function Test_dockerPusher_push (line 263) | func Test_dockerPusher_push(t *testing.T) {
FILE: pkg/remote/remotes/docker/referrers.go
method FetchReferrers (line 32) | func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.D...
FILE: pkg/remote/remotes/docker/registry.go
type HostCapabilities (line 43) | type HostCapabilities
method Has (line 66) | func (c HostCapabilities) Has(t HostCapabilities) bool {
constant HostCapabilityPull (line 48) | HostCapabilityPull HostCapabilities = 1 << iota
constant HostCapabilityResolve (line 52) | HostCapabilityResolve
constant HostCapabilityPush (line 56) | HostCapabilityPush
constant HostCapabilityReferrers (line 60) | HostCapabilityReferrers
type RegistryHost (line 73) | type RegistryHost struct
method isProxy (line 83) | func (h RegistryHost) isProxy(refhost string) bool {
type RegistryHosts (line 94) | type RegistryHosts
function Registries (line 102) | func Registries(registries ...RegistryHosts) RegistryHosts {
type registryOpts (line 117) | type registryOpts struct
type RegistryOpt (line 125) | type RegistryOpt
function WithPlainHTTP (line 129) | func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt {
function WithAuthorizer (line 136) | func WithAuthorizer(a Authorizer) RegistryOpt {
function WithHostTranslator (line 143) | func WithHostTranslator(h func(string) (string, error)) RegistryOpt {
function WithClient (line 150) | func WithClient(c *http.Client) RegistryOpt {
function ConfigureDefaultRegistries (line 160) | func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts {
function MatchAllHosts (line 205) | func MatchAllHosts(string) (bool, error) {
function MatchLocalhost (line 214) | func MatchLocalhost(host string) (bool, error) {
FILE: pkg/remote/remotes/docker/registry_test.go
function TestHasCapability (line 21) | func TestHasCapability(t *testing.T) {
function TestMatchLocalhost (line 49) | func TestMatchLocalhost(t *testing.T) {
FILE: pkg/remote/remotes/docker/resolver.go
type Authorizer (line 66) | type Authorizer interface
type ResolverOptions (line 89) | type ResolverOptions struct
function DefaultHost (line 125) | func DefaultHost(ns string) (string, error) {
type dockerResolver (line 132) | type dockerResolver struct
method Resolve (line 226) | func (r *dockerResolver) Resolve(ctx context.Context, ref string) (str...
method Fetcher (line 407) | func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (rem...
method Pusher (line 418) | func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remo...
method resolveDockerBase (line 431) | func (r *dockerResolver) resolveDockerBase(ref string) (*dockerBase, e...
method base (line 447) | func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, er...
function NewResolver (line 140) | func NewResolver(options ResolverOptions) remotes.Resolver {
function getManifestMediaType (line 198) | func getManifestMediaType(resp *http.Response) string {
type countingReader (line 213) | type countingReader struct
method Read (line 218) | func (r *countingReader) Read(p []byte) (int, error) {
type dockerBase (line 440) | type dockerBase struct
method filterHosts (line 464) | func (r *dockerBase) filterHosts(capsets ...HostCapabilities) (hosts [...
method request (line 476) | func (r *dockerBase) request(host RegistryHost, method string, ps ...s...
type request (line 537) | type request struct
method authorize (line 499) | func (r *request) authorize(ctx context.Context, req *http.Request) er...
method addQuery (line 510) | func (r *request) addQuery(key, value string) (err error) {
method addNamespace (line 530) | func (r *request) addNamespace(ns string) error {
method do (line 546) | func (r *request) do(ctx context.Context) (*http.Response, error) {
method doWithRetries (line 607) | func (r *request) doWithRetries(ctx context.Context, responses []*http...
method retryRequest (line 626) | func (r *request) retryRequest(ctx context.Context, responses []*http....
method String (line 658) | func (r *request) String() string {
function requestFields (line 662) | func requestFields(req *http.Request) log.Fields {
function responseFields (line 683) | func responseFields(resp *http.Response) log.Fields {
function IsLocalhost (line 702) | func IsLocalhost(host string) bool {
FILE: pkg/remote/remotes/docker/resolver_test.go
function TestHTTPResolver (line 41) | func TestHTTPResolver(t *testing.T) {
function TestHTTPSResolver (line 53) | func TestHTTPSResolver(t *testing.T) {
function TestBasicResolver (line 57) | func TestBasicResolver(t *testing.T) {
function TestAnonymousTokenResolver (line 86) | func TestAnonymousTokenResolver(t *testing.T) {
function TestBasicAuthTokenResolver (line 100) | func TestBasicAuthTokenResolver(t *testing.T) {
function TestRefreshTokenResolver (line 122) | func TestRefreshTokenResolver(t *testing.T) {
function TestFetchRefreshToken (line 145) | func TestFetchRefreshToken(t *testing.T) {
function TestPostBasicAuthTokenResolver (line 170) | func TestPostBasicAuthTokenResolver(t *testing.T) {
function TestBadTokenResolver (line 193) | func TestBadTokenResolver(t *testing.T) {
function TestHostFailureFallbackResolver (line 225) | func TestHostFailureFallbackResolver(t *testing.T) {
function TestHostTLSFailureFallbackResolver (line 262) | func TestHostTLSFailureFallbackResolver(t *testing.T) {
function TestResolveProxy (line 312) | func TestResolveProxy(t *testing.T) {
function TestResolveProxyFallback (line 375) | func TestResolveProxyFallback(t *testing.T) {
function flipLocalhost (line 447) | func flipLocalhost(host string) string {
function withTokenServer (line 457) | func withTokenServer(th http.Handler, creds func(string) (string, string...
function tlsServer (line 496) | func tlsServer(h http.Handler) (string, ResolverOptions, func()) {
type logHandler (line 520) | type logHandler struct
method ServeHTTP (line 525) | func (h logHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
type namespaceRouter (line 529) | type namespaceRouter
method ServeHTTP (line 531) | func (nr namespaceRouter) ServeHTTP(rw http.ResponseWriter, r *http.Re...
function runBasicTest (line 540) | func runBasicTest(t *testing.T, name string, sf func(h http.Handler) (st...
function testFetch (line 587) | func testFetch(ctx context.Context, f remotes.Fetcher, desc ocispec.Desc...
function testocimanifest (line 623) | func testocimanifest(ctx context.Context, f remotes.Fetcher, desc ocispe...
type testContent (line 649) | type testContent struct
method Descriptor (line 661) | func (tc testContent) Descriptor() ocispec.Descriptor {
method Digest (line 669) | func (tc testContent) Digest() digest.Digest {
method ServeHTTP (line 673) | func (tc testContent) ServeHTTP(w http.ResponseWriter, r *http.Request) {
function newContent (line 654) | func newContent(mediaType string, b []byte) testContent {
type testManifest (line 681) | type testManifest struct
method OCIManifest (line 693) | func (m testManifest) OCIManifest() []byte {
method RegisterHandler (line 708) | func (m testManifest) RegisterHandler(r *http.ServeMux, name string) {
function newManifest (line 686) | func newManifest(config testContent, refs ...testContent) testManifest {
function newRefreshTokenServer (line 714) | func newRefreshTokenServer(t testing.TB, name string, disablePOST bool, ...
type refreshTokenServer (line 727) | type refreshTokenServer struct
method isValidAuthorizationHeader (line 738) | func (srv *refreshTokenServer) isValidAuthorizationHeader(s string) bo...
method BasicTestFunc (line 743) | func (srv *refreshTokenServer) BasicTestFunc() func(h http.Handler) (s...
FILE: pkg/remote/remotes/docker/schema1/converter.go
constant manifestSizeLimit (line 49) | manifestSizeLimit = 8e6
constant labelDockerSchema1EmptyLayer (line 50) | labelDockerSchema1EmptyLayer = "containerd.io/docker.schema1.empty-layer"
type blobState (line 53) | type blobState struct
type Converter (line 59) | type Converter struct
method Handle (line 81) | func (c *Converter) Handle(ctx context.Context, desc ocispec.Descripto...
method Convert (line 151) | func (c *Converter) Convert(ctx context.Context, opts ...ConvertOpt) (...
method fetchManifest (line 243) | func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.De...
method fetchBlob (line 269) | func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descri...
method reuseLabelBlobState (line 387) | func (c *Converter) reuseLabelBlobState(ctx context.Context, desc ocis...
method schema1ManifestHistory (line 432) | func (c *Converter) schema1ManifestHistory() ([]ocispec.History, []dig...
function NewConverter (line 71) | func NewConverter(contentStore content.Store, fetcher remotes.Fetcher) *...
type ConvertOptions (line 128) | type ConvertOptions struct
type ConvertOpt (line 138) | type ConvertOpt
function UseDockerSchema2 (line 142) | func UseDockerSchema2() ConvertOpt {
function ReadStripSignature (line 234) | func ReadStripSignature(schema1Blob io.Reader) ([]byte, error) {
type fsLayer (line 471) | type fsLayer struct
type history (line 475) | type history struct
type manifest (line 479) | type manifest struct
type v1History (line 486) | type v1History struct
function isEmptyLayer (line 500) | func isEmptyLayer(compatHistory []byte) (bool, error) {
type signature (line 519) | type signature struct
type jsParsedSignature (line 523) | type jsParsedSignature struct
type protectedBlock (line 527) | type protectedBlock struct
function joseBase64UrlDecode (line 536) | func joseBase64UrlDecode(s string) ([]byte, error) {
function stripSignature (line 549) | func stripSignature(b []byte) ([]byte, error) {
type blobStateCalculator (line 579) | type blobStateCalculator struct
method Write (line 591) | func (c *blobStateCalculator) Write(p []byte) (int, error) {
method State (line 603) | func (c *blobStateCalculator) State() blobState {
function newBlobStateCalculator (line 584) | func newBlobStateCalculator() *blobStateCalculator {
FILE: pkg/remote/remotes/docker/scope.go
function RepositoryScope (line 32) | func RepositoryScope(refspec reference.Spec, push bool) (string, error) {
type tokenScopesKey (line 46) | type tokenScopesKey struct
function ContextWithRepositoryScope (line 49) | func ContextWithRepositoryScope(ctx context.Context, refspec reference.S...
function WithScope (line 58) | func WithScope(ctx context.Context, scope string) context.Context {
function ContextWithAppendPullRepositoryScope (line 71) | func ContextWithAppendPullRepositoryScope(ctx context.Context, repo stri...
function GetTokenScopes (line 76) | func GetTokenScopes(ctx context.Context, common []string) []string {
FILE: pkg/remote/remotes/docker/scope_test.go
function TestRepositoryScope (line 27) | func TestRepositoryScope(t *testing.T) {
function TestGetTokenScopes (line 59) | func TestGetTokenScopes(t *testing.T) {
function TestCustomScope (line 103) | func TestCustomScope(t *testing.T) {
FILE: pkg/remote/remotes/docker/status.go
type Status (line 29) | type Status struct
type StatusTracker (line 42) | type StatusTracker interface
type StatusTrackLocker (line 48) | type StatusTrackLocker interface
type memoryStatusTracker (line 54) | type memoryStatusTracker struct
method GetStatus (line 68) | func (t *memoryStatusTracker) GetStatus(ref string) (Status, error) {
method SetStatus (line 78) | func (t *memoryStatusTracker) SetStatus(ref string, status Status) {
method Lock (line 84) | func (t *memoryStatusTracker) Lock(ref string) {
method Unlock (line 88) | func (t *memoryStatusTracker) Unlock(ref string) {
function NewInMemoryTracker (line 61) | func NewInMemoryTracker() StatusTrackLocker {
FILE: pkg/remote/remotes/errors/errors.go
type ErrUnexpectedStatus (line 28) | type ErrUnexpectedStatus struct
method Error (line 35) | func (e ErrUnexpectedStatus) Error() string {
function NewUnexpectedStatusErr (line 40) | func NewUnexpectedStatusErr(resp *http.Response) error {
FILE: pkg/remote/remotes/handlers.go
type refKeyPrefix (line 38) | type refKeyPrefix struct
function WithMediaTypeKeyPrefix (line 44) | func WithMediaTypeKeyPrefix(ctx context.Context, mediaType, prefix strin...
function MakeRefKey (line 59) | func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
function FetchHandler (line 92) | func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.Han...
function Fetch (line 114) | func Fetch(ctx context.Context, ingester content.Ingester, fetcher Fetch...
function PushHandler (line 158) | func PushHandler(pusher Pusher, provider content.Provider) images.Handle...
function push (line 171) | func push(ctx context.Context, provider content.Provider, pusher Pusher,...
function PushContent (line 209) | func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descri...
function SkipNonDistributableBlobs (line 279) | func SkipNonDistributableBlobs(f images.HandlerFunc) images.HandlerFunc {
function FilterManifestByPlatformHandler (line 312) | func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.M...
function annotateDistributionSourceHandler (line 347) | func annotateDistributionSourceHandler(f images.HandlerFunc, manager con...
FILE: pkg/remote/remotes/handlers_test.go
function TestContextCustomKeyPrefix (line 33) | func TestContextCustomKeyPrefix(t *testing.T) {
function TestSkipNonDistributableBlobs (line 81) | func TestSkipNonDistributableBlobs(t *testing.T) {
type memoryLabelStore (line 173) | type memoryLabelStore struct
method Get (line 184) | func (mls *memoryLabelStore) Get(d digest.Digest) (map[string]string, ...
method Set (line 192) | func (mls *memoryLabelStore) Set(d digest.Digest, labels map[string]st...
method Update (line 200) | func (mls *memoryLabelStore) Update(d digest.Digest, update map[string...
function newMemoryLabelStore (line 178) | func newMemoryLabelStore() local.LabelStore {
FILE: pkg/remote/remotes/resolver.go
type Resolver (line 29) | type Resolver interface
type Fetcher (line 56) | type Fetcher interface
type FetcherByDigest (line 62) | type FetcherByDigest interface
type ReferrersFetcher (line 71) | type ReferrersFetcher interface
type Pusher (line 76) | type Pusher interface
type FetcherFunc (line 84) | type FetcherFunc
method Fetch (line 87) | func (fn FetcherFunc) Fetch(ctx context.Context, desc ocispec.Descript...
type PusherFunc (line 93) | type PusherFunc
method Push (line 96) | func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor...
FILE: pkg/remote/unpack.go
function Unpack (line 20) | func Unpack(reader io.Reader, source, target string) error {
FILE: pkg/resolve/resolver.go
type Resolver (line 23) | type Resolver struct
method Resolve (line 34) | func (r *Resolver) Resolve(ref, digest string, labels map[string]strin...
function NewResolver (line 27) | func NewResolver() *Resolver {
function newRetryHTTPClient (line 71) | func newRetryHTTPClient(tr http.RoundTripper) *retryablehttp.Client {
FILE: pkg/signature/signature.go
type Verifier (line 20) | type Verifier struct
method Verify (line 50) | func (v *Verifier) Verify(label map[string]string, bootstrapFile strin...
function NewVerifier (line 25) | func NewVerifier(publicKeyFile string, validateSignature bool) (*Verifie...
function getFromLabel (line 73) | func getFromLabel(labels map[string]string) ([]byte, error) {
FILE: pkg/snapshot/storage.go
function GetSnapshotInfo (line 21) | func GetSnapshotInfo(ctx context.Context, ms *storage.MetaStore, key str...
function GetSnapshot (line 41) | func GetSnapshot(ctx context.Context, ms *storage.MetaStore, key string)...
function IterateParentSnapshots (line 63) | func IterateParentSnapshots(ctx context.Context, ms *storage.MetaStore, ...
function UpdateSnapshotInfo (line 92) | func UpdateSnapshotInfo(ctx context.Context, ms *storage.MetaStore, info...
FILE: pkg/stargz/resolver.go
constant httpTimeout (line 30) | httpTimeout = 15 * time.Second
constant FooterSize (line 33) | FooterSize = 47
constant TocFileName (line 34) | TocFileName = "stargz.index.json"
type Resolver (line 37) | type Resolver struct
method GetBlob (line 110) | func (r *Resolver) GetBlob(ref, digest string, keychain authn.Keychain...
method resolve (line 152) | func (r *Resolver) resolve(ref, digest string, keychain authn.Keychain...
function NewResolver (line 41) | func NewResolver() *Resolver {
type Blob (line 48) | type Blob struct
method GetTocOffset (line 55) | func (bb *Blob) GetTocOffset() (int64, error) {
method ReadToc (line 65) | func (bb *Blob) ReadToc() (io.Reader, error) {
method GetDigest (line 102) | func (bb *Blob) GetDigest() string {
method GetImageReference (line 106) | func (bb *Blob) GetImageReference() string {
type readerAtFunc (line 128) | type readerAtFunc
method ReadAt (line 130) | func (f readerAtFunc) ReadAt(p []byte, offset int64) (int, error) { re...
function parseFooter (line 133) | func parseFooter(p []byte) (tocOffset int64, ok bool) {
function getSize (line 205) | func getSize(url string, tr http.RoundTripper) (int64, error) {
FILE: pkg/stargz/resolver_test.go
function TestResolver_resolve (line 27) | func TestResolver_resolve(t *testing.T) {
type MockResolver (line 56) | type MockResolver struct
method Resolve (line 59) | func (res *MockResolver) Resolve(_ name.Reference, _ string, _ authn.K...
type mockRoundTripper (line 63) | type mockRoundTripper struct
method RoundTrip (line 65) | func (tr *mockRoundTripper) RoundTrip(req *http.Request) (*http.Respon...
FILE: pkg/store/daemonstore.go
type DaemonRafsStore (line 17) | type DaemonRafsStore struct
method AddDaemon (line 28) | func (s *DaemonRafsStore) AddDaemon(d *daemon.Daemon) error {
method UpdateDaemon (line 34) | func (s *DaemonRafsStore) UpdateDaemon(d *daemon.Daemon) error {
method DeleteDaemon (line 38) | func (s *DaemonRafsStore) DeleteDaemon(id string) error {
method WalkDaemons (line 42) | func (s *DaemonRafsStore) WalkDaemons(ctx context.Context, cb func(d *...
method CleanupDaemons (line 46) | func (s *DaemonRafsStore) CleanupDaemons(ctx context.Context) error {
method AddRafsInstance (line 50) | func (s *DaemonRafsStore) AddRafsInstance(r *rafs.Rafs) error {
method UpdateRafsInstance (line 54) | func (s *DaemonRafsStore) UpdateRafsInstance(r *rafs.Rafs) error {
method DeleteRafsInstance (line 58) | func (s *DaemonRafsStore) DeleteRafsInstance(snapshotID string) error {
method WalkRafsInstances (line 62) | func (s *DaemonRafsStore) WalkRafsInstances(ctx context.Context, cb fu...
method NextInstanceSeq (line 66) | func (s *DaemonRafsStore) NextInstanceSeq() (uint64, error) {
function NewDaemonRafsStore (line 21) | func NewDaemonRafsStore(db *Database) (*DaemonRafsStore, error) {
FILE: pkg/store/database.go
constant databaseFileName (line 27) | databaseFileName = "nydus.db"
type Database (line 48) | type Database struct
method initDatabase (line 142) | func (db *Database) initDatabase() error {
method Close (line 193) | func (db *Database) Close() error {
method SaveDaemon (line 202) | func (db *Database) SaveDaemon(_ context.Context, d *daemon.Daemon) er...
method UpdateDaemon (line 213) | func (db *Database) UpdateDaemon(_ context.Context, d *daemon.Daemon) ...
method DeleteDaemon (line 226) | func (db *Database) DeleteDaemon(_ context.Context, id string) error {
method CleanupDaemons (line 239) | func (db *Database) CleanupDaemons(_ context.Context) error {
method WalkDaemons (line 249) | func (db *Database) WalkDaemons(_ context.Context, cb func(info *daemo...
method WalkRafsInstances (line 266) | func (db *Database) WalkRafsInstances(_ context.Context, cb func(r *ra...
method AddRafsInstance (line 282) | func (db *Database) AddRafsInstance(_ context.Context, instance *rafs....
method UpdateRafsInstance (line 290) | func (db *Database) UpdateRafsInstance(_ context.Context, instance *ra...
method DeleteRafsInstance (line 298) | func (db *Database) DeleteRafsInstance(_ context.Context, snapshotID s...
method NextInstanceSeq (line 310) | func (db *Database) NextInstanceSeq() (uint64, error) {
function NewDatabase (line 53) | func NewDatabase(rootDir string) (*Database, error) {
function ensureDirectory (line 72) | func ensureDirectory(dir string) error {
function getDaemonsBucket (line 80) | func getDaemonsBucket(tx *bolt.Tx) *bolt.Bucket {
function getInstancesBucket (line 85) | func getInstancesBucket(tx *bolt.Tx) *bolt.Bucket {
function updateObject (line 90) | func updateObject(bucket *bolt.Bucket, key string, obj interface{}) error {
function putObject (line 105) | func putObject(bucket *bolt.Bucket, key string, obj interface{}) error {
function getObject (line 125) | func getObject(bucket *bolt.Bucket, key string, obj interface{}) error {
FILE: pkg/store/database_compat.go
constant SharedNydusDaemonID (line 26) | SharedNydusDaemonID = "shared_daemon"
type CompatDaemon (line 28) | type CompatDaemon struct
method WalkCompatDaemons (line 45) | func (db *Database) WalkCompatDaemons(_ context.Context, handler func(cd...
function RedirectInstanceConfig (line 66) | func RedirectInstanceConfig(newPath, oldPath string) error {
method tryTranslateRecords (line 91) | func (db *Database) tryTranslateRecords() error {
method tryUpgradeRecords (line 203) | func (db *Database) tryUpgradeRecords(version string) error {
FILE: pkg/store/database_test.go
function Test_daemon (line 21) | func Test_daemon(t *testing.T) {
function TestLegacyRecordsMultipleDaemonModes (line 77) | func TestLegacyRecordsMultipleDaemonModes(t *testing.T) {
function TestLegacyRecordsSharedDaemonModes (line 148) | func TestLegacyRecordsSharedDaemonModes(t *testing.T) {
function prepareCompatTestConfig (line 231) | func prepareCompatTestConfig(t *testing.T, rootDir, fsDriver string, dae...
function writeLegacyDatabase (line 245) | func writeLegacyDatabase(t *testing.T, rootDir string, records []*Compat...
function writeConfigFile (line 277) | func writeConfigFile(t *testing.T, file string, content []byte) {
function listDaemons (line 284) | func listDaemons(t *testing.T, db *Database) map[string]daemon.ConfigSta...
function listRafsInstances (line 297) | func listRafsInstances(t *testing.T, db *Database) map[string]rafs.Rafs {
FILE: pkg/supervisor/supervisor.go
type StatesStorage (line 30) | type StatesStorage interface
type MemStatesStorage (line 40) | type MemStatesStorage struct
method Save (line 50) | func (mss *MemStatesStorage) Save(data []byte) {
method Load (line 55) | func (mss *MemStatesStorage) Load() ([]byte, error) {
method Clean (line 61) | func (mss *MemStatesStorage) Clean() {
function newMemStatesStorage (line 44) | func newMemStatesStorage() *MemStatesStorage {
type Supervisor (line 66) | type Supervisor struct
method save (line 77) | func (su *Supervisor) save(data []byte, fd int) {
method load (line 95) | func (su *Supervisor) load() ([]byte, int, error) {
method waitStatesTimeout (line 186) | func (su *Supervisor) waitStatesTimeout(to time.Duration) (func() erro...
method SendStatesTimeout (line 251) | func (su *Supervisor) SendStatesTimeout(to time.Duration) error {
method FetchDaemonStates (line 316) | func (su *Supervisor) FetchDaemonStates(trigger func() error) error {
method Sock (line 344) | func (su *Supervisor) Sock() string {
function recv (line 107) | func recv(uc *net.UnixConn) ([]byte, int, error) {
function send (line 164) | func send(uc *net.UnixConn, data []byte, fd int) error {
type SupervisorsSet (line 350) | type SupervisorsSet struct
method NewSupervisor (line 367) | func (ss *SupervisorsSet) NewSupervisor(id string) *Supervisor {
method GetSupervisor (line 389) | func (ss *SupervisorsSet) GetSupervisor(id string) *Supervisor {
method DestroySupervisor (line 396) | func (ss *SupervisorsSet) DestroySupervisor(id string) error {
function NewSupervisorSet (line 357) | func NewSupervisorSet(root string) (*SupervisorsSet, error) {
FILE: pkg/supervisor/supervisor_test.go
function TestSupervisor (line 20) | func TestSupervisor(t *testing.T) {
function TestSupervisorTimeout (line 84) | func TestSupervisorTimeout(t *testing.T) {
FILE: pkg/system/system.go
constant endpointDaemons (line 40) | endpointDaemons string = "/api/v1/daemons"
constant endpointDaemonRecords (line 43) | endpointDaemonRecords string = "/api/v1/daemons/records"
constant endpointDaemonsUpgrade (line 44) | endpointDaemonsUpgrade string = "/api/v1/daemons/upgrade"
constant endpointPrefetch (line 45) | endpointPrefetch string = "/api/v1/prefetch"
constant endpointGetBackend (line 47) | endpointGetBackend string = "/api/v1/daemons/{id}/backend"
constant defaultErrorCode (line 50) | defaultErrorCode string = "Unknown"
type Controller (line 60) | type Controller struct
method Run (line 161) | func (sc *Controller) Run() error {
method registerRouter (line 188) | func (sc *Controller) registerRouter() {
method getBackend (line 196) | func (sc *Controller) getBackend() func(w http.ResponseWriter, r *http...
method setPrefetchConfiguration (line 236) | func (sc *Controller) setPrefetchConfiguration() func(w http.ResponseW...
method describeDaemons (line 250) | func (sc *Controller) describeDaemons() func(w http.ResponseWriter, r ...
method getDaemonRecords (line 303) | func (sc *Controller) getDaemonRecords() func(w http.ResponseWriter, r...
method upgradeDaemons (line 328) | func (sc *Controller) upgradeDaemons() func(w http.ResponseWriter, r *...
method upgradeNydusDaemon (line 382) | func (sc *Controller) upgradeNydusDaemon(d *daemon.Daemon, c upgradeRe...
type upgradeRequest (line 70) | type upgradeRequest struct
type errorMessage (line 76) | type errorMessage struct
method encode (line 85) | func (m *errorMessage) encode() string {
function newErrorMessage (line 81) | func newErrorMessage(message string) errorMessage {
function jsonResponse (line 94) | func jsonResponse(w http.ResponseWriter, payload interface{}) {
type daemonInfo (line 110) | type daemonInfo struct
type rafsInstanceInfo (line 124) | type rafsInstanceInfo struct
function NewSystemController (line 131) | func NewSystemController(fs *filesystem.Filesystem, managers []*manager....
function buildNextAPISocket (line 466) | func buildNextAPISocket(cur string) (string, error) {
function upgradeNydusdWithSymlink (line 492) | func upgradeNydusdWithSymlink(sourcePath, destinationPath string) error {
FILE: pkg/system/system_test.go
function TestBuildUpgradeSocket (line 15) | func TestBuildUpgradeSocket(t *testing.T) {
FILE: pkg/tarfs/tarfs.go
constant TarfsStatusInit (line 45) | TarfsStatusInit = 0
constant TarfsStatusPrepare (line 46) | TarfsStatusPrepare = 1
constant TarfsStatusReady (line 47) | TarfsStatusReady = 2
constant TarfsStatusFailed (line 48) | TarfsStatusFailed = 3
constant MaxManifestConfigSize (line 52) | MaxManifestConfigSize = 0x100000
constant TarfsLayerBootstrapName (line 53) | TarfsLayerBootstrapName = "layer.boot"
constant TarfsImageBootstrapName (line 54) | TarfsImageBootstrapName = "image.boot"
constant TarfsLayerDiskName (line 55) | TarfsLayerDiskName = "layer.disk"
constant TarfsImageDiskName (line 56) | TarfsImageDiskName = "image.disk"
type Manager (line 59) | type Manager struct
method fetchImageInfo (line 105) | func (t *Manager) fetchImageInfo(ctx context.Context, remote *remote.R...
method fetchImageManifest (line 129) | func (t *Manager) fetchImageManifest(ctx context.Context, remote *remo...
method fetchImageConfig (line 154) | func (t *Manager) fetchImageConfig(ctx context.Context, remote *remote...
method getBlobDiffID (line 180) | func (t *Manager) getBlobDiffID(ctx context.Context, remote *remote.Re...
method getBlobStream (line 199) | func (t *Manager) getBlobStream(ctx context.Context, remote *remote.Re...
method generateBootstrap (line 214) | func (t *Manager) generateBootstrap(tarReader io.Reader, snapshotID, l...
method getImageBlobInfo (line 284) | func (t *Manager) getImageBlobInfo(metaFilePath string) (string, error) {
method blobProcess (line 309) | func (t *Manager) blobProcess(ctx context.Context, wg *sync.WaitGroup,...
method PrepareLayer (line 391) | func (t *Manager) PrepareLayer(snapshotID, ref string, manifestDigest,...
method MergeLayers (line 411) | func (t *Manager) MergeLayers(s storage.Snapshot, storageLocater func(...
method ExportBlockData (line 465) | func (t *Manager) ExportBlockData(s storage.Snapshot, perLayer bool, l...
method MountTarErofs (line 573) | func (t *Manager) MountTarErofs(snapshotID string, s *storage.Snapshot...
method UmountTarErofs (line 665) | func (t *Manager) UmountTarErofs(snapshotID string) error {
method DetachLayer (line 683) | func (t *Manager) DetachLayer(snapshotID string) error {
method getSnapshotStatus (line 726) | func (t *Manager) getSnapshotStatus(snapshotID string, lock bool) (*sn...
method waitLayerReady (line 739) | func (t *Manager) waitLayerReady(snapshotID string) error {
method attachLoopdev (line 754) | func (t *Manager) attachLoopdev(blob string) (*losetup.Device, error) {
method CheckTarfsHintAnnotation (line 762) | func (t *Manager) CheckTarfsHintAnnotation(ctx context.Context, ref st...
method GetConcurrentLimiter (line 799) | func (t *Manager) GetConcurrentLimiter(ref string) *semaphore.Weighted {
method copyTarfsAnnotations (line 813) | func (t *Manager) copyTarfsAnnotations(labels map[string]string, rafs ...
method layerTarFilePath (line 827) | func (t *Manager) layerTarFilePath(blobID string) string {
method LayerDiskFilePath (line 831) | func (t *Manager) LayerDiskFilePath(blobID string) string {
method ImageDiskFilePath (line 835) | func (t *Manager) ImageDiskFilePath(blobID string) string {
method layerMetaFilePath (line 839) | func (t *Manager) layerMetaFilePath(upperDirPath string) string {
method imageMetaFilePath (line 843) | func (t *Manager) imageMetaFilePath(upperDirPath string) string {
type snapshotStatus (line 75) | type snapshotStatus struct
function NewManager (line 87) | func NewManager(insecure, checkTarfsHint bool, cacheDirPath, nydusImageP...
FILE: pkg/utils/display/display.go
function ByteToReadableIEC (line 11) | func ByteToReadableIEC(b uint32) string {
function MicroSecondToReadable (line 25) | func MicroSecondToReadable(b uint64) string {
FILE: pkg/utils/erofs/erofs.go
function Mount (line 18) | func Mount(domainID, fscacheID, mountpoint string) error {
function Umount (line 42) | func Umount(mountPoint string) error {
function FscacheID (line 46) | func FscacheID(snapshotID string) string {
FILE: pkg/utils/file/file.go
function IsDirExisted (line 11) | func IsDirExisted(path string) (bool, error) {
FILE: pkg/utils/mount/mount.go
type Interface (line 22) | type Interface interface
type Mounter (line 26) | type Mounter struct
method Umount (line 29) | func (m *Mounter) Umount(target string) error {
function NormalizePath (line 42) | func NormalizePath(path string) (realPath string, err error) {
function IsMountpoint (line 56) | func IsMountpoint(path string) (bool, error) {
function WaitUntilUnmounted (line 84) | func WaitUntilUnmounted(path string) error {
FILE: pkg/utils/parser/parser.go
function InitUnitMultipliers (line 22) | func InitUnitMultipliers() {
function MemoryConfigToBytes (line 38) | func MemoryConfigToBytes(data string, totalMemoryBytes int) (int64, erro...
FILE: pkg/utils/parser/parser_test.go
function TestMemoryLimitToBytes (line 15) | func TestMemoryLimitToBytes(t *testing.T) {
FILE: pkg/utils/registry/registry.go
type Image (line 25) | type Image struct
function ConvertToVPCHost (line 30) | func ConvertToVPCHost(registryHost string) string {
function ParseImage (line 39) | func ParseImage(imageID string) (Image, error) {
function ParseLabels (line 52) | func ParseLabels(labels map[string]string) (rRef, rDigest string) {
function AuthnTransport (line 62) | func AuthnTransport(ref name.Reference, tr http.RoundTripper, keychain a...
FILE: pkg/utils/registry/registry_test.go
function TestConvertToVPCHost1 (line 14) | func TestConvertToVPCHost1(t *testing.T) {
function TestParseImage (line 47) | func TestParseImage(t *testing.T) {
FILE: pkg/utils/retry/retry.go
type RetryableFunc (line 16) | type RetryableFunc
type retryIfFunc (line 29) | type retryIfFunc
type AbortFunc (line 31) | type AbortFunc
type OnRetryFunc (line 35) | type OnRetryFunc
type DelayTypeFunc (line 37) | type DelayTypeFunc
type Config (line 39) | type Config struct
type Option (line 51) | type Option
function LastErrorOnly (line 55) | func LastErrorOnly(lastErrorOnly bool) Option {
function Attempts (line 63) | func Attempts(attempts uint) Option {
function OnlyRetryIf (line 70) | func OnlyRetryIf(abortFunc AbortFunc) Option {
function Delay (line 83) | func Delay(delay time.Duration) Option {
function MaxDelay (line 91) | func MaxDelay(maxDelay time.Duration) Option {
function MaxJitter (line 98) | func MaxJitter(maxJitter time.Duration) Option {
function DelayType (line 106) | func DelayType(delayType DelayTypeFunc) Option {
function BackOffDelay (line 113) | func BackOffDelay(n uint, config *Config) time.Duration {
function FixedDelay (line 118) | func FixedDelay(_ uint, config *Config) time.Duration {
function RandomDelay (line 123) | func RandomDelay(_ uint, config *Config) time.Duration {
function CombineDelay (line 128) | func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc {
function OnRetry (line 138) | func OnRetry(onRetry OnRetryFunc) Option {
function Do (line 144) | func Do(retryFunc RetryableFunc, opts ...Option) error {
type Error (line 210) | type Error
method Error (line 214) | func (e Error) Error() string {
method WrappedErrors (line 239) | func (e Error) WrappedErrors() []error {
function lenWithoutNil (line 225) | func lenWithoutNil(e Error) (count int) {
type unrecoverableError (line 243) | type unrecoverableError struct
function Unrecoverable (line 248) | func Unrecoverable(err error) error {
function IsRecoverable (line 253) | func IsRecoverable(err error) bool {
function unpackUnrecoverable (line 258) | func unpackUnrecoverable(err error) error {
FILE: pkg/utils/signals/signal.go
function SetupSignalHandler (line 22) | func SetupSignalHandler() (stopCh <-chan struct{}) {
FILE: pkg/utils/signals/signal_test.go
function TestSetupSignalHandler (line 18) | func TestSetupSignalHandler(t *testing.T) {
FILE: pkg/utils/signer/signer.go
type Signer (line 18) | type Signer struct
method Verify (line 33) | func (s *Signer) Verify(input io.Reader, signature []byte) error {
function New (line 22) | func New(publicKey []byte) (*Signer, error) {
FILE: pkg/utils/sysinfo/sysinfo.go
function GetSysinfo (line 20) | func GetSysinfo() {
function GetTotalMemoryBytes (line 31) | func GetTotalMemoryBytes() (int, error) {
FILE: pkg/utils/transport/pool.go
constant HTTPClientTimeOut (line 21) | HTTPClientTimeOut = time.Second * 60
type Pool (line 24) | type Pool struct
method Resolve (line 42) | func (r *Pool) Resolve(ref name.Reference, digest string, keychain aut...
function NewPool (line 30) | func NewPool() *Pool {
type Resolve (line 38) | type Resolve interface
function redirect (line 71) | func redirect(endpointURL string, tr http.RoundTripper) (url string, err...
FILE: pkg/utils/transport/pool_test.go
type FakeReference (line 14) | type FakeReference struct
method Context (line 21) | func (t FakeReference) Context() name.Repository {
method Identifier (line 25) | func (t FakeReference) Identifier() string {
method Name (line 29) | func (t FakeReference) Name() string {
method String (line 33) | func (t FakeReference) String() string {
method Scope (line 37) | func (t FakeReference) Scope(action string) string {
function TestResolve (line 41) | func TestResolve(t *testing.T) {
FILE: snapshot/mount_option.go
constant KataVirtualVolumeDefaultSource (line 31) | KataVirtualVolumeDefaultSource = "overlay"
constant KataVirtualVolumeDummySource (line 32) | KataVirtualVolumeDummySource = "dummy-image-reference"
type ExtraOption (line 35) | type ExtraOption struct
method remoteMountWithExtraOptions (line 42) | func (o *snapshotter) remoteMountWithExtraOptions(ctx context.Context, s...
method mountWithKataVolume (line 117) | func (o *snapshotter) mountWithKataVolume(ctx context.Context, id string...
method mountWithProxyVolume (line 170) | func (o *snapshotter) mountWithProxyVolume(rafs rafs.Rafs) ([]string, er...
method mountWithTarfsVolume (line 193) | func (o *snapshotter) mountWithTarfsVolume(ctx context.Context, rafs raf...
method prepareKataVirtualVolume (line 250) | func (o *snapshotter) prepareKataVirtualVolume(blockType, source, volume...
function parseTarfsDmVerityInfo (line 282) | func parseTarfsDmVerityInfo(info string) (DmVerityInfo, error) {
constant minBlockSize (line 307) | minBlockSize = 1 << 9
constant maxBlockSize (line 308) | maxBlockSize = 1 << 19
constant KataVirtualVolumeOptionName (line 312) | KataVirtualVolumeOptionName = "io.katacontainers.volume"
constant KataVirtualVolumeDirectBlockType (line 313) | KataVirtualVolumeDirectBlockType = "direct_block"
constant KataVirtualVolumeImageRawBlockType (line 314) | KataVirtualVolumeImageRawBlockType = "image_raw_block"
constant KataVirtualVolumeLayerRawBlockType (line 315) | KataVirtualVolumeLayerRawBlockType = "layer_raw_block"
constant KataVirtualVolumeImageNydusBlockType (line 316) | KataVirtualVolumeImageNydusBlockType = "image_nydus_block"
constant KataVirtualVolumeLayerNydusBlockType (line 317) | KataVirtualVolumeLayerNydusBlockType = "layer_nydus_block"
constant KataVirtualVolumeImageNydusFsType (line 318) | KataVirtualVolumeImageNydusFsType = "image_nydus_fs"
constant KataVirtualVolumeLayerNydusFsType (line 319) | KataVirtualVolumeLayerNydusFsType = "layer_nydus_fs"
constant KataVirtualVolumeImageGuestPullType (line 320) | KataVirtualVolumeImageGuestPullType = "image_guest_pull"
type DmVerityInfo (line 324) | type DmVerityInfo struct
method Validate (line 333) | func (d *DmVerityInfo) Validate() error {
method validateHashType (line 354) | func (d *DmVerityInfo) validateHashType() error {
method validateHash (line 365) | func (d *DmVerityInfo) validateHash(expectedLen int, hashType string) ...
function validateBlockSize (line 373) | func validateBlockSize(blockSize uint64) bool {
function ParseDmVerityInfo (line 377) | func ParseDmVerityInfo(option string) (*DmVerityInfo, error) {
type DirectAssignedVolume (line 389) | type DirectAssignedVolume struct
method Validate (line 393) | func (d *DirectAssignedVolume) Validate() bool {
type ImagePullVolume (line 398) | type ImagePullVolume struct
method Validate (line 402) | func (i *ImagePullVolume) Validate() bool {
type NydusImageVolume (line 407) | type NydusImageVolume struct
method Validate (line 412) | func (n *NydusImageVolume) Validate() bool {
type KataVirtualVolume (line 417) | type KataVirtualVolume struct
method Validate (line 428) | func (k *KataVirtualVolume) Validate() bool {
function ParseKataVirtualVolume (line 451) | func ParseKataVirtualVolume(option []byte) (*KataVirtualVolume, error) {
function ParseKataVirtualVolumeFromBase64 (line 463) | func ParseKataVirtualVolumeFromBase64(option string) (*KataVirtualVolume...
function EncodeKataVirtualVolumeToBase64 (line 471) | func EncodeKataVirtualVolumeToBase64(volume KataVirtualVolume) (string, ...
FILE: snapshot/mount_option_test.go
function TestDmVerityInfoValidation (line 11) | func TestDmVerityInfoValidation(t *testing.T) {
function TestDirectAssignedVolumeValidation (line 117) | func TestDirectAssignedVolumeValidation(t *testing.T) {
function TestImagePullVolumeValidation (line 129) | func TestImagePullVolumeValidation(t *testing.T) {
function TestNydusImageVolumeValidation (line 141) | func TestNydusImageVolumeValidation(t *testing.T) {
function TestKataVirtualVolumeValidation (line 155) | func TestKataVirtualVolumeValidation(t *testing.T) {
function TestParseDmVerityInfo (line 180) | func TestParseDmVerityInfo(t *testing.T) {
function TestParseKataVirtualVolume (line 206) | func TestParseKataVirtualVolume(t *testing.T) {
FILE: snapshot/process.go
function chooseProcessor (line 26) | func chooseProcessor(ctx context.Context, logger *logrus.Entry,
FILE: snapshot/renewal.go
function startCredentialRenewal (line 23) | func startCredentialRenewal(ctx context.Context, interval time.Duration,...
function credentialRenewalLoop (line 33) | func credentialRenewalLoop(ctx context.Context, interval time.Duration, ...
function reconcileCredentials (line 56) | func reconcileCredentials(ctx context.Context, managers []*mgr.Manager) {
FILE: snapshot/renewal_test.go
function TestStartCredentialRenewalLifecycle (line 20) | func TestStartCredentialRenewalLifecycle(t *testing.T) {
FILE: snapshot/snapshot.go
type snapshotter (line 54) | type snapshotter struct
method Cleanup (line 320) | func (o *snapshotter) Cleanup(ctx context.Context) error {
method Stat (line 361) | func (o *snapshotter) Stat(ctx context.Context, key string) (snapshots...
method Update (line 366) | func (o *snapshotter) Update(ctx context.Context, info snapshots.Info,...
method Usage (line 370) | func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot...
method Mounts (line 403) | func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount...
method Prepare (line 495) | func (o *snapshotter) Prepare(ctx context.Context, key, parent string,...
method View (line 531) | func (o *snapshotter) View(ctx context.Context, key, parent string, op...
method Commit (line 592) | func (o *snapshotter) Commit(ctx context.Context, name, key string, op...
method Remove (line 636) | func (o *snapshotter) Remove(ctx context.Context, key string) error {
method Walk (line 700) | func (o *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc,...
method Close (line 714) | func (o *snapshotter) Close() error {
method upperPath (line 735) | func (o *snapshotter) upperPath(id string) string {
method lowerPath (line 740) | func (o *snapshotter) lowerPath(id string) (mnt string, err error) {
method workPath (line 750) | func (o *snapshotter) workPath(id string) string {
method findIndexAlternativeLayer (line 754) | func (o *snapshotter) findIndexAlternativeLayer(ctx context.Context, k...
method findReferrerLayer (line 760) | func (o *snapshotter) findReferrerLayer(ctx context.Context, key strin...
method findMetaLayer (line 766) | func (o *snapshotter) findMetaLayer(ctx context.Context, key string) (...
method createSnapshot (line 772) | func (o *snapshotter) createSnapshot(ctx context.Context, kind snapsho...
method createSnapshotWithRecovery (line 781) | func (o *snapshotter) createSnapshotWithRecovery(ctx context.Context, ...
method isMissingParentError (line 891) | func (o *snapshotter) isMissingParentError(err error) bool {
method recoverParentFromContainerd (line 906) | func (o *snapshotter) recoverParentFromContainerd(ctx context.Context,...
method createPlaceholderSnapshot (line 931) | func (o *snapshotter) createPlaceholderSnapshot(ctx context.Context, k...
method mergeTarfs (line 1005) | func (o *snapshotter) mergeTarfs(ctx context.Context, s storage.Snapsh...
method mountProxy (line 1049) | func (o *snapshotter) mountProxy(ctx context.Context, s storage.Snapsh...
method mountRemote (line 1101) | func (o *snapshotter) mountRemote(ctx context.Context, labels map[stri...
method mountNative (line 1157) | func (o *snapshotter) mountNative(ctx context.Context, labels map[stri...
method prepareDirectory (line 1193) | func (o *snapshotter) prepareDirectory(snapshotDir string, kind snapsh...
method getCleanupDirectories (line 1212) | func (o *snapshotter) getCleanupDirectories(ctx context.Context) ([]st...
method cleanupDirectories (line 1246) | func (o *snapshotter) cleanupDirectories(ctx context.Context) ([]strin...
method cleanupSnapshotDirectory (line 1263) | func (o *snapshotter) cleanupSnapshotDirectory(ctx context.Context, di...
method getUnusedCacheBlobs (line 1284) | func (o *snapshotter) getUnusedCacheBlobs(ctx context.Context) ([]stri...
method snapshotRoot (line 1363) | func (o *snapshotter) snapshotRoot() string {
method snapshotDir (line 1367) | func (o *snapshotter) snapshotDir(id string) string {
function NewSnapshotter (line 68) | func NewSnapshotter(ctx context.Context, cfg *config.SnapshotterConfig) ...
function bindMount (line 1025) | func bindMount(source, roFlag string) []mount.Mount {
function overlayMount (line 1038) | func overlayMount(options []string) []mount.Mount {
function treatAsProxyDriver (line 1371) | func treatAsProxyDriver(labels map[string]string) bool {
FILE: snapshot/snapshot_test.go
function TestMountNative (line 23) | func TestMountNative(t *testing.T) {
function TestMountNativeConfigVolatile (line 228) | func TestMountNativeConfigVolatile(t *testing.T) {
FILE: snapshot/utils.go
function getSupportsDType (line 16) | func getSupportsDType(dir string) (bool, error) {
function lchown (line 20) | func lchown(target string, st os.FileInfo) error {
FILE: tests/converter_test.go
constant envNydusdPath (line 49) | envNydusdPath = "NYDUS_NYDUSD"
function hugeString (line 91) | func hugeString(mb int) string {
function dropCache (line 113) | func dropCache(t *testing.T) {
function ensureFile (line 120) | func ensureFile(t *testing.T, name string) {
function ensureNoFile (line 125) | func ensureNoFile(t *testing.T, name string) {
function writeFileToTar (line 130) | func writeFileToTar(t *testing.T, tw *tar.Writer, name string, data stri...
function writeDirToTar (line 151) | func writeDirToTar(t *testing.T, tw *tar.Writer, name string) {
function writeToFile (line 168) | func writeToFile(t *testing.T, reader io.Reader, fileName string) {
function buildChunkDictTar (line 177) | func buildChunkDictTar(t *testing.T, n int) io.ReadCloser {
function buildOCILowerTar (line 196) | func buildOCILowerTar(t *testing.T, n int) (io.ReadCloser, map[string]st...
function buildOCIUpperTar (line 225) | func buildOCIUpperTar(t *testing.T, teePath string, lowerFileTree map[st...
function packLayer (line 276) | func packLayer(t *testing.T, source io.ReadCloser, chunkDict, workDir st...
function packLayerRef (line 302) | func packLayerRef(t *testing.T, gzipSource io.ReadCloser, workDir string...
function unpackLayer (line 338) | func unpackLayer(t *testing.T, workDir string, ra content.ReaderAt, stre...
function verify (line 358) | func verify(t *testing.T, workDir string, expectedFileTree map[string]st...
function buildChunkDict (line 420) | func buildChunkDict(t *testing.T, workDir, fsVersion string, n int) (str...
function TestPack (line 459) | func TestPack(t *testing.T) {
function testPack (line 464) | func testPack(t *testing.T, fsVersion string) {
function TestPackRef (line 531) | func TestPackRef(t *testing.T) {
function TestUnpack (line 607) | func TestUnpack(t *testing.T) {
function testUnpack (line 612) | func testUnpack(t *testing.T, fsVersion string, tarSize int) {
type ConvertTestOption (line 637) | type ConvertTestOption struct
type ReConvertTestOption (line 648) | type ReConvertTestOption struct
function TestImageConvert (line 657) | func TestImageConvert(t *testing.T) {
function testImageConvertNoBackend (line 665) | func testImageConvertNoBackend(t *testing.T, fsVersion string) {
function testImageConvertS3Backend (line 672) | func testImageConvertS3Backend(t *testing.T, fsVersion string) {
function testImageConvertWithCrypt (line 735) | func testImageConvertWithCrypt(t *testing.T, fsVersion string) {
function testImageConvertBasic (line 773) | func testImageConvertBasic(testOpt *ConvertTestOption) {
function TestImageReConvert (line 890) | func TestImageReConvert(t *testing.T) {
function testImageReConvertNoBackend (line 894) | func testImageReConvertNoBackend(t *testing.T) {
function testImageReConvertBasic (line 900) | func testImageReConvertBasic(testOpt *ReConvertTestOption) {
FILE: tests/nydusd.go
type NydusdConfig (line 25) | type NydusdConfig struct
type Nydusd (line 40) | type Nydusd struct
method Mount (line 155) | func (nydusd *Nydusd) Mount() error {
method Umount (line 200) | func (nydusd *Nydusd) Umount() error {
type daemonInfo (line 44) | type daemonInfo struct
function makeConfig (line 75) | func makeConfig(conf NydusdConfig) error {
function checkReady (line 91) | func checkReady(ctx context.Context, sock string) <-chan bool {
function NewNydusd (line 146) | func NewNydusd(conf NydusdConfig) (*Nydusd, error) {
FILE: tools/optimizer-server/src/main.rs
type FanotifyEvent (line 30) | struct FanotifyEvent {
type EventInfo (line 41) | struct EventInfo {
method eq (line 48) | fn eq(&self, target: &EventInfo) -> bool {
constant DEFAULT_TARGET (line 58) | const DEFAULT_TARGET: &str = "/";
constant FAN_CLOEXEC (line 60) | const FAN_CLOEXEC: u32 = 0x0000_0001;
constant FAN_NONBLOCK (line 61) | const FAN_NONBLOCK: u32 = 0x0000_0002;
constant FAN_CLASS_CONTENT (line 62) | const FAN_CLASS_CONTENT: u32 = 0x0000_0004;
constant O_RDONLY (line 64) | const O_RDONLY: u32 = 0;
constant O_LARGEFILE (line 65) | const O_LARGEFILE: u32 = 0;
constant FAN_MARK_ADD (line 67) | const FAN_MARK_ADD: u32 = 0x0000_0001;
constant FAN_MARK_MOUNT (line 68) | const FAN_MARK_MOUNT: u32 = 0x0000_0010;
constant FAN_ACCESS (line 70) | const FAN_ACCESS: u64 = 0x0000_0001;
constant FAN_OPEN (line 71) | const FAN_OPEN: u64 = 0x0000_0020;
constant FAN_OPEN_EXEC (line 72) | const FAN_OPEN_EXEC: u64 = 0x00001000;
constant AT_FDCWD (line 73) | const AT_FDCWD: i32 = -100;
type SetnsError (line 77) | enum SetnsError {
type SendError (line 84) | enum SendError {
function get_pid (line 89) | fn get_pid() -> Option<String> {
function get_target (line 93) | fn get_target() -> String {
function get_fd_path (line 97) | fn get_fd_path(fd: i32) -> io::Result<PathBuf> {
function set_ns (line 102) | fn set_ns(ns_path: String, flags: CloneFlags) -> Result<(), SetnsError> {
function init_fanotify (line 107) | fn init_fanotify() -> Result<i32, io::Error> {
function mark_fanotify (line 119) | fn mark_fanotify(fd: i32, path: &str) -> Result<(), io::Error> {
function read_fanotify (line 135) | fn read_fanotify(fanotify_fd: i32) -> Vec<FanotifyEvent> {
function close_fd (line 150) | fn close_fd(fd: i32) {
function generate_event_info (line 156) | fn generate_event_info(path: &Path) -> Result<EventInfo, io::Error> {
function send_event (line 164) | fn send_event(event: &EventInfo) -> Result<(), SendError> {
function handle_event (line 173) | fn handle_event(event: &FanotifyEvent, event_duplicate: &mut Vec<String>...
function handle_fanotify_event (line 183) | fn handle_fanotify_event(fd: i32) {
function start_fanotify (line 240) | fn start_fanotify() -> Result<(), io::Error> {
function join_namespace (line 247) | fn join_namespace(pid: String) -> Result<(), SetnsError> {
function main (line 253) | fn main() {
Condensed preview — 271 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,832K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 2457,
"preview": "name: Bug report\ntitle: \"[Bug] Bug title\"\ndescription: Problems and issues with code of nydus-snapshotter\nlabels: [ \"bug"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yml",
"chars": 1404,
"preview": "name: Feature request\ndescription: Suggest an idea for nydus-snapshotter\ntitle: \"[Feature] Feature title\"\nlabels: [ \"fea"
},
{
"path": ".github/ISSUE_TEMPLATE/improvement-report.yml",
"chars": 1656,
"preview": "name: Improvement Report\ndescription: Suggest an improvement to an existing feature or process.\ntitle: \"[Improvement] Im"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 932,
"preview": "## Overview\n_Please briefly describe the changes your pull request makes._\n\n## Related Issues\n_Please link to the releva"
},
{
"path": ".github/codecov.yml",
"chars": 654,
"preview": "coverage:\n status:\n patch: off\n project:\n default:\n enabled: yes\n target: auto # auto compares"
},
{
"path": ".github/workflows/ci.yml",
"chars": 4027,
"preview": "name: CI\n\non:\n push:\n branches: [\"**\", \"stable/**\"]\n pull_request:\n branches: [\"**\", \"stable/**\"]\n\nenv:\n CARGO_"
},
{
"path": ".github/workflows/e2e.yml",
"chars": 1760,
"preview": "name: integration test\n\non:\n push:\n branches:\n - \"main\"\n tags:\n - v[0-9]+.[0-9]+.[0-9]+\n pull_request:"
},
{
"path": ".github/workflows/k8s-e2e-run.yml",
"chars": 458,
"preview": "name: E2E Test With Kubernetes\n\non:\n push:\n branches:\n - \"main\"\n tags:\n - v[0-9]+.[0-9]+.[0-9]+\n pull_"
},
{
"path": ".github/workflows/k8s-e2e.yml",
"chars": 2442,
"preview": "name: E2E Test With Kubernetes Template\n\non:\n workflow_call:\n inputs:\n auth-type:\n required: true\n "
},
{
"path": ".github/workflows/optimizer.yml",
"chars": 4209,
"preview": "name: optimizer test\n\non:\n push:\n branches:\n - \"main\"\n tags:\n - v[0-9]+.[0-9]+.[0-9]+\n pull_request:\n "
},
{
"path": ".github/workflows/release.yml",
"chars": 6153,
"preview": "name: release\n\non:\n push:\n tags:\n - v[0-9]+.[0-9]+.[0-9]+*\n\nenv:\n CARGO_TERM_COLOR: always\n REGISTRY: ghcr.io"
},
{
"path": ".gitignore",
"chars": 142,
"preview": "bin/\npkg/filesystem/stargz/testdata/db/\ncoverage.txt\n.vscode/\ntests/output/\nsmoke.tests\ntools/optimizer-server/target\nve"
},
{
"path": ".golangci.yml",
"chars": 2945,
"preview": "# https://golangci-lint.run/usage/configuration#config-file\n\nversion: \"2\"\n\nrun:\n concurrency: 4\n timeout: 5m\n issues-"
},
{
"path": "LICENSE",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "MAINTAINERS",
"chars": 674,
"preview": "# nydus-snapshotter maintainers\n#\n# As a containerd sub-project, containerd maintainers are also included from https://g"
},
{
"path": "Makefile",
"chars": 7649,
"preview": "all: clean build\noptimizer: clean-optimizer build-optimizer\n\nPKG = github.com/containerd/nydus-snapshotter\nPACKAGES ?= $"
},
{
"path": "README.md",
"chars": 10681,
"preview": "[**[⬇️ Download]**](https://github.com/containerd/nydus-snapshotter/releases)\n[**[📖 Website]**](https://nydus.dev/)\n[**["
},
{
"path": "cmd/containerd-nydus-grpc/main.go",
"chars": 3967,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "cmd/containerd-nydus-grpc/snapshotter.go",
"chars": 3708,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "cmd/converter/main.go",
"chars": 224,
"preview": "package main\n\n// Import the converter package so that it can be compiled during\n// `go build` to ensure cross-compilatio"
},
{
"path": "cmd/nydus-overlayfs/main.go",
"chars": 7156,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/urfave/c"
},
{
"path": "cmd/nydus-overlayfs/main_test.go",
"chars": 6054,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "cmd/optimizer-nri-plugin/main.go",
"chars": 7273,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "cmd/prefetchfiles-nri-plugin/main.go",
"chars": 5073,
"preview": "/*\n* Copyright (c) 2023. Nydus Developers. All rights reserved.\n*\n* SPDX-License-Identifier: Apache-2.0\n */\n\npackage mai"
},
{
"path": "config/config.go",
"chars": 14962,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "config/config_test.go",
"chars": 9024,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/daemonconfig/daemonconfig.go",
"chars": 9425,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "config/daemonconfig/daemonconfig_test.go",
"chars": 4559,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage daemonc"
},
{
"path": "config/daemonconfig/fscache.go",
"chars": 3124,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/daemonconfig/fuse.go",
"chars": 2890,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/daemonconfig/mirror_select_test.go",
"chars": 4316,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/daemonconfig/mirrors.go",
"chars": 7059,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/daemonconfig/mirrors_test.go",
"chars": 5459,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/default.go",
"chars": 2151,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "config/global.go",
"chars": 5626,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Expos"
},
{
"path": "docs/configure_nydus.md",
"chars": 1761,
"preview": "# Configure Nydus-snapshotter\n\nNydus-snapshotter can receive a toml file as its configurations to start providing image "
},
{
"path": "docs/crictl_dry_run.md",
"chars": 1127,
"preview": "# Start Container by crictl\n\n## Create crictl Config\n\nThe runtime endpoint can be set in the config file. Please refer t"
},
{
"path": "docs/index_detection.md",
"chars": 3679,
"preview": "# Index Detection\n\n## Overview\n\nIndex Detection is a feature that automatically discovers Nydus alternative manifests wi"
},
{
"path": "docs/optimize_nydus_image.md",
"chars": 5166,
"preview": "# Optimize a nydus image\n\nTo improve the prefetch hit rate, we can specify a prefetch table when converting an OCI image"
},
{
"path": "docs/registry_authentication.md",
"chars": 10406,
"preview": "# Registry Authentication\n\nAs [containerd#3731](https://github.com/containerd/containerd/issues/3731) discussed, contain"
},
{
"path": "docs/run_nydus_in_kubernetes.md",
"chars": 4728,
"preview": "# Run Dragonfly & Nydus in Kubernetes\n\nWe recommend using the Dragonfly P2P data distribution system to further improve "
},
{
"path": "docs/setup_snapshotter_by_daemonset.md",
"chars": 7558,
"preview": "# Setup Nydus Snapshotter by DaemonSet\n\nThis document will guide you through the simple steps of setting up and cleaning"
},
{
"path": "docs/tarfs.md",
"chars": 11135,
"preview": "# Nydus Tarfs Mode\n\n`Nydus Tarfs Mode` or `Tarfs` is a working mode for Nydus Image, which uses tar files as Nydus data "
},
{
"path": "export/snapshotter/snapshotter.go",
"chars": 1153,
"preview": "package snapshotter\n\nimport (\n\t\"github.com/containerd/containerd/v2/plugins\"\n\t\"github.com/containerd/platforms\"\n\t\"github"
},
{
"path": "go.mod",
"chars": 8466,
"preview": "module github.com/containerd/nydus-snapshotter\n\ngo 1.25.9\n\nrequire (\n\tdario.cat/mergo v1.0.1\n\tgithub.com/AdaLogics/go-fu"
},
{
"path": "go.sum",
"chars": 48330,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ndario.cat/mergo v1.0.1 h1:Ra4+bf83h2z"
},
{
"path": "integration/Dockerfile",
"chars": 2886,
"preview": "ARG CONTAINERD_VER=2.0.0-rc.3\nARG CONTAINERD_PROJECT=/containerd\nARG RUNC_VER=1.1.4\nARG NYDUS_SNAPSHOTTER_PROJECT=/nydus"
},
{
"path": "integration/entrypoint.sh",
"chars": 17823,
"preview": "#!/bin/bash\n\n# Copyright (c) 2022. Nydus Developers. All rights reserved.\n#\n# SPDX-License-Identifier: Apache-2.0\n\nset -"
},
{
"path": "internal/constant/values.go",
"chars": 2028,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// const"
},
{
"path": "internal/flags/flags.go",
"chars": 3461,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "internal/flags/flags_test.go",
"chars": 640,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage flags\n\n"
},
{
"path": "internal/logging/setup.go",
"chars": 1707,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n"
},
{
"path": "internal/logging/setup_test.go",
"chars": 1562,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "misc/example/10-containerd-net.conflist",
"chars": 444,
"preview": "{\n \"cniVersion\": \"1.0.0\",\n \"name\": \"containerd-net\",\n \"plugins\": [\n {\n \"type\": \"bridge\",\n \"bridge\": \"cni"
},
{
"path": "misc/example/README.md",
"chars": 3089,
"preview": "## Example to setup and test nydus-snapshotter\n\nThe directory holds a few example config files to setup a nydus POC envi"
},
{
"path": "misc/example/container.yaml",
"chars": 159,
"preview": "metadata:\n name: foobar-container\nimage:\n image: ghcr.io/dragonflyoss/image-service/ubuntu:nydus-latest\ncommand: [\"tai"
},
{
"path": "misc/example/containerd-config.toml",
"chars": 776,
"preview": "version = 2\nroot = \"/var/lib/containerd\"\nstate = \"/run/containerd\"\noom_score = 0\n\n[debug]\n level = \"debug\"\n\n[plugins.\"i"
},
{
"path": "misc/example/containerd-test-config.toml",
"chars": 882,
"preview": "version = 2\nroot = \"/var/lib/containerd-test\"\nstate = \"/run/containerd-test\"\noom_score = 0\n\n[grpc]\n address = \"/run/con"
},
{
"path": "misc/example/crictl.yaml",
"chars": 62,
"preview": "runtime-endpoint: unix:///run/containerd-test/containerd.sock\n"
},
{
"path": "misc/example/optimizer-nri-plugin.conf",
"chars": 516,
"preview": "# The directory to persist accessed files list for container.\npersist_dir = \"/opt/nri/optimizer/results\"\n# Whether to ma"
},
{
"path": "misc/example/pod.yaml",
"chars": 116,
"preview": "metadata:\n attempt: 1\n name: foobar\n namespace: default\nlog_directory: /tmp\nlinux:\n namespaces:\n options: {}\n"
},
{
"path": "misc/nri-prefetch/prefetchConfig.toml",
"chars": 138,
"preview": "[file_prefetch]\n# This is used to configure the socket address for the file prefetch.\nsocket_address = \"/run/containerd-"
},
{
"path": "misc/optimizer/containerd-config.toml",
"chars": 900,
"preview": "# Copyright 2018-2022 Docker Inc.\n\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not"
},
{
"path": "misc/optimizer/crictl.yaml",
"chars": 164,
"preview": "runtime-endpoint: unix:///run/containerd/containerd.sock\nimage-endpoint: unix:////run/containerd/containerd.sock\ntimeout"
},
{
"path": "misc/optimizer/nginx.yaml",
"chars": 213,
"preview": "metadata:\n name: nginx\n\nimage:\n image: nginx:1.23.3\n\nmounts:\n - host_path: script\n container_path: /script\n\ncomman"
},
{
"path": "misc/optimizer/sandbox.yaml",
"chars": 128,
"preview": "metadata:\n name: nginx-sandbox\n namespace: default\n attempt: 1\n uid: hdishd83djaidwnduwk28bcsb\nlog_directory: /tmp\nl"
},
{
"path": "misc/optimizer/script/entrypoint.sh",
"chars": 385,
"preview": "#!/usr/bin/env bash\n\npath=$1\n\ndefault_path=file_list_path.txt\nif [[ $# -eq 0 ]]; then\n path=${default_path}\nfi\n\nfiles"
},
{
"path": "misc/optimizer/script/file_list.txt",
"chars": 484,
"preview": "/lib/x86_64-linux-gnu/ld-2.31.so\n/lib/x86_64-linux-gnu/libc-2.31.so\n/lib/x86_64-linux-gnu/libtinfo.so.6.2\n/lib/x86_64-li"
},
{
"path": "misc/snapshotter/Dockerfile",
"chars": 1928,
"preview": "FROM alpine:3.17.0 AS base\n\nFROM base AS sourcer\nARG TARGETARCH\nARG NYDUS_VER=v2.3.0\n\nRUN apk add -q --no-cache curl && "
},
{
"path": "misc/snapshotter/base/kustomization.yaml",
"chars": 101,
"preview": "resources:\n- nydus-snapshotter.yaml\napiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\n\n"
},
{
"path": "misc/snapshotter/base/nydus-snapshotter.yaml",
"chars": 3939,
"preview": "---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: nydus-snapshotter-configs\n labels:\n app: nydus-snapshotter\n na"
},
{
"path": "misc/snapshotter/config-blockdev.toml",
"chars": 1515,
"preview": "version = 1\n# Snapshotter's own home directory where it stores and creates necessary resources\nroot = \"/var/lib/containe"
},
{
"path": "misc/snapshotter/config-proxy.toml",
"chars": 496,
"preview": "version = 1\n# Snapshotter's own home directory where it stores and creates necessary resources\nroot = \"/var/lib/containe"
},
{
"path": "misc/snapshotter/config.toml",
"chars": 6779,
"preview": "version = 1\n# Snapshotter's own home directory where it stores and creates necessary resources\nroot = \"/var/lib/containe"
},
{
"path": "misc/snapshotter/nydus-snapshotter-rbac.yaml",
"chars": 655,
"preview": "---\napiVersion: v1\nkind: Namespace\nmetadata:\n name: nydus-system\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n na"
},
{
"path": "misc/snapshotter/nydus-snapshotter.fscache.service",
"chars": 431,
"preview": "[Unit]\nDescription=nydus snapshotter\nAfter=network.target\nBefore=containerd.service\n\n[Service]\nType=simple\nEnvironment=H"
},
{
"path": "misc/snapshotter/nydus-snapshotter.fusedev.service",
"chars": 357,
"preview": "[Unit]\nDescription=nydus snapshotter\nAfter=network.target\nBefore=containerd.service\n\n[Service]\nType=simple\nEnvironment=H"
},
{
"path": "misc/snapshotter/nydus-snapshotter.service",
"chars": 363,
"preview": "[Unit]\nDescription=nydus snapshotter\nAfter=network.target\nBefore=containerd.service\n\n[Service]\nType=simple\nEnvironment=H"
},
{
"path": "misc/snapshotter/nydusd-config-localfs.json",
"chars": 412,
"preview": "{\n \"device\": {\n \"backend\": {\n \"type\": \"localfs\",\n \"config\": {\n \"dir\": \"/var/lib/containerd/io.conta"
},
{
"path": "misc/snapshotter/nydusd-config.fscache.json",
"chars": 285,
"preview": "{\n \"type\": \"bootstrap\",\n \"config\": {\n \"backend_type\": \"registry\",\n \"backend_config\": {},\n \"ca"
},
{
"path": "misc/snapshotter/nydusd-config.fusedev.json",
"chars": 467,
"preview": "{\n \"device\": {\n \"backend\": {\n \"type\": \"registry\",\n \"config\": {\n \"timeout\": 5,\n \"connect_time"
},
{
"path": "misc/snapshotter/overlays/k3s/kustomization.yaml",
"chars": 125,
"preview": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nresources:\n- ../../base\npatches:\n- path: mount_k3s_conf."
},
{
"path": "misc/snapshotter/overlays/k3s/mount_k3s_conf.yaml",
"chars": 254,
"preview": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n name: nydus-snapshotter\n namespace: nydus-system\nspec:\n template:\n "
},
{
"path": "misc/snapshotter/overlays/rke2/kustomization.yaml",
"chars": 126,
"preview": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nresources:\n- ../../base\npatches:\n- path: mount_rke2_conf"
},
{
"path": "misc/snapshotter/overlays/rke2/mount_rke2_conf.yaml",
"chars": 255,
"preview": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n name: nydus-snapshotter\n namespace: nydus-system\nspec:\n template:\n "
},
{
"path": "misc/snapshotter/snapshotter.sh",
"chars": 13615,
"preview": "#!/usr/bin/env bash\n# Copyright (c) 2023. Nydus Developers. All rights reserved.\n#\n# SPDX-License-Identifier: Apache-2.0"
},
{
"path": "pkg/auth/cri.go",
"chars": 3476,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/cri_test.go",
"chars": 3845,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/docker.go",
"chars": 2185,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage auth\n\ni"
},
{
"path": "pkg/auth/docker_test.go",
"chars": 2149,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage auth\n\ni"
},
{
"path": "pkg/auth/keychain.go",
"chars": 5266,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage auth\n\ni"
},
{
"path": "pkg/auth/kubelet.go",
"chars": 18466,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/kubelet_test.go",
"chars": 35141,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/kubesecret.go",
"chars": 6542,
"preview": "package auth\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/docker/cli/cli/config/configfile\"\n\t\"github"
},
{
"path": "pkg/auth/kubesecret_test.go",
"chars": 1763,
"preview": "package auth\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\tcorev1 \"k"
},
{
"path": "pkg/auth/labels.go",
"chars": 1133,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/labels_test.go",
"chars": 1093,
"preview": "/*\n * Copyright (c) 2020. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/provider.go",
"chars": 1952,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/renewal.go",
"chars": 4346,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/auth/renewal_test.go",
"chars": 11449,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/backend/backend.go",
"chars": 1763,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/backend/localfs.go",
"chars": 2216,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/backend/oss.go",
"chars": 4749,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/backend/s3.go",
"chars": 5770,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/backend/s3_test.go",
"chars": 2122,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cache/manager.go",
"chars": 4184,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cache/manager_test.go",
"chars": 2539,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cgroup/cgroup.go",
"chars": 1204,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cgroup/manager.go",
"chars": 889,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cgroup/v1/v1.go",
"chars": 2113,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/cgroup/v2/v2.go",
"chars": 1956,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/constant.go",
"chars": 1399,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/convert_unix.go",
"chars": 41048,
"preview": "//go:build !windows\n// +build !windows\n\n/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-Lice"
},
{
"path": "pkg/converter/convert_windows.go",
"chars": 1446,
"preview": "//go:build windows\n// +build windows\n\n/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-Licens"
},
{
"path": "pkg/converter/cs_proxy_unix.go",
"chars": 4105,
"preview": "//go:build !windows\n// +build !windows\n\n/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-Lice"
},
{
"path": "pkg/converter/merge_unix_test.go",
"chars": 3945,
"preview": "//go:build !windows\n// +build !windows\n\n/*\n * Copyright (c) 2024. Nydus Developers. All rights reserved.\n *\n * SPDX-Lice"
},
{
"path": "pkg/converter/reconvert_unix.go",
"chars": 9832,
"preview": "//go:build !windows\n// +build !windows\n\n/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-Lice"
},
{
"path": "pkg/converter/reconvert_unix_test.go",
"chars": 13015,
"preview": "//go:build !windows\n// +build !windows\n\n/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-Lice"
},
{
"path": "pkg/converter/tool/builder.go",
"chars": 9156,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/tool/feature.go",
"chars": 3850,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/tool/feature_test.go",
"chars": 32825,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/types.go",
"chars": 6892,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/converter/utils.go",
"chars": 4218,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/daemon/client.go",
"chars": 9426,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/daemon/client_test.go",
"chars": 3700,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage daemon\n"
},
{
"path": "pkg/daemon/command/command.go",
"chars": 4409,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/daemon/command/command_builder_test.go",
"chars": 1371,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/daemon/config.go",
"chars": 2681,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/daemon/daemon.go",
"chars": 18969,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/daemon/daemon_test.go",
"chars": 4040,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/daemon/idgen.go",
"chars": 205,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage daemon\n"
},
{
"path": "pkg/daemon/types/types.go",
"chars": 3491,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/encryption/encryption.go",
"chars": 8727,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/errdefs/errors.go",
"chars": 1308,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage errdefs"
},
{
"path": "pkg/fanotify/conn/conn.go",
"chars": 604,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/fanotify/fanotify.go",
"chars": 4007,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/filesystem/config.go",
"chars": 2317,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/filesystem/fs.go",
"chars": 29366,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/filesystem/index_adaptor.go",
"chars": 2492,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/filesystem/referer_adaptor.go",
"chars": 1452,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/filesystem/stargz_adaptor.go",
"chars": 7754,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/filesystem/tarfs_adaptor.go",
"chars": 2773,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/index/detector.go",
"chars": 5213,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/index/detector_test.go",
"chars": 6376,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/index/manager.go",
"chars": 3007,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/index/manager_test.go",
"chars": 1157,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/label/label.go",
"chars": 3567,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage label\n\n"
},
{
"path": "pkg/layout/layout.go",
"chars": 1956,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/manager/daemon_adaptor.go",
"chars": 6606,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/manager/daemon_cache.go",
"chars": 2234,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/manager/daemon_cache_test.go",
"chars": 1561,
"preview": "/*\n Copyright The nydus Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not us"
},
{
"path": "pkg/manager/daemon_event.go",
"chars": 6742,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/manager/manager.go",
"chars": 10991,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/manager/monitor.go",
"chars": 6134,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/manager/monitor_test.go",
"chars": 1920,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/manager/store.go",
"chars": 1018,
"preview": "/*\n * Copyright (c) 2020. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/metrics/collector/cache.go",
"chars": 2015,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/collector/collector.go",
"chars": 2055,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/collector/daemon.go",
"chars": 1241,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/collector/fs.go",
"chars": 2498,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/collector/snapshotter.go",
"chars": 2492,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/data/auth.go",
"chars": 973,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/data/cache.go",
"chars": 3182,
"preview": "/*\n * Copyright (c) 2025. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/data/daemon.go",
"chars": 1036,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/data/fs.go",
"chars": 1936,
"preview": "/*\n * Copyright (c) 2021. Alibaba Cloud. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserv"
},
{
"path": "pkg/metrics/data/labels.go",
"chars": 253,
"preview": "package data\n\nconst (\n\timageRefLabel = \"image_ref\"\n\tnydusdEventLabel = \"nydusd_event\"\n\tnydusdVersionLabel "
},
{
"path": "pkg/metrics/data/snapshotter.go",
"chars": 2427,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/listener.go",
"chars": 1263,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/metrics/registry/registry.go",
"chars": 1223,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage registr"
},
{
"path": "pkg/metrics/serve.go",
"chars": 6311,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n"
},
{
"path": "pkg/metrics/tool/common.go",
"chars": 1170,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/tool/stat.go",
"chars": 2724,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/tool/stat_test.go",
"chars": 333,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/metrics/types/ttl/gauge.go",
"chars": 1739,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage ttl\n\nim"
},
{
"path": "pkg/metrics/types/ttl/gauge_test.go",
"chars": 1744,
"preview": "/*\n * Copyright (c) 2021. Ant Group. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage ttl\n\nim"
},
{
"path": "pkg/metrics/types/types.go",
"chars": 1896,
"preview": "/*\n * Copyright (c) 2021. Alibaba Cloud. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage fs\n"
},
{
"path": "pkg/pprof/listener.go",
"chars": 1112,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/prefetch/prefetch.go",
"chars": 1202,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/rafs/rafs.go",
"chars": 4631,
"preview": "/*\n * Copyright (c) 2022. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/referrer/manager.go",
"chars": 2522,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/referrer/referrer.go",
"chars": 3985,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/remote/remote.go",
"chars": 4061,
"preview": "/*\n * Copyright (c) 2023. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/remote/remote_test.go",
"chars": 1675,
"preview": "/*\n * Copyright (c) 2026. Nydus Developers. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n */\n\npackage "
},
{
"path": "pkg/remote/remotes/docker/auth/fetch.go",
"chars": 6318,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/auth/fetch_test.go",
"chars": 2864,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/auth/parse.go",
"chars": 4893,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/auth/parse_test.go",
"chars": 2646,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/authorizer.go",
"chars": 9582,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/config/config_unix.go",
"chars": 1009,
"preview": "//go:build !windows\n\n/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"Li"
},
{
"path": "pkg/remote/remotes/docker/config/config_windows.go",
"chars": 1061,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/config/docker_fuzzer_internal.go",
"chars": 1017,
"preview": "//go:build gofuzz\n\n/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"Lice"
},
{
"path": "pkg/remote/remotes/docker/config/hosts.go",
"chars": 16978,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/config/hosts_test.go",
"chars": 11069,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/converter.go",
"chars": 2912,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/converter_fuzz.go",
"chars": 1411,
"preview": "//go:build gofuzz\n\n/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"Lice"
},
{
"path": "pkg/remote/remotes/docker/errcode.go",
"chars": 7274,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/errdesc.go",
"chars": 5013,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/fetcher.go",
"chars": 9213,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
},
{
"path": "pkg/remote/remotes/docker/fetcher_fuzz.go",
"chars": 1804,
"preview": "//go:build gofuzz\n\n/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"Lice"
},
{
"path": "pkg/remote/remotes/docker/fetcher_test.go",
"chars": 5527,
"preview": "/*\n Copyright The containerd Authors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may n"
}
]
// ... and 71 more files (download for full content)
About this extraction
This page contains the full source code of the containerd/nydus-snapshotter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 271 files (2.3 MB), approximately 623.5k tokens, and a symbol index with 1789 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.