Full Code of containerd/nydus-snapshotter for AI

main 389bddbab0da cached
271 files
2.3 MB
623.5k tokens
1789 symbols
1 requests
Download .txt
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>

[![Release Version](https://img.shields.io/github/v/release/containerd/nydus-snapshotter?style=flat)](https://github.com/containerd/nydus-snapshotter/releases)
[![LICENSE](https://img.shields.io/github/license/containerd/nydus-snapshotter.svg?style=flat)](https://github.com/containerd/nydus-snapshotter/blob/main/LICENSE)
![CI](https://github.com/containerd/nydus-snapshotter/actions/workflows/ci.yml/badge.svg?event=push)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/nydus-snapshotter?style=flat)](https://goreportcard.com/report/github.com/containerd/nydus-snapshotter)
[![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fdragonfly_oss)](https://twitter.com/dragonfly_oss)
[![Nydus Stars](https://img.shields.io/github/stars/dragonflyoss/nydus?label=Nydus%20Stars&style=social)](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

![fuse arch](./docs/diagram/nydus_fuse_arch.svg)

### Architecture Based on Fscache/Erofs

![fscache arch](./docs/diagram/nydus_fscache_erofs_arch.svg)

## 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

[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcontainerd%2Fnydus-snapshotter.svg?type=large)](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

![optimizer workload](./diagram/optmizer_workflow.svg)

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
Download .txt
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
Download .txt
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.

Copied to clipboard!