diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f9a494334dba..9828bb172949 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,7 +12,7 @@ "features": { "ghcr.io/devcontainers/features/docker-in-docker:2": {}, "ghcr.io/devcontainers/features/go:1": { - "version": "1.21" + "version": "1.23.3" } }, diff --git a/.github/actions/install-go/action.yml b/.github/actions/install-go/action.yml new file mode 100644 index 000000000000..641e071289e4 --- /dev/null +++ b/.github/actions/install-go/action.yml @@ -0,0 +1,16 @@ +name: "Setup Go" +description: "Reusable action to install Go, so there is one place to bump Go versions" +inputs: + go-version: + required: true + default: "1.23.3" + description: "Go version to install" + +runs: + using: composite + steps: + - name: "Setup Go" + uses: actions/setup-go@v5 + with: + go-version: ${{ inputs.go-version }} + cache: false # see actions/setup-go#368 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..6e6f108ef907 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + groups: + golang-x: + patterns: + - "golang.org/x/*" + k8s: + patterns: + - "k8s.io/*" + moby-sys: + patterns: + - "github.com/moby/sys/*" + otel: + patterns: + - "go.opentelemetry.io/*" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 diff --git a/.github/workflows/api-release.yml b/.github/workflows/api-release.yml new file mode 100644 index 000000000000..4d5ed91a3a86 --- /dev/null +++ b/.github/workflows/api-release.yml @@ -0,0 +1,80 @@ +on: + push: + tags: + - "api/v*" # Push events to matching api/v*, i.e. api/v1.0, api/v20.15.10 + +name: API Release + +env: + GO_VERSION: "1.23.3" + +permissions: # added using https://github.com/step-security/secure-workflows + contents: read + +jobs: + check: + name: Check Signed Tag + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/api/v') + runs-on: ubuntu-24.04 + timeout-minutes: 5 + outputs: + stringver: ${{ steps.contentrel.outputs.stringver }} + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.ref }} + path: src/github.com/containerd/containerd + + - name: Check signature + run: | + releasever=${{ github.ref }} + releasever="${releasever#refs/tags/}" + TAGCHECK=$(git tag -v ${releasever} 2>&1 >/dev/null) || + echo "${TAGCHECK}" | grep -q "error" && { + echo "::error::tag ${releasever} is not a signed tag. Failing release process." + exit 1 + } || { + echo "Tag ${releasever} is signed." + exit 0 + } + working-directory: src/github.com/containerd/containerd + + - name: Release content + id: contentrel + run: | + RELEASEVER=${{ github.ref }} + echo "stringver=${RELEASEVER#refs/tags/api/v}" >> $GITHUB_OUTPUT + git tag -l ${RELEASEVER#refs/tags/} -n20000 | tail -n +3 | cut -c 5- >release-notes.md + working-directory: src/github.com/containerd/containerd + + - name: Save release notes + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: containerd-release-notes + path: src/github.com/containerd/containerd/release-notes.md + + release: + name: Create containerd Release + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/api/v') + permissions: + contents: write + runs-on: ubuntu-24.04 + timeout-minutes: 10 + needs: [check] + steps: + - name: Download release notes + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: builds + - name: Create Release + uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fail_on_unmatched_files: true + name: containerd API ${{ needs.check.outputs.stringver }} + draft: false + make_latest: false + prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + body_path: ./builds/containerd-release-notes/release-notes.md diff --git a/.github/workflows/build-test-images.yml b/.github/workflows/build-test-images.yml index 1d7c87e2312a..2971aecea698 100644 --- a/.github/workflows/build-test-images.yml +++ b/.github/workflows/build-test-images.yml @@ -41,14 +41,12 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v3 - with: - go-version: "1.21.1" - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + - name: Set env shell: bash run: | @@ -74,18 +72,18 @@ jobs: echo "SSH_PUB_KEY=$(cat ~/.ssh/id_rsa.pub)" >> $GITHUB_ENV - name: Azure Login - uses: azure/login@v1 + uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 with: creds: ${{ secrets.AZURE_CREDS }} - name: Create Azure Resource Group - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group create -n ${{ env.AZURE_RESOURCE_GROUP }} -l ${{ github.event.inputs.azure_location }} --tags creationTimestamp=$(date +%Y-%m-%dT%T%z) - name: Create Windows Helper VM - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | PASSWORD="$(/usr/bin/tr -dc "a-zA-Z0-9@#$%^&*()_+?><~\`;" < /dev/urandom | /usr/bin/head -c 24; echo '')" @@ -100,7 +98,7 @@ jobs: az vm open-port --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --name WinDockerHelper --port 2376 --priority 102 - name: Prepare Windows image helper - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | # Installs Windows features, opens SSH and Docker port @@ -122,7 +120,7 @@ jobs: --parameters 'SSHPublicKey=${{ env.SSH_PUB_KEY }}' - name: Get Windows Helper IPs - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | VM_DETAILS=$(az vm show -d -g ${{ env.AZURE_RESOURCE_GROUP }} -n WinDockerHelper -o json) @@ -144,7 +142,7 @@ jobs: scp -i $HOME/.ssh/id_rsa ${{ env.SSH_OPTS }} azureuser@${{ env.PUBLIC_IP }}:/Users/azureuser/.docker/key.pem $HOME/.docker/key.pem - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -163,7 +161,7 @@ jobs: - name: Cleanup resources if: always() - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group delete -g ${{ env.AZURE_RESOURCE_GROUP }} --yes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e13aa2930b44..6720cd3c47c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,11 +6,6 @@ on: pull_request: branches: ['main', 'release/**'] -env: - # Go version we currently use to build containerd across all CI. - # Note: don't forget to update `Binaries` step, as it contains the matrix of all supported Go versions. - GO_VERSION: "1.21.1" - permissions: # added using https://github.com/step-security/secure-workflows contents: read @@ -28,18 +23,17 @@ jobs: strategy: matrix: - os: [ubuntu-22.04, macos-12, windows-2019] + os: [ubuntu-24.04, arm64-8core-32gb, macos-13, windows-2019] + exclude: + - os: ${{ github.repository != 'containerd/containerd' && 'arm64-8core-32gb' }} - steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - uses: actions/checkout@v3 - - uses: golangci/golangci-lint-action@v3 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go + - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: - version: v1.52.2 + version: v1.60.1 skip-cache: true args: --timeout=8m @@ -48,22 +42,19 @@ jobs: # project: name: Project Checks - if: github.repository == 'containerd/containerd' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd fetch-depth: 100 - - uses: containerd/project-checks@v1.1.0 + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + + - uses: containerd/project-checks@434a07157608eeaa1d5c8d4dd506154204cd9401 # v1.1.0 + if: github.repository == 'containerd/containerd' with: working-directory: src/github.com/containerd/containerd repo-access-token: ${{ secrets.GITHUB_TOKEN }} @@ -79,7 +70,7 @@ jobs: # protos: name: Protobuf - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 5 defaults: @@ -87,15 +78,12 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + - name: Set env shell: bash run: | @@ -116,15 +104,12 @@ jobs: man: name: Manpages - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 5 steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go - run: go install github.com/cpuguy83/go-md2man/v2@v2.0.2 - run: make man @@ -133,7 +118,7 @@ jobs: crossbuild: name: Crossbuild Binaries needs: [project, linters, protos, man] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 10 strategy: fail-fast: false @@ -154,11 +139,8 @@ jobs: goarm: "7" steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go - run: | set -e -x @@ -208,22 +190,15 @@ jobs: strategy: matrix: - os: [ubuntu-22.04, macos-12, windows-2019, windows-2022] - go-version: ["1.20.8", "1.21.1"] + os: [ubuntu-22.04, ubuntu-24.04, arm64-8core-32gb, macos-13, windows-2019, windows-2022] + go-version: ["1.22.9", "1.23.3"] + exclude: + - os: ${{ github.repository != 'containerd/containerd' && 'arm64-8core-32gb' }} steps: - - uses: actions/setup-go@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go with: go-version: ${{ matrix.go-version }} - cache: false # see actions/setup-go#368 - - - uses: actions/checkout@v3 - - # NOTE(aznashwan): starting with Golang 1.21, the windows-2019 GitHub runner's - # builtin MinGW version leads to DLL loading errors during runtime. - - name: Upgrade MinGW on Windows 2019 - if: matrix.os == 'windows-2019' - run: choco upgrade mingw - - name: Make run: | make build @@ -243,8 +218,8 @@ jobs: strategy: fail-fast: false matrix: - os: [windows-2019, windows-2022] - disable_cri_sandboxes: ["", "legacyCRI"] + os: [windows-2022, windows-2019] + cgroup_driver: [cgroupfs] defaults: run: @@ -252,19 +227,17 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd - - uses: actions/checkout@v3 + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: repository: kubernetes-sigs/cri-tools path: src/github.com/kubernetes-sigs/cri-tools + fetch-depth: 0 - name: Set env run: | @@ -275,19 +248,27 @@ jobs: - run: script/setup/install-dev-tools - # NOTE(aznashwan): starting with Golang 1.21, the windows-2019 GitHub runner's - # builtin MinGW version leads to DLL loading errors during runtime. + # needs to be a separate step since terminal reload is required to bring in new env variables and PATH + - name: Upgrade Chocolaty on Windows 2019 + if: matrix.os == 'windows-2019' + shell: powershell + run: .\script\setup\upgrade_chocolaty_windows_2019.ps1 + - name: Upgrade MinGW on Windows 2019 if: matrix.os == 'windows-2019' - run: choco upgrade mingw + shell: powershell + run: .\script\setup\upgrade_mingw_windows_2019.ps1 - name: Binaries + shell: bash env: CGO_ENABLED: 1 run: | set -o xtrace mingw32-make.exe binaries + CRITEST_VERSION=$(cat script/setup/critools-version) cd ../../kubernetes-sigs/cri-tools + git checkout "${CRITEST_VERSION}" make critest - run: script/setup/install-cni-windows @@ -335,7 +316,6 @@ jobs: - name: Integration 1 env: CGO_ENABLED: 1 - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-serial-junit.xml GOTESTSUM_JSONFILE: ${{github.workspace}}/test-integration-serial-gotest.json EXTRA_TESTFLAGS: "-timeout=20m" @@ -353,7 +333,6 @@ jobs: TESTFLAGS_PARALLEL: 1 EXTRA_TESTFLAGS: "-short" CGO_ENABLED: 1 - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-parallel-junit.xml GOTESTSUM_JSONFILE: ${{github.workspace}}/test-integration-parallel-gotest.json run: mingw32-make.exe integration @@ -366,15 +345,15 @@ jobs: - name: CRI Integration Test env: - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} TEST_IMAGE_LIST: ${{github.workspace}}/repolist.toml + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} run: | make cri-integration - name: cri-tools critest env: - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} CRI_TEST_IMAGES: ${{github.workspace}}/cri-test-images.yaml + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} shell: powershell run: | Start-Process -FilePath containerd.exe -NoNewWindow -RedirectStandardError true -PassThru @@ -388,10 +367,10 @@ jobs: } critest.exe --runtime-endpoint=npipe://.//pipe//containerd-containerd --test-images-file='${{env.CRI_TEST_IMAGES}}' --report-dir='${{github.workspace}}/critestreport' $skip - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: always() with: - name: TestResults ${{ matrix.os }} + name: TestResults ${{ matrix.os }} ${{ matrix.cgroup_driver }} path: | ${{github.workspace}}/*-junit.xml ${{github.workspace}}/*-gotest.json @@ -399,7 +378,7 @@ jobs: integration-linux: name: Linux Integration - runs-on: ubuntu-22.04 + runs-on: ${{ matrix.os }} timeout-minutes: 40 needs: [project, linters, protos, man] @@ -408,25 +387,24 @@ jobs: matrix: runtime: - io.containerd.runc.v2 - runc: [runc, crun] - DISABLE_CRI_SANDBOXES: ["", "legacyCRI"] + runc: [runc] # crun can be added here to debug crun issues + os: [ubuntu-22.04, ubuntu-24.04, arm64-8core-32gb] + exclude: + - os: ${{ github.repository != 'containerd/containerd' && 'arm64-8core-32gb' }} + cgroup_driver: [cgroupfs, systemd] env: GOTEST: gotestsum -- steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go - name: Install containerd dependencies env: RUNC_FLAVOR: ${{ matrix.runc }} run: | sudo apt-get update - sudo apt-get install -y gperf + sudo apt-get install -y gperf dmsetup strace xfsprogs script/setup/install-seccomp script/setup/install-runc script/setup/install-cni $(grep containernetworking/plugins go.mod | awk '{print $2}') @@ -434,6 +412,10 @@ jobs: script/setup/install-failpoint-binaries - name: Install criu + # NOTE: Required arm64 enable CONFIG_CHECKPOINT_RESTORE (need to confirm GitHub action runners config) + # + # REF: https://criu.org/Linux_kernel + if: matrix.os != 'arm64-8core-32gb' run: | sudo add-apt-repository -y ppa:criu/ppa sudo apt-get update @@ -464,7 +446,6 @@ jobs: env: TEST_RUNTIME: ${{ matrix.runtime }} RUNC_FLAVOR: ${{ matrix.runc }} - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-serial-junit.xml GOTESTSUM_JSONFILE: ${{github.workspace}}/test-integration-serial-gotest.json run: | @@ -483,7 +464,6 @@ jobs: env: TEST_RUNTIME: ${{ matrix.runtime }} RUNC_FLAVOR: ${{ matrix.runc }} - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} GOTESTSUM_JUNITFILE: ${{github.workspace}}/test-integration-parallel-junit.xml GOTESTSUM_JSONFILE: ${{github.workspace}}/test-integration-parallel-gotest.json run: | @@ -500,15 +480,23 @@ jobs: - name: CRI Integration Test env: TEST_RUNTIME: ${{ matrix.runtime }} - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} + RUNC_FLAVOR: ${{ matrix.runc }} run: | + cat /sys/fs/cgroup/cgroup.controllers + systemctl status + [ "${RUNC_FLAVOR}" == "crun" ] && { + export XDG_RUNTIME_DIR=/run/user/$(id -u) + } + runc --version CONTAINERD_RUNTIME=$TEST_RUNTIME make cri-integration - name: cri-tools critest env: TEST_RUNTIME: ${{ matrix.runtime }} - DISABLE_CRI_SANDBOXES: ${{ matrix.disable_cri_sandboxes }} + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} run: | + env sudo -E PATH=$PATH ./script/critest.sh "${{github.workspace}}/report" # Log the status of this VM to investigate issues like @@ -522,12 +510,14 @@ jobs: losetup -l - name: Kernel Message if: failure() - run: sudo dmesg -T -f kern + run: | + sudo lsmod + sudo dmesg -T -f kern - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: always() with: - name: TestResults ${{ matrix.runtime }} ${{matrix.runc}} + name: TestResults ${{ matrix.runtime }} ${{matrix.runc}} ${{ matrix.os }} ${{ matrix.cgroup_driver }} path: | *-junit.xml *-gotest.json @@ -536,21 +526,46 @@ jobs: integration-vagrant: name: Vagrant integration - # "Larger" runner is needed for nested virtualization - # https://github.com/organizations/containerd/settings/actions/runners - runs-on: ubuntu-latest-4-cores + runs-on: ubuntu-24.04 timeout-minutes: 60 needs: [project, linters, protos, man] strategy: fail-fast: false matrix: - box: - - fedora/38-cloud-base - - rockylinux/8@8.0.0 + include: + - box: fedora/40-cloud-base + cgroup_driver: cgroupfs + runc: runc + - box: fedora/40-cloud-base + cgroup_driver: systemd + runc: runc + - box: fedora/40-cloud-base + cgroup_driver: cgroupfs + runc: crun + - box: fedora/40-cloud-base + cgroup_driver: systemd + runc: crun + # We have to keep EL8 to test old glibc, cgroup, kernel, etc. + # The image was changed from rockylinux/8 to almalinux/8, + # as the former one no longer works: + # https://github.com/containerd/containerd/pull/10297 + - box: almalinux/8 + cgroup_driver: cgroupfs + runc: runc + - box: almalinux/8 + cgroup_driver: systemd + runc: runc + - box: rockylinux/9@4.0.0 + cgroup_driver: cgroupfs + runc: runc + - box: rockylinux/9@4.0.0 + cgroup_driver: systemd + runc: runc env: BOX: ${{ matrix.box }} - + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} + RUNC_FLAVOR: ${{ matrix.runc }} steps: - name: Show the host info run: | @@ -559,8 +574,8 @@ jobs: cat /etc/os-release cat /proc/cpuinfo free -mt - - uses: actions/checkout@v3 - - uses: actions/cache@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 with: path: /root/.vagrant.d key: vagrant-${{ matrix.box }} @@ -570,31 +585,38 @@ jobs: # So we have to install Vagrant >= 2.3.1 from the upstream: https://github.com/opencontainers/runc/blob/v1.1.8/.cirrus.yml#L41-L49 curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list - sudo sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list + sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources sudo apt-get update - sudo apt-get install -y libvirt-daemon libvirt-daemon-system vagrant + sudo apt-get install -y libvirt-daemon libvirt-daemon-system vagrant ovmf + # https://github.com/vagrant-libvirt/vagrant-libvirt/issues/1725#issuecomment-1454058646 + sudo cp /usr/share/OVMF/OVMF_VARS_4M.fd /var/lib/libvirt/qemu/nvram/ sudo systemctl enable --now libvirtd - sudo apt-get build-dep -y vagrant ruby-libvirt + sudo apt-get build-dep -y ruby-libvirt sudo apt-get install -y --no-install-recommends libxslt-dev libxml2-dev libvirt-dev ruby-bundler ruby-dev zlib1g-dev sudo vagrant plugin install vagrant-libvirt - name: Boot VM - run: sudo BOX=$BOX vagrant up --no-tty + run: sudo BOX=$BOX RUNC_FLAVOR=$RUNC_FLAVOR vagrant up --no-tty - name: test-integration - run: sudo BOX=$BOX vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-integration + run: sudo BOX=$BOX RUNC_FLAVOR=$RUNC_FLAVOR vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-integration - name: test-cri-integration - run: sudo BOX=$BOX vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-cri-integration + run: sudo BOX=$BOX CGROUP_DRIVER=$CGROUP_DRIVER RUNC_FLAVOR=$RUNC_FLAVOR vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-cri-integration - name: test-cri - run: sudo BOX=$BOX vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-cri + run: sudo BOX=$BOX CGROUP_DRIVER=$CGROUP_DRIVER RUNC_FLAVOR=$RUNC_FLAVOR vagrant up --provision-with=selinux,install-runc,install-gotestsum,test-cri tests-cri-in-userns: name: "CRI-in-UserNS" - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 timeout-minutes: 40 needs: [project, linters, protos, man] + strategy: + fail-fast: false + matrix: + cgroup_driver: [cgroupfs, systemd] + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up cgroup v2 delegation run: | sudo mkdir -p /etc/systemd/system/user@.service.d @@ -604,26 +626,47 @@ jobs: EOF sudo systemctl daemon-reload - name: Build cri-in-userns image - run: podman build --target cri-in-userns -t cri-in-userns -f ./contrib/Dockerfile.test . + env: + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} + run: | + if [ "$CGROUP_DRIVER" = "systemd" ];then + podman build --target cri-in-userns-systemd -t cri-in-userns-systemd -f ./contrib/Dockerfile.test . + else + podman build --target cri-in-userns -t cri-in-userns -f ./contrib/Dockerfile.test . + fi + - name: Run cri-in-userns image + env: + CGROUP_DRIVER: ${{ matrix.cgroup_driver }} # Rootless Podman is used for testing CRI-in-UserNS # (We could use rootless Docker or rootless nerdctl, but we are using Podman here because it is preinstalled) - run: podman run --rm --privileged cri-in-userns + run: | + if [ "$CGROUP_DRIVER" = "systemd" ];then + set +e + touch ./critest_exit_code.txt + podman run --rm --privileged --group-add keep-groups -v ./critest_exit_code.txt:/tmp/critest_exit_code.txt cri-in-userns-systemd + exit_code=`cat ./critest_exit_code.txt` + echo "exit_code:"$exit_code + if [ "$exit_code" -gt 0 ]; then + exit 1 + else + exit 0 + fi + else + podman run --rm --privileged cri-in-userns + fi tests-mac-os: name: MacOS unit tests - runs-on: macos-12 + runs-on: macos-13 timeout-minutes: 10 needs: [project, linters, protos, man] env: GOTEST: gotestsum -- steps: - - uses: actions/setup-go@v4 - with: - go-version: ${{ env.GO_VERSION }} - cache: false # see actions/setup-go#368 - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go - run: script/setup/install-gotestsum - run: script/setup/install-teststat - name: Tests @@ -635,10 +678,27 @@ jobs: if: always() - run: script/test/test2annotation.sh *-gotest.json if: always() - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: always() with: name: TestResults MacOS path: | *-junit.xml *-gotest.json + + # Currently Github actions UI supports no masks to mark matrix jobs as required to pass status checks. + # This means that every time version of Go, containerd, or OS is changed, a corresponding job should + # be added to the list of required checks. Which is not very convenient. + # To workaround this, a special job is added to report statuses of all other jobs, with fixed title. + # So it needs to be added to the list of required checks only once. + # + # See https://github.com/orgs/community/discussions/26822 + results: + name: Report required job statuses + runs-on: ubuntu-latest + # List job dependencies which are required to pass status checks in order to be merged via merge queue. + needs: [linters, project, protos, binaries, integration-linux, integration-windows, tests-cri-in-userns, tests-mac-os] + if: ${{ always() }} + steps: + - run: exit 1 + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d6ae47155372..d0129d3ef729 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,15 +30,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-go@v3 - with: - go-version: 1.21.1 + - uses: ./.github/actions/install-go # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java @@ -48,4 +46,4 @@ jobs: make - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4 diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index a44c0d7ec796..5e7152c95e7a 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -14,19 +14,19 @@ jobs: steps: - name: Build Fuzzers id: build - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@abe2c06d0e162320403dd10e8268adbb0b8923f8 # master with: oss-fuzz-project-name: 'containerd' language: go - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@abe2c06d0e162320403dd10e8268adbb0b8923f8 # master with: oss-fuzz-project-name: 'containerd' fuzz-seconds: 300 language: go continue-on-error: true - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: failure() && steps.build.outcome == 'success' with: name: artifacts @@ -40,8 +40,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/setup-go@v3 - with: - go-version: 1.21.x - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/install-go - run: script/go-test-fuzz.sh diff --git a/.github/workflows/images.yml b/.github/workflows/images.yml index 035681982653..07c99fcca827 100644 --- a/.github/workflows/images.yml +++ b/.github/workflows/images.yml @@ -26,14 +26,12 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v3 - with: - go-version: "1.21.1" - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + - name: Set env shell: bash run: | diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 000000000000..a96f712769d9 --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,30 @@ +name: Links + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" # Every day at midnight + pull_request: + paths: + - ".github/workflows/links.yml" + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-latest + if: github.repository == 'containerd/containerd' + name: lychee + timeout-minutes: 15 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: lycheeverse/lychee-action@f81112d0d2814ded911bd23e3beaa9dda9093915 # v2.1.0 + with: + # Fail action on broken links + fail: true + args: --exclude-path vendor --exclude-path releases --timeout 30 --no-progress './**/*.md' + format: markdown + # Write GitHub job summary + jobSummary: true diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a4e482997eb6..e19fbef5fdc7 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -6,9 +6,6 @@ on: paths: - ".github/workflows/nightly.yml" -env: - GO_VERSION: "1.21.1" - permissions: # added using https://github.com/step-security/secure-workflows contents: read @@ -23,14 +20,12 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v3 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + - name: Set env shell: bash run: | @@ -104,31 +99,31 @@ jobs: # - name: Upload artifacts (linux_amd64) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: linux_amd64 path: src/github.com/containerd/containerd/bin_amd64 - name: Upload artifacts (linux_arm64) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: linux_arm64 path: src/github.com/containerd/containerd/bin_arm64 - name: Upload artifacts (linux_s390x) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: linux_s390x path: src/github.com/containerd/containerd/bin_s390x - name: Upload artifacts (linux_ppc64le) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: linux_ppc64le path: src/github.com/containerd/containerd/bin_ppc64le - name: Upload artifacts (linux_riscv64) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: linux_riscv64 path: src/github.com/containerd/containerd/bin_riscv64 @@ -143,14 +138,12 @@ jobs: working-directory: src/github.com/containerd/containerd steps: - - uses: actions/setup-go@v3 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: path: src/github.com/containerd/containerd + - uses: ./src/github.com/containerd/containerd/.github/actions/install-go + - name: Set env shell: bash run: | @@ -165,7 +158,7 @@ jobs: make binaries - name: Upload artifacts (windows_amd64) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: windows_amd64 path: src/github.com/containerd/containerd/bin/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96c730bbd3b5..6de0a923a640 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ on: name: Release env: - GO_VERSION: "1.21.1" + GO_VERSION: "1.23.3" permissions: # added using https://github.com/step-security/secure-workflows contents: read @@ -22,14 +22,14 @@ jobs: check: name: Check Signed Tag if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 timeout-minutes: 5 outputs: stringver: ${{ steps.contentrel.outputs.stringver }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.ref }} path: src/github.com/containerd/containerd @@ -57,7 +57,7 @@ jobs: working-directory: src/github.com/containerd/containerd - name: Save release notes - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: containerd-release-notes path: src/github.com/containerd/containerd/release-notes.md @@ -93,7 +93,7 @@ jobs: releasever="${releasever#refs/tags/}" echo "RELEASE_VER=${releasever}" >> $GITHUB_ENV - name: Checkout containerd - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # Intentionally use github.repository instead of containerd/containerd to # make this action runnable on forks. @@ -103,10 +103,10 @@ jobs: path: src/github.com/containerd/containerd - name: Setup buildx instance - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 with: use: true - - uses: crazy-max/ghaction-github-runtime@v2 # sets up needed vars for caching to github + - uses: crazy-max/ghaction-github-runtime@b3a9207c0e1ef41f4cf215303c976869d0c2c1c4 # v3.0.0 - name: Make shell: bash run: | @@ -121,13 +121,13 @@ jobs: docker buildx build ${cache} --build-arg RELEASE_VER --build-arg UBUNTU_VERSION=${{ matrix.dockerfile-ubuntu }} --build-arg GO_VERSION ${BUILD_ARGS} -f .github/workflows/release/Dockerfile --platform=${PLATFORM} -o releases/ . echo PLATFORM_CLEAN=${PLATFORM/\//-} >> $GITHUB_ENV - # Remove symlinks since we don't want these in the release Artifacts - find ./releases/ -maxdepth 1 -type l | xargs rm + # Remove symlinks since we don't want these in the release Artifacts (if any) + find ./releases/ -maxdepth 1 -type l | xargs rm -f working-directory: src/github.com/containerd/containerd env: PLATFORM: ${{ matrix.dockerfile-platform }} - name: Save Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: release-tars-${{env.PLATFORM_CLEAN}} path: src/github.com/containerd/containerd/releases/*.tar.gz* @@ -137,16 +137,18 @@ jobs: if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') permissions: contents: write - runs-on: ubuntu-20.04 + id-token: write + attestations: write + runs-on: ubuntu-24.04 timeout-minutes: 10 needs: [build, check] steps: - name: Download builds and release notes - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: path: builds - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 with: token: ${{ secrets.GITHUB_TOKEN }} fail_on_unmatched_files: true @@ -156,3 +158,8 @@ jobs: body_path: ./builds/containerd-release-notes/release-notes.md files: | builds/release-tars-**/* + make_latest: false + - name: Attest Artifacts + uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 + with: + subject-path: ./builds/release-tars-**/*.tar.gz diff --git a/.github/workflows/release/Dockerfile b/.github/workflows/release/Dockerfile index 84938ead0df9..979b3e9ec11f 100644 --- a/.github/workflows/release/Dockerfile +++ b/.github/workflows/release/Dockerfile @@ -27,7 +27,8 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get install -y dpkg-dev git make pkg-config ARG TARGETPLATFORM -RUN xx-apt-get install -y libseccomp-dev btrfs-progs gcc +# gcc is needed for github.com/containerd/btrfs/v2 +RUN xx-apt-get install -y gcc ENV PATH=/usr/local/go/bin:$PATH ENV GOPATH=/go ENV CGO_ENABLED=1 @@ -49,13 +50,13 @@ RUN \ --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg \ export CC=$(xx-info)-gcc && xx-go --wrap && \ - make release static-release cri-release cri-cni-release && \ + make release static-release && \ for f in $(find bin -executable -type f); do xx-verify $f; done # check git working tree after build RUN \ export GIT_STATUS_OUTPUT=$(git status --porcelain) && \ - test -z $GIT_STATUS_OUTPUT || (echo $GIT_STATUS_OUTPUT && exit 1) + test -z $GIT_STATUS_OUTPUT || (echo "repository contains uncommitted changes" && exit 1) FROM scratch AS release COPY --from=target /go/src/github.com/containerd/containerd/releases/ / diff --git a/.github/workflows/release/Dockerfile.dockerignore b/.github/workflows/release/Dockerfile.dockerignore new file mode 100644 index 000000000000..c553fed57faa --- /dev/null +++ b/.github/workflows/release/Dockerfile.dockerignore @@ -0,0 +1,19 @@ +# Exclude files that may cause cache-busts. These are generally expected +# to be in a global .gitignore, but still can cause the build-cache to +# be invalidated. +**/.DS_Store + +# exclusions below are copied from .gitignore at the root of the repository +# when updating, consider updating .gitignore accordingly. + +/bin/ +/man/ +coverage.txt +profile.out +containerd.test +_site/ +# Allow repeated builds without copying back previous builds +releases/*.tar.gz +releases/*.tar.gz.sha256sum +_output/ +.vagrant/ diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 28fb62fb90f2..c4fa30e78e16 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -22,12 +22,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # tag=v3.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@865b4092859256271290c77adbd10a43f4779972 # tag=v2.0.3 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # tag=v2.4.0 with: results_file: results.sarif results_format: sarif @@ -41,7 +41,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # tag=v3.0.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # tag=v4.4.3 with: name: SARIF file path: results.sarif @@ -49,6 +49,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@cc7986c02bac29104a72998e67239bb5ee2ee110 # tag=v2.1.28 + uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 with: sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 22a60e77a52d..16c57b5fb9f0 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -6,15 +6,18 @@ on: paths: - '.github/workflows/stale.yml' -permissions: - issues: write - pull-requests: write +permissions: read-all jobs: stale: runs-on: ubuntu-latest + + permissions: + issues: write + pull-requests: write + steps: - - uses: actions/stale@v8 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 # All stale bot options: https://github.com/actions/stale#all-options with: # Idle number of days before marking issues/PRs stale @@ -22,7 +25,7 @@ jobs: # Idle number of days before closing stale issues/PRs days-before-close: 7 # Only issues/PRs with ANY of these labels are checked - any-of-labels: 'status/more-info-needed,status/needs-update' + any-of-labels: 'status/more-info-needed,status/needs-update,needs-rebase' # Comment on the staled issues stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. This issue will be closed in 7 days unless new comments are made or the stale label is removed.' # Comment on the staled PRs diff --git a/.github/workflows/windows-hyperv-periodic.yml b/.github/workflows/windows-hyperv-periodic.yml index 11732ef0ec1d..4878c4f34c59 100644 --- a/.github/workflows/windows-hyperv-periodic.yml +++ b/.github/workflows/windows-hyperv-periodic.yml @@ -46,16 +46,16 @@ jobs: win_ver: [ltsc2019, ltsc2022] include: - win_ver: ltsc2019 - AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2019-Datacenter:17763.4377.230505" + AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest" AZURE_RESOURCE_GROUP: ctrd-integration-ltsc2019-${{ github.run_id }} GOOGLE_BUCKET: "containerd-integration/logs/windows-ltsc2019-hyperv/" - win_ver: ltsc2022 - AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2022-datacenter-smalldisk-g2:20348.1607.230310" + AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2022-datacenter-smalldisk-g2:latest" AZURE_RESOURCE_GROUP: ctrd-integration-ltsc2022-${{ github.run_id }} GOOGLE_BUCKET: "containerd-integration/logs/windows-ltsc2022-hyperv/" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install required packages run: | @@ -81,18 +81,18 @@ jobs: echo "SSH_PUB_KEY=$(cat ~/.ssh/id_rsa.pub)" >> $GITHUB_ENV - name: AZLogin - uses: azure/login@v1 + uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 with: creds: ${{ secrets.AZURE_CREDS }} - name: AZResourceGroupCreate - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group create -n ${{ matrix.AZURE_RESOURCE_GROUP }} -l ${{ env.AZURE_DEFAULT_LOCATION }} --tags creationTimestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ') - name: AZTestVMCreate - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | DETAILS=$(az vm create -n winTestVM --admin-username ${{ env.DEFAULT_ADMIN_USERNAME }} --admin-password ${{ env.PASSWORD }} --image ${{ matrix.AZURE_IMG }} -g ${{ matrix.AZURE_RESOURCE_GROUP }} --nsg-rule SSH --size ${{ env.AZURE_DEFAULT_VM_SIZE }} --public-ip-sku Standard -o json) @@ -116,7 +116,7 @@ jobs: echo "VM_PUB_IP=$PUB_IP" >> $GITHUB_ENV - name: EnableAZVMSSH - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az vm run-command invoke --command-id RunPowerShellScript -n winTestVM -g ${{ matrix.AZURE_RESOURCE_GROUP }} --scripts @$GITHUB_WORKSPACE/script/setup/enable_ssh_windows.ps1 --parameters 'SSHPublicKey=${{ env.SSH_PUB_KEY }}' @@ -306,14 +306,14 @@ jobs: echo 'GCP_WORKLOAD_IDENTITY_PROVIDER=${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}' >> $GITHUB_OUTPUT - name: AuthGcp - uses: google-github-actions/auth@v0 + uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} - name: UploadJobReport - uses: google-github-actions/upload-cloud-storage@v0.10.4 + uses: google-github-actions/upload-cloud-storage@386ab77f37fdf51c0e38b3d229fad286861cc0d0 # v2.2.1 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: path: ${{ github.workspace }}/latest-build.txt @@ -321,7 +321,7 @@ jobs: parent: false - name: UploadLogsDir - uses: google-github-actions/upload-cloud-storage@v0.10.4 + uses: google-github-actions/upload-cloud-storage@386ab77f37fdf51c0e38b3d229fad286861cc0d0 # v2.2.1 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: path: ${{ env.LOGS_DIR }} @@ -329,7 +329,7 @@ jobs: parent: false - name: Check all CI stages succeeded - uses: actions/github-script@v6 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const stepResults = { @@ -349,7 +349,7 @@ jobs: - name: ResourceCleanup if: always() - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group delete -g ${{ matrix.AZURE_RESOURCE_GROUP }} --yes diff --git a/.github/workflows/windows-periodic.yml b/.github/workflows/windows-periodic.yml index 17a72491cae6..761469a5038e 100644 --- a/.github/workflows/windows-periodic.yml +++ b/.github/workflows/windows-periodic.yml @@ -45,17 +45,17 @@ jobs: win_ver: [ltsc2019, ltsc2022] include: - win_ver: ltsc2019 - AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2019-Datacenter:17763.4377.230505" + AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2019-Datacenter:latest" AZURE_RESOURCE_GROUP: ctrd-integration-ltsc2019-${{ github.run_id }} GOOGLE_BUCKET: "containerd-integration/logs/windows-ltsc2019/" - win_ver: ltsc2022 - AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2022-datacenter-smalldisk-g2:20348.1607.230310" + AZURE_IMG: "MicrosoftWindowsServer:WindowsServer:2022-datacenter-smalldisk-g2:latest" AZURE_RESOURCE_GROUP: ctrd-integration-ltsc2022-${{ github.run_id }} GOOGLE_BUCKET: "containerd-integration/logs/windows-ltsc2022/" runs-on: ubuntu-latest timeout-minutes: 90 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install required packages run: | @@ -81,18 +81,18 @@ jobs: echo "SSH_PUB_KEY=$(cat ~/.ssh/id_rsa.pub)" >> $GITHUB_ENV - name: AZLogin - uses: azure/login@v1 + uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 with: creds: ${{ secrets.AZURE_CREDS }} - name: AZResourceGroupCreate - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group create -n ${{ matrix.AZURE_RESOURCE_GROUP }} -l ${{ env.AZURE_DEFAULT_LOCATION }} --tags creationTimestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ') - name: AZTestVMCreate - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | DETAILS=$(az vm create -n winTestVM --admin-username ${{ env.DEFAULT_ADMIN_USERNAME }} --admin-password ${{ env.PASSWORD }} --image ${{ matrix.AZURE_IMG }} -g ${{ matrix.AZURE_RESOURCE_GROUP }} --nsg-rule SSH --size ${{ env.AZURE_DEFAULT_VM_SIZE }} --public-ip-sku Standard -o json) @@ -116,7 +116,7 @@ jobs: echo "VM_PUB_IP=$PUB_IP" >> $GITHUB_ENV - name: EnableAZVMSSH - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az vm run-command invoke --command-id RunPowerShellScript -n winTestVM -g ${{ matrix.AZURE_RESOURCE_GROUP }} --scripts @$GITHUB_WORKSPACE/script/setup/enable_ssh_windows.ps1 --parameters 'SSHPublicKey=${{ env.SSH_PUB_KEY }}' @@ -256,14 +256,14 @@ jobs: echo 'GCP_WORKLOAD_IDENTITY_PROVIDER=${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}' >> $GITHUB_OUTPUT - name: AuthGcp - uses: google-github-actions/auth@v0 + uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }} workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} - name: UploadJobReport - uses: google-github-actions/upload-cloud-storage@v0.10.4 + uses: google-github-actions/upload-cloud-storage@386ab77f37fdf51c0e38b3d229fad286861cc0d0 # v2.2.1 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: path: ${{ github.workspace }}/latest-build.txt @@ -271,7 +271,7 @@ jobs: parent: false - name: UploadLogsDir - uses: google-github-actions/upload-cloud-storage@v0.10.4 + uses: google-github-actions/upload-cloud-storage@386ab77f37fdf51c0e38b3d229fad286861cc0d0 # v2.2.1 if: steps.AssignGcpCreds.outputs.GCP_SERVICE_ACCOUNT && steps.AssignGcpCreds.outputs.GCP_WORKLOAD_IDENTITY_PROVIDER with: path: ${{ env.LOGS_DIR }} @@ -279,7 +279,7 @@ jobs: parent: false - name: Check all CI stages succeeded - uses: actions/github-script@v6 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: script: | const stepResults = { @@ -301,7 +301,7 @@ jobs: - name: ResourceCleanup if: always() - uses: azure/CLI@v1 + uses: azure/CLI@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 with: inlinescript: | az group delete -g ${{ matrix.AZURE_RESOURCE_GROUP }} --yes diff --git a/.gitignore b/.gitignore index 73ba2c68530f..58fff8c76ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# If you want to ignore files created by your editor/tools, please consider a +# [global .gitignore](https://help.github.com/articles/ignoring-files). + /bin/ /man/ coverage.txt diff --git a/.golangci.yml b/.golangci.yml index fec369f6d4af..5ad1b03026b9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,6 @@ linters: enable: + - depguard # Checks for dependencies that should not be (re)introduced. See "linter-settings" for further details. - exportloopref # Checks for pointers to enclosing loop variables - gofmt - goimports @@ -12,7 +13,7 @@ linters: - tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17 - unconvert - unused - - vet + - govet - dupword # Checks for duplicate words in the source code disable: - errcheck @@ -32,6 +33,8 @@ issues: - path: 'archive[\\/]tarheader[\\/]' # conversion is necessary on Linux, unnecessary on macOS text: "unnecessary conversion" + - path: 'integration[\\/]client' + text: "dot-imports:" - linters: - revive text: "if-return" @@ -52,6 +55,13 @@ issues: text: "redefines-builtin-id" linters-settings: + depguard: + rules: + main: + deny: + - pkg: github.com/opencontainers/runc + desc: We don't want to depend on runc (libcontainer), unless there is no other option; see https://github.com/opencontainers/runc/issues/3028. + gosec: # The following issues surfaced when `gosec` linter # was enabled. They are temporarily excluded to unblock @@ -63,15 +73,16 @@ linters-settings: - G306 - G402 - G404 + nolintlint: + allow-unused: true -run: - timeout: 8m - skip-dirs: + exclude-dirs: - api - cluster - - design - docs - docs/man - releases - - reports - test # e2e scripts + +run: + timeout: 8m diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 000000000000..7fc4f702d67e --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,8 @@ +# This file accompanies links verification nightly CI job. Add links to ignore here. + +# These fail often due its popularity +https://packages.debian.org/buster-backports/libseccomp2 +https://packages.ubuntu.com/trusty-backports/libseccomp2 + +# Fails often with 'Too Many Requests', easy to scare +https://tanzu.vmware.com/kubernetes-grid diff --git a/.mailmap b/.mailmap index 87221c9af07e..f2e324e22af6 100644 --- a/.mailmap +++ b/.mailmap @@ -3,12 +3,15 @@ Abhinandan Prativadi Ace-Tang Adam Korcz Aditi Sharma +Akhil Mohan Akihiro Suda Akihiro Suda Allen Sun +Alex Ellis Alexander Morozov Antonio Ojea Antonio Ojea +Amir M. Ghazanfari Amit Krishnan Andrei Vagin Andrey Kolomentsev @@ -26,8 +29,10 @@ Cory Bennett Cristian Staretu Cristian Staretu Daniel Dao +Danny Canter Derek McGowan Edgar Lee +Enrico Weigelt Eric Ernst Eric Lin Eric Ren @@ -50,7 +55,8 @@ haoyun Harry Zhang Hu Shuai Hu Shuai -Iceber Gu +Iceber Gu +Iceber Gu Jaana Burcu Dogan Jess Valarezo Jess Valarezo @@ -69,17 +75,22 @@ Lorenz Brun Luc Perkins James Sturtevant Jiajun Jiang +Jin Dong Julien Balestra Jun Lin Chen <1913688+mc256@users.noreply.github.com> Justin Cormack Justin Terry Justin Terry Kante +Kazuyoshi Kato +Kazuyoshi Kato Kazuyoshi Kato Kenfe-Mickaël Laventure Kevin Kern Kevin Parsons Kevin Xu +Kirtana Ashok +Kirtana Ashok Kitt Hsu Kohei Tokunaga Krasi Georgiev @@ -89,17 +100,22 @@ lengrongfu <1275177125@qq.com> Li Yuxuan Lifubang Lu Jingxiao +Lucas Rattz +Mahamed Ali Maksym Pavlenko <865334+mxpv@users.noreply.github.com> Maksym Pavlenko +Maksym Pavlenko Maksym Pavlenko Mario Hros Mario Hros Mario Macias Mark Gordon +Markus Lehtonen Marvin Giessing Mathis Michel Michael Crosby Michael Katsoulis +Michael Zappa Mike Brown Mohammad Asif Siddiqui Nabeel Rana @@ -108,11 +124,13 @@ Ning Li ningmingxiao Nishchay Kumar Oliver Stenbom +Pan Yibo Phil Estes Phil Estes Qian Zhang Reid Li Robin Winkelewski +roman-kiselenko Ross Boucher Ruediger Maass Rui Cao @@ -147,6 +165,7 @@ wangzhan Wei Fu Wei Fu wen chen +William Chen Xiaodong Zhang Xuean Yan Yang Yang @@ -155,6 +174,7 @@ Yuxing Liu Zechun Chen zhang he Zhang Wei +zhangpeng zhangyadong Zhenguang Zhu Zhiyu Li @@ -162,5 +182,7 @@ Zhiyu Li <404977848@qq.com> Zhongming Chang Zhoulin Xie Zhoulin Xie <42261994+JoeWrightss@users.noreply.github.com> +zounengren zounengren 张潇 +张钰 diff --git a/ADOPTERS.md b/ADOPTERS.md index fabf3d8519d9..407593cb81f7 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -32,8 +32,6 @@ including the Balena project listed below. **_Rancher's Rio project_** - Rancher Labs [Rio](https://github.com/rancher/rio) project uses containerd as the runtime for a combined Kubernetes, Istio, and container "Cloud Native Container Distribution" platform. -**_Eliot_** - The [Eliot](https://github.com/ernoaapa/eliot) container project for IoT device container management uses containerd as the runtime. - **_Balena_** - Resin's [Balena](https://github.com/resin-os/balena) container engine, based on moby/moby but for edge, embedded, and IoT use cases, uses the containerd and runc stack in the same way that the Docker engine uses containerd. **_LinuxKit_** - the Moby project's [LinuxKit](https://github.com/linuxkit/linuxkit) for building secure, minimal Linux OS images in a container-native model uses containerd as the core runtime for system and service containers. @@ -58,7 +56,9 @@ including the Balena project listed below. **_Deckhouse_** - [Deckhouse Kubernetes Platform](https://deckhouse.io/) from Flant allows you to manage Kubernetes clusters anywhere in a fully automatic and uniform fashion. It uses containerd as the default CRI runtime. -**_[Actuated](https://actuated.dev)** - Actuated is a platform for running self-hosted CI in securely-isolated Firecracker VMs. Actuated uses containerd's image pulling facility to distribute and update the root filesystem for VMs for CI agents. +**_[Actuated](https://actuated.dev)_** - Actuated is a platform for running self-hosted CI in securely-isolated Firecracker VMs. Actuated uses containerd's image pulling facility to distribute and update the root filesystem for VMs for CI agents. + +**_[Syself Autopilot](https://syself.com)** - Syself Autopilot is a simplified Kubernetes platform based on Cluster API that can run on various providers. Syself Autopilot uses containerd as the default CRI runtime. **_Other Projects_** - While the above list provides a cross-section of well known uses of containerd, the simplicity and clear API layer for containerd has inspired many smaller projects around providing simple container management platforms. Several examples of building higher layer functionality on top of the containerd base have come from various containerd community participants: - Michael Crosby's [boss](https://github.com/crosbymichael/boss) project, diff --git a/BUILDING.md b/BUILDING.md index 9efc1881af23..0c6d5b747824 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -25,7 +25,7 @@ A codespace will open in a web-based version of Visual Studio Code. The [dev con To build the `containerd` daemon, and the `ctr` simple test client, the following build system dependencies are required: -* Go 1.20.x or above +* Go 1.22.x or above * Protoc 3.x compiler and headers (download at the [Google protobuf releases page](https://github.com/protocolbuffers/protobuf/releases)) * Btrfs headers and libraries for your distribution. Note that building the btrfs driver can be disabled via the build tag `no_btrfs`, removing this dependency. @@ -150,46 +150,44 @@ make STATIC=1 # Via Docker container -The following instructions assume you are at the parent directory of containerd source directory. +> [!NOTE] +> The following instructions assume you are at the **parent** directory of containerd source directory. ## Build containerd in a container -You can build `containerd` via a Linux-based Docker container. -You can build an image from this `Dockerfile`: +You can build `containerd` via a Linux-based Docker container using the [Docker official `golang` image](https://hub.docker.com/_/golang/) -```dockerfile -FROM golang -``` - -Let's suppose that you built an image called `containerd/build`. From the -containerd source root directory you can run the following command: +From the **parent** directory of `containerd`'s cloned repo you can run the following command: ```sh docker run -it \ - -v ${PWD}/containerd:/go/src/github.com/containerd/containerd \ - -e GOPATH=/go \ - -w /go/src/github.com/containerd/containerd containerd/build sh + -v ${PWD}/containerd:/src/containerd \ + -w /src/containerd golang ``` -This mounts `containerd` repository - -You are now ready to [build](#build-containerd): +This mounts the `containerd` repository inside the image at `/src/containerd` and, by default, runs a shell at that directory. -```sh -make && make install -``` +Now, you are now ready to follow the [build instructions](#build-containerd): ## Build containerd and runc in a container To have complete core container runtime, you will need both `containerd` and `runc`. It is possible to build both of these via Docker container. -You can use `git` to checkout `runc`: +You can clone `runc` in the same parent directory where you cloned `containerd` and you should clone [the latest stable version of `runc`](https://github.com/opencontainers/runc/releases), e.g. v1.1.13: ```sh -git clone https://github.com/opencontainers/runc +git clone --branch https://github.com/opencontainers/runc ``` -We can build an image from this `Dockerfile`: +In our Docker container we will build `runc` build, which includes +[seccomp](https://en.wikipedia.org/wiki/seccomp), [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), +and [AppArmor](https://en.wikipedia.org/wiki/AppArmor) support. Seccomp support +in runc requires `libseccomp-dev` as a dependency (AppArmor and SELinux support +do not require external libraries at build time). Refer to [RUNC.md](docs/RUNC.md) +in the docs directory to for details about building runc, and to learn about +supported versions of `runc` as used by containerd. + +Since we need [`libseccomp-dev`](https://packages.debian.org/stable/libseccomp-dev) installed as a dependency, we will need a custom Docker image derived from the official `golang` image. You can use the following `Dockerfile` to build your custom image: ```sh FROM golang @@ -198,44 +196,57 @@ RUN apt-get update && \ apt-get install -y libseccomp-dev ``` -In our Docker container we will build `runc` build, which includes -[seccomp](https://en.wikipedia.org/wiki/seccomp), [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux), -and [AppArmor](https://en.wikipedia.org/wiki/AppArmor) support. Seccomp support -in runc requires `libseccomp-dev` as a dependency (AppArmor and SELinux support -do not require external libraries at build time). Refer to [RUNC.md](docs/RUNC.md) -in the docs directory to for details about building runc, and to learn about -supported versions of `runc` as used by containerd. +Let's suppose you've built an image named `containerd/build` from the above `Dockerfile`. -Let's suppose you build an image called `containerd/build` from the above Dockerfile. You can run the following command: +You can run the following command: ```sh -docker run -it --privileged \ - -v /var/lib/containerd \ - -v ${PWD}/runc:/go/src/github.com/opencontainers/runc \ - -v ${PWD}/containerd:/go/src/github.com/containerd/containerd \ - -e GOPATH=/go \ - -w /go/src/github.com/containerd/containerd containerd/build sh +docker run -it \ + -v ${PWD}/containerd:/src/containerd \ + -v ${PWD}/runc:/src/runc \ + -w /src/containerd \ + containerd/build ``` This mounts both `runc` and `containerd` repositories in our Docker container. -From within our Docker container let's build `containerd`: +From within the Docker container, let's build `containerd`: ```sh -cd /go/src/github.com/containerd/containerd make && make install ``` -These binaries can be found in the `./bin` directory in your host. -`make install` will move the binaries in your `$PATH`. +You can check the installed binaries with: + +```sh +$ which containerd +/usr/local/bin/containerd + +$ containerd --version +containerd github.com/containerd/containerd/v2 v2.0.0-rc.3-195-gf5d5407c2 f5d5407c2ff12865653a9a132d5783196be82763 +``` Next, let's build `runc`: ```sh -cd /go/src/github.com/opencontainers/runc +cd /src/runc make && make install ``` +You can check the installed binaries with: + +```sh +$ which runc +/usr/local/sbin/runc + +$ runc --version +runc version 1.1.13 +commit: v1.1.13-0-g58aa9203 +spec: 1.0.2-dev +go: go1.23.0 +libseccomp: 2.5.4 +``` + For further details about building runc, refer to [RUNC.md](docs/RUNC.md) in the docs directory. @@ -259,25 +270,25 @@ name and also how to use the flag directly against `go test` to run root-requiri ```sh # run the test : -go test -v -run "" . +go test -v -run "" ./path/to/package # enable the root-requiring tests: -go test -v -run . -test.root +go test -v -run ./path/to/package -test.root ``` Example output from directly running `go test` to execute the `TestContainerList` test: ```sh -sudo go test -v -run "TestContainerList" . -test.root -INFO[0000] running tests against containerd revision=f2ae8a020a985a8d9862c9eb5ab66902c2888361 version=v1.0.0-beta.2-49-gf2ae8a0 +sudo go test -v -run "TestContainerList" ./integration/client -test.root === RUN TestContainerList --- PASS: TestContainerList (0.00s) PASS -ok github.com/containerd/containerd 4.778s + +ok github.com/containerd/containerd/v2/integration/client 2.584s ``` > *Note*: in order to run `sudo go` you need to > - either keep user PATH environment variable. ex: `sudo "PATH=$PATH" env go test ` -> - or use `go test -exec` ex: `go test -exec sudo -v -run "TestTarWithXattr" ./archive/ -test.root` +> - or use `go test -exec` ex: `go test -exec sudo -v -run "TestTarWithXattr" ./pkg/archive -test.root` ## Additional tools diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..f6f655f7403c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,72 @@ +# Contributors' Guide + +This guide will help familiarize contributors to the `containerd/containerd` repository. + +## Prerequisite + +First read the containerd project's [general guidelines around contribution](https://github.com/containerd/project/blob/main/CONTRIBUTING.md) +which apply to all containerd projects. + +## Getting started + +See [`BUILDING.md`](https://github.com/containerd/containerd/blob/main/BUILDING.md) for instructions for setting up a development environment. + +If you are also a new user to containerd, you can first check out the [_Getting started with containerd_](https://github.com/containerd/containerd/blob/main/docs/getting-started.md) guide. + +## Setting up your local environment + +At a minimum, the dev tools from `script/setup/install-dev-tools` should be installed. +Run `make install-deps` to install dependencies used for running and developing the CRI plugin. +Other install scripts under `script/setup` may need to be run depending on your environment and your preference for installing libraries and dependencies. +The versions used by `containerd/containerd` CI can be found in `script/setup` and referred to if installing manually. + +``` +$ script/setup/install-dev-tools +$ make install-deps +``` + +## Code style + +- Go files adhere to standard Go formatting and styling +- Protobuf files use tabs for indentation +- Other files must not contain trailing whitespace and should end with a single new line character + +Use the `check` command in the makefile to verify your code matches the expected style. + +``` +make check +``` + +## Updating protobuf files + +Ensure protoc and dev tools have been installed, then run `make protos` + +> **Note** +> When running `make protos`, the current working directory should be found under the `GOPATH` environment +> variable to ensure protoc can properly resolve the paths of protofiles in the project. + +## Naming packages + +Package names should be short and simple. Avoid using `_` and repeating words from parent directories. + +### Where to put packages + +Try to put a new package under the appropriate root directories. The root directory is reserved for +configuration and build files, no source files will be accepted in root since containerd v2.0. + +- `api` - All protobuf service definitions and types used by services +- `bin` - Autogenerated during build, do not check in file here +- `client` - All Go files for the containerd client (formerly in `containerd/containerd` root in 1.x) +- `cmd` - All Go main packages and the packages used only for that main package +- `contrib` - Files, configurations, and packages related to external tools or libraries +- `core` - Core Go packages with interface definitions and built-in implementations +- `docs` - All containerd technical documentation using markdown +- `internal` - All utility packages used by containerd and not intended for direct import +- `man`- All containerd reference manuals used for the `man` command +- `pkg` - Non-core Go packages used by clients and other containerd packages +- `plugins` - All included containerd plugins which are registered via init +- `releases` - All release note files +- `script` - All scripts used for testing, development, and CI +- `test` - Test scripts used for external end to end testing of containerd, do not add new files here +- `vendor` - Autogenerated vendor files from `make vendor` command, do not manually edit files here +- `version` - Version package with the current containerd version diff --git a/Makefile b/Makefile index ecf1d4c39168..3fce2bf7b1d4 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ TEST_IMAGE_LIST ?= # Used to populate variables in version package. VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty='.m' --always) REVISION ?= $(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi) -PACKAGE=github.com/containerd/containerd +PACKAGE=github.com/containerd/containerd/v2 SHIM_CGO_ENABLED ?= 0 ifneq "$(strip $(shell command -v $(GO) 2>/dev/null))" "" @@ -81,7 +81,7 @@ STATICRELEASE=containerd-static-$(VERSION:v%=%)-${GOOS}-${GOARCH} CRIRELEASE=cri-containerd-$(VERSION:v%=%)-${GOOS}-${GOARCH} CRICNIRELEASE=cri-containerd-cni-$(VERSION:v%=%)-${GOOS}-${GOARCH} -PKG=github.com/containerd/containerd +PKG=github.com/containerd/containerd/v2 # Project binaries. COMMANDS=ctr containerd containerd-stress @@ -96,7 +96,11 @@ GO_BUILDTAGS += ${DEBUG_TAGS} ifneq ($(STATIC),) GO_BUILDTAGS += osusergo netgo static_build endif + +SHIM_GO_BUILDTAGS := $(GO_BUILDTAGS) no_grpc + GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(strip $(GO_BUILDTAGS))",) +SHIM_GO_TAGS=$(if $(SHIM_GO_BUILDTAGS),-tags "$(strip $(SHIM_GO_BUILDTAGS))",) GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS) ifneq ($(STATIC),) @@ -109,7 +113,6 @@ SHIM_GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version # Project packages. PACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration) API_PACKAGES=$(shell (cd api && $(GO) list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration)) -NON_API_PACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration | grep -v "containerd/api") TEST_REQUIRES_ROOT_PACKAGES=$(filter \ ${PACKAGES}, \ $(shell \ @@ -129,7 +132,7 @@ endif GOPATHS=$(shell $(GO) env GOPATH | tr ":" "\n" | tr ";" "\n") TESTFLAGS_RACE= -GO_BUILD_FLAGS= +GO_BUILD_FLAGS ?= # See Golang issue re: '-trimpath': https://github.com/golang/go/issues/13809 GO_GCFLAGS=$(shell \ set -- ${GOPATHS}; \ @@ -151,7 +154,8 @@ GOTEST ?= $(GO) test OUTPUTDIR = $(join $(ROOTDIR), _output) CRIDIR=$(OUTPUTDIR)/cri -.PHONY: clean all AUTHORS build binaries test integration generate protos check-protos coverage ci check help install uninstall vendor release static-release mandir install-man install-doc genman install-cri-deps cri-release cri-cni-release cri-integration install-deps bin/cri-integration.test + +.PHONY: clean all AUTHORS build binaries test integration generate protos check-protos coverage ci check help install uninstall vendor release static-release mandir install-man install-doc genman install-cri-deps cri-release cri-cni-release cri-integration install-deps bin/cri-integration.test remove-replace clean-vendor .DEFAULT: default # Forcibly set the default goal to all, in case an include above brought in a rule definition. @@ -172,16 +176,19 @@ generate: protos @echo "$(WHALE) $@" @PATH="${ROOTDIR}/bin:${PATH}" $(GO) generate -x ${PACKAGES} -protos: bin/protoc-gen-go-fieldpath +protos: bin/protoc-gen-go-fieldpath bin/go-buildtag @echo "$(WHALE) $@" @find . -path ./vendor -prune -false -o -name '*.pb.go' | xargs rm $(eval TMPDIR := $(shell mktemp -d)) @mv ${ROOTDIR}/vendor ${TMPDIR} @(cd ${ROOTDIR}/api && PATH="${ROOTDIR}/bin:${PATH}" protobuild --quiet ${API_PACKAGES}) - @(PATH="${ROOTDIR}/bin:${PATH}" protobuild --quiet ${NON_API_PACKAGES}) @mv ${TMPDIR}/vendor ${ROOTDIR} - @rm -rf ${TMPDIR} - go-fix-acronym -w -a '(Id|Io|Uuid|Os)$$' $(shell find api/ runtime/ -name '*.pb.go') + @rm -rf ${TMPDIR} v2 + go-fix-acronym -w -a '^Os' $(shell find api/ -name '*.pb.go') + go-fix-acronym -w -a '(Id|Io|Uuid|Os)$$' $(shell find api/ -name '*.pb.go') + bin/go-buildtag -w --tags '!no_grpc' $(shell find api/ -name '*_grpc.pb.go') + @test -z "$$(git status --short | grep "api/next.pb.txt" | tee /dev/stderr)" || \ + $(GO) mod edit -replace=github.com/containerd/containerd/api=./api check-protos: protos ## check if protobufs needs to be generated again @echo "$(WHALE) $@" @@ -229,13 +236,18 @@ cri-integration: binaries bin/cri-integration.test ## run cri integration tests # build runc shimv2 with failpoint control, only used by integration test bin/containerd-shim-runc-fp-v1: integration/failpoint/cmd/containerd-shim-runc-fp-v1 FORCE @echo "$(WHALE) $@" - @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./integration/failpoint/cmd/containerd-shim-runc-fp-v1 + @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ${SHIM_GO_TAGS} ./integration/failpoint/cmd/containerd-shim-runc-fp-v1 # build CNI bridge plugin wrapper with failpoint support, only used by integration test bin/cni-bridge-fp: integration/failpoint/cmd/cni-bridge-fp FORCE @echo "$(WHALE) $@" @$(GO) build ${GO_BUILD_FLAGS} -o $@ ./integration/failpoint/cmd/cni-bridge-fp +# build runc-fp as runc wrapper to support failpoint, only used by integration test +bin/runc-fp: integration/failpoint/cmd/runc-fp FORCE + @echo "$(WHALE) $@" + @$(GO) build ${GO_BUILD_FLAGS} -o $@ ./integration/failpoint/cmd/runc-fp + benchmark: ## run benchmarks tests @echo "$(WHALE) $@" @$(GO) test ${TESTFLAGS} -bench . -run Benchmark -test.root @@ -258,7 +270,7 @@ bin/gen-manpages: cmd/gen-manpages FORCE bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 @echo "$(WHALE) $@" - @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 + CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${SHIM_GO_TAGS} ./cmd/containerd-shim-runc-v2 binaries: $(BINARIES) ## build binaries @echo "$(WHALE) $@" @@ -380,11 +392,11 @@ releases/$(CRICNIRELEASE).tar.gz: install-cri-deps $(CRIDIR)/cri-containerd.DEPR @tar -czf releases/$(CRICNIRELEASE).tar.gz -C $(CRIDIR) cri-containerd.DEPRECATED.txt etc usr opt endif -cri-release: releases/$(CRIRELEASE).tar.gz +cri-release: releases/$(CRIRELEASE).tar.gz ## Deprecated (only kept for external CI) @echo "$(WHALE) $@" @cd releases && sha256sum $(CRIRELEASE).tar.gz >$(CRIRELEASE).tar.gz.sha256sum && ln -sf $(CRIRELEASE).tar.gz cri-containerd.tar.gz -cri-cni-release: releases/$(CRICNIRELEASE).tar.gz +cri-cni-release: releases/$(CRICNIRELEASE).tar.gz ## Deprecated (only kept for external CI) @echo "$(WHALE) $@" @cd releases && sha256sum $(CRICNIRELEASE).tar.gz >$(CRICNIRELEASE).tar.gz.sha256sum && ln -sf $(CRICNIRELEASE).tar.gz cri-cni-containerd.tar.gz @@ -462,22 +474,29 @@ root-coverage: ## generate coverage profiles for unit tests that require root fi; \ done ) +remove-replace: + @echo "$(WHALE) $@" + @$(GO) mod edit -dropreplace=github.com/containerd/containerd/api + vendor: ## ensure all the go.mod/go.sum files are up-to-date including vendor/ directory @echo "$(WHALE) $@" @$(GO) mod tidy @$(GO) mod vendor @$(GO) mod verify - @(cd ${ROOTDIR}/integration/client && ${GO} mod tidy) + @(cd ${ROOTDIR}/api && ${GO} mod tidy) verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date @echo "$(WHALE) $@" $(eval TMPDIR := $(shell mktemp -d)) @cp -R ${ROOTDIR} ${TMPDIR} @(cd ${TMPDIR}/containerd && ${GO} mod tidy) - @(cd ${TMPDIR}/containerd/integration/client && ${GO} mod tidy) + @(cd ${TMPDIR}/containerd && ${GO} mod vendor) + @(cd ${TMPDIR}/containerd && ${GO} mod verify) + @(cd ${TMPDIR}/containerd/api && ${GO} mod tidy) @diff -r -u -q ${ROOTDIR} ${TMPDIR}/containerd @rm -rf ${TMPDIR} - @${ROOTDIR}/script/verify-go-modules.sh integration/client + +clean-vendor: remove-replace vendor help: ## this help diff --git a/Protobuild.toml b/Protobuild.toml deleted file mode 100644 index 976174e5dff5..000000000000 --- a/Protobuild.toml +++ /dev/null @@ -1,21 +0,0 @@ -version = "2" -generators = ["go"] - -# Control protoc include paths. Below are usually some good defaults, but feel -# free to try it without them if it works for your project. -[includes] - # Include paths that will be added before all others. Typically, you want to - # treat the root of the project as an include, but this may not be necessary. - before = ["./protobuf"] - - # Paths that will be added untouched to the end of the includes. We use - # `/usr/local/include` to pickup the common install location of protobuf. - # This is the default. - after = ["/usr/local/include", "/usr/include"] - -[[descriptors]] -prefix = "github.com/containerd/containerd/runtime/v2/runc/options" -target = "runtime/v2/runc/options/next.pb.txt" -ignore_files = [ - "google/protobuf/descriptor.proto", -] diff --git a/README.md b/README.md index 76d0845944df..28ee01e7aa87 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ ![containerd banner light mode](https://raw.githubusercontent.com/cncf/artwork/master/projects/containerd/horizontal/color/containerd-horizontal-color.png#gh-light-mode-only) ![containerd banner dark mode](https://raw.githubusercontent.com/cncf/artwork/master/projects/containerd/horizontal/white/containerd-horizontal-white.png#gh-dark-mode-only) -[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/containerd)](https://pkg.go.dev/github.com/containerd/containerd) -[![Build Status](https://github.com/containerd/containerd/workflows/CI/badge.svg)](https://github.com/containerd/containerd/actions?query=workflow%3ACI) +[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/containerd/v2)](https://pkg.go.dev/github.com/containerd/containerd/v2) +[![Build Status](https://github.com/containerd/containerd/actions/workflows/ci.yml/badge.svg?event=merge_group)](https://github.com/containerd/containerd/actions?query=workflow%3ACI+event%3Amerge_group) [![Nightlies](https://github.com/containerd/containerd/workflows/Nightly/badge.svg)](https://github.com/containerd/containerd/actions?query=workflow%3ANightly) -[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/containerd)](https://goreportcard.com/report/github.com/containerd/containerd) +[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/containerd/v2)](https://goreportcard.com/report/github.com/containerd/containerd/v2) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1271/badge)](https://bestpractices.coreinfrastructure.org/projects/1271) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/containerd/containerd/badge)](https://scorecard.dev/viewer/?uri=github.com/containerd/containerd) +[![Check Links](https://github.com/containerd/containerd/actions/workflows/links.yml/badge.svg)](https://github.com/containerd/containerd/actions/workflows/links.yml) containerd is an industry-standard container runtime with an emphasis on simplicity, robustness, and portability. It is available as a daemon for Linux and Windows, which can manage the complete container lifecycle of its host system: image transfer and storage, container execution and supervision, low-level storage and network attachments, etc. @@ -17,16 +19,8 @@ containerd is designed to be embedded into a larger system, rather than being us ## Announcements -### Hello Kubernetes v1.24! -The containerd project would like to announce containerd [v1.6.4](https://github.com/containerd/containerd/releases/tag/v1.6.4). While other prior releases are supported, this latest release and the containerd [v1.5.11](https://github.com/containerd/containerd/releases/tag/v1.5.11) release are recommended for Kubernetes v1.24. - -We felt it important to announce this, particularly in view of [the dockershim removal from this release of Kubernetes](https://kubernetes.io/blog/2022/05/03/dockershim-historical-context/). - -It should be noted here that moving to CRI integrations has been in the plan for many years. `containerd` began as part of `Docker` and was donated to `CNCF`. `containerd` remains in use today by Docker/moby/buildkit etc., and has many other [adopters](https://github.com/containerd/containerd/blob/main/ADOPTERS.md). `containerd` has a namespace that isolates use of `containerd` from various clients/adopters. The Kubernetes namespace is appropriately named `k8s.io`. The CRI API and `containerd` CRI plugin project has, from the start, been an effort to reduce the impact surface for Kubernetes container runtime integration. If you can't tell, we are excited to see this come to fruition. - -If you have any concerns or questions, we will be here to answer them in [issues, discussions, and/or on slack](#communication). Below you will find information/detail about our [CRI Integration](#cri) implementation. - -For containerd users already on v1.6.0-v1.6.3, there are known issues addressed by [v1.6.4](https://github.com/containerd/containerd/releases/tag/v1.6.4). The issues are primarily related to [CNI setup](https://github.com/kubernetes/website/blob/dev-1.24/content/en/docs/tasks/administer-cluster/migrating-from-dockershim/troubleshooting-cni-plugin-related-errors.md) +### containerd v2.0 is now released! +See [`docs/containerd-2.0.md`](docs/containerd-2.0.md). ### Now Recruiting @@ -47,7 +41,7 @@ See our documentation on [containerd.io](https://containerd.io): * [namespaces](docs/namespaces.md) * [client options](docs/client-opts.md) -See how to build containerd from source at [BUILDING](BUILDING.md). +To get started contributing to containerd, see [CONTRIBUTING](CONTRIBUTING.md). If you are interested in trying out containerd see our example at [Getting Started](docs/getting-started.md). @@ -98,164 +92,8 @@ For configuring registries, see [registry host configuration documentation](docs ## Features -### Client - -containerd offers a full client package to help you integrate containerd into your platform. - -```go - -import ( - "context" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/namespaces" -) - - -func main() { - client, err := containerd.New("/run/containerd/containerd.sock") - defer client.Close() -} - -``` - -### Namespaces - -Namespaces allow multiple consumers to use the same containerd without conflicting with each other. It has the benefit of sharing content while maintaining separation with containers and images. - -To set a namespace for requests to the API: - -```go -context = context.Background() -// create a context for docker -docker = namespaces.WithNamespace(context, "docker") - -containerd, err := client.NewContainer(docker, "id") -``` - -To set a default namespace on the client: - -```go -client, err := containerd.New(address, containerd.WithDefaultNamespace("docker")) -``` - -### Distribution - -```go -// pull an image -image, err := client.Pull(context, "docker.io/library/redis:latest") - -// push an image -err := client.Push(context, "docker.io/library/redis:latest", image.Target()) -``` - -### Containers - -In containerd, a container is a metadata object. Resources such as an OCI runtime specification, image, root filesystem, and other metadata can be attached to a container. - -```go -redis, err := client.NewContainer(context, "redis-master") -defer redis.Delete(context) -``` - -### OCI Runtime Specification - -containerd fully supports the OCI runtime specification for running containers. We have built-in functions to help you generate runtime specifications based on images as well as custom parameters. - -You can specify options when creating a container about how to modify the specification. - -```go -redis, err := client.NewContainer(context, "redis-master", containerd.WithNewSpec(oci.WithImageConfig(image))) -``` - -### Root Filesystems - -containerd allows you to use overlay or snapshot filesystems with your containers. It comes with built-in support for overlayfs and btrfs. - -```go -// pull an image and unpack it into the configured snapshotter -image, err := client.Pull(context, "docker.io/library/redis:latest", containerd.WithPullUnpack) - -// allocate a new RW root filesystem for a container based on the image -redis, err := client.NewContainer(context, "redis-master", - containerd.WithNewSnapshot("redis-rootfs", image), - containerd.WithNewSpec(oci.WithImageConfig(image)), -) - -// use a readonly filesystem with multiple containers -for i := 0; i < 10; i++ { - id := fmt.Sprintf("id-%s", i) - container, err := client.NewContainer(ctx, id, - containerd.WithNewSnapshotView(id, image), - containerd.WithNewSpec(oci.WithImageConfig(image)), - ) -} -``` - -### Tasks - -Taking a container object and turning it into a runnable process on a system is done by creating a new `Task` from the container. A task represents the runnable object within containerd. - -```go -// create a new task -task, err := redis.NewTask(context, cio.NewCreator(cio.WithStdio)) -defer task.Delete(context) - -// the task is now running and has a pid that can be used to setup networking -// or other runtime settings outside of containerd -pid := task.Pid() - -// start the redis-server process inside the container -err := task.Start(context) - -// wait for the task to exit and get the exit status -status, err := task.Wait(context) -``` - -### Checkpoint and Restore - -If you have [criu](https://criu.org/Main_Page) installed on your machine you can checkpoint and restore containers and their tasks. This allows you to clone and/or live migrate containers to other machines. - -```go -// checkpoint the task then push it to a registry -checkpoint, err := task.Checkpoint(context) - -err := client.Push(context, "myregistry/checkpoints/redis:master", checkpoint) - -// on a new machine pull the checkpoint and restore the redis container -checkpoint, err := client.Pull(context, "myregistry/checkpoints/redis:master") - -redis, err = client.NewContainer(context, "redis-master", containerd.WithNewSnapshot("redis-rootfs", checkpoint)) -defer container.Delete(context) - -task, err = redis.NewTask(context, cio.NewCreator(cio.WithStdio), containerd.WithTaskCheckpoint(checkpoint)) -defer task.Delete(context) - -err := task.Start(context) -``` - -### Snapshot Plugins - -In addition to the built-in Snapshot plugins in containerd, additional external -plugins can be configured using GRPC. An external plugin is made available using -the configured name and appears as a plugin alongside the built-in ones. - -To add an external snapshot plugin, add the plugin to containerd's config file -(by default at `/etc/containerd/config.toml`). The string following -`proxy_plugin.` will be used as the name of the snapshotter and the address -should refer to a socket with a GRPC listener serving containerd's Snapshot -GRPC API. Remember to restart containerd for any configuration changes to take -effect. - -``` -[proxy_plugins] - [proxy_plugins.customsnapshot] - type = "snapshot" - address = "/var/run/mysnapshotter.sock" -``` - -See [PLUGINS.md](/docs/PLUGINS.md) for how to create plugins +For a detailed overview of containerd's core concepts and the features it supports, +please refer to the [FEATURES.MD](./docs/features.md) document. ### Releases and API Stability @@ -299,9 +137,6 @@ loaded for the user's shell environment. `cri` is a native plugin of containerd. Since containerd 1.1, the cri plugin is built into the release binaries and enabled by default. -> **Note:** As of containerd 1.5, the `cri` plugin is merged into the containerd/containerd repo. For example, the source code previously stored under [`containerd/cri/pkg`](https://github.com/containerd/cri/tree/release/1.4/pkg) -was moved to [`containerd/containerd/pkg/cri` package](https://github.com/containerd/containerd/tree/main/pkg/cri). - The `cri` plugin has reached GA status, representing that it is: * Feature complete * Works with Kubernetes 1.10 and above @@ -309,7 +144,7 @@ The `cri` plugin has reached GA status, representing that it is: * Passes all [node e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md). * Passes all [e2e tests](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-testing/e2e-tests.md). -See results on the containerd k8s [test dashboard](https://k8s-testgrid.appspot.com/sig-node-containerd) +See results on the containerd k8s [test dashboard](https://testgrid.k8s.io/containerd) #### Validating Your `cri` Setup A Kubernetes incubator project, [cri-tools](https://github.com/kubernetes-sigs/cri-tools), includes programs for exercising CRI implementations. More importantly, cri-tools includes the program `critest` which is used for running [CRI Validation Testing](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-validation.md). diff --git a/RELEASES.md b/RELEASES.md index 086ba6f1faef..d469cc448ed0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -106,21 +106,27 @@ convert to a regular _Active_ release with stricter backport criteria. The current state is available in the following tables: -| Release | Status | Start | End of Life | -| --------- | ------------- | ------------------ | ------------------- | -| [0.0](https://github.com/containerd/containerd/releases/tag/0.0.5) | End of Life | Dec 4, 2015 | - | -| [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - | -| [0.2](https://github.com/containerd/containerd/tree/v0.2.x) | End of Life | Apr 21, 2016 | December 5, 2017 | -| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.3) | End of Life | December 5, 2017 | December 5, 2018 | -| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | End of Life | April 23, 2018 | October 23, 2019 | -| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.13) | End of Life | October 24, 2018 | October 15, 2020 | -| [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.10) | End of Life | September 26, 2019 | March 4, 2021 | -| [1.4](https://github.com/containerd/containerd/releases/tag/v1.4.13) | End of Life | August 17, 2020 | March 3, 2022 | -| [1.5](https://github.com/containerd/containerd/releases/tag/v1.5.18) | End of Life | May 3, 2021 | February 28, 2023 | -| [1.6](https://github.com/containerd/containerd/releases/tag/v1.6.23) | LTS | February 15, 2022 | max(February 15, 2025 or next LTS + 6 months) | -| [1.7](https://github.com/containerd/containerd/releases/tag/v1.7.3) | Active | March 10, 2023 | max(March 10, 2024 or release of 2.0 + 6 months) | -| [2.0](https://github.com/containerd/containerd/milestone/35) | Next | TBD | TBD | - +| Release | Status | Start | End of Life | +| --------- | ------------- | ------------------ | ------------------- | +| [0.0](https://github.com/containerd/containerd/releases/tag/0.0.5) | End of Life | Dec 4, 2015 | - | +| [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - | +| [0.2](https://github.com/containerd/containerd/tree/v0.2.x) | End of Life | Apr 21, 2016 | December 5, 2017 | +| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.3) | End of Life | December 5, 2017 | December 5, 2018 | +| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | End of Life | April 23, 2018 | October 23, 2019 | +| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.13) | End of Life | October 24, 2018 | October 15, 2020 | +| [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.10) | End of Life | September 26, 2019 | March 4, 2021 | +| [1.4](https://github.com/containerd/containerd/releases/tag/v1.4.13) | End of Life | August 17, 2020 | March 3, 2022 | +| [1.5](https://github.com/containerd/containerd/releases/tag/v1.5.18) | End of Life | May 3, 2021 | February 28, 2023 | +| [1.6](https://github.com/containerd/containerd/releases/tag/v1.6.36) | LTS | February 15, 2022 | next LTS + 6 months | +| [1.7](https://github.com/containerd/containerd/releases/tag/v1.7.23) | Active | March 10, 2023 | active(May 5, 2025), extended(EOL of 1.6) | +| [2.0](https://github.com/containerd/containerd/releases/tag/v2.0.0) | Active | November 5, 2024 | max(November 5, 2025 or release of 2.1 + 6 months) | +| [2.1](https://github.com/containerd/containerd/milestone/48) | Next | TBD | TBD | + +> **_NOTE_** containerd v1.7 will end of life at the same time as v1.6 LTS. Due to +> [Minimal Version Selection](https://go.dev/ref/mod#minimal-version-selection) used +> by Go modules, 1.7 must be supported until EOL of all 1.x releases. Once 1.7 is in +> extended support, it will continue to accept security patches in addition to client +> changes relevant for package importers using the 1.6 LTS daemon. ### Kubernetes Support @@ -133,26 +139,25 @@ for the list of actively tested versions. Kubernetes only supports n-3 minor release versions and containerd will ensure there is always a supported version of containerd for every supported version of Kubernetes. -| Kubernetes Version | containerd Version | CRI Version | -|--------------------|--------------------|-----------------| -| 1.24 | 1.7.0+, 1.6.4+ | v1, v1alpha2 | -| 1.25 | 1.7.0+, 1.6.4+ | v1, v1alpha2 ** | -| 1.26 | 1.7.0+, 1.6.15+ | v1 | -| 1.27 | 1.7.0+, 1.6.15+ | v1 | -| 1.28 | 1.7.0+, 1.6.15+ | v1 | - -** Note: containerd v1.6.*, and v1.7.* support CRI v1 and v1alpha2 through EOL as those releases continue to support older versions of k8s, cloud providers, and other clients using CRI v1alpha2. CRI v1alpha2 is deprecated in v1.7 and will be removed in containerd v2.0. +| Kubernetes Version | containerd Version | CRI Version | +|--------------------|-------------------------------|-----------------| +| 1.29 | 1.7.11+, 1.6.27+ | v1 | +| 1.30 | 2.0.0+, 1.7.13+, 1.6.28+ | v1 | +| 1.31 | 2.0.0+, 1.7.20+, 1.6.34+ | v1 | Deprecated containerd and kubernetes versions -| Containerd Version | Kubernetes Version | CRI Version | -|--------------------------|--------------------|----------------------| -| v1.0 (w/ cri-containerd) | 1.7, 1.8, 1.9 | v1alpha1 | -| v1.1 | 1.10+ | v1alpha2 | -| v1.2 | 1.10+ | v1alpha2 | -| v1.3 | 1.12+ | v1alpha2 | -| v1.4 | 1.19+ | v1alpha2 | -| v1.5 | 1.20+ | v1 (1.23+), v1alpha2 | +| Containerd Version | Kubernetes Version | CRI Version | +|--------------------------|--------------------|--------------------------------------| +| v1.0 (w/ cri-containerd) | 1.7, 1.8, 1.9 | v1alpha1 | +| v1.1 | 1.10+ | v1alpha2 | +| v1.2 | 1.10+ | v1alpha2 | +| v1.3 | 1.12+ | v1alpha2 | +| v1.4 | 1.19+ | v1alpha2 | +| v1.5 | 1.20+ | v1 (1.23+), v1alpha2 (until 1.25) ** | +| v1.6.15+, v1.7.0+ | 1.26+ | v1 | + +** Note: containerd v1.6.*, and v1.7.* support CRI v1 and v1alpha2 through EOL as those releases continue to support older versions of k8s, cloud providers, and other clients using CRI v1alpha2. CRI v1alpha2 is deprecated in v1.7 and will be removed in containerd v2.0. ### Backporting @@ -240,7 +245,7 @@ containerd versions: | Runtime Shim API | Stable | 1.2 | - | | Daemon Config | Stable | 1.0 | - | | CRI GRPC API | Stable | 1.6 (_CRI v1_) | [cri-api](https://github.com/kubernetes/cri-api/tree/master/pkg/apis/runtime/v1) | -| Go client API | Unstable | _future_ | [godoc](https://godoc.org/github.com/containerd/containerd) | +| Go client API | Stable | 2.0 | [godoc](https://pkg.go.dev/github.com/containerd/containerd/v2/client) | | `ctr` tool | Unstable | Out of scope | - | From the version stated in the above table, that component must adhere to the @@ -250,6 +255,11 @@ Unless explicitly stated here, components that are called out as unstable or not covered may change in a future minor version. Breaking changes to "unstable" components will be avoided in patch versions. +Go client API stability includes the `client`, `defaults` and `version` package +as well as all packages under `pkg`, `core`, `api` and `protobuf`. +All packages under `cmd`, `contrib`, `integration`, and `internal` are not +considered part of the stable client API. + ### GRPC API The primary product of containerd is the GRPC API. As of the 1.0.0 release, the @@ -268,6 +278,36 @@ and new fields on messages may be added if they are optional. to the API by having a diff that the CI can run. These files are not intended to be consumed or used by clients. +As of containerd 2.0, the API version diverges from the main containerd version. +While containerd 2.0 is a _major_ version jump for containerd, the API will remain +on 1.x to remain backwards compatible with prior releases and existing clients. +The 2.0 release adds the API to a separate Go module which can remain as the +`github.com/containerd/containerd/api` Go package and imported separately from the +rest of containerd. + +The API minor version will continue to be incremented for each major and minor +version release of containerd. However, the API is tagged directly out of the +main branch with the minor version incrementing earlier in the next release cycle +rather than at the end. This means that after the containerd 2.0 release, the next +API change is tagged as `api/v1.9.0` prior to any containerd 2.1 release. The +latest API version should be backported to all supported versions and patch +releases for prior API versions should be avoided if possible. + + +| Containerd Version | API Version at Release | +|--------------------|------------------------| +| v1.0 | 1.0 | +| v1.1 | 1.1 | +| v1.2 | 1.2 | +| v1.3 | 1.3 | +| v1.4 | 1.4 | +| v1.5 | 1.5 | +| v1.6 | 1.6 | +| v1.7 | 1.7 | +| v2.0 | 1.8 | +| next | 1.9 | + + ### Metrics API The metrics API that outputs prometheus style metrics will be versioned independently, @@ -308,7 +348,7 @@ follow that format. ### Go client API The Go client API, documented in -[godoc](https://godoc.org/github.com/containerd/containerd), is currently +[godoc](https://godoc.org/github.com/containerd/containerd/v2/client), is currently considered unstable. It is recommended to vendor the necessary components to stabilize your project build. Note that because the Go API interfaces with the GRPC API, clients written against a 1.0 Go API should remain compatible with @@ -351,9 +391,26 @@ We will do our best to not break compatibility in the tool in _patch_ releases. The daemon's configuration file, commonly located in `/etc/containerd/config.toml` is versioned and backwards compatible. The `version` field in the config file specifies the config's version. If no version number is specified inside -the config file then it is assumed to be a version 1 config and parsed as such. -Please use `version = 2` to enable version 2 config as version 1 has been -deprecated. +the config file then it is assumed to be a version `1` config and parsed as such. +The latest version is `version = 2`. The `main` branch is being prepared to support +the next config version `3`. The configuration is automatically migrated to the +latest version on each startup, leaving the configuration file unchanged. To avoid +the migration and optimize the daemon startup time, use `containerd config migrate` +to output the configuration as the latest version. Version `1` is no longer deprecated +and is supported by migration, however, it is recommended to use at least version `2`. + +Migrating a configuration to the latest version will limit the prior versions +of containerd in which the configuration can be used. It is suggested not to +migrate your configuration file until you are confident you do not need to +quickly rollback your containerd version. Use the table of configuration +versions to containerd releases to know the minimum version of containerd for +each configuration version. + +| Configuration Version | Minimum containerd version | +|-----------------------|----------------------------| +| 1 | v1.0.0 | +| 2 | v1.3.0 | +| 3 | v2.0.0 | ### Not Covered @@ -379,18 +436,20 @@ against total impact. The deprecated features are shown in the following table: -| Component | Deprecation release | Target release for removal | Recommendation | -|----------------------------------------------------------------------------------|---------------------|----------------------------|------------------------------------------| -| Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | -| Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | -| config.toml `version = 1` | containerd v1.5 | containerd v2.0 ✅ | Use config.toml `version = 2` | -| Built-in `aufs` snapshotter | containerd v1.5 | containerd v2.0 ✅ | Use `overlayfs` snapshotter | -| Container label `containerd.io/restart.logpath` | containerd v1.5 | containerd v2.0 ✅ | Use `containerd.io/restart.loguri` label | -| `cri-containerd-*.tar.gz` release bundles | containerd v1.6 | containerd v2.0 | Use `containerd-*.tar.gz` bundles | -| Pulling Schema 1 images (`application/vnd.docker.distribution.manifest.v1+json`) | containerd v1.7 | containerd v2.0 | Use Schema 2 or OCI images | -| CRI `v1alpha2` | containerd v1.7 | containerd v2.0 ✅ | Use CRI `v1` | -| Legacy CRI implementation of podsandbox support | containerd v2.0 | containerd v2.1 | Disabled by default in 2.0 in favor of core sandboxed CRI plugin (use `DISABLE_CRI_SANDBOXES=1` to fallback to prior CRI podsandbox implementation) | - +| Component | Deprecation release | Target release for removal | Recommendation | +|----------------------------------------------------------------------------------|---------------------|---------------------------------------|------------------------------------------| +| Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | +| Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`) | containerd v1.4 | containerd v2.0 ✅ | Use `io.containerd.runc.v2` | +| Built-in `aufs` snapshotter | containerd v1.5 | containerd v2.0 ✅ | Use `overlayfs` snapshotter | +| Container label `containerd.io/restart.logpath` | containerd v1.5 | containerd v2.0 ✅ | Use `containerd.io/restart.loguri` label | +| `cri-containerd-*.tar.gz` release bundles | containerd v1.6 | containerd v2.0 ✅ | Use `containerd-*.tar.gz` bundles | +| Pulling Schema 1 images (`application/vnd.docker.distribution.manifest.v1+prettyjws`) | containerd v1.7 | containerd v2.1 (Disabled in v2.0 ✅) | Use Schema 2 or OCI images | +| CRI `v1alpha2` | containerd v1.7 | containerd v2.0 ✅ | Use CRI `v1` | +| Legacy CRI implementation of podsandbox support | containerd v2.0 | containerd v2.0 ✅ | | +| Go-Plugin library (`*.so`) as containerd runtime plugin | containerd v2.0 | containerd v2.1 | Use external plugins (proxy or binary) | + +- Pulling Schema 1 images has been disabled in containerd v2.0, but it still can be enabled by setting an environment variable `CONTAINERD_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE=1` + until containerd v2.1. `ctr` users have to specify `--local` too (e.g., `ctr images pull --local`). Users of CRI clients (such as Kubernetes and `crictl`) have to specify this environment variable on the containerd daemon (usually in the systemd unit). ### Deprecated config properties The deprecated properties in [`config.toml`](./docs/cri/config.md) are shown in the following table: @@ -402,10 +461,14 @@ The deprecated properties in [`config.toml`](./docs/cri/config.md) are shown in |`[plugins."io.containerd.grpc.v1.cri".containerd]` | `default_runtime` | containerd v1.3 | containerd v2.0 ✅ | Use `default_runtime_name` | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]` | `runtime_engine` | containerd v1.3 | containerd v2.0 ✅ | Use runtime v2 | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]` | `runtime_root` | containerd v1.3 | containerd v2.0 ✅ | Use `options.Root` | +|`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]` | `disable_cgroup` | - | containerd v2.0 ✅ | Use [cgroup v2 delegation](https://rootlesscontaine.rs/getting-started/common/cgroup2/) | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*.options]` | `CriuPath` | containerd v1.7 | containerd v2.0 ✅ | Set `$PATH` to the `criu` binary | -|`[plugins."io.containerd.grpc.v1.cri".registry]` | `auths` | containerd v1.3 | containerd v2.0 | Use [`ImagePullSecrets`](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). See also [#8228](https://github.com/containerd/containerd/issues/8228). | -|`[plugins."io.containerd.grpc.v1.cri".registry]` | `configs` | containerd v1.5 | containerd v2.0 | Use [`config_path`](./docs/hosts.md) | -|`[plugins."io.containerd.grpc.v1.cri".registry]` | `mirrors` | containerd v1.5 | containerd v2.0 | Use [`config_path`](./docs/hosts.md) | +|`[plugins."io.containerd.grpc.v1.cri".registry]` | `auths` | containerd v1.3 | containerd v2.1 | Use [`ImagePullSecrets`](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). See also [#8228](https://github.com/containerd/containerd/issues/8228). | +|`[plugins."io.containerd.grpc.v1.cri".registry]` | `configs` | containerd v1.5 | containerd v2.1 | Use [`config_path`](./docs/hosts.md) | +|`[plugins."io.containerd.grpc.v1.cri".registry]` | `mirrors` | containerd v1.5 | containerd v2.1 | Use [`config_path`](./docs/hosts.md) | +|`[plugins."io.containerd.tracing.processor.v1.otlp"]` | `endpoint`, `protocol`, `insecure` | containerd v1.6.29 | containerd v2.0 | Use [OTLP environment variables](https://opentelemetry.io/docs/specs/otel/protocol/exporter/), e.g. OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_SDK_DISABLED | +|`[plugins."io.containerd.internal.v1.tracing"]` | `service_name`, `sampling_ratio` | containerd v1.6.29 | containerd v2.0 | Instead use [OTel environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/), e.g. OTEL_SERVICE_NAME, OTEL_TRACES_SAMPLER* | + > **Note** > @@ -461,4 +524,4 @@ more quickly. | [NRI in CRI Support](https://github.com/containerd/containerd/pull/6019) | containerd v1.7 | containerd v2.0 | | [gRPC Shim](https://github.com/containerd/containerd/pull/8052) | containerd v1.7 | containerd v2.0 | | [CRI Runtime Specific Snapshotter](https://github.com/containerd/containerd/pull/6899) | containerd v1.7 | containerd v2.0 | -| [CRI Support for User Namespaces](https://github.com/containerd/containerd/pull/7679) | containerd v1.7 | containerd v2.0 | +| [CRI Support for User Namespaces](./docs/user-namespaces/README.md) | containerd v1.7 | containerd v2.0 | diff --git a/Vagrantfile b/Vagrantfile index 7d374ff1332a..4a4f119a11fe 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -17,7 +17,7 @@ # Vagrantfile for Fedora and EL Vagrant.configure("2") do |config| - config.vm.box = ENV["BOX"] ? ENV["BOX"].split("@")[0] : "fedora/38-cloud-base" + config.vm.box = ENV["BOX"] ? ENV["BOX"].split("@")[0] : "fedora/40-cloud-base" # BOX_VERSION is deprecated. Use "BOX=@". config.vm.box_version = ENV["BOX_VERSION"] || (ENV["BOX"].split("@")[1] if ENV["BOX"]) @@ -35,7 +35,10 @@ Vagrant.configure("2") do |config| v.memory = memory v.cpus = cpus v.machine_virtual_size = disk_size - v.loader = "/usr/share/OVMF/OVMF_CODE.fd" + # https://github.com/vagrant-libvirt/vagrant-libvirt/issues/1725#issuecomment-1454058646 + # Needs `sudo cp /usr/share/OVMF/OVMF_VARS_4M.fd /var/lib/libvirt/qemu/nvram/` + v.loader = '/usr/share/OVMF/OVMF_CODE_4M.fd' + v.nvram = '/var/lib/libvirt/qemu/nvram/OVMF_VARS_4M.fd' end config.vm.synced_folder ".", "/vagrant", type: "rsync" @@ -104,7 +107,7 @@ EOF config.vm.provision "install-golang", type: "shell", run: "once" do |sh| sh.upload_path = "/tmp/vagrant-install-golang" sh.env = { - 'GO_VERSION': ENV['GO_VERSION'] || "1.21.1", + 'GO_VERSION': ENV['GO_VERSION'] || "1.23.3", } sh.inline = <<~SHELL #!/usr/bin/env bash @@ -257,7 +260,7 @@ EOF set -eux -o pipefail rm -rf /var/lib/containerd-test /run/containerd-test cd ${GOPATH}/src/github.com/containerd/containerd - go test -v -count=1 -race ./metrics/cgroups + go test -v -count=1 -race ./core/metrics/cgroups make integration EXTRA_TESTFLAGS="-timeout 15m -no-criu -test.v" TEST_RUNTIME=io.containerd.runc.v2 RUNC_FLAVOR=$RUNC_FLAVOR SHELL end @@ -272,7 +275,7 @@ EOF 'GOTESTSUM_JUNITFILE': ENV['GOTESTSUM_JUNITFILE'], 'GOTESTSUM_JSONFILE': ENV['GOTESTSUM_JSONFILE'], 'GITHUB_WORKSPACE': '', - 'DISABLE_CRI_SANDBOXES': ENV['DISABLE_CRI_SANDBOXES'], + 'CGROUP_DRIVER': ENV['CGROUP_DRIVER'], } sh.inline = <<~SHELL #!/usr/bin/env bash @@ -300,6 +303,7 @@ EOF sh.env = { 'GOTEST': ENV['GOTEST'] || "go test", 'REPORT_DIR': ENV['REPORT_DIR'], + 'CGROUP_DRIVER': ENV['CGROUP_DRIVER'], } sh.inline = <<~SHELL #!/usr/bin/env bash diff --git a/api/Protobuild.toml b/api/Protobuild.toml index b75f815a4f50..9920fd581fc5 100644 --- a/api/Protobuild.toml +++ b/api/Protobuild.toml @@ -1,5 +1,5 @@ version = "2" -generators = ["go", "go-grpc"] +generators = ["go", "go-grpc", "go-ttrpc"] # Control protoc include paths. Below are usually some good defaults, but feel # free to try it without them if it works for your project. @@ -18,13 +18,22 @@ generators = ["go", "go-grpc"] [packages] "google/rpc/status.proto" = "google.golang.org/genproto/googleapis/rpc/status" +[parameters.go-ttrpc] +prefix = "TTRPC" + [[overrides]] prefixes = ["github.com/containerd/containerd/api/events"] generators = ["go", "go-ttrpc", "go-fieldpath"] +[overrides.parameters.go-ttrpc] +prefix = "" + [[overrides]] prefixes = ["github.com/containerd/containerd/api/services/ttrpc/events/v1"] -generators = ["go", "go-ttrpc", "go-fieldpath"] +generators = ["go", "go-ttrpc"] + +[overrides.parameters.go-ttrpc] +prefix = "" [[overrides]] # enable ttrpc and disable fieldpath and grpc for the shim @@ -33,24 +42,21 @@ prefixes = [ ] generators = ["go", "go-ttrpc"] +[overrides.parameters.go-ttrpc] +prefix = "" + [[overrides]] prefixes = [ "github.com/containerd/containerd/api/runtime/sandbox/v1", ] generators = ["go", "go-ttrpc", "go-grpc"] -[overrides.parameters.go-ttrpc] -prefix = "TTRPC" - [[overrides]] prefixes = [ "github.com/containerd/containerd/api/runtime/task/v3", ] generators = ["go", "go-ttrpc", "go-grpc"] -[overrides.parameters.go-ttrpc] -prefix = "TTRPC" - # Aggregrate the API descriptors to lock down API changes. [[descriptors]] prefix = "github.com/containerd/containerd/api" diff --git a/api/events/container.pb.go b/api/events/container.pb.go index d7d40258c31c..7b2992487abf 100644 --- a/api/events/container.pb.go +++ b/api/events/container.pb.go @@ -22,7 +22,7 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + _ "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" @@ -282,45 +282,44 @@ var file_github_com_containerd_containerd_api_events_container_proto_rawDesc = [ 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x40, 0x67, 0x69, 0x74, + 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcc, 0x01, - 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x75, 0x6e, - 0x74, 0x69, 0x6d, 0x65, 0x52, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x4d, 0x0a, - 0x07, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xdd, 0x01, 0x0a, - 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4b, 0x65, - 0x79, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x21, 0x0a, 0x0f, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x42, - 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, + 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xcc, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x12, 0x44, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x07, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x4d, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x74, 0x69, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xdd, 0x01, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, + 0x12, 0x46, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x21, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, + 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/container.proto b/api/events/container.proto index 29fd18f88dde..bacee0d0c4a1 100644 --- a/api/events/container.proto +++ b/api/events/container.proto @@ -19,10 +19,10 @@ syntax = "proto3"; package containerd.events; import "google/protobuf/any.proto"; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message ContainerCreate { string id = 1; diff --git a/api/events/content.pb.go b/api/events/content.pb.go index 9e3f843e2bff..8f183f60c0fa 100644 --- a/api/events/content.pb.go +++ b/api/events/content.pb.go @@ -22,7 +22,7 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + _ "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -90,18 +90,18 @@ var file_github_com_containerd_containerd_api_events_content_proto_rawDesc = []b 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x40, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, - 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x27, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, - 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x27, 0x0a, 0x0d, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/content.proto b/api/events/content.proto index 97d424139147..6b023d6b6427 100644 --- a/api/events/content.proto +++ b/api/events/content.proto @@ -18,10 +18,10 @@ syntax = "proto3"; package containerd.events; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message ContentDelete { string digest = 1; diff --git a/api/events/image.pb.go b/api/events/image.pb.go index 111af29e6c70..1f8137d4bff3 100644 --- a/api/events/image.pb.go +++ b/api/events/image.pb.go @@ -22,7 +22,7 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + _ "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -201,39 +201,39 @@ var file_github_com_containerd_containerd_api_events_image_proto_rawDesc = []byt 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, - 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xac, 0x01, 0x0a, 0x0b, 0x49, - 0x6d, 0x61, 0x67, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4e, - 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, - 0x6d, 0x61, 0x67, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, - 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xac, 0x01, 0x0a, 0x0b, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, - 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, - 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x21, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x38, 0x5a, 0x32, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xac, 0x01, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0xac, 0x01, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4e, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x21, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/image.proto b/api/events/image.proto index c09c7384f3af..0fa2430e0bcd 100644 --- a/api/events/image.proto +++ b/api/events/image.proto @@ -18,10 +18,10 @@ syntax = "proto3"; package containerd.services.images.v1; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message ImageCreate { string name = 1; diff --git a/api/events/namespace.pb.go b/api/events/namespace.pb.go index 801c1219e8a9..f6cca3a64e51 100644 --- a/api/events/namespace.pb.go +++ b/api/events/namespace.pb.go @@ -22,7 +22,7 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + _ "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -201,39 +201,38 @@ var file_github_com_containerd_containerd_api_events_namespace_proto_rawDesc = [ 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x1a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0xa8, 0x01, 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8, 0x01, - 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, - 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x25, 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, - 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x01, 0x0a, + 0x0f, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, + 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa8, 0x01, 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x46, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x25, 0x0a, 0x0f, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, + 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/namespace.proto b/api/events/namespace.proto index 9bae531d7fe5..f7757e4cbbae 100644 --- a/api/events/namespace.proto +++ b/api/events/namespace.proto @@ -18,10 +18,10 @@ syntax = "proto3"; package containerd.events; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message NamespaceCreate { string name = 1; diff --git a/api/events/snapshot.pb.go b/api/events/snapshot.pb.go index e074f9df21c3..fecc9f52fff7 100644 --- a/api/events/snapshot.pb.go +++ b/api/events/snapshot.pb.go @@ -22,7 +22,7 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + _ "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -225,31 +225,30 @@ var file_github_com_containerd_containerd_api_events_snapshot_proto_rawDesc = [] 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, - 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x5d, 0x0a, 0x0f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x50, 0x72, 0x65, - 0x70, 0x61, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x20, - 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, - 0x22, 0x58, 0x0a, 0x0e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, + 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x0f, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x22, 0x44, 0x0a, 0x0e, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, - 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, - 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x22, 0x58, 0x0a, 0x0e, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, + 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x74, 0x65, 0x72, 0x22, 0x44, 0x0a, 0x0e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x74, 0x65, 0x72, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/snapshot.proto b/api/events/snapshot.proto index effd86913679..b00c0231df3c 100644 --- a/api/events/snapshot.proto +++ b/api/events/snapshot.proto @@ -18,10 +18,10 @@ syntax = "proto3"; package containerd.events; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message SnapshotPrepare { string key = 1; diff --git a/api/events/task.pb.go b/api/events/task.pb.go index 33fd521b6c87..198b01b6a2f5 100644 --- a/api/events/task.pb.go +++ b/api/events/task.pb.go @@ -23,7 +23,6 @@ package events import ( types "github.com/containerd/containerd/api/types" - _ "github.com/containerd/containerd/protobuf/plugin" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" @@ -738,86 +737,86 @@ var file_github_com_containerd_containerd_api_events_task_proto_rawDesc = []byte 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x01, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, 0x64, - 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, - 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, - 0x73, 0x12, 0x29, 0x0a, 0x02, 0x69, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x4f, 0x52, 0x02, 0x69, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, - 0x70, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x40, - 0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, - 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xd5, 0x01, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x6a, - 0x0a, 0x06, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x4f, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1a, - 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x08, 0x54, - 0x61, 0x73, 0x6b, 0x45, 0x78, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, - 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, - 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, - 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x2c, 0x0a, 0x07, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x4f, - 0x4d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, - 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x6f, + 0x6f, 0x74, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x06, 0x72, 0x6f, 0x6f, 0x74, 0x66, 0x73, 0x12, 0x29, 0x0a, 0x02, 0x69, + 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x54, 0x61, 0x73, 0x6b, + 0x49, 0x4f, 0x52, 0x02, 0x69, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x40, 0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, - 0x64, 0x22, 0x5f, 0x0a, 0x0f, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, - 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, - 0x69, 0x64, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x50, 0x61, 0x75, 0x73, 0x65, 0x64, - 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6d, - 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x55, 0x0a, 0x10, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0xab, 0x01, 0x0a, 0x0a, 0x54, + 0x61, 0x73, 0x6b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x38, 0x5a, 0x32, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, + 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, + 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x6a, 0x0a, 0x06, 0x54, 0x61, 0x73, 0x6b, + 0x49, 0x4f, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, + 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, + 0x69, 0x6e, 0x61, 0x6c, 0x22, 0xa9, 0x01, 0x0a, 0x08, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x69, + 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, + 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x22, 0x2c, 0x0a, 0x07, 0x54, 0x61, 0x73, 0x6b, 0x4f, 0x4f, 0x4d, 0x12, 0x21, 0x0a, 0x0c, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x4b, + 0x0a, 0x0d, 0x54, 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x22, 0x5f, 0x0a, 0x0f, 0x54, + 0x61, 0x73, 0x6b, 0x45, 0x78, 0x65, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x22, 0x2f, 0x0a, 0x0a, + 0x54, 0x61, 0x73, 0x6b, 0x50, 0x61, 0x75, 0x73, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, 0x30, 0x0a, + 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x22, + 0x55, 0x0a, 0x10, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x42, 0x38, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0xa0, 0xf4, 0x1e, 0x01, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/events/task.proto b/api/events/task.proto index 238564dfe2d0..4964a1635993 100644 --- a/api/events/task.proto +++ b/api/events/task.proto @@ -20,10 +20,10 @@ package containerd.events; import "google/protobuf/timestamp.proto"; import "github.com/containerd/containerd/api/types/mount.proto"; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/fieldpath.proto"; option go_package = "github.com/containerd/containerd/api/events;events"; -option (containerd.plugin.fieldpath_all) = true; +option (containerd.types.fieldpath_all) = true; message TaskCreate { string container_id = 1; diff --git a/api/go.mod b/api/go.mod new file mode 100644 index 000000000000..e7ad7e4d50f5 --- /dev/null +++ b/api/go.mod @@ -0,0 +1,23 @@ +module github.com/containerd/containerd/api + +go 1.21 + +require ( + github.com/containerd/ttrpc v1.2.5 + github.com/containerd/typeurl/v2 v2.1.1 + github.com/opencontainers/image-spec v1.1.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda + google.golang.org/grpc v1.59.0 + google.golang.org/protobuf v1.33.0 +) + +require ( + github.com/containerd/log v0.1.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect +) diff --git a/api/go.sum b/api/go.sum new file mode 100644 index 000000000000..0311d1c1a227 --- /dev/null +++ b/api/go.sum @@ -0,0 +1,80 @@ +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= +github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= +github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= +github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/api/next.pb.txt b/api/next.pb.txt index d31c6c47019a..b2e8b837c221 100644 --- a/api/next.pb.txt +++ b/api/next.pb.txt @@ -29,8 +29,8 @@ file { syntax: "proto3" } file { - name: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" - package: "containerd.plugin" + name: "github.com/containerd/containerd/api/types/fieldpath.proto" + package: "containerd.types" dependency: "google/protobuf/descriptor.proto" extension { name: "fieldpath_all" @@ -39,6 +39,7 @@ file { label: LABEL_OPTIONAL type: TYPE_BOOL json_name: "fieldpathAll" + proto3_optional: true } extension { name: "fieldpath" @@ -47,16 +48,18 @@ file { label: LABEL_OPTIONAL type: TYPE_BOOL json_name: "fieldpath" + proto3_optional: true } options { - go_package: "github.com/containerd/containerd/protobuf/plugin" + go_package: "github.com/containerd/containerd/api/types;types" } + syntax: "proto3" } file { name: "github.com/containerd/containerd/api/events/container.proto" package: "containerd.events" dependency: "google/protobuf/any.proto" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "ContainerCreate" field { @@ -171,7 +174,7 @@ file { file { name: "github.com/containerd/containerd/api/events/content.proto" package: "containerd.events" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "ContentDelete" field { @@ -191,7 +194,7 @@ file { file { name: "github.com/containerd/containerd/api/events/image.proto" package: "containerd.services.images.v1" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "ImageCreate" field { @@ -287,7 +290,7 @@ file { file { name: "github.com/containerd/containerd/api/events/namespace.proto" package: "containerd.events" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "NamespaceCreate" field { @@ -468,7 +471,7 @@ file { file { name: "github.com/containerd/containerd/api/events/snapshot.proto" package: "containerd.events" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "SnapshotPrepare" field { @@ -584,7 +587,7 @@ file { package: "containerd.events" dependency: "google/protobuf/timestamp.proto" dependency: "github.com/containerd/containerd/api/types/mount.proto" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" message_type { name: "TaskCreate" field { @@ -878,6 +881,13 @@ file { type: TYPE_STRING json_name: "variant" } + field { + name: "os_version" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "osVersion" + } } options { go_package: "github.com/containerd/containerd/api/types;types" @@ -3821,6 +3831,13 @@ file { type_name: ".containerd.services.diff.v1.ApplyRequest.PayloadsEntry" json_name: "payloads" } + field { + name: "sync_fs" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "syncFs" + } nested_type { name: "PayloadsEntry" field { @@ -3952,13 +3969,59 @@ file { } syntax: "proto3" } +file { + name: "github.com/containerd/containerd/api/types/event.proto" + package: "containerd.types" + dependency: "github.com/containerd/containerd/api/types/fieldpath.proto" + dependency: "google/protobuf/any.proto" + dependency: "google/protobuf/timestamp.proto" + message_type { + name: "Envelope" + field { + name: "timestamp" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Timestamp" + json_name: "timestamp" + } + field { + name: "namespace" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "namespace" + } + field { + name: "topic" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "topic" + } + field { + name: "event" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "event" + } + options { + 64400: 1 + } + } + options { + go_package: "github.com/containerd/containerd/api/types;types" + } + syntax: "proto3" +} file { name: "github.com/containerd/containerd/api/services/events/v1/events.proto" package: "containerd.services.events.v1" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" + dependency: "github.com/containerd/containerd/api/types/event.proto" dependency: "google/protobuf/any.proto" dependency: "google/protobuf/empty.proto" - dependency: "google/protobuf/timestamp.proto" message_type { name: "PublishRequest" field { @@ -3984,7 +4047,7 @@ file { number: 1 label: LABEL_OPTIONAL type: TYPE_MESSAGE - type_name: ".containerd.services.events.v1.Envelope" + type_name: ".containerd.types.Envelope" json_name: "envelope" } } @@ -3998,42 +4061,6 @@ file { json_name: "filters" } } - message_type { - name: "Envelope" - field { - name: "timestamp" - number: 1 - label: LABEL_OPTIONAL - type: TYPE_MESSAGE - type_name: ".google.protobuf.Timestamp" - json_name: "timestamp" - } - field { - name: "namespace" - number: 2 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "namespace" - } - field { - name: "topic" - number: 3 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "topic" - } - field { - name: "event" - number: 4 - label: LABEL_OPTIONAL - type: TYPE_MESSAGE - type_name: ".google.protobuf.Any" - json_name: "event" - } - options { - 64400: 1 - } - } service { name: "Events" method { @@ -4049,7 +4076,7 @@ file { method { name: "Subscribe" input_type: ".containerd.services.events.v1.SubscribeRequest" - output_type: ".containerd.services.events.v1.Envelope" + output_type: ".containerd.types.Envelope" server_streaming: true } } @@ -4253,6 +4280,19 @@ file { type: TYPE_BOOL json_name: "sync" } + field { + name: "target" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.types.Descriptor" + oneof_index: 0 + json_name: "target" + proto3_optional: true + } + oneof_decl { + name: "_target" + } } service { name: "Images" @@ -4287,6 +4327,112 @@ file { } syntax: "proto3" } +file { + name: "github.com/containerd/containerd/api/types/introspection.proto" + package: "containerd.types" + dependency: "google/protobuf/any.proto" + message_type { + name: "RuntimeRequest" + field { + name: "runtime_path" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "runtimePath" + } + field { + name: "options" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "options" + } + } + message_type { + name: "RuntimeVersion" + field { + name: "version" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "version" + } + field { + name: "revision" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "revision" + } + } + message_type { + name: "RuntimeInfo" + field { + name: "name" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "name" + } + field { + name: "version" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.types.RuntimeVersion" + json_name: "version" + } + field { + name: "options" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "options" + } + field { + name: "features" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "features" + } + field { + name: "annotations" + number: 5 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.types.RuntimeInfo.AnnotationsEntry" + json_name: "annotations" + } + nested_type { + name: "AnnotationsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "value" + } + options { + map_entry: true + } + } + } + options { + go_package: "github.com/containerd/containerd/api/types;types" + } + syntax: "proto3" +} file { name: "google/rpc/status.proto" package: "google.rpc" @@ -4328,9 +4474,12 @@ file { file { name: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto" package: "containerd.services.introspection.v1" + dependency: "google/protobuf/any.proto" + dependency: "github.com/containerd/containerd/api/types/introspection.proto" dependency: "github.com/containerd/containerd/api/types/platform.proto" dependency: "google/rpc/status.proto" dependency: "google/protobuf/empty.proto" + dependency: "google/protobuf/timestamp.proto" message_type { name: "Plugin" field { @@ -4450,32 +4599,17 @@ file { type: TYPE_UINT64 json_name: "pidns" } - } - service { - name: "Introspection" - method { - name: "Plugins" - input_type: ".containerd.services.introspection.v1.PluginsRequest" - output_type: ".containerd.services.introspection.v1.PluginsResponse" - } - method { - name: "Server" - input_type: ".google.protobuf.Empty" - output_type: ".containerd.services.introspection.v1.ServerResponse" + field { + name: "deprecations" + number: 4 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.introspection.v1.DeprecationWarning" + json_name: "deprecations" } } - options { - go_package: "github.com/containerd/containerd/api/services/introspection/v1;introspection" - } - syntax: "proto3" -} -file { - name: "github.com/containerd/containerd/api/services/leases/v1/leases.proto" - package: "containerd.services.leases.v1" - dependency: "google/protobuf/empty.proto" - dependency: "google/protobuf/timestamp.proto" message_type { - name: "Lease" + name: "DeprecationWarning" field { name: "id" number: 1 @@ -4484,33 +4618,130 @@ file { json_name: "id" } field { - name: "created_at" + name: "message" number: 2 label: LABEL_OPTIONAL - type: TYPE_MESSAGE - type_name: ".google.protobuf.Timestamp" - json_name: "createdAt" + type: TYPE_STRING + json_name: "message" } field { - name: "labels" + name: "last_occurrence" number: 3 - label: LABEL_REPEATED + label: LABEL_OPTIONAL type: TYPE_MESSAGE - type_name: ".containerd.services.leases.v1.Lease.LabelsEntry" - json_name: "labels" + type_name: ".google.protobuf.Timestamp" + json_name: "lastOccurrence" } - nested_type { - name: "LabelsEntry" - field { - name: "key" - number: 1 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "key" - } - field { - name: "value" - number: 2 + } + message_type { + name: "PluginInfoRequest" + field { + name: "type" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "type" + } + field { + name: "id" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "options" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "options" + } + } + message_type { + name: "PluginInfoResponse" + field { + name: "plugin" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.services.introspection.v1.Plugin" + json_name: "plugin" + } + field { + name: "extra" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Any" + json_name: "extra" + } + } + service { + name: "Introspection" + method { + name: "Plugins" + input_type: ".containerd.services.introspection.v1.PluginsRequest" + output_type: ".containerd.services.introspection.v1.PluginsResponse" + } + method { + name: "Server" + input_type: ".google.protobuf.Empty" + output_type: ".containerd.services.introspection.v1.ServerResponse" + } + method { + name: "PluginInfo" + input_type: ".containerd.services.introspection.v1.PluginInfoRequest" + output_type: ".containerd.services.introspection.v1.PluginInfoResponse" + } + } + options { + go_package: "github.com/containerd/containerd/api/services/introspection/v1;introspection" + } + syntax: "proto3" +} +file { + name: "github.com/containerd/containerd/api/services/leases/v1/leases.proto" + package: "containerd.services.leases.v1" + dependency: "google/protobuf/empty.proto" + dependency: "google/protobuf/timestamp.proto" + message_type { + name: "Lease" + field { + name: "id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "id" + } + field { + name: "created_at" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".google.protobuf.Timestamp" + json_name: "createdAt" + } + field { + name: "labels" + number: 3 + label: LABEL_REPEATED + type: TYPE_MESSAGE + type_name: ".containerd.services.leases.v1.Lease.LabelsEntry" + json_name: "labels" + } + nested_type { + name: "LabelsEntry" + field { + name: "key" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "key" + } + field { + name: "value" + number: 2 label: LABEL_OPTIONAL type: TYPE_STRING json_name: "value" @@ -4961,6 +5192,13 @@ file { type_name: ".containerd.types.Sandbox.ExtensionsEntry" json_name: "extensions" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } nested_type { name: "Runtime" field { @@ -5181,6 +5419,21 @@ file { type_name: ".containerd.services.sandbox.v1.ControllerCreateRequest.AnnotationsEntry" json_name: "annotations" } + field { + name: "sandbox" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.types.Sandbox" + json_name: "sandbox" + } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } nested_type { name: "AnnotationsEntry" field { @@ -5221,6 +5474,13 @@ file { type: TYPE_STRING json_name: "sandboxId" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerStartResponse" @@ -5254,6 +5514,20 @@ file { type_name: ".containerd.services.sandbox.v1.ControllerStartResponse.LabelsEntry" json_name: "labels" } + field { + name: "address" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "address" + } + field { + name: "version" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "version" + } nested_type { name: "LabelsEntry" field { @@ -5284,6 +5558,13 @@ file { type: TYPE_STRING json_name: "sandboxId" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerPlatformResponse" @@ -5312,6 +5593,13 @@ file { type: TYPE_UINT32 json_name: "timeoutSecs" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerStopResponse" @@ -5325,6 +5613,13 @@ file { type: TYPE_STRING json_name: "sandboxId" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerWaitResponse" @@ -5360,6 +5655,13 @@ file { type: TYPE_BOOL json_name: "verbose" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerStatusResponse" @@ -5416,6 +5718,20 @@ file { type_name: ".google.protobuf.Any" json_name: "extra" } + field { + name: "address" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "address" + } + field { + name: "version" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "version" + } nested_type { name: "InfoEntry" field { @@ -5446,6 +5762,13 @@ file { type: TYPE_STRING json_name: "sandboxId" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerShutdownResponse" @@ -5459,6 +5782,13 @@ file { type: TYPE_STRING json_name: "sandboxId" } + field { + name: "sandboxer" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } } message_type { name: "ControllerMetricsResponse" @@ -5471,6 +5801,41 @@ file { json_name: "metrics" } } + message_type { + name: "ControllerUpdateRequest" + field { + name: "sandbox_id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxId" + } + field { + name: "sandboxer" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "sandboxer" + } + field { + name: "sandbox" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.types.Sandbox" + json_name: "sandbox" + } + field { + name: "fields" + number: 4 + label: LABEL_REPEATED + type: TYPE_STRING + json_name: "fields" + } + } + message_type { + name: "ControllerUpdateResponse" + } service { name: "Store" method { @@ -5541,6 +5906,11 @@ file { input_type: ".containerd.services.sandbox.v1.ControllerMetricsRequest" output_type: ".containerd.services.sandbox.v1.ControllerMetricsResponse" } + method { + name: "Update" + input_type: ".containerd.services.sandbox.v1.ControllerUpdateRequest" + output_type: ".containerd.services.sandbox.v1.ControllerUpdateResponse" + } } options { go_package: "github.com/containerd/containerd/api/services/sandbox/v1;sandbox" @@ -6793,10 +7163,8 @@ file { file { name: "github.com/containerd/containerd/api/services/ttrpc/events/v1/events.proto" package: "containerd.services.events.ttrpc.v1" - dependency: "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto" - dependency: "google/protobuf/any.proto" + dependency: "github.com/containerd/containerd/api/types/event.proto" dependency: "google/protobuf/empty.proto" - dependency: "google/protobuf/timestamp.proto" message_type { name: "ForwardRequest" field { @@ -6804,46 +7172,10 @@ file { number: 1 label: LABEL_OPTIONAL type: TYPE_MESSAGE - type_name: ".containerd.services.events.ttrpc.v1.Envelope" + type_name: ".containerd.types.Envelope" json_name: "envelope" } } - message_type { - name: "Envelope" - field { - name: "timestamp" - number: 1 - label: LABEL_OPTIONAL - type: TYPE_MESSAGE - type_name: ".google.protobuf.Timestamp" - json_name: "timestamp" - } - field { - name: "namespace" - number: 2 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "namespace" - } - field { - name: "topic" - number: 3 - label: LABEL_OPTIONAL - type: TYPE_STRING - json_name: "topic" - } - field { - name: "event" - number: 4 - label: LABEL_OPTIONAL - type: TYPE_MESSAGE - type_name: ".google.protobuf.Any" - json_name: "event" - } - options { - 64400: 1 - } - } service { name: "Events" method { @@ -6891,6 +7223,213 @@ file { } syntax: "proto3" } +file { + name: "github.com/containerd/containerd/api/types/runc/options/oci.proto" + package: "containerd.runc.v1" + message_type { + name: "Options" + field { + name: "no_pivot_root" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "noPivotRoot" + } + field { + name: "no_new_keyring" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "noNewKeyring" + } + field { + name: "shim_cgroup" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "shimCgroup" + } + field { + name: "io_uid" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "ioUid" + } + field { + name: "io_gid" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "ioGid" + } + field { + name: "binary_name" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "binaryName" + } + field { + name: "root" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "root" + } + field { + name: "systemd_cgroup" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "systemdCgroup" + } + field { + name: "criu_image_path" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuImagePath" + } + field { + name: "criu_work_path" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuWorkPath" + } + field { + name: "task_api_address" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "taskApiAddress" + } + field { + name: "task_api_version" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "taskApiVersion" + } + reserved_range { + start: 8 + end: 9 + } + } + message_type { + name: "CheckpointOptions" + field { + name: "exit" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "exit" + } + field { + name: "open_tcp" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "openTcp" + } + field { + name: "external_unix_sockets" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "externalUnixSockets" + } + field { + name: "terminal" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "terminal" + } + field { + name: "file_locks" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "fileLocks" + } + field { + name: "empty_namespaces" + number: 6 + label: LABEL_REPEATED + type: TYPE_STRING + json_name: "emptyNamespaces" + } + field { + name: "cgroups_mode" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "cgroupsMode" + } + field { + name: "image_path" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "imagePath" + } + field { + name: "work_path" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "workPath" + } + } + message_type { + name: "ProcessDetails" + field { + name: "exec_id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "execId" + } + } + options { + go_package: "github.com/containerd/containerd/api/types/runc/options;options" + } + syntax: "proto3" +} +file { + name: "github.com/containerd/containerd/api/types/runtimeoptions/v1/api.proto" + package: "runtimeoptions.v1" + message_type { + name: "Options" + field { + name: "type_url" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "typeUrl" + } + field { + name: "config_path" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "configPath" + } + field { + name: "config_body" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_BYTES + json_name: "configBody" + } + } + options { + go_package: "github.com/containerd/containerd/api/types/runtimeoptions/v1;runtimeoptions" + } + syntax: "proto3" +} file { name: "github.com/containerd/containerd/api/types/transfer/imagestore.proto" package: "containerd.types.transfer" @@ -7114,6 +7653,7 @@ file { file { name: "github.com/containerd/containerd/api/types/transfer/progress.proto" package: "containerd.types.transfer" + dependency: "github.com/containerd/containerd/api/types/descriptor.proto" message_type { name: "Progress" field { @@ -7151,6 +7691,14 @@ file { type: TYPE_INT64 json_name: "total" } + field { + name: "desc" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: ".containerd.types.Descriptor" + json_name: "desc" + } } options { go_package: "github.com/containerd/containerd/api/types/transfer" @@ -7196,6 +7744,20 @@ file { type_name: ".containerd.types.transfer.RegistryResolver.HeadersEntry" json_name: "headers" } + field { + name: "host_dir" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "hostDir" + } + field { + name: "default_scheme" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "defaultScheme" + } nested_type { name: "HeadersEntry" field { diff --git a/api/releases/v1.8.0.toml b/api/releases/v1.8.0.toml new file mode 100644 index 000000000000..ad3d12c83b59 --- /dev/null +++ b/api/releases/v1.8.0.toml @@ -0,0 +1,17 @@ +# commit to be tagged for new release +commit = "HEAD" + +project_name = "containerd" +github_repo = "containerd/containerd" +sub_path = "api" +ignore_deps = [ "github.com/containerd/containerd" ] + +# previous release +previous = "v1.7.0" + +pre_release = false + +preface = """\ +The first dedicated release for the containerd API. This release continues the 1.x +line of API compatibility with the 9th minor release of the 1.x API. +""" diff --git a/api/runtime/sandbox/v1/sandbox.proto b/api/runtime/sandbox/v1/sandbox.proto index 904b9c7c766e..0cf801c909c2 100644 --- a/api/runtime/sandbox/v1/sandbox.proto +++ b/api/runtime/sandbox/v1/sandbox.proto @@ -145,5 +145,5 @@ message SandboxMetricsRequest { } message SandboxMetricsResponse { - types.Metric metrics = 1; + containerd.types.Metric metrics = 1; } diff --git a/api/runtime/sandbox/v1/sandbox_grpc.pb.go b/api/runtime/sandbox/v1/sandbox_grpc.pb.go index aff8317c825f..ae5b9a1e9e54 100644 --- a/api/runtime/sandbox/v1/sandbox_grpc.pb.go +++ b/api/runtime/sandbox/v1/sandbox_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/runtime/task/v3/shim_grpc.pb.go b/api/runtime/task/v3/shim_grpc.pb.go index 9bc8a8955ce7..a7aa4723bfb7 100644 --- a/api/runtime/task/v3/shim_grpc.pb.go +++ b/api/runtime/task/v3/shim_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/containers/v1/containers_grpc.pb.go b/api/services/containers/v1/containers_grpc.pb.go index 701e5c1ebce5..93dab77d10d6 100644 --- a/api/services/containers/v1/containers_grpc.pb.go +++ b/api/services/containers/v1/containers_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/containers/v1/containers_ttrpc.pb.go b/api/services/containers/v1/containers_ttrpc.pb.go new file mode 100644 index 000000000000..8090011df33a --- /dev/null +++ b/api/services/containers/v1/containers_ttrpc.pb.go @@ -0,0 +1,174 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/containers/v1/containers.proto +package containers + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCContainersService interface { + Get(context.Context, *GetContainerRequest) (*GetContainerResponse, error) + List(context.Context, *ListContainersRequest) (*ListContainersResponse, error) + ListStream(context.Context, *ListContainersRequest, TTRPCContainers_ListStreamServer) error + Create(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error) + Update(context.Context, *UpdateContainerRequest) (*UpdateContainerResponse, error) + Delete(context.Context, *DeleteContainerRequest) (*emptypb.Empty, error) +} + +type TTRPCContainers_ListStreamServer interface { + Send(*ListContainerMessage) error + ttrpc.StreamServer +} + +type ttrpccontainersListStreamServer struct { + ttrpc.StreamServer +} + +func (x *ttrpccontainersListStreamServer) Send(m *ListContainerMessage) error { + return x.StreamServer.SendMsg(m) +} + +func RegisterTTRPCContainersService(srv *ttrpc.Server, svc TTRPCContainersService) { + srv.RegisterService("containerd.services.containers.v1.Containers", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Get": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req GetContainerRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Get(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListContainersRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateContainerRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateContainerRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteContainerRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + }, + Streams: map[string]ttrpc.Stream{ + "ListStream": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(ListContainersRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.ListStream(ctx, m, &ttrpccontainersListStreamServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + }, + }) +} + +type TTRPCContainersClient interface { + Get(context.Context, *GetContainerRequest) (*GetContainerResponse, error) + List(context.Context, *ListContainersRequest) (*ListContainersResponse, error) + ListStream(context.Context, *ListContainersRequest) (TTRPCContainers_ListStreamClient, error) + Create(context.Context, *CreateContainerRequest) (*CreateContainerResponse, error) + Update(context.Context, *UpdateContainerRequest) (*UpdateContainerResponse, error) + Delete(context.Context, *DeleteContainerRequest) (*emptypb.Empty, error) +} + +type ttrpccontainersClient struct { + client *ttrpc.Client +} + +func NewTTRPCContainersClient(client *ttrpc.Client) TTRPCContainersClient { + return &ttrpccontainersClient{ + client: client, + } +} + +func (c *ttrpccontainersClient) Get(ctx context.Context, req *GetContainerRequest) (*GetContainerResponse, error) { + var resp GetContainerResponse + if err := c.client.Call(ctx, "containerd.services.containers.v1.Containers", "Get", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontainersClient) List(ctx context.Context, req *ListContainersRequest) (*ListContainersResponse, error) { + var resp ListContainersResponse + if err := c.client.Call(ctx, "containerd.services.containers.v1.Containers", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontainersClient) ListStream(ctx context.Context, req *ListContainersRequest) (TTRPCContainers_ListStreamClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "containerd.services.containers.v1.Containers", "ListStream", req) + if err != nil { + return nil, err + } + x := &ttrpccontainersListStreamClient{stream} + return x, nil +} + +type TTRPCContainers_ListStreamClient interface { + Recv() (*ListContainerMessage, error) + ttrpc.ClientStream +} + +type ttrpccontainersListStreamClient struct { + ttrpc.ClientStream +} + +func (x *ttrpccontainersListStreamClient) Recv() (*ListContainerMessage, error) { + m := new(ListContainerMessage) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ttrpccontainersClient) Create(ctx context.Context, req *CreateContainerRequest) (*CreateContainerResponse, error) { + var resp CreateContainerResponse + if err := c.client.Call(ctx, "containerd.services.containers.v1.Containers", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontainersClient) Update(ctx context.Context, req *UpdateContainerRequest) (*UpdateContainerResponse, error) { + var resp UpdateContainerResponse + if err := c.client.Call(ctx, "containerd.services.containers.v1.Containers", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontainersClient) Delete(ctx context.Context, req *DeleteContainerRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.containers.v1.Containers", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/content/v1/content_grpc.pb.go b/api/services/content/v1/content_grpc.pb.go index e230c45a6705..68efff90e12e 100644 --- a/api/services/content/v1/content_grpc.pb.go +++ b/api/services/content/v1/content_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/content/v1/content_ttrpc.pb.go b/api/services/content/v1/content_ttrpc.pb.go new file mode 100644 index 000000000000..efa241a2b256 --- /dev/null +++ b/api/services/content/v1/content_ttrpc.pb.go @@ -0,0 +1,311 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/content/v1/content.proto +package content + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCContentService interface { + Info(context.Context, *InfoRequest) (*InfoResponse, error) + Update(context.Context, *UpdateRequest) (*UpdateResponse, error) + List(context.Context, *ListContentRequest, TTRPCContent_ListServer) error + Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error) + Read(context.Context, *ReadContentRequest, TTRPCContent_ReadServer) error + Status(context.Context, *StatusRequest) (*StatusResponse, error) + ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error) + Write(context.Context, TTRPCContent_WriteServer) error + Abort(context.Context, *AbortRequest) (*emptypb.Empty, error) +} + +type TTRPCContent_ListServer interface { + Send(*ListContentResponse) error + ttrpc.StreamServer +} + +type ttrpccontentListServer struct { + ttrpc.StreamServer +} + +func (x *ttrpccontentListServer) Send(m *ListContentResponse) error { + return x.StreamServer.SendMsg(m) +} + +type TTRPCContent_ReadServer interface { + Send(*ReadContentResponse) error + ttrpc.StreamServer +} + +type ttrpccontentReadServer struct { + ttrpc.StreamServer +} + +func (x *ttrpccontentReadServer) Send(m *ReadContentResponse) error { + return x.StreamServer.SendMsg(m) +} + +type TTRPCContent_WriteServer interface { + Send(*WriteContentResponse) error + Recv() (*WriteContentRequest, error) + ttrpc.StreamServer +} + +type ttrpccontentWriteServer struct { + ttrpc.StreamServer +} + +func (x *ttrpccontentWriteServer) Send(m *WriteContentResponse) error { + return x.StreamServer.SendMsg(m) +} + +func (x *ttrpccontentWriteServer) Recv() (*WriteContentRequest, error) { + m := new(WriteContentRequest) + if err := x.StreamServer.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func RegisterTTRPCContentService(srv *ttrpc.Server, svc TTRPCContentService) { + srv.RegisterService("containerd.services.content.v1.Content", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Info": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req InfoRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Info(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteContentRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + "Status": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StatusRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Status(ctx, &req) + }, + "ListStatuses": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListStatusesRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ListStatuses(ctx, &req) + }, + "Abort": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req AbortRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Abort(ctx, &req) + }, + }, + Streams: map[string]ttrpc.Stream{ + "List": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(ListContentRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.List(ctx, m, &ttrpccontentListServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + "Read": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(ReadContentRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.Read(ctx, m, &ttrpccontentReadServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + "Write": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + return nil, svc.Write(ctx, &ttrpccontentWriteServer{stream}) + }, + StreamingClient: true, + StreamingServer: true, + }, + }, + }) +} + +type TTRPCContentClient interface { + Info(context.Context, *InfoRequest) (*InfoResponse, error) + Update(context.Context, *UpdateRequest) (*UpdateResponse, error) + List(context.Context, *ListContentRequest) (TTRPCContent_ListClient, error) + Delete(context.Context, *DeleteContentRequest) (*emptypb.Empty, error) + Read(context.Context, *ReadContentRequest) (TTRPCContent_ReadClient, error) + Status(context.Context, *StatusRequest) (*StatusResponse, error) + ListStatuses(context.Context, *ListStatusesRequest) (*ListStatusesResponse, error) + Write(context.Context) (TTRPCContent_WriteClient, error) + Abort(context.Context, *AbortRequest) (*emptypb.Empty, error) +} + +type ttrpccontentClient struct { + client *ttrpc.Client +} + +func NewTTRPCContentClient(client *ttrpc.Client) TTRPCContentClient { + return &ttrpccontentClient{ + client: client, + } +} + +func (c *ttrpccontentClient) Info(ctx context.Context, req *InfoRequest) (*InfoResponse, error) { + var resp InfoResponse + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Info", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontentClient) Update(ctx context.Context, req *UpdateRequest) (*UpdateResponse, error) { + var resp UpdateResponse + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontentClient) List(ctx context.Context, req *ListContentRequest) (TTRPCContent_ListClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "containerd.services.content.v1.Content", "List", req) + if err != nil { + return nil, err + } + x := &ttrpccontentListClient{stream} + return x, nil +} + +type TTRPCContent_ListClient interface { + Recv() (*ListContentResponse, error) + ttrpc.ClientStream +} + +type ttrpccontentListClient struct { + ttrpc.ClientStream +} + +func (x *ttrpccontentListClient) Recv() (*ListContentResponse, error) { + m := new(ListContentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ttrpccontentClient) Delete(ctx context.Context, req *DeleteContentRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontentClient) Read(ctx context.Context, req *ReadContentRequest) (TTRPCContent_ReadClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "containerd.services.content.v1.Content", "Read", req) + if err != nil { + return nil, err + } + x := &ttrpccontentReadClient{stream} + return x, nil +} + +type TTRPCContent_ReadClient interface { + Recv() (*ReadContentResponse, error) + ttrpc.ClientStream +} + +type ttrpccontentReadClient struct { + ttrpc.ClientStream +} + +func (x *ttrpccontentReadClient) Recv() (*ReadContentResponse, error) { + m := new(ReadContentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ttrpccontentClient) Status(ctx context.Context, req *StatusRequest) (*StatusResponse, error) { + var resp StatusResponse + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Status", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontentClient) ListStatuses(ctx context.Context, req *ListStatusesRequest) (*ListStatusesResponse, error) { + var resp ListStatusesResponse + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "ListStatuses", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontentClient) Write(ctx context.Context) (TTRPCContent_WriteClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: true, + StreamingServer: true, + }, "containerd.services.content.v1.Content", "Write", nil) + if err != nil { + return nil, err + } + x := &ttrpccontentWriteClient{stream} + return x, nil +} + +type TTRPCContent_WriteClient interface { + Send(*WriteContentRequest) error + Recv() (*WriteContentResponse, error) + ttrpc.ClientStream +} + +type ttrpccontentWriteClient struct { + ttrpc.ClientStream +} + +func (x *ttrpccontentWriteClient) Send(m *WriteContentRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *ttrpccontentWriteClient) Recv() (*WriteContentResponse, error) { + m := new(WriteContentResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ttrpccontentClient) Abort(ctx context.Context, req *AbortRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.content.v1.Content", "Abort", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/diff/v1/diff.pb.go b/api/services/diff/v1/diff.pb.go index 4552734ab510..1c8db0b0219d 100644 --- a/api/services/diff/v1/diff.pb.go +++ b/api/services/diff/v1/diff.pb.go @@ -47,6 +47,8 @@ type ApplyRequest struct { Diff *types.Descriptor `protobuf:"bytes,1,opt,name=diff,proto3" json:"diff,omitempty"` Mounts []*types.Mount `protobuf:"bytes,2,rep,name=mounts,proto3" json:"mounts,omitempty"` Payloads map[string]*anypb.Any `protobuf:"bytes,3,rep,name=payloads,proto3" json:"payloads,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // SyncFs is to synchronize the underlying filesystem containing files. + SyncFs bool `protobuf:"varint,4,opt,name=sync_fs,json=syncFs,proto3" json:"sync_fs,omitempty"` } func (x *ApplyRequest) Reset() { @@ -102,6 +104,13 @@ func (x *ApplyRequest) GetPayloads() map[string]*anypb.Any { return nil } +func (x *ApplyRequest) GetSyncFs() bool { + if x != nil { + return x.SyncFs + } + return false +} + type ApplyResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -322,7 +331,7 @@ var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_rawDes 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x99, 0x02, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x22, 0xb2, 0x02, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64, @@ -334,61 +343,62 @@ var file_github_com_containerd_containerd_api_services_diff_v1_diff_proto_rawDes 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x08, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, - 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x0d, - 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, - 0x07, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x65, 0x64, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6c, 0x65, - 0x66, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, - 0x65, 0x66, 0x12, 0x4c, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x12, 0x46, 0x0a, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, - 0x61, 0x74, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x0c, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x69, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, - 0x04, 0x64, 0x69, 0x66, 0x66, 0x32, 0xc3, 0x01, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x5e, - 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, - 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, - 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, - 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x66, - 0x66, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, 0x66, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x08, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x79, 0x6e, + 0x63, 0x5f, 0x66, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x79, 0x6e, 0x63, + 0x46, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x64, 0x22, 0xeb, + 0x02, 0x0a, 0x0b, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, + 0x0a, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x04, 0x6c, 0x65, 0x66, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x6f, + 0x75, 0x6e, 0x74, 0x52, 0x05, 0x72, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x66, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, 0x4c, 0x0a, 0x06, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x46, 0x0a, 0x11, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x61, 0x74, 0x65, 0x45, 0x70, 0x6f, 0x63, + 0x68, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x40, 0x0a, 0x0c, + 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, + 0x64, 0x69, 0x66, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64, 0x69, 0x66, 0x66, 0x32, 0xc3, + 0x01, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, 0x5e, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, + 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x04, 0x44, 0x69, 0x66, 0x66, 0x12, + 0x28, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, + 0x66, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x64, 0x69, 0x66, 0x66, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x66, 0x66, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x69, + 0x66, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/services/diff/v1/diff.proto b/api/services/diff/v1/diff.proto index 17a26211c601..2aa5ad8a1109 100644 --- a/api/services/diff/v1/diff.proto +++ b/api/services/diff/v1/diff.proto @@ -44,6 +44,8 @@ message ApplyRequest { repeated containerd.types.Mount mounts = 2; map payloads = 3; + // SyncFs is to synchronize the underlying filesystem containing files. + bool sync_fs = 4; } message ApplyResponse { diff --git a/api/services/diff/v1/diff_grpc.pb.go b/api/services/diff/v1/diff_grpc.pb.go index daa3b1801ac4..9a932b79eee8 100644 --- a/api/services/diff/v1/diff_grpc.pb.go +++ b/api/services/diff/v1/diff_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/diff/v1/diff_ttrpc.pb.go b/api/services/diff/v1/diff_ttrpc.pb.go new file mode 100644 index 000000000000..0aa063fb3d6c --- /dev/null +++ b/api/services/diff/v1/diff_ttrpc.pb.go @@ -0,0 +1,60 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/diff/v1/diff.proto +package diff + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" +) + +type TTRPCDiffService interface { + Apply(context.Context, *ApplyRequest) (*ApplyResponse, error) + Diff(context.Context, *DiffRequest) (*DiffResponse, error) +} + +func RegisterTTRPCDiffService(srv *ttrpc.Server, svc TTRPCDiffService) { + srv.RegisterService("containerd.services.diff.v1.Diff", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Apply": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ApplyRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Apply(ctx, &req) + }, + "Diff": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DiffRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Diff(ctx, &req) + }, + }, + }) +} + +type ttrpcdiffClient struct { + client *ttrpc.Client +} + +func NewTTRPCDiffClient(client *ttrpc.Client) TTRPCDiffService { + return &ttrpcdiffClient{ + client: client, + } +} + +func (c *ttrpcdiffClient) Apply(ctx context.Context, req *ApplyRequest) (*ApplyResponse, error) { + var resp ApplyResponse + if err := c.client.Call(ctx, "containerd.services.diff.v1.Diff", "Apply", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcdiffClient) Diff(ctx context.Context, req *DiffRequest) (*DiffResponse, error) { + var resp DiffResponse + if err := c.client.Call(ctx, "containerd.services.diff.v1.Diff", "Diff", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/events/v1/doc.go b/api/services/events/v1/doc.go index b7f86da86951..4470a663e8e2 100644 --- a/api/services/events/v1/doc.go +++ b/api/services/events/v1/doc.go @@ -16,3 +16,8 @@ // Package events defines the event pushing and subscription service. package events + +import types "github.com/containerd/containerd/api/types" + +// Deprecated: Use [types.Envelope]. +type Envelope = types.Envelope diff --git a/api/services/events/v1/events.pb.go b/api/services/events/v1/events.pb.go index f083d9fce29c..9a4f09328ac6 100644 --- a/api/services/events/v1/events.pb.go +++ b/api/services/events/v1/events.pb.go @@ -22,12 +22,11 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + types "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" emptypb "google.golang.org/protobuf/types/known/emptypb" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -99,7 +98,7 @@ type ForwardRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Envelope *Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` + Envelope *types.Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` } func (x *ForwardRequest) Reset() { @@ -134,7 +133,7 @@ func (*ForwardRequest) Descriptor() ([]byte, []int) { return file_github_com_containerd_containerd_api_services_events_v1_events_proto_rawDescGZIP(), []int{1} } -func (x *ForwardRequest) GetEnvelope() *Envelope { +func (x *ForwardRequest) GetEnvelope() *types.Envelope { if x != nil { return x.Envelope } @@ -188,77 +187,6 @@ func (x *SubscribeRequest) GetFilters() []string { return nil } -type Envelope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` - Event *anypb.Any `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` -} - -func (x *Envelope) Reset() { - *x = Envelope{} - if protoimpl.UnsafeEnabled { - mi := &file_github_com_containerd_containerd_api_services_events_v1_events_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Envelope) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Envelope) ProtoMessage() {} - -func (x *Envelope) ProtoReflect() protoreflect.Message { - mi := &file_github_com_containerd_containerd_api_services_events_v1_events_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Envelope.ProtoReflect.Descriptor instead. -func (*Envelope) Descriptor() ([]byte, []int) { - return file_github_com_containerd_containerd_api_services_events_v1_events_proto_rawDescGZIP(), []int{3} -} - -func (x *Envelope) GetTimestamp() *timestamppb.Timestamp { - if x != nil { - return x.Timestamp - } - return nil -} - -func (x *Envelope) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -func (x *Envelope) GetTopic() string { - if x != nil { - return x.Topic - } - return "" -} - -func (x *Envelope) GetEvent() *anypb.Any { - if x != nil { - return x.Event - } - return nil -} - var File_github_com_containerd_containerd_api_services_events_v1_events_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_events_v1_events_proto_rawDesc = []byte{ @@ -268,63 +196,48 @@ var file_github_com_containerd_containerd_api_services_events_v1_events_proto_ra 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x74, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, - 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x52, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x22, 0x55, 0x0a, 0x0e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, - 0x65, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x22, 0x2c, 0x0a, 0x10, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x08, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x3a, 0x04, 0x80, 0xb9, 0x1f, 0x01, 0x32, 0x95, 0x02, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x50, 0x0a, 0x07, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x2d, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x2d, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x46, - 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x67, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x30, 0x01, 0x42, 0x40, - 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, + 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a, 0x0e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2a, 0x0a, + 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, + 0x6e, 0x79, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x48, 0x0a, 0x0e, 0x46, 0x6f, 0x72, + 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x08, 0x65, + 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, + 0x6f, 0x70, 0x65, 0x22, 0x2c, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x73, 0x32, 0x88, 0x02, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x07, + 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, + 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x5a, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x2f, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x30, 0x01, 0x42, 0x40, 0x5a, 0x3e, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -339,32 +252,29 @@ func file_github_com_containerd_containerd_api_services_events_v1_events_proto_r return file_github_com_containerd_containerd_api_services_events_v1_events_proto_rawDescData } -var file_github_com_containerd_containerd_api_services_events_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_github_com_containerd_containerd_api_services_events_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_github_com_containerd_containerd_api_services_events_v1_events_proto_goTypes = []interface{}{ - (*PublishRequest)(nil), // 0: containerd.services.events.v1.PublishRequest - (*ForwardRequest)(nil), // 1: containerd.services.events.v1.ForwardRequest - (*SubscribeRequest)(nil), // 2: containerd.services.events.v1.SubscribeRequest - (*Envelope)(nil), // 3: containerd.services.events.v1.Envelope - (*anypb.Any)(nil), // 4: google.protobuf.Any - (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 6: google.protobuf.Empty + (*PublishRequest)(nil), // 0: containerd.services.events.v1.PublishRequest + (*ForwardRequest)(nil), // 1: containerd.services.events.v1.ForwardRequest + (*SubscribeRequest)(nil), // 2: containerd.services.events.v1.SubscribeRequest + (*anypb.Any)(nil), // 3: google.protobuf.Any + (*types.Envelope)(nil), // 4: containerd.types.Envelope + (*emptypb.Empty)(nil), // 5: google.protobuf.Empty } var file_github_com_containerd_containerd_api_services_events_v1_events_proto_depIdxs = []int32{ - 4, // 0: containerd.services.events.v1.PublishRequest.event:type_name -> google.protobuf.Any - 3, // 1: containerd.services.events.v1.ForwardRequest.envelope:type_name -> containerd.services.events.v1.Envelope - 5, // 2: containerd.services.events.v1.Envelope.timestamp:type_name -> google.protobuf.Timestamp - 4, // 3: containerd.services.events.v1.Envelope.event:type_name -> google.protobuf.Any - 0, // 4: containerd.services.events.v1.Events.Publish:input_type -> containerd.services.events.v1.PublishRequest - 1, // 5: containerd.services.events.v1.Events.Forward:input_type -> containerd.services.events.v1.ForwardRequest - 2, // 6: containerd.services.events.v1.Events.Subscribe:input_type -> containerd.services.events.v1.SubscribeRequest - 6, // 7: containerd.services.events.v1.Events.Publish:output_type -> google.protobuf.Empty - 6, // 8: containerd.services.events.v1.Events.Forward:output_type -> google.protobuf.Empty - 3, // 9: containerd.services.events.v1.Events.Subscribe:output_type -> containerd.services.events.v1.Envelope - 7, // [7:10] is the sub-list for method output_type - 4, // [4:7] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 3, // 0: containerd.services.events.v1.PublishRequest.event:type_name -> google.protobuf.Any + 4, // 1: containerd.services.events.v1.ForwardRequest.envelope:type_name -> containerd.types.Envelope + 0, // 2: containerd.services.events.v1.Events.Publish:input_type -> containerd.services.events.v1.PublishRequest + 1, // 3: containerd.services.events.v1.Events.Forward:input_type -> containerd.services.events.v1.ForwardRequest + 2, // 4: containerd.services.events.v1.Events.Subscribe:input_type -> containerd.services.events.v1.SubscribeRequest + 5, // 5: containerd.services.events.v1.Events.Publish:output_type -> google.protobuf.Empty + 5, // 6: containerd.services.events.v1.Events.Forward:output_type -> google.protobuf.Empty + 4, // 7: containerd.services.events.v1.Events.Subscribe:output_type -> containerd.types.Envelope + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_github_com_containerd_containerd_api_services_events_v1_events_proto_init() } @@ -409,18 +319,6 @@ func file_github_com_containerd_containerd_api_services_events_v1_events_proto_i return nil } } - file_github_com_containerd_containerd_api_services_events_v1_events_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Envelope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -428,7 +326,7 @@ func file_github_com_containerd_containerd_api_services_events_v1_events_proto_i GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_containerd_containerd_api_services_events_v1_events_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 3, NumExtensions: 0, NumServices: 1, }, diff --git a/api/services/events/v1/events.proto b/api/services/events/v1/events.proto index 3e0f11ffb840..3ea43e38acd7 100644 --- a/api/services/events/v1/events.proto +++ b/api/services/events/v1/events.proto @@ -18,10 +18,9 @@ syntax = "proto3"; package containerd.services.events.v1; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; +import "github.com/containerd/containerd/api/types/event.proto"; import "google/protobuf/any.proto"; import "google/protobuf/empty.proto"; -import "google/protobuf/timestamp.proto"; option go_package = "github.com/containerd/containerd/api/services/events/v1;events"; @@ -46,7 +45,7 @@ service Events { // from all namespaces unless otherwise specified. If this is not desired, // a filter can be provided in the format 'namespace==' to // restrict the received events. - rpc Subscribe(SubscribeRequest) returns (stream Envelope); + rpc Subscribe(SubscribeRequest) returns (stream containerd.types.Envelope); } message PublishRequest { @@ -55,17 +54,9 @@ message PublishRequest { } message ForwardRequest { - Envelope envelope = 1; + containerd.types.Envelope envelope = 1; } message SubscribeRequest { repeated string filters = 1; } - -message Envelope { - option (containerd.plugin.fieldpath) = true; - google.protobuf.Timestamp timestamp = 1; - string namespace = 2; - string topic = 3; - google.protobuf.Any event = 4; -} diff --git a/api/services/events/v1/events_grpc.pb.go b/api/services/events/v1/events_grpc.pb.go index 768306555cf1..a91362a1e074 100644 --- a/api/services/events/v1/events_grpc.pb.go +++ b/api/services/events/v1/events_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 @@ -8,6 +10,7 @@ package events import ( context "context" + types "github.com/containerd/containerd/api/types" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -86,7 +89,7 @@ func (c *eventsClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts } type Events_SubscribeClient interface { - Recv() (*Envelope, error) + Recv() (*types.Envelope, error) grpc.ClientStream } @@ -94,8 +97,8 @@ type eventsSubscribeClient struct { grpc.ClientStream } -func (x *eventsSubscribeClient) Recv() (*Envelope, error) { - m := new(Envelope) +func (x *eventsSubscribeClient) Recv() (*types.Envelope, error) { + m := new(types.Envelope) if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err } @@ -199,7 +202,7 @@ func _Events_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error } type Events_SubscribeServer interface { - Send(*Envelope) error + Send(*types.Envelope) error grpc.ServerStream } @@ -207,7 +210,7 @@ type eventsSubscribeServer struct { grpc.ServerStream } -func (x *eventsSubscribeServer) Send(m *Envelope) error { +func (x *eventsSubscribeServer) Send(m *types.Envelope) error { return x.ServerStream.SendMsg(m) } diff --git a/api/services/events/v1/events_ttrpc.pb.go b/api/services/events/v1/events_ttrpc.pb.go new file mode 100644 index 000000000000..ad8e3fecb902 --- /dev/null +++ b/api/services/events/v1/events_ttrpc.pb.go @@ -0,0 +1,124 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/events/v1/events.proto +package events + +import ( + context "context" + types "github.com/containerd/containerd/api/types" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCEventsService interface { + Publish(context.Context, *PublishRequest) (*emptypb.Empty, error) + Forward(context.Context, *ForwardRequest) (*emptypb.Empty, error) + Subscribe(context.Context, *SubscribeRequest, TTRPCEvents_SubscribeServer) error +} + +type TTRPCEvents_SubscribeServer interface { + Send(*types.Envelope) error + ttrpc.StreamServer +} + +type ttrpceventsSubscribeServer struct { + ttrpc.StreamServer +} + +func (x *ttrpceventsSubscribeServer) Send(m *types.Envelope) error { + return x.StreamServer.SendMsg(m) +} + +func RegisterTTRPCEventsService(srv *ttrpc.Server, svc TTRPCEventsService) { + srv.RegisterService("containerd.services.events.v1.Events", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Publish": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PublishRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Publish(ctx, &req) + }, + "Forward": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ForwardRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Forward(ctx, &req) + }, + }, + Streams: map[string]ttrpc.Stream{ + "Subscribe": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(SubscribeRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.Subscribe(ctx, m, &ttrpceventsSubscribeServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + }, + }) +} + +type TTRPCEventsClient interface { + Publish(context.Context, *PublishRequest) (*emptypb.Empty, error) + Forward(context.Context, *ForwardRequest) (*emptypb.Empty, error) + Subscribe(context.Context, *SubscribeRequest) (TTRPCEvents_SubscribeClient, error) +} + +type ttrpceventsClient struct { + client *ttrpc.Client +} + +func NewTTRPCEventsClient(client *ttrpc.Client) TTRPCEventsClient { + return &ttrpceventsClient{ + client: client, + } +} + +func (c *ttrpceventsClient) Publish(ctx context.Context, req *PublishRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.events.v1.Events", "Publish", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpceventsClient) Forward(ctx context.Context, req *ForwardRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.events.v1.Events", "Forward", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpceventsClient) Subscribe(ctx context.Context, req *SubscribeRequest) (TTRPCEvents_SubscribeClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "containerd.services.events.v1.Events", "Subscribe", req) + if err != nil { + return nil, err + } + x := &ttrpceventsSubscribeClient{stream} + return x, nil +} + +type TTRPCEvents_SubscribeClient interface { + Recv() (*types.Envelope, error) + ttrpc.ClientStream +} + +type ttrpceventsSubscribeClient struct { + ttrpc.ClientStream +} + +func (x *ttrpceventsSubscribeClient) Recv() (*types.Envelope, error) { + m := new(types.Envelope) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} diff --git a/api/services/images/v1/images.pb.go b/api/services/images/v1/images.pb.go index 52aff3dd2f1c..ef5b7faa2c29 100644 --- a/api/services/images/v1/images.pb.go +++ b/api/services/images/v1/images.pb.go @@ -555,6 +555,11 @@ type DeleteImageRequest struct { // // Default is false Sync bool `protobuf:"varint,2,opt,name=sync,proto3" json:"sync,omitempty"` + // Target value for image to be deleted + // + // If image descriptor does not match the same digest, + // the delete operation will return "not found" error. + Target *types.Descriptor `protobuf:"bytes,3,opt,name=target,proto3,oneof" json:"target,omitempty"` } func (x *DeleteImageRequest) Reset() { @@ -603,6 +608,13 @@ func (x *DeleteImageRequest) GetSync() bool { return false } +func (x *DeleteImageRequest) GetTarget() *types.Descriptor { + if x != nil { + return x.Target + } + return nil +} + var File_github_com_containerd_containerd_api_services_images_v1_images_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_images_v1_images_proto_rawDesc = []byte{ @@ -692,49 +704,53 @@ var file_github_com_containerd_containerd_api_services_images_v1_images_proto_ra 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x06, 0x69, 0x6d, - 0x61, 0x67, 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, 0x79, - 0x6e, 0x63, 0x32, 0x94, 0x04, 0x0a, 0x06, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x66, 0x0a, - 0x03, 0x47, 0x65, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x61, 0x67, 0x65, 0x73, 0x22, 0x82, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x73, + 0x79, 0x6e, 0x63, 0x12, 0x39, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x48, 0x00, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x88, 0x01, 0x01, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x32, 0x94, 0x04, 0x0a, 0x06, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x73, 0x12, 0x66, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x2e, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x06, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x06, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x31, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x31, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -781,21 +797,22 @@ var file_github_com_containerd_containerd_api_services_images_v1_images_proto_de 12, // 10: containerd.services.images.v1.UpdateImageRequest.source_date_epoch:type_name -> google.protobuf.Timestamp 0, // 11: containerd.services.images.v1.UpdateImageResponse.image:type_name -> containerd.services.images.v1.Image 0, // 12: containerd.services.images.v1.ListImagesResponse.images:type_name -> containerd.services.images.v1.Image - 1, // 13: containerd.services.images.v1.Images.Get:input_type -> containerd.services.images.v1.GetImageRequest - 7, // 14: containerd.services.images.v1.Images.List:input_type -> containerd.services.images.v1.ListImagesRequest - 3, // 15: containerd.services.images.v1.Images.Create:input_type -> containerd.services.images.v1.CreateImageRequest - 5, // 16: containerd.services.images.v1.Images.Update:input_type -> containerd.services.images.v1.UpdateImageRequest - 9, // 17: containerd.services.images.v1.Images.Delete:input_type -> containerd.services.images.v1.DeleteImageRequest - 2, // 18: containerd.services.images.v1.Images.Get:output_type -> containerd.services.images.v1.GetImageResponse - 8, // 19: containerd.services.images.v1.Images.List:output_type -> containerd.services.images.v1.ListImagesResponse - 4, // 20: containerd.services.images.v1.Images.Create:output_type -> containerd.services.images.v1.CreateImageResponse - 6, // 21: containerd.services.images.v1.Images.Update:output_type -> containerd.services.images.v1.UpdateImageResponse - 14, // 22: containerd.services.images.v1.Images.Delete:output_type -> google.protobuf.Empty - 18, // [18:23] is the sub-list for method output_type - 13, // [13:18] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 11, // 13: containerd.services.images.v1.DeleteImageRequest.target:type_name -> containerd.types.Descriptor + 1, // 14: containerd.services.images.v1.Images.Get:input_type -> containerd.services.images.v1.GetImageRequest + 7, // 15: containerd.services.images.v1.Images.List:input_type -> containerd.services.images.v1.ListImagesRequest + 3, // 16: containerd.services.images.v1.Images.Create:input_type -> containerd.services.images.v1.CreateImageRequest + 5, // 17: containerd.services.images.v1.Images.Update:input_type -> containerd.services.images.v1.UpdateImageRequest + 9, // 18: containerd.services.images.v1.Images.Delete:input_type -> containerd.services.images.v1.DeleteImageRequest + 2, // 19: containerd.services.images.v1.Images.Get:output_type -> containerd.services.images.v1.GetImageResponse + 8, // 20: containerd.services.images.v1.Images.List:output_type -> containerd.services.images.v1.ListImagesResponse + 4, // 21: containerd.services.images.v1.Images.Create:output_type -> containerd.services.images.v1.CreateImageResponse + 6, // 22: containerd.services.images.v1.Images.Update:output_type -> containerd.services.images.v1.UpdateImageResponse + 14, // 23: containerd.services.images.v1.Images.Delete:output_type -> google.protobuf.Empty + 19, // [19:24] is the sub-list for method output_type + 14, // [14:19] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name } func init() { file_github_com_containerd_containerd_api_services_images_v1_images_proto_init() } @@ -925,6 +942,7 @@ func file_github_com_containerd_containerd_api_services_images_v1_images_proto_i } } } + file_github_com_containerd_containerd_api_services_images_v1_images_proto_msgTypes[9].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/api/services/images/v1/images.proto b/api/services/images/v1/images.proto index b32df4b051cf..2f47ab284de9 100644 --- a/api/services/images/v1/images.proto +++ b/api/services/images/v1/images.proto @@ -140,4 +140,10 @@ message DeleteImageRequest { // // Default is false bool sync = 2; + + // Target value for image to be deleted + // + // If image descriptor does not match the same digest, + // the delete operation will return "not found" error. + optional containerd.types.Descriptor target = 3; } diff --git a/api/services/images/v1/images_grpc.pb.go b/api/services/images/v1/images_grpc.pb.go index 86a4602e036a..39c488af0b28 100644 --- a/api/services/images/v1/images_grpc.pb.go +++ b/api/services/images/v1/images_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/images/v1/images_ttrpc.pb.go b/api/services/images/v1/images_ttrpc.pb.go new file mode 100644 index 000000000000..442e1ac5c1a7 --- /dev/null +++ b/api/services/images/v1/images_ttrpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/images/v1/images.proto +package images + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCImagesService interface { + Get(context.Context, *GetImageRequest) (*GetImageResponse, error) + List(context.Context, *ListImagesRequest) (*ListImagesResponse, error) + Create(context.Context, *CreateImageRequest) (*CreateImageResponse, error) + Update(context.Context, *UpdateImageRequest) (*UpdateImageResponse, error) + Delete(context.Context, *DeleteImageRequest) (*emptypb.Empty, error) +} + +func RegisterTTRPCImagesService(srv *ttrpc.Server, svc TTRPCImagesService) { + srv.RegisterService("containerd.services.images.v1.Images", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Get": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req GetImageRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Get(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListImagesRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateImageRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateImageRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteImageRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + }, + }) +} + +type ttrpcimagesClient struct { + client *ttrpc.Client +} + +func NewTTRPCImagesClient(client *ttrpc.Client) TTRPCImagesService { + return &ttrpcimagesClient{ + client: client, + } +} + +func (c *ttrpcimagesClient) Get(ctx context.Context, req *GetImageRequest) (*GetImageResponse, error) { + var resp GetImageResponse + if err := c.client.Call(ctx, "containerd.services.images.v1.Images", "Get", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcimagesClient) List(ctx context.Context, req *ListImagesRequest) (*ListImagesResponse, error) { + var resp ListImagesResponse + if err := c.client.Call(ctx, "containerd.services.images.v1.Images", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcimagesClient) Create(ctx context.Context, req *CreateImageRequest) (*CreateImageResponse, error) { + var resp CreateImageResponse + if err := c.client.Call(ctx, "containerd.services.images.v1.Images", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcimagesClient) Update(ctx context.Context, req *UpdateImageRequest) (*UpdateImageResponse, error) { + var resp UpdateImageResponse + if err := c.client.Call(ctx, "containerd.services.images.v1.Images", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcimagesClient) Delete(ctx context.Context, req *DeleteImageRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.images.v1.Images", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/introspection/v1/introspection.pb.go b/api/services/introspection/v1/introspection.pb.go index aeef7c3a0253..0d2f8c62324b 100644 --- a/api/services/introspection/v1/introspection.pb.go +++ b/api/services/introspection/v1/introspection.pb.go @@ -26,7 +26,9 @@ import ( status "google.golang.org/genproto/googleapis/rpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -272,9 +274,10 @@ type ServerResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UUID string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` - Pid uint64 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` - Pidns uint64 `protobuf:"varint,3,opt,name=pidns,proto3" json:"pidns,omitempty"` // PID namespace, such as 4026531836 + UUID string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + Pid uint64 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` + Pidns uint64 `protobuf:"varint,3,opt,name=pidns,proto3" json:"pidns,omitempty"` // PID namespace, such as 4026531836 + Deprecations []*DeprecationWarning `protobuf:"bytes,4,rep,name=deprecations,proto3" json:"deprecations,omitempty"` } func (x *ServerResponse) Reset() { @@ -330,6 +333,198 @@ func (x *ServerResponse) GetPidns() uint64 { return 0 } +func (x *ServerResponse) GetDeprecations() []*DeprecationWarning { + if x != nil { + return x.Deprecations + } + return nil +} + +type DeprecationWarning struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + LastOccurrence *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=last_occurrence,json=lastOccurrence,proto3" json:"last_occurrence,omitempty"` +} + +func (x *DeprecationWarning) Reset() { + *x = DeprecationWarning{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeprecationWarning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeprecationWarning) ProtoMessage() {} + +func (x *DeprecationWarning) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeprecationWarning.ProtoReflect.Descriptor instead. +func (*DeprecationWarning) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescGZIP(), []int{4} +} + +func (x *DeprecationWarning) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *DeprecationWarning) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *DeprecationWarning) GetLastOccurrence() *timestamppb.Timestamp { + if x != nil { + return x.LastOccurrence + } + return nil +} + +type PluginInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + ID string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // Options may be used to request extra dynamic information from + // a plugin. + // This object is determined by the plugin and the plugin may return + // NotImplemented or InvalidArgument if it is not supported + Options *anypb.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *PluginInfoRequest) Reset() { + *x = PluginInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PluginInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PluginInfoRequest) ProtoMessage() {} + +func (x *PluginInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PluginInfoRequest.ProtoReflect.Descriptor instead. +func (*PluginInfoRequest) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescGZIP(), []int{5} +} + +func (x *PluginInfoRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PluginInfoRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *PluginInfoRequest) GetOptions() *anypb.Any { + if x != nil { + return x.Options + } + return nil +} + +type PluginInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Plugin *Plugin `protobuf:"bytes,1,opt,name=plugin,proto3" json:"plugin,omitempty"` + Extra *anypb.Any `protobuf:"bytes,2,opt,name=extra,proto3" json:"extra,omitempty"` +} + +func (x *PluginInfoResponse) Reset() { + *x = PluginInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PluginInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PluginInfoResponse) ProtoMessage() {} + +func (x *PluginInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PluginInfoResponse.ProtoReflect.Descriptor instead. +func (*PluginInfoResponse) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescGZIP(), []int{6} +} + +func (x *PluginInfoResponse) GetPlugin() *Plugin { + if x != nil { + return x.Plugin + } + return nil +} + +func (x *PluginInfoResponse) GetExtra() *anypb.Any { + if x != nil { + return x.Extra + } + return nil +} + var File_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDesc = []byte{ @@ -340,70 +535,115 @@ var file_github_com_containerd_containerd_api_services_introspection_v1_introspe 0x2f, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, - 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x39, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, - 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x02, 0x0a, 0x06, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, - 0x72, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, - 0x12, 0x53, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, 0x69, - 0x74, 0x5f, 0x65, 0x72, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x07, 0x69, 0x6e, 0x69, 0x74, 0x45, 0x72, 0x72, 0x1a, 0x3a, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2a, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, - 0x22, 0x59, 0x0a, 0x0f, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, - 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0x4c, 0x0a, 0x0e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, - 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, - 0x70, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x32, 0xdf, 0x01, 0x0a, 0x0d, 0x49, 0x6e, - 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x76, 0x0a, 0x07, 0x50, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, - 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, - 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x63, + 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe6, 0x02, 0x0a, 0x06, 0x50, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x52, 0x09, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x73, 0x12, 0x53, 0x0a, 0x07, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x08, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x65, 0x72, + 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x69, 0x6e, 0x69, + 0x74, 0x45, 0x72, 0x72, 0x1a, 0x3a, 0x0a, 0x0c, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x2a, 0x0a, 0x0e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x59, 0x0a, 0x0f, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x46, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x07, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x10, + 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x70, 0x69, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x70, 0x69, 0x64, 0x6e, 0x73, 0x12, 0x5c, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, + 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6f, 0x63, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, + 0x4f, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x67, 0x0a, 0x11, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x12, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x06, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x32, 0xe0, 0x02, 0x0a, + 0x0d, 0x49, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x76, + 0x0a, 0x07, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, + 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, + 0x0a, 0x0a, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x72, - 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4e, 0x5a, 0x4c, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, - 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, - 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, + 0x67, 0x69, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, + 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2f, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, + 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -418,31 +658,43 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp return file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDescData } -var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_goTypes = []interface{}{ - (*Plugin)(nil), // 0: containerd.services.introspection.v1.Plugin - (*PluginsRequest)(nil), // 1: containerd.services.introspection.v1.PluginsRequest - (*PluginsResponse)(nil), // 2: containerd.services.introspection.v1.PluginsResponse - (*ServerResponse)(nil), // 3: containerd.services.introspection.v1.ServerResponse - nil, // 4: containerd.services.introspection.v1.Plugin.ExportsEntry - (*types.Platform)(nil), // 5: containerd.types.Platform - (*status.Status)(nil), // 6: google.rpc.Status - (*emptypb.Empty)(nil), // 7: google.protobuf.Empty + (*Plugin)(nil), // 0: containerd.services.introspection.v1.Plugin + (*PluginsRequest)(nil), // 1: containerd.services.introspection.v1.PluginsRequest + (*PluginsResponse)(nil), // 2: containerd.services.introspection.v1.PluginsResponse + (*ServerResponse)(nil), // 3: containerd.services.introspection.v1.ServerResponse + (*DeprecationWarning)(nil), // 4: containerd.services.introspection.v1.DeprecationWarning + (*PluginInfoRequest)(nil), // 5: containerd.services.introspection.v1.PluginInfoRequest + (*PluginInfoResponse)(nil), // 6: containerd.services.introspection.v1.PluginInfoResponse + nil, // 7: containerd.services.introspection.v1.Plugin.ExportsEntry + (*types.Platform)(nil), // 8: containerd.types.Platform + (*status.Status)(nil), // 9: google.rpc.Status + (*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp + (*anypb.Any)(nil), // 11: google.protobuf.Any + (*emptypb.Empty)(nil), // 12: google.protobuf.Empty } var file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_depIdxs = []int32{ - 5, // 0: containerd.services.introspection.v1.Plugin.platforms:type_name -> containerd.types.Platform - 4, // 1: containerd.services.introspection.v1.Plugin.exports:type_name -> containerd.services.introspection.v1.Plugin.ExportsEntry - 6, // 2: containerd.services.introspection.v1.Plugin.init_err:type_name -> google.rpc.Status - 0, // 3: containerd.services.introspection.v1.PluginsResponse.plugins:type_name -> containerd.services.introspection.v1.Plugin - 1, // 4: containerd.services.introspection.v1.Introspection.Plugins:input_type -> containerd.services.introspection.v1.PluginsRequest - 7, // 5: containerd.services.introspection.v1.Introspection.Server:input_type -> google.protobuf.Empty - 2, // 6: containerd.services.introspection.v1.Introspection.Plugins:output_type -> containerd.services.introspection.v1.PluginsResponse - 3, // 7: containerd.services.introspection.v1.Introspection.Server:output_type -> containerd.services.introspection.v1.ServerResponse - 6, // [6:8] is the sub-list for method output_type - 4, // [4:6] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 8, // 0: containerd.services.introspection.v1.Plugin.platforms:type_name -> containerd.types.Platform + 7, // 1: containerd.services.introspection.v1.Plugin.exports:type_name -> containerd.services.introspection.v1.Plugin.ExportsEntry + 9, // 2: containerd.services.introspection.v1.Plugin.init_err:type_name -> google.rpc.Status + 0, // 3: containerd.services.introspection.v1.PluginsResponse.plugins:type_name -> containerd.services.introspection.v1.Plugin + 4, // 4: containerd.services.introspection.v1.ServerResponse.deprecations:type_name -> containerd.services.introspection.v1.DeprecationWarning + 10, // 5: containerd.services.introspection.v1.DeprecationWarning.last_occurrence:type_name -> google.protobuf.Timestamp + 11, // 6: containerd.services.introspection.v1.PluginInfoRequest.options:type_name -> google.protobuf.Any + 0, // 7: containerd.services.introspection.v1.PluginInfoResponse.plugin:type_name -> containerd.services.introspection.v1.Plugin + 11, // 8: containerd.services.introspection.v1.PluginInfoResponse.extra:type_name -> google.protobuf.Any + 1, // 9: containerd.services.introspection.v1.Introspection.Plugins:input_type -> containerd.services.introspection.v1.PluginsRequest + 12, // 10: containerd.services.introspection.v1.Introspection.Server:input_type -> google.protobuf.Empty + 5, // 11: containerd.services.introspection.v1.Introspection.PluginInfo:input_type -> containerd.services.introspection.v1.PluginInfoRequest + 2, // 12: containerd.services.introspection.v1.Introspection.Plugins:output_type -> containerd.services.introspection.v1.PluginsResponse + 3, // 13: containerd.services.introspection.v1.Introspection.Server:output_type -> containerd.services.introspection.v1.ServerResponse + 6, // 14: containerd.services.introspection.v1.Introspection.PluginInfo:output_type -> containerd.services.introspection.v1.PluginInfoResponse + 12, // [12:15] is the sub-list for method output_type + 9, // [9:12] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { @@ -501,6 +753,42 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp return nil } } + file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeprecationWarning); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PluginInfoRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PluginInfoResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -508,7 +796,7 @@ func file_github_com_containerd_containerd_api_services_introspection_v1_introsp GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_containerd_containerd_api_services_introspection_v1_introspection_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/api/services/introspection/v1/introspection.proto b/api/services/introspection/v1/introspection.proto index 38864f1ec6d1..12fbcf5b96a2 100644 --- a/api/services/introspection/v1/introspection.proto +++ b/api/services/introspection/v1/introspection.proto @@ -18,9 +18,12 @@ syntax = "proto3"; package containerd.services.introspection.v1; +import "google/protobuf/any.proto"; +import "github.com/containerd/containerd/api/types/introspection.proto"; import "github.com/containerd/containerd/api/types/platform.proto"; import "google/rpc/status.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; option go_package = "github.com/containerd/containerd/api/services/introspection/v1;introspection"; @@ -32,6 +35,8 @@ service Introspection { rpc Plugins(PluginsRequest) returns (PluginsResponse); // Server returns information about the containerd server rpc Server(google.protobuf.Empty) returns (ServerResponse); + // PluginInfo returns information directly from a plugin if the plugin supports it + rpc PluginInfo(PluginInfoRequest) returns (PluginInfoResponse); } message Plugin { @@ -102,4 +107,27 @@ message ServerResponse { string uuid = 1; uint64 pid = 2; uint64 pidns = 3; // PID namespace, such as 4026531836 + repeated DeprecationWarning deprecations = 4; +} + +message DeprecationWarning { + string id = 1; + string message = 2; + google.protobuf.Timestamp last_occurrence = 3; +} + +message PluginInfoRequest { + string type = 1; + string id = 2; + + // Options may be used to request extra dynamic information from + // a plugin. + // This object is determined by the plugin and the plugin may return + // NotImplemented or InvalidArgument if it is not supported + google.protobuf.Any options = 3; +} + +message PluginInfoResponse { + Plugin plugin = 1; + google.protobuf.Any extra = 2; } diff --git a/api/services/introspection/v1/introspection_grpc.pb.go b/api/services/introspection/v1/introspection_grpc.pb.go index c2cf80765ccb..135028ee9bae 100644 --- a/api/services/introspection/v1/introspection_grpc.pb.go +++ b/api/services/introspection/v1/introspection_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 @@ -30,6 +32,8 @@ type IntrospectionClient interface { Plugins(ctx context.Context, in *PluginsRequest, opts ...grpc.CallOption) (*PluginsResponse, error) // Server returns information about the containerd server Server(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ServerResponse, error) + // PluginInfo returns information directly from a plugin if the plugin supports it + PluginInfo(ctx context.Context, in *PluginInfoRequest, opts ...grpc.CallOption) (*PluginInfoResponse, error) } type introspectionClient struct { @@ -58,6 +62,15 @@ func (c *introspectionClient) Server(ctx context.Context, in *emptypb.Empty, opt return out, nil } +func (c *introspectionClient) PluginInfo(ctx context.Context, in *PluginInfoRequest, opts ...grpc.CallOption) (*PluginInfoResponse, error) { + out := new(PluginInfoResponse) + err := c.cc.Invoke(ctx, "/containerd.services.introspection.v1.Introspection/PluginInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // IntrospectionServer is the server API for Introspection service. // All implementations must embed UnimplementedIntrospectionServer // for forward compatibility @@ -69,6 +82,8 @@ type IntrospectionServer interface { Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error) // Server returns information about the containerd server Server(context.Context, *emptypb.Empty) (*ServerResponse, error) + // PluginInfo returns information directly from a plugin if the plugin supports it + PluginInfo(context.Context, *PluginInfoRequest) (*PluginInfoResponse, error) mustEmbedUnimplementedIntrospectionServer() } @@ -82,6 +97,9 @@ func (UnimplementedIntrospectionServer) Plugins(context.Context, *PluginsRequest func (UnimplementedIntrospectionServer) Server(context.Context, *emptypb.Empty) (*ServerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Server not implemented") } +func (UnimplementedIntrospectionServer) PluginInfo(context.Context, *PluginInfoRequest) (*PluginInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PluginInfo not implemented") +} func (UnimplementedIntrospectionServer) mustEmbedUnimplementedIntrospectionServer() {} // UnsafeIntrospectionServer may be embedded to opt out of forward compatibility for this service. @@ -131,6 +149,24 @@ func _Introspection_Server_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Introspection_PluginInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PluginInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntrospectionServer).PluginInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.introspection.v1.Introspection/PluginInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntrospectionServer).PluginInfo(ctx, req.(*PluginInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Introspection_ServiceDesc is the grpc.ServiceDesc for Introspection service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -146,6 +182,10 @@ var Introspection_ServiceDesc = grpc.ServiceDesc{ MethodName: "Server", Handler: _Introspection_Server_Handler, }, + { + MethodName: "PluginInfo", + Handler: _Introspection_PluginInfo_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "github.com/containerd/containerd/api/services/introspection/v1/introspection.proto", diff --git a/api/services/introspection/v1/introspection_ttrpc.pb.go b/api/services/introspection/v1/introspection_ttrpc.pb.go new file mode 100644 index 000000000000..d8027d5f943f --- /dev/null +++ b/api/services/introspection/v1/introspection_ttrpc.pb.go @@ -0,0 +1,77 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/introspection/v1/introspection.proto +package introspection + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCIntrospectionService interface { + Plugins(context.Context, *PluginsRequest) (*PluginsResponse, error) + Server(context.Context, *emptypb.Empty) (*ServerResponse, error) + PluginInfo(context.Context, *PluginInfoRequest) (*PluginInfoResponse, error) +} + +func RegisterTTRPCIntrospectionService(srv *ttrpc.Server, svc TTRPCIntrospectionService) { + srv.RegisterService("containerd.services.introspection.v1.Introspection", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Plugins": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PluginsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Plugins(ctx, &req) + }, + "Server": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req emptypb.Empty + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Server(ctx, &req) + }, + "PluginInfo": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PluginInfoRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.PluginInfo(ctx, &req) + }, + }, + }) +} + +type ttrpcintrospectionClient struct { + client *ttrpc.Client +} + +func NewTTRPCIntrospectionClient(client *ttrpc.Client) TTRPCIntrospectionService { + return &ttrpcintrospectionClient{ + client: client, + } +} + +func (c *ttrpcintrospectionClient) Plugins(ctx context.Context, req *PluginsRequest) (*PluginsResponse, error) { + var resp PluginsResponse + if err := c.client.Call(ctx, "containerd.services.introspection.v1.Introspection", "Plugins", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcintrospectionClient) Server(ctx context.Context, req *emptypb.Empty) (*ServerResponse, error) { + var resp ServerResponse + if err := c.client.Call(ctx, "containerd.services.introspection.v1.Introspection", "Server", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcintrospectionClient) PluginInfo(ctx context.Context, req *PluginInfoRequest) (*PluginInfoResponse, error) { + var resp PluginInfoResponse + if err := c.client.Call(ctx, "containerd.services.introspection.v1.Introspection", "PluginInfo", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/leases/v1/leases_grpc.pb.go b/api/services/leases/v1/leases_grpc.pb.go index 1ecf91ecf10a..7f5f5531ff45 100644 --- a/api/services/leases/v1/leases_grpc.pb.go +++ b/api/services/leases/v1/leases_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/leases/v1/leases_ttrpc.pb.go b/api/services/leases/v1/leases_ttrpc.pb.go new file mode 100644 index 000000000000..af63dc0907bc --- /dev/null +++ b/api/services/leases/v1/leases_ttrpc.pb.go @@ -0,0 +1,125 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/leases/v1/leases.proto +package leases + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCLeasesService interface { + Create(context.Context, *CreateRequest) (*CreateResponse, error) + Delete(context.Context, *DeleteRequest) (*emptypb.Empty, error) + List(context.Context, *ListRequest) (*ListResponse, error) + AddResource(context.Context, *AddResourceRequest) (*emptypb.Empty, error) + DeleteResource(context.Context, *DeleteResourceRequest) (*emptypb.Empty, error) + ListResources(context.Context, *ListResourcesRequest) (*ListResourcesResponse, error) +} + +func RegisterTTRPCLeasesService(srv *ttrpc.Server, svc TTRPCLeasesService) { + srv.RegisterService("containerd.services.leases.v1.Leases", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "AddResource": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req AddResourceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.AddResource(ctx, &req) + }, + "DeleteResource": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteResourceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.DeleteResource(ctx, &req) + }, + "ListResources": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListResourcesRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ListResources(ctx, &req) + }, + }, + }) +} + +type ttrpcleasesClient struct { + client *ttrpc.Client +} + +func NewTTRPCLeasesClient(client *ttrpc.Client) TTRPCLeasesService { + return &ttrpcleasesClient{ + client: client, + } +} + +func (c *ttrpcleasesClient) Create(ctx context.Context, req *CreateRequest) (*CreateResponse, error) { + var resp CreateResponse + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcleasesClient) Delete(ctx context.Context, req *DeleteRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcleasesClient) List(ctx context.Context, req *ListRequest) (*ListResponse, error) { + var resp ListResponse + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcleasesClient) AddResource(ctx context.Context, req *AddResourceRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "AddResource", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcleasesClient) DeleteResource(ctx context.Context, req *DeleteResourceRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "DeleteResource", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcleasesClient) ListResources(ctx context.Context, req *ListResourcesRequest) (*ListResourcesResponse, error) { + var resp ListResourcesResponse + if err := c.client.Call(ctx, "containerd.services.leases.v1.Leases", "ListResources", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/namespaces/v1/namespace_grpc.pb.go b/api/services/namespaces/v1/namespace_grpc.pb.go index ed4e4c2ffe59..d35d71d7bcb3 100644 --- a/api/services/namespaces/v1/namespace_grpc.pb.go +++ b/api/services/namespaces/v1/namespace_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/namespaces/v1/namespace_ttrpc.pb.go b/api/services/namespaces/v1/namespace_ttrpc.pb.go new file mode 100644 index 000000000000..09f94c1d1f15 --- /dev/null +++ b/api/services/namespaces/v1/namespace_ttrpc.pb.go @@ -0,0 +1,109 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/namespaces/v1/namespace.proto +package namespaces + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCNamespacesService interface { + Get(context.Context, *GetNamespaceRequest) (*GetNamespaceResponse, error) + List(context.Context, *ListNamespacesRequest) (*ListNamespacesResponse, error) + Create(context.Context, *CreateNamespaceRequest) (*CreateNamespaceResponse, error) + Update(context.Context, *UpdateNamespaceRequest) (*UpdateNamespaceResponse, error) + Delete(context.Context, *DeleteNamespaceRequest) (*emptypb.Empty, error) +} + +func RegisterTTRPCNamespacesService(srv *ttrpc.Server, svc TTRPCNamespacesService) { + srv.RegisterService("containerd.services.namespaces.v1.Namespaces", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Get": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req GetNamespaceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Get(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListNamespacesRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateNamespaceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateNamespaceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteNamespaceRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + }, + }) +} + +type ttrpcnamespacesClient struct { + client *ttrpc.Client +} + +func NewTTRPCNamespacesClient(client *ttrpc.Client) TTRPCNamespacesService { + return &ttrpcnamespacesClient{ + client: client, + } +} + +func (c *ttrpcnamespacesClient) Get(ctx context.Context, req *GetNamespaceRequest) (*GetNamespaceResponse, error) { + var resp GetNamespaceResponse + if err := c.client.Call(ctx, "containerd.services.namespaces.v1.Namespaces", "Get", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcnamespacesClient) List(ctx context.Context, req *ListNamespacesRequest) (*ListNamespacesResponse, error) { + var resp ListNamespacesResponse + if err := c.client.Call(ctx, "containerd.services.namespaces.v1.Namespaces", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcnamespacesClient) Create(ctx context.Context, req *CreateNamespaceRequest) (*CreateNamespaceResponse, error) { + var resp CreateNamespaceResponse + if err := c.client.Call(ctx, "containerd.services.namespaces.v1.Namespaces", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcnamespacesClient) Update(ctx context.Context, req *UpdateNamespaceRequest) (*UpdateNamespaceResponse, error) { + var resp UpdateNamespaceResponse + if err := c.client.Call(ctx, "containerd.services.namespaces.v1.Namespaces", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcnamespacesClient) Delete(ctx context.Context, req *DeleteNamespaceRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.namespaces.v1.Namespaces", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/sandbox/v1/sandbox.pb.go b/api/services/sandbox/v1/sandbox.pb.go index 98c40071dcf0..235081b7a8f7 100644 --- a/api/services/sandbox/v1/sandbox.pb.go +++ b/api/services/sandbox/v1/sandbox.pb.go @@ -525,6 +525,8 @@ type ControllerCreateRequest struct { Options *anypb.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` NetnsPath string `protobuf:"bytes,4,opt,name=netns_path,json=netnsPath,proto3" json:"netns_path,omitempty"` Annotations map[string]string `protobuf:"bytes,5,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Sandbox *types.Sandbox `protobuf:"bytes,6,opt,name=sandbox,proto3" json:"sandbox,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerCreateRequest) Reset() { @@ -594,6 +596,20 @@ func (x *ControllerCreateRequest) GetAnnotations() map[string]string { return nil } +func (x *ControllerCreateRequest) GetSandbox() *types.Sandbox { + if x != nil { + return x.Sandbox + } + return nil +} + +func (x *ControllerCreateRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerCreateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -647,6 +663,7 @@ type ControllerStartRequest struct { unknownFields protoimpl.UnknownFields SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerStartRequest) Reset() { @@ -688,6 +705,13 @@ func (x *ControllerStartRequest) GetSandboxID() string { return "" } +func (x *ControllerStartRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerStartResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -697,6 +721,11 @@ type ControllerStartResponse struct { Pid uint32 `protobuf:"varint,2,opt,name=pid,proto3" json:"pid,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` Labels map[string]string `protobuf:"bytes,4,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Address of the sandbox for containerd to connect, + // for calling Task or other APIs serving in the sandbox. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + Address string `protobuf:"bytes,5,opt,name=address,proto3" json:"address,omitempty"` + Version uint32 `protobuf:"varint,6,opt,name=version,proto3" json:"version,omitempty"` } func (x *ControllerStartResponse) Reset() { @@ -759,12 +788,27 @@ func (x *ControllerStartResponse) GetLabels() map[string]string { return nil } +func (x *ControllerStartResponse) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *ControllerStartResponse) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + type ControllerPlatformRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerPlatformRequest) Reset() { @@ -806,6 +850,13 @@ func (x *ControllerPlatformRequest) GetSandboxID() string { return "" } +func (x *ControllerPlatformRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerPlatformResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -860,6 +911,7 @@ type ControllerStopRequest struct { SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` TimeoutSecs uint32 `protobuf:"varint,2,opt,name=timeout_secs,json=timeoutSecs,proto3" json:"timeout_secs,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerStopRequest) Reset() { @@ -908,6 +960,13 @@ func (x *ControllerStopRequest) GetTimeoutSecs() uint32 { return 0 } +func (x *ControllerStopRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerStopResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -952,6 +1011,7 @@ type ControllerWaitRequest struct { unknownFields protoimpl.UnknownFields SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerWaitRequest) Reset() { @@ -993,6 +1053,13 @@ func (x *ControllerWaitRequest) GetSandboxID() string { return "" } +func (x *ControllerWaitRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerWaitResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1055,6 +1122,7 @@ type ControllerStatusRequest struct { SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` Verbose bool `protobuf:"varint,2,opt,name=verbose,proto3" json:"verbose,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerStatusRequest) Reset() { @@ -1103,6 +1171,13 @@ func (x *ControllerStatusRequest) GetVerbose() bool { return false } +func (x *ControllerStatusRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerStatusResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1115,6 +1190,11 @@ type ControllerStatusResponse struct { CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` ExitedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=exited_at,json=exitedAt,proto3" json:"exited_at,omitempty"` Extra *anypb.Any `protobuf:"bytes,7,opt,name=extra,proto3" json:"extra,omitempty"` + // Address of the sandbox for containerd to connect, + // for calling Task or other APIs serving in the sandbox. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + Address string `protobuf:"bytes,8,opt,name=address,proto3" json:"address,omitempty"` + Version uint32 `protobuf:"varint,9,opt,name=version,proto3" json:"version,omitempty"` } func (x *ControllerStatusResponse) Reset() { @@ -1198,12 +1278,27 @@ func (x *ControllerStatusResponse) GetExtra() *anypb.Any { return nil } +func (x *ControllerStatusResponse) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *ControllerStatusResponse) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + type ControllerShutdownRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerShutdownRequest) Reset() { @@ -1245,6 +1340,13 @@ func (x *ControllerShutdownRequest) GetSandboxID() string { return "" } +func (x *ControllerShutdownRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerShutdownResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1289,6 +1391,7 @@ type ControllerMetricsRequest struct { unknownFields protoimpl.UnknownFields SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *ControllerMetricsRequest) Reset() { @@ -1330,6 +1433,13 @@ func (x *ControllerMetricsRequest) GetSandboxID() string { return "" } +func (x *ControllerMetricsRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type ControllerMetricsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1377,6 +1487,115 @@ func (x *ControllerMetricsResponse) GetMetrics() *types.Metric { return nil } +type ControllerUpdateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SandboxID string `protobuf:"bytes,1,opt,name=sandbox_id,json=sandboxId,proto3" json:"sandbox_id,omitempty"` + Sandboxer string `protobuf:"bytes,2,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` + Sandbox *types.Sandbox `protobuf:"bytes,3,opt,name=sandbox,proto3" json:"sandbox,omitempty"` + Fields []string `protobuf:"bytes,4,rep,name=fields,proto3" json:"fields,omitempty"` +} + +func (x *ControllerUpdateRequest) Reset() { + *x = ControllerUpdateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ControllerUpdateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ControllerUpdateRequest) ProtoMessage() {} + +func (x *ControllerUpdateRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ControllerUpdateRequest.ProtoReflect.Descriptor instead. +func (*ControllerUpdateRequest) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_rawDescGZIP(), []int{26} +} + +func (x *ControllerUpdateRequest) GetSandboxID() string { + if x != nil { + return x.SandboxID + } + return "" +} + +func (x *ControllerUpdateRequest) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + +func (x *ControllerUpdateRequest) GetSandbox() *types.Sandbox { + if x != nil { + return x.Sandbox + } + return nil +} + +func (x *ControllerUpdateRequest) GetFields() []string { + if x != nil { + return x.Fields + } + return nil +} + +type ControllerUpdateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ControllerUpdateResponse) Reset() { + *x = ControllerUpdateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ControllerUpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ControllerUpdateResponse) ProtoMessage() {} + +func (x *ControllerUpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ControllerUpdateResponse.ProtoReflect.Descriptor instead. +func (*ControllerUpdateResponse) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_rawDescGZIP(), []int{27} +} + var File_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_rawDesc = []byte{ @@ -1444,7 +1663,7 @@ var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x52, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x22, 0xe4, 0x02, 0x0a, 0x17, 0x43, + 0x78, 0x52, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x22, 0xb7, 0x03, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, @@ -1463,212 +1682,257 @@ var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_ 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x39, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x37, 0x0a, 0x16, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x9d, 0x02, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, - 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, - 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5b, 0x0a, - 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3a, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, - 0x64, 0x22, 0x54, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x36, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x59, 0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x33, 0x0a, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x07, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x65, 0x72, 0x1a, 0x3e, 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x22, 0x39, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, - 0x63, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x36, 0x0a, 0x15, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x49, 0x64, 0x22, 0x72, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, - 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x52, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x22, 0x92, 0x03, 0x0a, - 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, + 0x55, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x56, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, + 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x22, 0xd1, 0x02, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, + 0x70, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5b, + 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x05, - 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, - 0x79, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x49, 0x6e, 0x66, 0x6f, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x3a, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x1c, 0x0a, - 0x1a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x68, 0x75, 0x74, 0x64, - 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x0a, 0x18, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, + 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x19, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x4f, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x32, 0xb7, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x12, 0x71, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, + 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x65, 0x72, 0x22, 0x54, 0x0a, 0x1a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x36, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x77, 0x0a, 0x15, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, + 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x53, 0x65, 0x63, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x65, 0x72, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x0a, + 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x65, 0x72, 0x22, 0x72, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0a, 0x65, 0x78, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x37, + 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, + 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x70, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, + 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x22, 0xc6, 0x03, 0x0a, 0x18, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, - 0x72, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x32, + 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x37, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x08, 0x65, 0x78, 0x69, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x78, 0x74, + 0x72, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, + 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x37, 0x0a, 0x09, 0x49, 0x6e, 0x66, + 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x58, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x22, 0x1c, 0x0a, 0x1a, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, + 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x57, 0x0a, 0x18, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x65, 0x72, 0x22, 0x4f, 0x0a, 0x19, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x32, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x12, 0x33, 0x0a, + 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb7, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0x12, 0x71, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, + 0x53, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x32, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x2f, + 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x04, 0x4c, 0x69, 0x73, + 0x74, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x2f, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x74, 0x6f, 0x72, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0xf6, 0x07, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x12, 0x7b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x53, 0x74, 0x6f, 0x72, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0xf3, 0x08, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, + 0x7b, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, - 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, + 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x04, 0x53, 0x74, + 0x6f, 0x70, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, + 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x75, 0x0a, 0x04, 0x57, 0x61, 0x69, 0x74, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, + 0x77, 0x6e, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x68, + 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x07, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x04, 0x53, - 0x74, 0x6f, 0x70, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, - 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x75, 0x0a, 0x04, 0x57, 0x61, 0x69, 0x74, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x57, 0x61, 0x69, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x06, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x39, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7b, 0x0a, 0x06, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, + 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, - 0x6f, 0x77, 0x6e, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, - 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x07, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x39, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x2f, 0x76, 0x31, 0x3b, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2f, + 0x76, 0x31, 0x3b, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1683,7 +1947,7 @@ func file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto return file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_rawDescData } -var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_goTypes = []interface{}{ (*StoreCreateRequest)(nil), // 0: containerd.services.sandbox.v1.StoreCreateRequest (*StoreCreateResponse)(nil), // 1: containerd.services.sandbox.v1.StoreCreateResponse @@ -1711,66 +1975,72 @@ var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_ (*ControllerShutdownResponse)(nil), // 23: containerd.services.sandbox.v1.ControllerShutdownResponse (*ControllerMetricsRequest)(nil), // 24: containerd.services.sandbox.v1.ControllerMetricsRequest (*ControllerMetricsResponse)(nil), // 25: containerd.services.sandbox.v1.ControllerMetricsResponse - nil, // 26: containerd.services.sandbox.v1.ControllerCreateRequest.AnnotationsEntry - nil, // 27: containerd.services.sandbox.v1.ControllerStartResponse.LabelsEntry - nil, // 28: containerd.services.sandbox.v1.ControllerStatusResponse.InfoEntry - (*types.Sandbox)(nil), // 29: containerd.types.Sandbox - (*types.Mount)(nil), // 30: containerd.types.Mount - (*anypb.Any)(nil), // 31: google.protobuf.Any - (*timestamppb.Timestamp)(nil), // 32: google.protobuf.Timestamp - (*types.Platform)(nil), // 33: containerd.types.Platform - (*types.Metric)(nil), // 34: containerd.types.Metric + (*ControllerUpdateRequest)(nil), // 26: containerd.services.sandbox.v1.ControllerUpdateRequest + (*ControllerUpdateResponse)(nil), // 27: containerd.services.sandbox.v1.ControllerUpdateResponse + nil, // 28: containerd.services.sandbox.v1.ControllerCreateRequest.AnnotationsEntry + nil, // 29: containerd.services.sandbox.v1.ControllerStartResponse.LabelsEntry + nil, // 30: containerd.services.sandbox.v1.ControllerStatusResponse.InfoEntry + (*types.Sandbox)(nil), // 31: containerd.types.Sandbox + (*types.Mount)(nil), // 32: containerd.types.Mount + (*anypb.Any)(nil), // 33: google.protobuf.Any + (*timestamppb.Timestamp)(nil), // 34: google.protobuf.Timestamp + (*types.Platform)(nil), // 35: containerd.types.Platform + (*types.Metric)(nil), // 36: containerd.types.Metric } var file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_depIdxs = []int32{ - 29, // 0: containerd.services.sandbox.v1.StoreCreateRequest.sandbox:type_name -> containerd.types.Sandbox - 29, // 1: containerd.services.sandbox.v1.StoreCreateResponse.sandbox:type_name -> containerd.types.Sandbox - 29, // 2: containerd.services.sandbox.v1.StoreUpdateRequest.sandbox:type_name -> containerd.types.Sandbox - 29, // 3: containerd.services.sandbox.v1.StoreUpdateResponse.sandbox:type_name -> containerd.types.Sandbox - 29, // 4: containerd.services.sandbox.v1.StoreListResponse.list:type_name -> containerd.types.Sandbox - 29, // 5: containerd.services.sandbox.v1.StoreGetResponse.sandbox:type_name -> containerd.types.Sandbox - 30, // 6: containerd.services.sandbox.v1.ControllerCreateRequest.rootfs:type_name -> containerd.types.Mount - 31, // 7: containerd.services.sandbox.v1.ControllerCreateRequest.options:type_name -> google.protobuf.Any - 26, // 8: containerd.services.sandbox.v1.ControllerCreateRequest.annotations:type_name -> containerd.services.sandbox.v1.ControllerCreateRequest.AnnotationsEntry - 32, // 9: containerd.services.sandbox.v1.ControllerStartResponse.created_at:type_name -> google.protobuf.Timestamp - 27, // 10: containerd.services.sandbox.v1.ControllerStartResponse.labels:type_name -> containerd.services.sandbox.v1.ControllerStartResponse.LabelsEntry - 33, // 11: containerd.services.sandbox.v1.ControllerPlatformResponse.platform:type_name -> containerd.types.Platform - 32, // 12: containerd.services.sandbox.v1.ControllerWaitResponse.exited_at:type_name -> google.protobuf.Timestamp - 28, // 13: containerd.services.sandbox.v1.ControllerStatusResponse.info:type_name -> containerd.services.sandbox.v1.ControllerStatusResponse.InfoEntry - 32, // 14: containerd.services.sandbox.v1.ControllerStatusResponse.created_at:type_name -> google.protobuf.Timestamp - 32, // 15: containerd.services.sandbox.v1.ControllerStatusResponse.exited_at:type_name -> google.protobuf.Timestamp - 31, // 16: containerd.services.sandbox.v1.ControllerStatusResponse.extra:type_name -> google.protobuf.Any - 34, // 17: containerd.services.sandbox.v1.ControllerMetricsResponse.metrics:type_name -> containerd.types.Metric - 0, // 18: containerd.services.sandbox.v1.Store.Create:input_type -> containerd.services.sandbox.v1.StoreCreateRequest - 2, // 19: containerd.services.sandbox.v1.Store.Update:input_type -> containerd.services.sandbox.v1.StoreUpdateRequest - 4, // 20: containerd.services.sandbox.v1.Store.Delete:input_type -> containerd.services.sandbox.v1.StoreDeleteRequest - 6, // 21: containerd.services.sandbox.v1.Store.List:input_type -> containerd.services.sandbox.v1.StoreListRequest - 8, // 22: containerd.services.sandbox.v1.Store.Get:input_type -> containerd.services.sandbox.v1.StoreGetRequest - 10, // 23: containerd.services.sandbox.v1.Controller.Create:input_type -> containerd.services.sandbox.v1.ControllerCreateRequest - 12, // 24: containerd.services.sandbox.v1.Controller.Start:input_type -> containerd.services.sandbox.v1.ControllerStartRequest - 14, // 25: containerd.services.sandbox.v1.Controller.Platform:input_type -> containerd.services.sandbox.v1.ControllerPlatformRequest - 16, // 26: containerd.services.sandbox.v1.Controller.Stop:input_type -> containerd.services.sandbox.v1.ControllerStopRequest - 18, // 27: containerd.services.sandbox.v1.Controller.Wait:input_type -> containerd.services.sandbox.v1.ControllerWaitRequest - 20, // 28: containerd.services.sandbox.v1.Controller.Status:input_type -> containerd.services.sandbox.v1.ControllerStatusRequest - 22, // 29: containerd.services.sandbox.v1.Controller.Shutdown:input_type -> containerd.services.sandbox.v1.ControllerShutdownRequest - 24, // 30: containerd.services.sandbox.v1.Controller.Metrics:input_type -> containerd.services.sandbox.v1.ControllerMetricsRequest - 1, // 31: containerd.services.sandbox.v1.Store.Create:output_type -> containerd.services.sandbox.v1.StoreCreateResponse - 3, // 32: containerd.services.sandbox.v1.Store.Update:output_type -> containerd.services.sandbox.v1.StoreUpdateResponse - 5, // 33: containerd.services.sandbox.v1.Store.Delete:output_type -> containerd.services.sandbox.v1.StoreDeleteResponse - 7, // 34: containerd.services.sandbox.v1.Store.List:output_type -> containerd.services.sandbox.v1.StoreListResponse - 9, // 35: containerd.services.sandbox.v1.Store.Get:output_type -> containerd.services.sandbox.v1.StoreGetResponse - 11, // 36: containerd.services.sandbox.v1.Controller.Create:output_type -> containerd.services.sandbox.v1.ControllerCreateResponse - 13, // 37: containerd.services.sandbox.v1.Controller.Start:output_type -> containerd.services.sandbox.v1.ControllerStartResponse - 15, // 38: containerd.services.sandbox.v1.Controller.Platform:output_type -> containerd.services.sandbox.v1.ControllerPlatformResponse - 17, // 39: containerd.services.sandbox.v1.Controller.Stop:output_type -> containerd.services.sandbox.v1.ControllerStopResponse - 19, // 40: containerd.services.sandbox.v1.Controller.Wait:output_type -> containerd.services.sandbox.v1.ControllerWaitResponse - 21, // 41: containerd.services.sandbox.v1.Controller.Status:output_type -> containerd.services.sandbox.v1.ControllerStatusResponse - 23, // 42: containerd.services.sandbox.v1.Controller.Shutdown:output_type -> containerd.services.sandbox.v1.ControllerShutdownResponse - 25, // 43: containerd.services.sandbox.v1.Controller.Metrics:output_type -> containerd.services.sandbox.v1.ControllerMetricsResponse - 31, // [31:44] is the sub-list for method output_type - 18, // [18:31] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 31, // 0: containerd.services.sandbox.v1.StoreCreateRequest.sandbox:type_name -> containerd.types.Sandbox + 31, // 1: containerd.services.sandbox.v1.StoreCreateResponse.sandbox:type_name -> containerd.types.Sandbox + 31, // 2: containerd.services.sandbox.v1.StoreUpdateRequest.sandbox:type_name -> containerd.types.Sandbox + 31, // 3: containerd.services.sandbox.v1.StoreUpdateResponse.sandbox:type_name -> containerd.types.Sandbox + 31, // 4: containerd.services.sandbox.v1.StoreListResponse.list:type_name -> containerd.types.Sandbox + 31, // 5: containerd.services.sandbox.v1.StoreGetResponse.sandbox:type_name -> containerd.types.Sandbox + 32, // 6: containerd.services.sandbox.v1.ControllerCreateRequest.rootfs:type_name -> containerd.types.Mount + 33, // 7: containerd.services.sandbox.v1.ControllerCreateRequest.options:type_name -> google.protobuf.Any + 28, // 8: containerd.services.sandbox.v1.ControllerCreateRequest.annotations:type_name -> containerd.services.sandbox.v1.ControllerCreateRequest.AnnotationsEntry + 31, // 9: containerd.services.sandbox.v1.ControllerCreateRequest.sandbox:type_name -> containerd.types.Sandbox + 34, // 10: containerd.services.sandbox.v1.ControllerStartResponse.created_at:type_name -> google.protobuf.Timestamp + 29, // 11: containerd.services.sandbox.v1.ControllerStartResponse.labels:type_name -> containerd.services.sandbox.v1.ControllerStartResponse.LabelsEntry + 35, // 12: containerd.services.sandbox.v1.ControllerPlatformResponse.platform:type_name -> containerd.types.Platform + 34, // 13: containerd.services.sandbox.v1.ControllerWaitResponse.exited_at:type_name -> google.protobuf.Timestamp + 30, // 14: containerd.services.sandbox.v1.ControllerStatusResponse.info:type_name -> containerd.services.sandbox.v1.ControllerStatusResponse.InfoEntry + 34, // 15: containerd.services.sandbox.v1.ControllerStatusResponse.created_at:type_name -> google.protobuf.Timestamp + 34, // 16: containerd.services.sandbox.v1.ControllerStatusResponse.exited_at:type_name -> google.protobuf.Timestamp + 33, // 17: containerd.services.sandbox.v1.ControllerStatusResponse.extra:type_name -> google.protobuf.Any + 36, // 18: containerd.services.sandbox.v1.ControllerMetricsResponse.metrics:type_name -> containerd.types.Metric + 31, // 19: containerd.services.sandbox.v1.ControllerUpdateRequest.sandbox:type_name -> containerd.types.Sandbox + 0, // 20: containerd.services.sandbox.v1.Store.Create:input_type -> containerd.services.sandbox.v1.StoreCreateRequest + 2, // 21: containerd.services.sandbox.v1.Store.Update:input_type -> containerd.services.sandbox.v1.StoreUpdateRequest + 4, // 22: containerd.services.sandbox.v1.Store.Delete:input_type -> containerd.services.sandbox.v1.StoreDeleteRequest + 6, // 23: containerd.services.sandbox.v1.Store.List:input_type -> containerd.services.sandbox.v1.StoreListRequest + 8, // 24: containerd.services.sandbox.v1.Store.Get:input_type -> containerd.services.sandbox.v1.StoreGetRequest + 10, // 25: containerd.services.sandbox.v1.Controller.Create:input_type -> containerd.services.sandbox.v1.ControllerCreateRequest + 12, // 26: containerd.services.sandbox.v1.Controller.Start:input_type -> containerd.services.sandbox.v1.ControllerStartRequest + 14, // 27: containerd.services.sandbox.v1.Controller.Platform:input_type -> containerd.services.sandbox.v1.ControllerPlatformRequest + 16, // 28: containerd.services.sandbox.v1.Controller.Stop:input_type -> containerd.services.sandbox.v1.ControllerStopRequest + 18, // 29: containerd.services.sandbox.v1.Controller.Wait:input_type -> containerd.services.sandbox.v1.ControllerWaitRequest + 20, // 30: containerd.services.sandbox.v1.Controller.Status:input_type -> containerd.services.sandbox.v1.ControllerStatusRequest + 22, // 31: containerd.services.sandbox.v1.Controller.Shutdown:input_type -> containerd.services.sandbox.v1.ControllerShutdownRequest + 24, // 32: containerd.services.sandbox.v1.Controller.Metrics:input_type -> containerd.services.sandbox.v1.ControllerMetricsRequest + 26, // 33: containerd.services.sandbox.v1.Controller.Update:input_type -> containerd.services.sandbox.v1.ControllerUpdateRequest + 1, // 34: containerd.services.sandbox.v1.Store.Create:output_type -> containerd.services.sandbox.v1.StoreCreateResponse + 3, // 35: containerd.services.sandbox.v1.Store.Update:output_type -> containerd.services.sandbox.v1.StoreUpdateResponse + 5, // 36: containerd.services.sandbox.v1.Store.Delete:output_type -> containerd.services.sandbox.v1.StoreDeleteResponse + 7, // 37: containerd.services.sandbox.v1.Store.List:output_type -> containerd.services.sandbox.v1.StoreListResponse + 9, // 38: containerd.services.sandbox.v1.Store.Get:output_type -> containerd.services.sandbox.v1.StoreGetResponse + 11, // 39: containerd.services.sandbox.v1.Controller.Create:output_type -> containerd.services.sandbox.v1.ControllerCreateResponse + 13, // 40: containerd.services.sandbox.v1.Controller.Start:output_type -> containerd.services.sandbox.v1.ControllerStartResponse + 15, // 41: containerd.services.sandbox.v1.Controller.Platform:output_type -> containerd.services.sandbox.v1.ControllerPlatformResponse + 17, // 42: containerd.services.sandbox.v1.Controller.Stop:output_type -> containerd.services.sandbox.v1.ControllerStopResponse + 19, // 43: containerd.services.sandbox.v1.Controller.Wait:output_type -> containerd.services.sandbox.v1.ControllerWaitResponse + 21, // 44: containerd.services.sandbox.v1.Controller.Status:output_type -> containerd.services.sandbox.v1.ControllerStatusResponse + 23, // 45: containerd.services.sandbox.v1.Controller.Shutdown:output_type -> containerd.services.sandbox.v1.ControllerShutdownResponse + 25, // 46: containerd.services.sandbox.v1.Controller.Metrics:output_type -> containerd.services.sandbox.v1.ControllerMetricsResponse + 27, // 47: containerd.services.sandbox.v1.Controller.Update:output_type -> containerd.services.sandbox.v1.ControllerUpdateResponse + 34, // [34:48] is the sub-list for method output_type + 20, // [20:34] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_init() } @@ -2091,6 +2361,30 @@ func file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto return nil } } + file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ControllerUpdateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ControllerUpdateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -2098,7 +2392,7 @@ func file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_containerd_containerd_api_services_sandbox_v1_sandbox_proto_rawDesc, NumEnums: 0, - NumMessages: 29, + NumMessages: 31, NumExtensions: 0, NumServices: 2, }, diff --git a/api/services/sandbox/v1/sandbox.proto b/api/services/sandbox/v1/sandbox.proto old mode 100644 new mode 100755 index ae605804c08d..87e6ec3a34bd --- a/api/services/sandbox/v1/sandbox.proto +++ b/api/services/sandbox/v1/sandbox.proto @@ -95,6 +95,7 @@ service Controller { rpc Status(ControllerStatusRequest) returns (ControllerStatusResponse); rpc Shutdown(ControllerShutdownRequest) returns (ControllerShutdownResponse); rpc Metrics(ControllerMetricsRequest) returns (ControllerMetricsResponse); + rpc Update(ControllerUpdateRequest) returns (ControllerUpdateResponse); } message ControllerCreateRequest { @@ -103,6 +104,8 @@ message ControllerCreateRequest { google.protobuf.Any options = 3; string netns_path = 4; map annotations = 5; + containerd.types.Sandbox sandbox = 6; + string sandboxer = 10; } message ControllerCreateResponse { @@ -111,6 +114,7 @@ message ControllerCreateResponse { message ControllerStartRequest { string sandbox_id = 1; + string sandboxer = 10; } message ControllerStartResponse { @@ -118,10 +122,16 @@ message ControllerStartResponse { uint32 pid = 2; google.protobuf.Timestamp created_at = 3; map labels = 4; + // Address of the sandbox for containerd to connect, + // for calling Task or other APIs serving in the sandbox. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + string address = 5; + uint32 version = 6; } message ControllerPlatformRequest { string sandbox_id = 1; + string sandboxer = 10; } message ControllerPlatformResponse { @@ -131,12 +141,14 @@ message ControllerPlatformResponse { message ControllerStopRequest { string sandbox_id = 1; uint32 timeout_secs = 2; + string sandboxer = 10; } message ControllerStopResponse {} message ControllerWaitRequest { string sandbox_id = 1; + string sandboxer = 10; } message ControllerWaitResponse { @@ -147,6 +159,7 @@ message ControllerWaitResponse { message ControllerStatusRequest { string sandbox_id = 1; bool verbose = 2; + string sandboxer = 10; } message ControllerStatusResponse { @@ -157,18 +170,35 @@ message ControllerStatusResponse { google.protobuf.Timestamp created_at = 5; google.protobuf.Timestamp exited_at = 6; google.protobuf.Any extra = 7; + // Address of the sandbox for containerd to connect, + // for calling Task or other APIs serving in the sandbox. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + string address = 8; + uint32 version = 9; } message ControllerShutdownRequest { string sandbox_id = 1; + string sandboxer = 10; } message ControllerShutdownResponse {} message ControllerMetricsRequest { string sandbox_id = 1; + string sandboxer = 10; } message ControllerMetricsResponse { types.Metric metrics = 1; -} \ No newline at end of file +} + +message ControllerUpdateRequest { + string sandbox_id = 1; + string sandboxer = 2; + containerd.types.Sandbox sandbox = 3; + repeated string fields = 4; +} + +message ControllerUpdateResponse { +} diff --git a/api/services/sandbox/v1/sandbox_grpc.pb.go b/api/services/sandbox/v1/sandbox_grpc.pb.go index 3b4381092a66..6a5ec2804588 100644 --- a/api/services/sandbox/v1/sandbox_grpc.pb.go +++ b/api/services/sandbox/v1/sandbox_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 @@ -260,6 +262,7 @@ type ControllerClient interface { Status(ctx context.Context, in *ControllerStatusRequest, opts ...grpc.CallOption) (*ControllerStatusResponse, error) Shutdown(ctx context.Context, in *ControllerShutdownRequest, opts ...grpc.CallOption) (*ControllerShutdownResponse, error) Metrics(ctx context.Context, in *ControllerMetricsRequest, opts ...grpc.CallOption) (*ControllerMetricsResponse, error) + Update(ctx context.Context, in *ControllerUpdateRequest, opts ...grpc.CallOption) (*ControllerUpdateResponse, error) } type controllerClient struct { @@ -342,6 +345,15 @@ func (c *controllerClient) Metrics(ctx context.Context, in *ControllerMetricsReq return out, nil } +func (c *controllerClient) Update(ctx context.Context, in *ControllerUpdateRequest, opts ...grpc.CallOption) (*ControllerUpdateResponse, error) { + out := new(ControllerUpdateResponse) + err := c.cc.Invoke(ctx, "/containerd.services.sandbox.v1.Controller/Update", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ControllerServer is the server API for Controller service. // All implementations must embed UnimplementedControllerServer // for forward compatibility @@ -354,6 +366,7 @@ type ControllerServer interface { Status(context.Context, *ControllerStatusRequest) (*ControllerStatusResponse, error) Shutdown(context.Context, *ControllerShutdownRequest) (*ControllerShutdownResponse, error) Metrics(context.Context, *ControllerMetricsRequest) (*ControllerMetricsResponse, error) + Update(context.Context, *ControllerUpdateRequest) (*ControllerUpdateResponse, error) mustEmbedUnimplementedControllerServer() } @@ -385,6 +398,9 @@ func (UnimplementedControllerServer) Shutdown(context.Context, *ControllerShutdo func (UnimplementedControllerServer) Metrics(context.Context, *ControllerMetricsRequest) (*ControllerMetricsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Metrics not implemented") } +func (UnimplementedControllerServer) Update(context.Context, *ControllerUpdateRequest) (*ControllerUpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") +} func (UnimplementedControllerServer) mustEmbedUnimplementedControllerServer() {} // UnsafeControllerServer may be embedded to opt out of forward compatibility for this service. @@ -542,6 +558,24 @@ func _Controller_Metrics_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Controller_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ControllerUpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControllerServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.sandbox.v1.Controller/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControllerServer).Update(ctx, req.(*ControllerUpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Controller_ServiceDesc is the grpc.ServiceDesc for Controller service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -581,6 +615,10 @@ var Controller_ServiceDesc = grpc.ServiceDesc{ MethodName: "Metrics", Handler: _Controller_Metrics_Handler, }, + { + MethodName: "Update", + Handler: _Controller_Update_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "github.com/containerd/containerd/api/services/sandbox/v1/sandbox.proto", diff --git a/api/services/sandbox/v1/sandbox_ttrpc.pb.go b/api/services/sandbox/v1/sandbox_ttrpc.pb.go new file mode 100644 index 000000000000..924a54f6e71f --- /dev/null +++ b/api/services/sandbox/v1/sandbox_ttrpc.pb.go @@ -0,0 +1,272 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/sandbox/v1/sandbox.proto +package sandbox + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" +) + +type TTRPCStoreService interface { + Create(context.Context, *StoreCreateRequest) (*StoreCreateResponse, error) + Update(context.Context, *StoreUpdateRequest) (*StoreUpdateResponse, error) + Delete(context.Context, *StoreDeleteRequest) (*StoreDeleteResponse, error) + List(context.Context, *StoreListRequest) (*StoreListResponse, error) + Get(context.Context, *StoreGetRequest) (*StoreGetResponse, error) +} + +func RegisterTTRPCStoreService(srv *ttrpc.Server, svc TTRPCStoreService) { + srv.RegisterService("containerd.services.sandbox.v1.Store", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StoreCreateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StoreUpdateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StoreDeleteRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StoreListRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "Get": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StoreGetRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Get(ctx, &req) + }, + }, + }) +} + +type ttrpcstoreClient struct { + client *ttrpc.Client +} + +func NewTTRPCStoreClient(client *ttrpc.Client) TTRPCStoreService { + return &ttrpcstoreClient{ + client: client, + } +} + +func (c *ttrpcstoreClient) Create(ctx context.Context, req *StoreCreateRequest) (*StoreCreateResponse, error) { + var resp StoreCreateResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Store", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcstoreClient) Update(ctx context.Context, req *StoreUpdateRequest) (*StoreUpdateResponse, error) { + var resp StoreUpdateResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Store", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcstoreClient) Delete(ctx context.Context, req *StoreDeleteRequest) (*StoreDeleteResponse, error) { + var resp StoreDeleteResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Store", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcstoreClient) List(ctx context.Context, req *StoreListRequest) (*StoreListResponse, error) { + var resp StoreListResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Store", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcstoreClient) Get(ctx context.Context, req *StoreGetRequest) (*StoreGetResponse, error) { + var resp StoreGetResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Store", "Get", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +type TTRPCControllerService interface { + Create(context.Context, *ControllerCreateRequest) (*ControllerCreateResponse, error) + Start(context.Context, *ControllerStartRequest) (*ControllerStartResponse, error) + Platform(context.Context, *ControllerPlatformRequest) (*ControllerPlatformResponse, error) + Stop(context.Context, *ControllerStopRequest) (*ControllerStopResponse, error) + Wait(context.Context, *ControllerWaitRequest) (*ControllerWaitResponse, error) + Status(context.Context, *ControllerStatusRequest) (*ControllerStatusResponse, error) + Shutdown(context.Context, *ControllerShutdownRequest) (*ControllerShutdownResponse, error) + Metrics(context.Context, *ControllerMetricsRequest) (*ControllerMetricsResponse, error) + Update(context.Context, *ControllerUpdateRequest) (*ControllerUpdateResponse, error) +} + +func RegisterTTRPCControllerService(srv *ttrpc.Server, svc TTRPCControllerService) { + srv.RegisterService("containerd.services.sandbox.v1.Controller", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerCreateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Start": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerStartRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Start(ctx, &req) + }, + "Platform": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerPlatformRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Platform(ctx, &req) + }, + "Stop": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerStopRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Stop(ctx, &req) + }, + "Wait": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerWaitRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Wait(ctx, &req) + }, + "Status": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerStatusRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Status(ctx, &req) + }, + "Shutdown": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerShutdownRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Shutdown(ctx, &req) + }, + "Metrics": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerMetricsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Metrics(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ControllerUpdateRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + }, + }) +} + +type ttrpccontrollerClient struct { + client *ttrpc.Client +} + +func NewTTRPCControllerClient(client *ttrpc.Client) TTRPCControllerService { + return &ttrpccontrollerClient{ + client: client, + } +} + +func (c *ttrpccontrollerClient) Create(ctx context.Context, req *ControllerCreateRequest) (*ControllerCreateResponse, error) { + var resp ControllerCreateResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Start(ctx context.Context, req *ControllerStartRequest) (*ControllerStartResponse, error) { + var resp ControllerStartResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Start", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Platform(ctx context.Context, req *ControllerPlatformRequest) (*ControllerPlatformResponse, error) { + var resp ControllerPlatformResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Platform", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Stop(ctx context.Context, req *ControllerStopRequest) (*ControllerStopResponse, error) { + var resp ControllerStopResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Stop", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Wait(ctx context.Context, req *ControllerWaitRequest) (*ControllerWaitResponse, error) { + var resp ControllerWaitResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Wait", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Status(ctx context.Context, req *ControllerStatusRequest) (*ControllerStatusResponse, error) { + var resp ControllerStatusResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Status", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Shutdown(ctx context.Context, req *ControllerShutdownRequest) (*ControllerShutdownResponse, error) { + var resp ControllerShutdownResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Shutdown", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Metrics(ctx context.Context, req *ControllerMetricsRequest) (*ControllerMetricsResponse, error) { + var resp ControllerMetricsResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Metrics", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpccontrollerClient) Update(ctx context.Context, req *ControllerUpdateRequest) (*ControllerUpdateResponse, error) { + var resp ControllerUpdateResponse + if err := c.client.Call(ctx, "containerd.services.sandbox.v1.Controller", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/snapshots/v1/snapshots_grpc.pb.go b/api/services/snapshots/v1/snapshots_grpc.pb.go index 765c0274465d..ac50d0066b0e 100644 --- a/api/services/snapshots/v1/snapshots_grpc.pb.go +++ b/api/services/snapshots/v1/snapshots_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/snapshots/v1/snapshots_ttrpc.pb.go b/api/services/snapshots/v1/snapshots_ttrpc.pb.go new file mode 100644 index 000000000000..8ab278cb4e03 --- /dev/null +++ b/api/services/snapshots/v1/snapshots_ttrpc.pb.go @@ -0,0 +1,242 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/snapshots/v1/snapshots.proto +package snapshots + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCSnapshotsService interface { + Prepare(context.Context, *PrepareSnapshotRequest) (*PrepareSnapshotResponse, error) + View(context.Context, *ViewSnapshotRequest) (*ViewSnapshotResponse, error) + Mounts(context.Context, *MountsRequest) (*MountsResponse, error) + Commit(context.Context, *CommitSnapshotRequest) (*emptypb.Empty, error) + Remove(context.Context, *RemoveSnapshotRequest) (*emptypb.Empty, error) + Stat(context.Context, *StatSnapshotRequest) (*StatSnapshotResponse, error) + Update(context.Context, *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) + List(context.Context, *ListSnapshotsRequest, TTRPCSnapshots_ListServer) error + Usage(context.Context, *UsageRequest) (*UsageResponse, error) + Cleanup(context.Context, *CleanupRequest) (*emptypb.Empty, error) +} + +type TTRPCSnapshots_ListServer interface { + Send(*ListSnapshotsResponse) error + ttrpc.StreamServer +} + +type ttrpcsnapshotsListServer struct { + ttrpc.StreamServer +} + +func (x *ttrpcsnapshotsListServer) Send(m *ListSnapshotsResponse) error { + return x.StreamServer.SendMsg(m) +} + +func RegisterTTRPCSnapshotsService(srv *ttrpc.Server, svc TTRPCSnapshotsService) { + srv.RegisterService("containerd.services.snapshots.v1.Snapshots", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Prepare": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PrepareSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Prepare(ctx, &req) + }, + "View": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ViewSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.View(ctx, &req) + }, + "Mounts": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req MountsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Mounts(ctx, &req) + }, + "Commit": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CommitSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Commit(ctx, &req) + }, + "Remove": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req RemoveSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Remove(ctx, &req) + }, + "Stat": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StatSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Stat(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateSnapshotRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Usage": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UsageRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Usage(ctx, &req) + }, + "Cleanup": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CleanupRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Cleanup(ctx, &req) + }, + }, + Streams: map[string]ttrpc.Stream{ + "List": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(ListSnapshotsRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.List(ctx, m, &ttrpcsnapshotsListServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + }, + }) +} + +type TTRPCSnapshotsClient interface { + Prepare(context.Context, *PrepareSnapshotRequest) (*PrepareSnapshotResponse, error) + View(context.Context, *ViewSnapshotRequest) (*ViewSnapshotResponse, error) + Mounts(context.Context, *MountsRequest) (*MountsResponse, error) + Commit(context.Context, *CommitSnapshotRequest) (*emptypb.Empty, error) + Remove(context.Context, *RemoveSnapshotRequest) (*emptypb.Empty, error) + Stat(context.Context, *StatSnapshotRequest) (*StatSnapshotResponse, error) + Update(context.Context, *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) + List(context.Context, *ListSnapshotsRequest) (TTRPCSnapshots_ListClient, error) + Usage(context.Context, *UsageRequest) (*UsageResponse, error) + Cleanup(context.Context, *CleanupRequest) (*emptypb.Empty, error) +} + +type ttrpcsnapshotsClient struct { + client *ttrpc.Client +} + +func NewTTRPCSnapshotsClient(client *ttrpc.Client) TTRPCSnapshotsClient { + return &ttrpcsnapshotsClient{ + client: client, + } +} + +func (c *ttrpcsnapshotsClient) Prepare(ctx context.Context, req *PrepareSnapshotRequest) (*PrepareSnapshotResponse, error) { + var resp PrepareSnapshotResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Prepare", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) View(ctx context.Context, req *ViewSnapshotRequest) (*ViewSnapshotResponse, error) { + var resp ViewSnapshotResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "View", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Mounts(ctx context.Context, req *MountsRequest) (*MountsResponse, error) { + var resp MountsResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Mounts", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Commit(ctx context.Context, req *CommitSnapshotRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Commit", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Remove(ctx context.Context, req *RemoveSnapshotRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Remove", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Stat(ctx context.Context, req *StatSnapshotRequest) (*StatSnapshotResponse, error) { + var resp StatSnapshotResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Stat", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Update(ctx context.Context, req *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) { + var resp UpdateSnapshotResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) List(ctx context.Context, req *ListSnapshotsRequest) (TTRPCSnapshots_ListClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "containerd.services.snapshots.v1.Snapshots", "List", req) + if err != nil { + return nil, err + } + x := &ttrpcsnapshotsListClient{stream} + return x, nil +} + +type TTRPCSnapshots_ListClient interface { + Recv() (*ListSnapshotsResponse, error) + ttrpc.ClientStream +} + +type ttrpcsnapshotsListClient struct { + ttrpc.ClientStream +} + +func (x *ttrpcsnapshotsListClient) Recv() (*ListSnapshotsResponse, error) { + m := new(ListSnapshotsResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ttrpcsnapshotsClient) Usage(ctx context.Context, req *UsageRequest) (*UsageResponse, error) { + var resp UsageResponse + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Usage", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpcsnapshotsClient) Cleanup(ctx context.Context, req *CleanupRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.snapshots.v1.Snapshots", "Cleanup", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/streaming/v1/streaming_grpc.pb.go b/api/services/streaming/v1/streaming_grpc.pb.go index a0a0bc59c8c1..2a2971df4828 100644 --- a/api/services/streaming/v1/streaming_grpc.pb.go +++ b/api/services/streaming/v1/streaming_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/streaming/v1/streaming_ttrpc.pb.go b/api/services/streaming/v1/streaming_ttrpc.pb.go new file mode 100644 index 000000000000..9e30233d4311 --- /dev/null +++ b/api/services/streaming/v1/streaming_ttrpc.pb.go @@ -0,0 +1,97 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/streaming/v1/streaming.proto +package streaming + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + anypb "google.golang.org/protobuf/types/known/anypb" +) + +type TTRPCStreamingService interface { + Stream(context.Context, TTRPCStreaming_StreamServer) error +} + +type TTRPCStreaming_StreamServer interface { + Send(*anypb.Any) error + Recv() (*anypb.Any, error) + ttrpc.StreamServer +} + +type ttrpcstreamingStreamServer struct { + ttrpc.StreamServer +} + +func (x *ttrpcstreamingStreamServer) Send(m *anypb.Any) error { + return x.StreamServer.SendMsg(m) +} + +func (x *ttrpcstreamingStreamServer) Recv() (*anypb.Any, error) { + m := new(anypb.Any) + if err := x.StreamServer.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func RegisterTTRPCStreamingService(srv *ttrpc.Server, svc TTRPCStreamingService) { + srv.RegisterService("containerd.services.streaming.v1.Streaming", &ttrpc.ServiceDesc{ + Streams: map[string]ttrpc.Stream{ + "Stream": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + return nil, svc.Stream(ctx, &ttrpcstreamingStreamServer{stream}) + }, + StreamingClient: true, + StreamingServer: true, + }, + }, + }) +} + +type TTRPCStreamingClient interface { + Stream(context.Context) (TTRPCStreaming_StreamClient, error) +} + +type ttrpcstreamingClient struct { + client *ttrpc.Client +} + +func NewTTRPCStreamingClient(client *ttrpc.Client) TTRPCStreamingClient { + return &ttrpcstreamingClient{ + client: client, + } +} + +func (c *ttrpcstreamingClient) Stream(ctx context.Context) (TTRPCStreaming_StreamClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: true, + StreamingServer: true, + }, "containerd.services.streaming.v1.Streaming", "Stream", nil) + if err != nil { + return nil, err + } + x := &ttrpcstreamingStreamClient{stream} + return x, nil +} + +type TTRPCStreaming_StreamClient interface { + Send(*anypb.Any) error + Recv() (*anypb.Any, error) + ttrpc.ClientStream +} + +type ttrpcstreamingStreamClient struct { + ttrpc.ClientStream +} + +func (x *ttrpcstreamingStreamClient) Send(m *anypb.Any) error { + return x.ClientStream.SendMsg(m) +} + +func (x *ttrpcstreamingStreamClient) Recv() (*anypb.Any, error) { + m := new(anypb.Any) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} diff --git a/api/services/tasks/v1/tasks_grpc.pb.go b/api/services/tasks/v1/tasks_grpc.pb.go index 3fd4057e9b9b..1bc23522abbc 100644 --- a/api/services/tasks/v1/tasks_grpc.pb.go +++ b/api/services/tasks/v1/tasks_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/tasks/v1/tasks_ttrpc.pb.go b/api/services/tasks/v1/tasks_ttrpc.pb.go new file mode 100644 index 000000000000..859eec58e0b1 --- /dev/null +++ b/api/services/tasks/v1/tasks_ttrpc.pb.go @@ -0,0 +1,301 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/tasks/v1/tasks.proto +package tasks + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCTasksService interface { + Create(context.Context, *CreateTaskRequest) (*CreateTaskResponse, error) + Start(context.Context, *StartRequest) (*StartResponse, error) + Delete(context.Context, *DeleteTaskRequest) (*DeleteResponse, error) + DeleteProcess(context.Context, *DeleteProcessRequest) (*DeleteResponse, error) + Get(context.Context, *GetRequest) (*GetResponse, error) + List(context.Context, *ListTasksRequest) (*ListTasksResponse, error) + Kill(context.Context, *KillRequest) (*emptypb.Empty, error) + Exec(context.Context, *ExecProcessRequest) (*emptypb.Empty, error) + ResizePty(context.Context, *ResizePtyRequest) (*emptypb.Empty, error) + CloseIO(context.Context, *CloseIORequest) (*emptypb.Empty, error) + Pause(context.Context, *PauseTaskRequest) (*emptypb.Empty, error) + Resume(context.Context, *ResumeTaskRequest) (*emptypb.Empty, error) + ListPids(context.Context, *ListPidsRequest) (*ListPidsResponse, error) + Checkpoint(context.Context, *CheckpointTaskRequest) (*CheckpointTaskResponse, error) + Update(context.Context, *UpdateTaskRequest) (*emptypb.Empty, error) + Metrics(context.Context, *MetricsRequest) (*MetricsResponse, error) + Wait(context.Context, *WaitRequest) (*WaitResponse, error) +} + +func RegisterTTRPCTasksService(srv *ttrpc.Server, svc TTRPCTasksService) { + srv.RegisterService("containerd.services.tasks.v1.Tasks", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Create(ctx, &req) + }, + "Start": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StartRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Start(ctx, &req) + }, + "Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Delete(ctx, &req) + }, + "DeleteProcess": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req DeleteProcessRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.DeleteProcess(ctx, &req) + }, + "Get": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req GetRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Get(ctx, &req) + }, + "List": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListTasksRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.List(ctx, &req) + }, + "Kill": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req KillRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Kill(ctx, &req) + }, + "Exec": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ExecProcessRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Exec(ctx, &req) + }, + "ResizePty": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ResizePtyRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ResizePty(ctx, &req) + }, + "CloseIO": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CloseIORequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.CloseIO(ctx, &req) + }, + "Pause": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PauseTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Pause(ctx, &req) + }, + "Resume": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ResumeTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Resume(ctx, &req) + }, + "ListPids": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ListPidsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ListPids(ctx, &req) + }, + "Checkpoint": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CheckpointTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Checkpoint(ctx, &req) + }, + "Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req UpdateTaskRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Update(ctx, &req) + }, + "Metrics": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req MetricsRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Metrics(ctx, &req) + }, + "Wait": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req WaitRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Wait(ctx, &req) + }, + }, + }) +} + +type ttrpctasksClient struct { + client *ttrpc.Client +} + +func NewTTRPCTasksClient(client *ttrpc.Client) TTRPCTasksService { + return &ttrpctasksClient{ + client: client, + } +} + +func (c *ttrpctasksClient) Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) { + var resp CreateTaskResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Create", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) { + var resp StartResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Start", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Delete(ctx context.Context, req *DeleteTaskRequest) (*DeleteResponse, error) { + var resp DeleteResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Delete", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) DeleteProcess(ctx context.Context, req *DeleteProcessRequest) (*DeleteResponse, error) { + var resp DeleteResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "DeleteProcess", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Get(ctx context.Context, req *GetRequest) (*GetResponse, error) { + var resp GetResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Get", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) List(ctx context.Context, req *ListTasksRequest) (*ListTasksResponse, error) { + var resp ListTasksResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "List", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Kill(ctx context.Context, req *KillRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Kill", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Exec(ctx context.Context, req *ExecProcessRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Exec", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "ResizePty", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) CloseIO(ctx context.Context, req *CloseIORequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "CloseIO", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Pause(ctx context.Context, req *PauseTaskRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Pause", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Resume(ctx context.Context, req *ResumeTaskRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Resume", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) ListPids(ctx context.Context, req *ListPidsRequest) (*ListPidsResponse, error) { + var resp ListPidsResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "ListPids", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*CheckpointTaskResponse, error) { + var resp CheckpointTaskResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Checkpoint", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Update(ctx context.Context, req *UpdateTaskRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Update", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Metrics(ctx context.Context, req *MetricsRequest) (*MetricsResponse, error) { + var resp MetricsResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Metrics", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *ttrpctasksClient) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) { + var resp WaitResponse + if err := c.client.Call(ctx, "containerd.services.tasks.v1.Tasks", "Wait", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/transfer/v1/transfer_grpc.pb.go b/api/services/transfer/v1/transfer_grpc.pb.go index cf108744bd62..90c71224d32b 100644 --- a/api/services/transfer/v1/transfer_grpc.pb.go +++ b/api/services/transfer/v1/transfer_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/transfer/v1/transfer_ttrpc.pb.go b/api/services/transfer/v1/transfer_ttrpc.pb.go new file mode 100644 index 000000000000..848eb1933fa0 --- /dev/null +++ b/api/services/transfer/v1/transfer_ttrpc.pb.go @@ -0,0 +1,45 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/transfer/v1/transfer.proto +package transfer + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCTransferService interface { + Transfer(context.Context, *TransferRequest) (*emptypb.Empty, error) +} + +func RegisterTTRPCTransferService(srv *ttrpc.Server, svc TTRPCTransferService) { + srv.RegisterService("containerd.services.transfer.v1.Transfer", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Transfer": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req TransferRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Transfer(ctx, &req) + }, + }, + }) +} + +type ttrpctransferClient struct { + client *ttrpc.Client +} + +func NewTTRPCTransferClient(client *ttrpc.Client) TTRPCTransferService { + return &ttrpctransferClient{ + client: client, + } +} + +func (c *ttrpctransferClient) Transfer(ctx context.Context, req *TransferRequest) (*emptypb.Empty, error) { + var resp emptypb.Empty + if err := c.client.Call(ctx, "containerd.services.transfer.v1.Transfer", "Transfer", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/services/ttrpc/events/v1/doc.go b/api/services/ttrpc/events/v1/doc.go index d3d9839d639a..b374dde261bb 100644 --- a/api/services/ttrpc/events/v1/doc.go +++ b/api/services/ttrpc/events/v1/doc.go @@ -16,3 +16,8 @@ // Package events defines the ttrpc event service. package events + +import types "github.com/containerd/containerd/api/types" + +// Deprecated: Use [types.Envelope]. +type Envelope = types.Envelope diff --git a/api/services/ttrpc/events/v1/events.pb.go b/api/services/ttrpc/events/v1/events.pb.go index 221b183f7cef..d7e6bdfd45e3 100644 --- a/api/services/ttrpc/events/v1/events.pb.go +++ b/api/services/ttrpc/events/v1/events.pb.go @@ -22,12 +22,10 @@ package events import ( - _ "github.com/containerd/containerd/protobuf/plugin" + types "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - anypb "google.golang.org/protobuf/types/known/anypb" emptypb "google.golang.org/protobuf/types/known/emptypb" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -44,7 +42,7 @@ type ForwardRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Envelope *Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` + Envelope *types.Envelope `protobuf:"bytes,1,opt,name=envelope,proto3" json:"envelope,omitempty"` } func (x *ForwardRequest) Reset() { @@ -79,84 +77,13 @@ func (*ForwardRequest) Descriptor() ([]byte, []int) { return file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_rawDescGZIP(), []int{0} } -func (x *ForwardRequest) GetEnvelope() *Envelope { +func (x *ForwardRequest) GetEnvelope() *types.Envelope { if x != nil { return x.Envelope } return nil } -type Envelope struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` - Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` - Event *anypb.Any `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` -} - -func (x *Envelope) Reset() { - *x = Envelope{} - if protoimpl.UnsafeEnabled { - mi := &file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Envelope) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Envelope) ProtoMessage() {} - -func (x *Envelope) ProtoReflect() protoreflect.Message { - mi := &file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Envelope.ProtoReflect.Descriptor instead. -func (*Envelope) Descriptor() ([]byte, []int) { - return file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_rawDescGZIP(), []int{1} -} - -func (x *Envelope) GetTimestamp() *timestamppb.Timestamp { - if x != nil { - return x.Timestamp - } - return nil -} - -func (x *Envelope) GetNamespace() string { - if x != nil { - return x.Namespace - } - return "" -} - -func (x *Envelope) GetTopic() string { - if x != nil { - return x.Topic - } - return "" -} - -func (x *Envelope) GetEvent() *anypb.Any { - if x != nil { - return x.Event - } - return nil -} - var File_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_rawDesc = []byte{ @@ -167,44 +94,28 @@ var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_pr 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x76, - 0x31, 0x1a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, + 0x31, 0x1a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x6c, 0x75, - 0x67, 0x69, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5b, 0x0a, 0x0e, - 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x49, - 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x74, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, - 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x08, 0x45, 0x6e, - 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x3a, 0x04, 0x80, 0xb9, 0x1f, 0x01, 0x32, 0x60, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x56, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x33, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x76, - 0x31, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2f, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x48, 0x0a, 0x0e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x08, 0x65, 0x6e, 0x76, 0x65, + 0x6c, 0x6f, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x45, 0x6e, + 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x52, 0x08, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, + 0x32, 0x60, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x56, 0x0a, 0x07, 0x46, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x2e, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2f, 0x74, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -219,25 +130,21 @@ func file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_p return file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_rawDescData } -var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_goTypes = []interface{}{ - (*ForwardRequest)(nil), // 0: containerd.services.events.ttrpc.v1.ForwardRequest - (*Envelope)(nil), // 1: containerd.services.events.ttrpc.v1.Envelope - (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp - (*anypb.Any)(nil), // 3: google.protobuf.Any - (*emptypb.Empty)(nil), // 4: google.protobuf.Empty + (*ForwardRequest)(nil), // 0: containerd.services.events.ttrpc.v1.ForwardRequest + (*types.Envelope)(nil), // 1: containerd.types.Envelope + (*emptypb.Empty)(nil), // 2: google.protobuf.Empty } var file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_depIdxs = []int32{ - 1, // 0: containerd.services.events.ttrpc.v1.ForwardRequest.envelope:type_name -> containerd.services.events.ttrpc.v1.Envelope - 2, // 1: containerd.services.events.ttrpc.v1.Envelope.timestamp:type_name -> google.protobuf.Timestamp - 3, // 2: containerd.services.events.ttrpc.v1.Envelope.event:type_name -> google.protobuf.Any - 0, // 3: containerd.services.events.ttrpc.v1.Events.Forward:input_type -> containerd.services.events.ttrpc.v1.ForwardRequest - 4, // 4: containerd.services.events.ttrpc.v1.Events.Forward:output_type -> google.protobuf.Empty - 4, // [4:5] is the sub-list for method output_type - 3, // [3:4] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 1, // 0: containerd.services.events.ttrpc.v1.ForwardRequest.envelope:type_name -> containerd.types.Envelope + 0, // 1: containerd.services.events.ttrpc.v1.Events.Forward:input_type -> containerd.services.events.ttrpc.v1.ForwardRequest + 2, // 2: containerd.services.events.ttrpc.v1.Events.Forward:output_type -> google.protobuf.Empty + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_init() } @@ -258,18 +165,6 @@ func file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_p return nil } } - file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Envelope); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -277,7 +172,7 @@ func file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_p GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_containerd_containerd_api_services_ttrpc_events_v1_events_proto_rawDesc, NumEnums: 0, - NumMessages: 2, + NumMessages: 1, NumExtensions: 0, NumServices: 1, }, diff --git a/api/services/ttrpc/events/v1/events.proto b/api/services/ttrpc/events/v1/events.proto index e0c2f232d364..e20e66601899 100644 --- a/api/services/ttrpc/events/v1/events.proto +++ b/api/services/ttrpc/events/v1/events.proto @@ -18,10 +18,8 @@ syntax = "proto3"; package containerd.services.events.ttrpc.v1; -import "github.com/containerd/containerd/protobuf/plugin/fieldpath.proto"; -import "google/protobuf/any.proto"; +import "github.com/containerd/containerd/api/types/event.proto"; import "google/protobuf/empty.proto"; -import "google/protobuf/timestamp.proto"; option go_package = "github.com/containerd/containerd/api/services/ttrpc/events/v1;events"; @@ -35,13 +33,5 @@ service Events { } message ForwardRequest { - Envelope envelope = 1; -} - -message Envelope { - option (containerd.plugin.fieldpath) = true; - google.protobuf.Timestamp timestamp = 1; - string namespace = 2; - string topic = 3; - google.protobuf.Any event = 4; + containerd.types.Envelope envelope = 1; } diff --git a/api/services/ttrpc/events/v1/events_fieldpath.pb.go b/api/services/ttrpc/events/v1/events_fieldpath.pb.go deleted file mode 100644 index ad48127be919..000000000000 --- a/api/services/ttrpc/events/v1/events_fieldpath.pb.go +++ /dev/null @@ -1,55 +0,0 @@ -// Code generated by protoc-gen-go-fieldpath. DO NOT EDIT. -// source: github.com/containerd/containerd/api/services/ttrpc/events/v1/events.proto -package events - -import ( - v2 "github.com/containerd/typeurl/v2" -) - -// Field returns the value for the given fieldpath as a string, if defined. -// If the value is not defined, the second value will be false. -func (m *ForwardRequest) Field(fieldpath []string) (string, bool) { - if len(fieldpath) == 0 { - return "", false - } - switch fieldpath[0] { - case "envelope": - // NOTE(stevvooe): This is probably not correct in many cases. - // We assume that the target message also implements the Field - // method, which isn't likely true in a lot of cases. - // - // If you have a broken build and have found this comment, - // you may be closer to a solution. - if m.Envelope == nil { - return "", false - } - return m.Envelope.Field(fieldpath[1:]) - } - return "", false -} - -// Field returns the value for the given fieldpath as a string, if defined. -// If the value is not defined, the second value will be false. -func (m *Envelope) Field(fieldpath []string) (string, bool) { - if len(fieldpath) == 0 { - return "", false - } - switch fieldpath[0] { - // unhandled: timestamp - case "namespace": - return string(m.Namespace), len(m.Namespace) > 0 - case "topic": - return string(m.Topic), len(m.Topic) > 0 - case "event": - decoded, err := v2.UnmarshalAny(m.Event) - if err != nil { - return "", false - } - adaptor, ok := decoded.(interface{ Field([]string) (string, bool) }) - if !ok { - return "", false - } - return adaptor.Field(fieldpath[1:]) - } - return "", false -} diff --git a/api/services/version/v1/version_grpc.pb.go b/api/services/version/v1/version_grpc.pb.go index 4070fd834750..e96eddefb79f 100644 --- a/api/services/version/v1/version_grpc.pb.go +++ b/api/services/version/v1/version_grpc.pb.go @@ -1,3 +1,5 @@ +//go:build !no_grpc + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 diff --git a/api/services/version/v1/version_ttrpc.pb.go b/api/services/version/v1/version_ttrpc.pb.go new file mode 100644 index 000000000000..c284f14e72d8 --- /dev/null +++ b/api/services/version/v1/version_ttrpc.pb.go @@ -0,0 +1,45 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/containerd/containerd/api/services/version/v1/version.proto +package version + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +type TTRPCVersionService interface { + Version(context.Context, *emptypb.Empty) (*VersionResponse, error) +} + +func RegisterTTRPCVersionService(srv *ttrpc.Server, svc TTRPCVersionService) { + srv.RegisterService("containerd.services.version.v1.Version", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "Version": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req emptypb.Empty + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Version(ctx, &req) + }, + }, + }) +} + +type ttrpcversionClient struct { + client *ttrpc.Client +} + +func NewTTRPCVersionClient(client *ttrpc.Client) TTRPCVersionService { + return &ttrpcversionClient{ + client: client, + } +} + +func (c *ttrpcversionClient) Version(ctx context.Context, req *emptypb.Empty) (*VersionResponse, error) { + var resp VersionResponse + if err := c.client.Call(ctx, "containerd.services.version.v1.Version", "Version", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/api/types/event.pb.go b/api/types/event.pb.go new file mode 100644 index 000000000000..6ebe1e26ddb2 --- /dev/null +++ b/api/types/event.pb.go @@ -0,0 +1,209 @@ +// +//Copyright The containerd Authors. +// +//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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/containerd/api/types/event.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Envelope struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"` + Topic string `protobuf:"bytes,3,opt,name=topic,proto3" json:"topic,omitempty"` + Event *anypb.Any `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"` +} + +func (x *Envelope) Reset() { + *x = Envelope{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_event_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Envelope) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Envelope) ProtoMessage() {} + +func (x *Envelope) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_event_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Envelope.ProtoReflect.Descriptor instead. +func (*Envelope) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_event_proto_rawDescGZIP(), []int{0} +} + +func (x *Envelope) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *Envelope) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *Envelope) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *Envelope) GetEvent() *anypb.Any { + if x != nil { + return x.Event + } + return nil +} + +var File_github_com_containerd_containerd_api_types_event_proto protoreflect.FileDescriptor + +var file_github_com_containerd_containerd_api_types_event_proto_rawDesc = []byte{ + 0x0a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x3a, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xaa, 0x01, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, + 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2a, 0x0a, + 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, + 0x6e, 0x79, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x04, 0x80, 0xb9, 0x1f, 0x01, 0x42, + 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_github_com_containerd_containerd_api_types_event_proto_rawDescOnce sync.Once + file_github_com_containerd_containerd_api_types_event_proto_rawDescData = file_github_com_containerd_containerd_api_types_event_proto_rawDesc +) + +func file_github_com_containerd_containerd_api_types_event_proto_rawDescGZIP() []byte { + file_github_com_containerd_containerd_api_types_event_proto_rawDescOnce.Do(func() { + file_github_com_containerd_containerd_api_types_event_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_api_types_event_proto_rawDescData) + }) + return file_github_com_containerd_containerd_api_types_event_proto_rawDescData +} + +var file_github_com_containerd_containerd_api_types_event_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_github_com_containerd_containerd_api_types_event_proto_goTypes = []interface{}{ + (*Envelope)(nil), // 0: containerd.types.Envelope + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp + (*anypb.Any)(nil), // 2: google.protobuf.Any +} +var file_github_com_containerd_containerd_api_types_event_proto_depIdxs = []int32{ + 1, // 0: containerd.types.Envelope.timestamp:type_name -> google.protobuf.Timestamp + 2, // 1: containerd.types.Envelope.event:type_name -> google.protobuf.Any + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_containerd_api_types_event_proto_init() } +func file_github_com_containerd_containerd_api_types_event_proto_init() { + if File_github_com_containerd_containerd_api_types_event_proto != nil { + return + } + file_github_com_containerd_containerd_api_types_fieldpath_proto_init() + if !protoimpl.UnsafeEnabled { + file_github_com_containerd_containerd_api_types_event_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Envelope); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_containerd_api_types_event_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_containerd_api_types_event_proto_goTypes, + DependencyIndexes: file_github_com_containerd_containerd_api_types_event_proto_depIdxs, + MessageInfos: file_github_com_containerd_containerd_api_types_event_proto_msgTypes, + }.Build() + File_github_com_containerd_containerd_api_types_event_proto = out.File + file_github_com_containerd_containerd_api_types_event_proto_rawDesc = nil + file_github_com_containerd_containerd_api_types_event_proto_goTypes = nil + file_github_com_containerd_containerd_api_types_event_proto_depIdxs = nil +} diff --git a/api/types/event.proto b/api/types/event.proto new file mode 100644 index 000000000000..a73bc9d45077 --- /dev/null +++ b/api/types/event.proto @@ -0,0 +1,33 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +package containerd.types; + +import "github.com/containerd/containerd/api/types/fieldpath.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +message Envelope { + option (containerd.types.fieldpath) = true; + google.protobuf.Timestamp timestamp = 1; + string namespace = 2; + string topic = 3; + google.protobuf.Any event = 4; +} diff --git a/api/types/fieldpath.pb.go b/api/types/fieldpath.pb.go new file mode 100644 index 000000000000..0f8feb415b4a --- /dev/null +++ b/api/types/fieldpath.pb.go @@ -0,0 +1,144 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/containerd/api/types/fieldpath.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var file_github_com_containerd_containerd_api_types_fieldpath_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.FileOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 63300, + Name: "containerd.types.fieldpath_all", + Tag: "varint,63300,opt,name=fieldpath_all", + Filename: "github.com/containerd/containerd/api/types/fieldpath.proto", + }, + { + ExtendedType: (*descriptorpb.MessageOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 64400, + Name: "containerd.types.fieldpath", + Tag: "varint,64400,opt,name=fieldpath", + Filename: "github.com/containerd/containerd/api/types/fieldpath.proto", + }, +} + +// Extension fields to descriptorpb.FileOptions. +var ( + // optional bool fieldpath_all = 63300; + E_FieldpathAll = &file_github_com_containerd_containerd_api_types_fieldpath_proto_extTypes[0] +) + +// Extension fields to descriptorpb.MessageOptions. +var ( + // optional bool fieldpath = 64400; + E_Fieldpath = &file_github_com_containerd_containerd_api_types_fieldpath_proto_extTypes[1] +) + +var File_github_com_containerd_containerd_api_types_fieldpath_proto protoreflect.FileDescriptor + +var file_github_com_containerd_containerd_api_types_fieldpath_proto_rawDesc = []byte{ + 0x0a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x1a, 0x20, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x3a, 0x46, 0x0a, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x61, 0x6c, + 0x6c, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0xc4, 0xee, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, + 0x74, 0x68, 0x41, 0x6c, 0x6c, 0x88, 0x01, 0x01, 0x3a, 0x42, 0x0a, 0x09, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x90, 0xf7, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x70, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x42, 0x32, 0x5a, 0x30, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_github_com_containerd_containerd_api_types_fieldpath_proto_goTypes = []interface{}{ + (*descriptorpb.FileOptions)(nil), // 0: google.protobuf.FileOptions + (*descriptorpb.MessageOptions)(nil), // 1: google.protobuf.MessageOptions +} +var file_github_com_containerd_containerd_api_types_fieldpath_proto_depIdxs = []int32{ + 0, // 0: containerd.types.fieldpath_all:extendee -> google.protobuf.FileOptions + 1, // 1: containerd.types.fieldpath:extendee -> google.protobuf.MessageOptions + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 0, // [0:2] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_containerd_api_types_fieldpath_proto_init() } +func file_github_com_containerd_containerd_api_types_fieldpath_proto_init() { + if File_github_com_containerd_containerd_api_types_fieldpath_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_containerd_api_types_fieldpath_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 2, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_containerd_api_types_fieldpath_proto_goTypes, + DependencyIndexes: file_github_com_containerd_containerd_api_types_fieldpath_proto_depIdxs, + ExtensionInfos: file_github_com_containerd_containerd_api_types_fieldpath_proto_extTypes, + }.Build() + File_github_com_containerd_containerd_api_types_fieldpath_proto = out.File + file_github_com_containerd_containerd_api_types_fieldpath_proto_rawDesc = nil + file_github_com_containerd_containerd_api_types_fieldpath_proto_goTypes = nil + file_github_com_containerd_containerd_api_types_fieldpath_proto_depIdxs = nil +} diff --git a/api/types/fieldpath.proto b/api/types/fieldpath.proto new file mode 100644 index 000000000000..8b290842b010 --- /dev/null +++ b/api/types/fieldpath.proto @@ -0,0 +1,42 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; +package containerd.types; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +extend google.protobuf.FileOptions { + optional bool fieldpath_all = 63300; +} + +extend google.protobuf.MessageOptions { + optional bool fieldpath = 64400; +} diff --git a/api/types/introspection.pb.go b/api/types/introspection.pb.go new file mode 100644 index 000000000000..2f9c2ac44957 --- /dev/null +++ b/api/types/introspection.pb.go @@ -0,0 +1,375 @@ +// +//Copyright The containerd Authors. +// +//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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/containerd/api/types/introspection.proto + +package types + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type RuntimeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RuntimePath string `protobuf:"bytes,1,opt,name=runtime_path,json=runtimePath,proto3" json:"runtime_path,omitempty"` + // Options correspond to CreateTaskRequest.options. + // This is needed to pass the runc binary path, etc. + Options *anypb.Any `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *RuntimeRequest) Reset() { + *x = RuntimeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RuntimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RuntimeRequest) ProtoMessage() {} + +func (x *RuntimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RuntimeRequest.ProtoReflect.Descriptor instead. +func (*RuntimeRequest) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_introspection_proto_rawDescGZIP(), []int{0} +} + +func (x *RuntimeRequest) GetRuntimePath() string { + if x != nil { + return x.RuntimePath + } + return "" +} + +func (x *RuntimeRequest) GetOptions() *anypb.Any { + if x != nil { + return x.Options + } + return nil +} + +type RuntimeVersion struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"` +} + +func (x *RuntimeVersion) Reset() { + *x = RuntimeVersion{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RuntimeVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RuntimeVersion) ProtoMessage() {} + +func (x *RuntimeVersion) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RuntimeVersion.ProtoReflect.Descriptor instead. +func (*RuntimeVersion) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_introspection_proto_rawDescGZIP(), []int{1} +} + +func (x *RuntimeVersion) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *RuntimeVersion) GetRevision() string { + if x != nil { + return x.Revision + } + return "" +} + +type RuntimeInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Version *RuntimeVersion `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + // Options correspond to RuntimeInfoRequest.Options (contains runc binary path, etc.) + Options *anypb.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"` + // OCI-compatible runtimes should use https://github.com/opencontainers/runtime-spec/blob/main/features.md + Features *anypb.Any `protobuf:"bytes,4,opt,name=features,proto3" json:"features,omitempty"` + // Annotations of the shim. Irrelevant to features.Annotations. + Annotations map[string]string `protobuf:"bytes,5,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *RuntimeInfo) Reset() { + *x = RuntimeInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RuntimeInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RuntimeInfo) ProtoMessage() {} + +func (x *RuntimeInfo) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RuntimeInfo.ProtoReflect.Descriptor instead. +func (*RuntimeInfo) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_introspection_proto_rawDescGZIP(), []int{2} +} + +func (x *RuntimeInfo) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *RuntimeInfo) GetVersion() *RuntimeVersion { + if x != nil { + return x.Version + } + return nil +} + +func (x *RuntimeInfo) GetOptions() *anypb.Any { + if x != nil { + return x.Options + } + return nil +} + +func (x *RuntimeInfo) GetFeatures() *anypb.Any { + if x != nil { + return x.Features + } + return nil +} + +func (x *RuntimeInfo) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +var File_github_com_containerd_containerd_api_types_introspection_proto protoreflect.FileDescriptor + +var file_github_com_containerd_containerd_api_types_introspection_proto_rawDesc = []byte{ + 0x0a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x69, 0x6e, 0x74, + 0x72, 0x6f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x63, 0x0a, + 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x46, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, + 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xd1, 0x02, 0x0a, 0x0b, 0x52, + 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x08, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, + 0x6e, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x50, 0x0a, 0x0b, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3e, + 0x0a, 0x10, 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x32, + 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_github_com_containerd_containerd_api_types_introspection_proto_rawDescOnce sync.Once + file_github_com_containerd_containerd_api_types_introspection_proto_rawDescData = file_github_com_containerd_containerd_api_types_introspection_proto_rawDesc +) + +func file_github_com_containerd_containerd_api_types_introspection_proto_rawDescGZIP() []byte { + file_github_com_containerd_containerd_api_types_introspection_proto_rawDescOnce.Do(func() { + file_github_com_containerd_containerd_api_types_introspection_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_api_types_introspection_proto_rawDescData) + }) + return file_github_com_containerd_containerd_api_types_introspection_proto_rawDescData +} + +var file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_github_com_containerd_containerd_api_types_introspection_proto_goTypes = []interface{}{ + (*RuntimeRequest)(nil), // 0: containerd.types.RuntimeRequest + (*RuntimeVersion)(nil), // 1: containerd.types.RuntimeVersion + (*RuntimeInfo)(nil), // 2: containerd.types.RuntimeInfo + nil, // 3: containerd.types.RuntimeInfo.AnnotationsEntry + (*anypb.Any)(nil), // 4: google.protobuf.Any +} +var file_github_com_containerd_containerd_api_types_introspection_proto_depIdxs = []int32{ + 4, // 0: containerd.types.RuntimeRequest.options:type_name -> google.protobuf.Any + 1, // 1: containerd.types.RuntimeInfo.version:type_name -> containerd.types.RuntimeVersion + 4, // 2: containerd.types.RuntimeInfo.options:type_name -> google.protobuf.Any + 4, // 3: containerd.types.RuntimeInfo.features:type_name -> google.protobuf.Any + 3, // 4: containerd.types.RuntimeInfo.annotations:type_name -> containerd.types.RuntimeInfo.AnnotationsEntry + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_containerd_api_types_introspection_proto_init() } +func file_github_com_containerd_containerd_api_types_introspection_proto_init() { + if File_github_com_containerd_containerd_api_types_introspection_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RuntimeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RuntimeVersion); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RuntimeInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_containerd_api_types_introspection_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_containerd_api_types_introspection_proto_goTypes, + DependencyIndexes: file_github_com_containerd_containerd_api_types_introspection_proto_depIdxs, + MessageInfos: file_github_com_containerd_containerd_api_types_introspection_proto_msgTypes, + }.Build() + File_github_com_containerd_containerd_api_types_introspection_proto = out.File + file_github_com_containerd_containerd_api_types_introspection_proto_rawDesc = nil + file_github_com_containerd_containerd_api_types_introspection_proto_goTypes = nil + file_github_com_containerd_containerd_api_types_introspection_proto_depIdxs = nil +} diff --git a/api/types/introspection.proto b/api/types/introspection.proto new file mode 100644 index 000000000000..8f3fcb5a4827 --- /dev/null +++ b/api/types/introspection.proto @@ -0,0 +1,46 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +syntax = "proto3"; + +package containerd.types; + +import "google/protobuf/any.proto"; + +option go_package = "github.com/containerd/containerd/api/types;types"; + +message RuntimeRequest { + string runtime_path = 1; + // Options correspond to CreateTaskRequest.options. + // This is needed to pass the runc binary path, etc. + google.protobuf.Any options = 2; +} + +message RuntimeVersion { + string version = 1; + string revision = 2; +} + +message RuntimeInfo { + string name = 1; + RuntimeVersion version = 2; + // Options correspond to RuntimeInfoRequest.Options (contains runc binary path, etc.) + google.protobuf.Any options = 3; + // OCI-compatible runtimes should use https://github.com/opencontainers/runtime-spec/blob/main/features.md + google.protobuf.Any features = 4; + // Annotations of the shim. Irrelevant to features.Annotations. + map annotations = 5; +} diff --git a/api/types/platform.pb.go b/api/types/platform.pb.go index 3e206cbafbda..daa62b834e12 100644 --- a/api/types/platform.pb.go +++ b/api/types/platform.pb.go @@ -45,6 +45,7 @@ type Platform struct { OS string `protobuf:"bytes,1,opt,name=os,proto3" json:"os,omitempty"` Architecture string `protobuf:"bytes,2,opt,name=architecture,proto3" json:"architecture,omitempty"` Variant string `protobuf:"bytes,3,opt,name=variant,proto3" json:"variant,omitempty"` + OSVersion string `protobuf:"bytes,4,opt,name=os_version,json=osVersion,proto3" json:"os_version,omitempty"` } func (x *Platform) Reset() { @@ -100,6 +101,13 @@ func (x *Platform) GetVariant() string { return "" } +func (x *Platform) GetOsVersion() string { + if x != nil { + return x.OSVersion + } + return "" +} + var File_github_com_containerd_containerd_api_types_platform_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_types_platform_proto_rawDesc = []byte{ @@ -107,17 +115,19 @@ var file_github_com_containerd_containerd_api_types_platform_proto_rawDesc = []b 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x58, 0x0a, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x77, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x73, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/api/types/platform.proto b/api/types/platform.proto index b6088251f007..0b9180016de4 100644 --- a/api/types/platform.proto +++ b/api/types/platform.proto @@ -26,4 +26,5 @@ message Platform { string os = 1; string architecture = 2; string variant = 3; + string os_version = 4; } diff --git a/api/types/platform_helpers.go b/api/types/platform_helpers.go new file mode 100644 index 000000000000..d8c1a6877052 --- /dev/null +++ b/api/types/platform_helpers.go @@ -0,0 +1,49 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package types + +import oci "github.com/opencontainers/image-spec/specs-go/v1" + +// OCIPlatformToProto converts from a slice of OCI [specs.Platform] to a +// slice of the protobuf definition [Platform]. +func OCIPlatformToProto(platforms []oci.Platform) []*Platform { + ap := make([]*Platform, len(platforms)) + for i := range platforms { + ap[i] = &Platform{ + OS: platforms[i].OS, + OSVersion: platforms[i].OSVersion, + Architecture: platforms[i].Architecture, + Variant: platforms[i].Variant, + } + } + return ap +} + +// OCIPlatformFromProto converts a slice of the protobuf definition [Platform] +// to a slice of OCI [specs.Platform]. +func OCIPlatformFromProto(platforms []*Platform) []oci.Platform { + op := make([]oci.Platform, len(platforms)) + for i := range platforms { + op[i] = oci.Platform{ + OS: platforms[i].OS, + OSVersion: platforms[i].OSVersion, + Architecture: platforms[i].Architecture, + Variant: platforms[i].Variant, + } + } + return op +} diff --git a/runtime/v2/runc/options/doc.go b/api/types/runc/options/doc.go similarity index 100% rename from runtime/v2/runc/options/doc.go rename to api/types/runc/options/doc.go diff --git a/api/types/runc/options/next.pb.txt b/api/types/runc/options/next.pb.txt new file mode 100755 index 000000000000..6b5ce784b4e3 --- /dev/null +++ b/api/types/runc/options/next.pb.txt @@ -0,0 +1,175 @@ +file { + name: "github.com/containerd/containerd/core/runtime/v2/runc/options/oci.proto" + package: "containerd.runc.v1" + message_type { + name: "Options" + field { + name: "no_pivot_root" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "noPivotRoot" + } + field { + name: "no_new_keyring" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "noNewKeyring" + } + field { + name: "shim_cgroup" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "shimCgroup" + } + field { + name: "io_uid" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "ioUid" + } + field { + name: "io_gid" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "ioGid" + } + field { + name: "binary_name" + number: 6 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "binaryName" + } + field { + name: "root" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "root" + } + field { + name: "systemd_cgroup" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "systemdCgroup" + } + field { + name: "criu_image_path" + number: 10 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuImagePath" + } + field { + name: "criu_work_path" + number: 11 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "criuWorkPath" + } + field { + name: "task_api_address" + number: 12 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "taskApiAddress" + } + field { + name: "task_api_version" + number: 13 + label: LABEL_OPTIONAL + type: TYPE_UINT32 + json_name: "taskApiVersion" + } + reserved_range { + start: 8 + end: 9 + } + } + message_type { + name: "CheckpointOptions" + field { + name: "exit" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "exit" + } + field { + name: "open_tcp" + number: 2 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "openTcp" + } + field { + name: "external_unix_sockets" + number: 3 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "externalUnixSockets" + } + field { + name: "terminal" + number: 4 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "terminal" + } + field { + name: "file_locks" + number: 5 + label: LABEL_OPTIONAL + type: TYPE_BOOL + json_name: "fileLocks" + } + field { + name: "empty_namespaces" + number: 6 + label: LABEL_REPEATED + type: TYPE_STRING + json_name: "emptyNamespaces" + } + field { + name: "cgroups_mode" + number: 7 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "cgroupsMode" + } + field { + name: "image_path" + number: 8 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "imagePath" + } + field { + name: "work_path" + number: 9 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "workPath" + } + } + message_type { + name: "ProcessDetails" + field { + name: "exec_id" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + json_name: "execId" + } + } + options { + go_package: "github.com/containerd/containerd/v2/core/runtime/v2/runc/options;options" + } + syntax: "proto3" +} diff --git a/api/types/runc/options/oci.pb.go b/api/types/runc/options/oci.pb.go new file mode 100644 index 000000000000..aa55fc46fdab --- /dev/null +++ b/api/types/runc/options/oci.pb.go @@ -0,0 +1,491 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/containerd/api/types/runc/options/oci.proto + +package options + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Options struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // disable pivot root when creating a container + NoPivotRoot bool `protobuf:"varint,1,opt,name=no_pivot_root,json=noPivotRoot,proto3" json:"no_pivot_root,omitempty"` + // create a new keyring for the container + NoNewKeyring bool `protobuf:"varint,2,opt,name=no_new_keyring,json=noNewKeyring,proto3" json:"no_new_keyring,omitempty"` + // place the shim in a cgroup + ShimCgroup string `protobuf:"bytes,3,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"` + // set the I/O's pipes uid + IoUid uint32 `protobuf:"varint,4,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"` + // set the I/O's pipes gid + IoGid uint32 `protobuf:"varint,5,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"` + // binary name of the runc binary + BinaryName string `protobuf:"bytes,6,opt,name=binary_name,json=binaryName,proto3" json:"binary_name,omitempty"` + // runc root directory + Root string `protobuf:"bytes,7,opt,name=root,proto3" json:"root,omitempty"` + // enable systemd cgroups + SystemdCgroup bool `protobuf:"varint,9,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` + // criu image path + CriuImagePath string `protobuf:"bytes,10,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"` + // criu work path + CriuWorkPath string `protobuf:"bytes,11,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"` + // task api address, can be a unix domain socket, or vsock address. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + TaskApiAddress string `protobuf:"bytes,12,opt,name=task_api_address,json=taskApiAddress,proto3" json:"task_api_address,omitempty"` + // task api version, currently supported value is 2 and 3. + TaskApiVersion uint32 `protobuf:"varint,13,opt,name=task_api_version,json=taskApiVersion,proto3" json:"task_api_version,omitempty"` +} + +func (x *Options) Reset() { + *x = Options{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Options) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Options) ProtoMessage() {} + +func (x *Options) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Options.ProtoReflect.Descriptor instead. +func (*Options) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescGZIP(), []int{0} +} + +func (x *Options) GetNoPivotRoot() bool { + if x != nil { + return x.NoPivotRoot + } + return false +} + +func (x *Options) GetNoNewKeyring() bool { + if x != nil { + return x.NoNewKeyring + } + return false +} + +func (x *Options) GetShimCgroup() string { + if x != nil { + return x.ShimCgroup + } + return "" +} + +func (x *Options) GetIoUid() uint32 { + if x != nil { + return x.IoUid + } + return 0 +} + +func (x *Options) GetIoGid() uint32 { + if x != nil { + return x.IoGid + } + return 0 +} + +func (x *Options) GetBinaryName() string { + if x != nil { + return x.BinaryName + } + return "" +} + +func (x *Options) GetRoot() string { + if x != nil { + return x.Root + } + return "" +} + +func (x *Options) GetSystemdCgroup() bool { + if x != nil { + return x.SystemdCgroup + } + return false +} + +func (x *Options) GetCriuImagePath() string { + if x != nil { + return x.CriuImagePath + } + return "" +} + +func (x *Options) GetCriuWorkPath() string { + if x != nil { + return x.CriuWorkPath + } + return "" +} + +func (x *Options) GetTaskApiAddress() string { + if x != nil { + return x.TaskApiAddress + } + return "" +} + +func (x *Options) GetTaskApiVersion() uint32 { + if x != nil { + return x.TaskApiVersion + } + return 0 +} + +type CheckpointOptions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // exit the container after a checkpoint + Exit bool `protobuf:"varint,1,opt,name=exit,proto3" json:"exit,omitempty"` + // checkpoint open tcp connections + OpenTcp bool `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` + // checkpoint external unix sockets + ExternalUnixSockets bool `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` + // checkpoint terminals (ptys) + Terminal bool `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` + // allow checkpointing of file locks + FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"` + // restore provided namespaces as empty namespaces + EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces,proto3" json:"empty_namespaces,omitempty"` + // set the cgroups mode, soft, full, strict + CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` + // checkpoint image path + ImagePath string `protobuf:"bytes,8,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"` + // checkpoint work path + WorkPath string `protobuf:"bytes,9,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"` +} + +func (x *CheckpointOptions) Reset() { + *x = CheckpointOptions{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckpointOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckpointOptions) ProtoMessage() {} + +func (x *CheckpointOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckpointOptions.ProtoReflect.Descriptor instead. +func (*CheckpointOptions) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescGZIP(), []int{1} +} + +func (x *CheckpointOptions) GetExit() bool { + if x != nil { + return x.Exit + } + return false +} + +func (x *CheckpointOptions) GetOpenTcp() bool { + if x != nil { + return x.OpenTcp + } + return false +} + +func (x *CheckpointOptions) GetExternalUnixSockets() bool { + if x != nil { + return x.ExternalUnixSockets + } + return false +} + +func (x *CheckpointOptions) GetTerminal() bool { + if x != nil { + return x.Terminal + } + return false +} + +func (x *CheckpointOptions) GetFileLocks() bool { + if x != nil { + return x.FileLocks + } + return false +} + +func (x *CheckpointOptions) GetEmptyNamespaces() []string { + if x != nil { + return x.EmptyNamespaces + } + return nil +} + +func (x *CheckpointOptions) GetCgroupsMode() string { + if x != nil { + return x.CgroupsMode + } + return "" +} + +func (x *CheckpointOptions) GetImagePath() string { + if x != nil { + return x.ImagePath + } + return "" +} + +func (x *CheckpointOptions) GetWorkPath() string { + if x != nil { + return x.WorkPath + } + return "" +} + +type ProcessDetails struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // exec process id if the process is managed by a shim + ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` +} + +func (x *ProcessDetails) Reset() { + *x = ProcessDetails{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProcessDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessDetails) ProtoMessage() {} + +func (x *ProcessDetails) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProcessDetails.ProtoReflect.Descriptor instead. +func (*ProcessDetails) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescGZIP(), []int{2} +} + +func (x *ProcessDetails) GetExecID() string { + if x != nil { + return x.ExecID + } + return "" +} + +var File_github_com_containerd_containerd_api_types_runc_options_oci_proto protoreflect.FileDescriptor + +var file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDesc = []byte{ + 0x0a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x6e, + 0x63, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x6f, 0x63, 0x69, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x72, 0x75, 0x6e, 0x63, 0x2e, 0x76, 0x31, 0x22, 0xa6, 0x03, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x5f, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x5f, + 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x50, 0x69, + 0x76, 0x6f, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x6f, 0x5f, 0x6e, 0x65, + 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0c, 0x6e, 0x6f, 0x4e, 0x65, 0x77, 0x4b, 0x65, 0x79, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x73, 0x68, 0x69, 0x6d, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x15, + 0x0a, 0x06, 0x69, 0x6f, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, + 0x69, 0x6f, 0x55, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x6f, 0x5f, 0x67, 0x69, 0x64, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6f, 0x47, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, + 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6f, + 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x64, 0x5f, 0x63, 0x67, 0x72, + 0x6f, 0x75, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x64, 0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x72, 0x69, 0x75, + 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x63, 0x72, 0x69, 0x75, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, + 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x75, 0x57, 0x6f, + 0x72, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, + 0x70, 0x69, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x41, 0x70, 0x69, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, + 0x41, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, + 0x22, 0xbb, 0x02, 0x0a, 0x11, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x69, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x65, 0x78, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, + 0x65, 0x6e, 0x5f, 0x74, 0x63, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x70, + 0x65, 0x6e, 0x54, 0x63, 0x70, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x55, 0x6e, + 0x69, 0x78, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, + 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, + 0x63, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x4c, + 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, + 0x21, 0x0a, 0x0c, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4d, 0x6f, + 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, + 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x22, 0x29, + 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x63, 0x2f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescOnce sync.Once + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescData = file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDesc +) + +func file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescGZIP() []byte { + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescOnce.Do(func() { + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescData) + }) + return file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDescData +} + +var file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_github_com_containerd_containerd_api_types_runc_options_oci_proto_goTypes = []interface{}{ + (*Options)(nil), // 0: containerd.runc.v1.Options + (*CheckpointOptions)(nil), // 1: containerd.runc.v1.CheckpointOptions + (*ProcessDetails)(nil), // 2: containerd.runc.v1.ProcessDetails +} +var file_github_com_containerd_containerd_api_types_runc_options_oci_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_containerd_api_types_runc_options_oci_proto_init() } +func file_github_com_containerd_containerd_api_types_runc_options_oci_proto_init() { + if File_github_com_containerd_containerd_api_types_runc_options_oci_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Options); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckpointOptions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProcessDetails); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_containerd_api_types_runc_options_oci_proto_goTypes, + DependencyIndexes: file_github_com_containerd_containerd_api_types_runc_options_oci_proto_depIdxs, + MessageInfos: file_github_com_containerd_containerd_api_types_runc_options_oci_proto_msgTypes, + }.Build() + File_github_com_containerd_containerd_api_types_runc_options_oci_proto = out.File + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_rawDesc = nil + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_goTypes = nil + file_github_com_containerd_containerd_api_types_runc_options_oci_proto_depIdxs = nil +} diff --git a/api/types/runc/options/oci.proto b/api/types/runc/options/oci.proto new file mode 100644 index 000000000000..a30b5bbff82a --- /dev/null +++ b/api/types/runc/options/oci.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +package containerd.runc.v1; + +option go_package = "github.com/containerd/containerd/api/types/runc/options;options"; + +message Options { + // disable pivot root when creating a container + bool no_pivot_root = 1; + // create a new keyring for the container + bool no_new_keyring = 2; + // place the shim in a cgroup + string shim_cgroup = 3; + // set the I/O's pipes uid + uint32 io_uid = 4; + // set the I/O's pipes gid + uint32 io_gid = 5; + // binary name of the runc binary + string binary_name = 6; + // runc root directory + string root = 7; + // criu binary path. + // + // Removed in containerd v2.0: string criu_path = 8; + reserved 8; + // enable systemd cgroups + bool systemd_cgroup = 9; + // criu image path + string criu_image_path = 10; + // criu work path + string criu_work_path = 11; + // task api address, can be a unix domain socket, or vsock address. + // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://:. + string task_api_address = 12; + // task api version, currently supported value is 2 and 3. + uint32 task_api_version = 13; +} + +message CheckpointOptions { + // exit the container after a checkpoint + bool exit = 1; + // checkpoint open tcp connections + bool open_tcp = 2; + // checkpoint external unix sockets + bool external_unix_sockets = 3; + // checkpoint terminals (ptys) + bool terminal = 4; + // allow checkpointing of file locks + bool file_locks = 5; + // restore provided namespaces as empty namespaces + repeated string empty_namespaces = 6; + // set the cgroups mode, soft, full, strict + string cgroups_mode = 7; + // checkpoint image path + string image_path = 8; + // checkpoint work path + string work_path = 9; +} + +message ProcessDetails { + // exec process id if the process is managed by a shim + string exec_id = 1; +} diff --git a/api/types/runtimeoptions/v1/api.pb.go b/api/types/runtimeoptions/v1/api.pb.go new file mode 100644 index 000000000000..45c10fcecc7a --- /dev/null +++ b/api/types/runtimeoptions/v1/api.pb.go @@ -0,0 +1,177 @@ +// To regenerate api.pb.go run `make protos` + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.20.1 +// source: github.com/containerd/containerd/api/types/runtimeoptions/v1/api.proto + +package runtimeoptions + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Options struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // TypeUrl specifies the type of the content inside the config file. + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` + // ConfigPath specifies the filesystem location of the config file + // used by the runtime. + ConfigPath string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3" json:"config_path,omitempty"` + // Blob specifies an in-memory TOML blob passed from containerd's configuration section + // for this runtime. This will be used if config_path is not specified. + ConfigBody []byte `protobuf:"bytes,3,opt,name=config_body,json=configBody,proto3" json:"config_body,omitempty"` +} + +func (x *Options) Reset() { + *x = Options{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Options) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Options) ProtoMessage() {} + +func (x *Options) ProtoReflect() protoreflect.Message { + mi := &file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Options.ProtoReflect.Descriptor instead. +func (*Options) Descriptor() ([]byte, []int) { + return file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescGZIP(), []int{0} +} + +func (x *Options) GetTypeUrl() string { + if x != nil { + return x.TypeUrl + } + return "" +} + +func (x *Options) GetConfigPath() string { + if x != nil { + return x.ConfigPath + } + return "" +} + +func (x *Options) GetConfigBody() []byte { + if x != nil { + return x.ConfigBody + } + return nil +} + +var File_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto protoreflect.FileDescriptor + +var file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDesc = []byte{ + 0x0a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, + 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x11, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x22, 0x66, 0x0a, 0x07, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, + 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x79, 0x70, 0x65, 0x55, 0x72, + 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x62, 0x6f, 0x64, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, + 0x6f, 0x64, 0x79, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescOnce sync.Once + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescData = file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDesc +) + +func file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescGZIP() []byte { + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescOnce.Do(func() { + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescData) + }) + return file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDescData +} + +var file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_goTypes = []interface{}{ + (*Options)(nil), // 0: runtimeoptions.v1.Options +} +var file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_init() } +func file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_init() { + if File_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Options); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_goTypes, + DependencyIndexes: file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_depIdxs, + MessageInfos: file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_msgTypes, + }.Build() + File_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto = out.File + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_rawDesc = nil + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_goTypes = nil + file_github_com_containerd_containerd_api_types_runtimeoptions_v1_api_proto_depIdxs = nil +} diff --git a/api/types/runtimeoptions/v1/api.proto b/api/types/runtimeoptions/v1/api.proto new file mode 100644 index 000000000000..f0a7d56b8b1f --- /dev/null +++ b/api/types/runtimeoptions/v1/api.proto @@ -0,0 +1,17 @@ +// To regenerate api.pb.go run `make protos` +syntax = "proto3"; + +package runtimeoptions.v1; + +option go_package = "github.com/containerd/containerd/api/types/runtimeoptions/v1;runtimeoptions"; + +message Options { + // TypeUrl specifies the type of the content inside the config file. + string type_url = 1; + // ConfigPath specifies the filesystem location of the config file + // used by the runtime. + string config_path = 2; + // Blob specifies an in-memory TOML blob passed from containerd's configuration section + // for this runtime. This will be used if config_path is not specified. + bytes config_body = 3; +} diff --git a/api/types/runtimeoptions/v1/doc.go b/api/types/runtimeoptions/v1/doc.go new file mode 100644 index 000000000000..c590b9b63146 --- /dev/null +++ b/api/types/runtimeoptions/v1/doc.go @@ -0,0 +1,17 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package runtimeoptions diff --git a/api/types/sandbox.pb.go b/api/types/sandbox.pb.go index 67594f416c81..77888bf33208 100644 --- a/api/types/sandbox.pb.go +++ b/api/types/sandbox.pb.go @@ -59,6 +59,8 @@ type Sandbox struct { UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` // Extensions allow clients to provide optional blobs that can be handled by runtime. Extensions map[string]*anypb.Any `protobuf:"bytes,7,rep,name=extensions,proto3" json:"extensions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Sandboxer is the name of the sandbox controller who manages the sandbox. + Sandboxer string `protobuf:"bytes,10,opt,name=sandboxer,proto3" json:"sandboxer,omitempty"` } func (x *Sandbox) Reset() { @@ -142,6 +144,13 @@ func (x *Sandbox) GetExtensions() map[string]*anypb.Any { return nil } +func (x *Sandbox) GetSandboxer() string { + if x != nil { + return x.Sandboxer + } + return "" +} + type Sandbox_Runtime struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -211,7 +220,7 @@ var file_github_com_containerd_containerd_api_types_sandbox_proto_rawDesc = []by 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xee, 0x04, 0x0a, 0x07, 0x53, 0x61, 0x6e, + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8c, 0x05, 0x0a, 0x07, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x07, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, @@ -236,25 +245,27 @@ var file_github_com_containerd_containerd_api_types_sandbox_proto_rawDesc = []by 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x4d, 0x0a, 0x07, 0x52, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, - 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x53, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x72, 0x1a, 0x4d, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x1a, 0x53, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, + 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/api/types/sandbox.proto b/api/types/sandbox.proto index b607706194b2..b0bf233b954b 100644 --- a/api/types/sandbox.proto +++ b/api/types/sandbox.proto @@ -41,11 +41,14 @@ message Sandbox { // bundle directory (similary to OCI spec). google.protobuf.Any spec = 3; // Labels provides an area to include arbitrary data on containers. - map labels = 4; + map labels = 4; // CreatedAt is the time the container was first created. google.protobuf.Timestamp created_at = 5; // UpdatedAt is the last time the container was mutated. google.protobuf.Timestamp updated_at = 6; // Extensions allow clients to provide optional blobs that can be handled by runtime. map extensions = 7; + // Sandboxer is the name of the sandbox controller who manages the sandbox. + string sandboxer = 10; + } diff --git a/api/types/transfer/progress.pb.go b/api/types/transfer/progress.pb.go index 62d12b34db37..d1fb1625dff7 100644 --- a/api/types/transfer/progress.pb.go +++ b/api/types/transfer/progress.pb.go @@ -22,6 +22,7 @@ package transfer import ( + types "github.com/containerd/containerd/api/types" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -40,11 +41,12 @@ type Progress struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Event string `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Parents []string `protobuf:"bytes,3,rep,name=parents,proto3" json:"parents,omitempty"` - Progress int64 `protobuf:"varint,4,opt,name=progress,proto3" json:"progress,omitempty"` - Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"` + Event string `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Parents []string `protobuf:"bytes,3,rep,name=parents,proto3" json:"parents,omitempty"` + Progress int64 `protobuf:"varint,4,opt,name=progress,proto3" json:"progress,omitempty"` + Total int64 `protobuf:"varint,5,opt,name=total,proto3" json:"total,omitempty"` + Desc *types.Descriptor `protobuf:"bytes,6,opt,name=desc,proto3" json:"desc,omitempty"` } func (x *Progress) Reset() { @@ -114,6 +116,13 @@ func (x *Progress) GetTotal() int64 { return 0 } +func (x *Progress) GetDesc() *types.Descriptor { + if x != nil { + return x.Desc + } + return nil +} + var File_github_com_containerd_containerd_api_types_transfer_progress_proto protoreflect.FileDescriptor var file_github_com_containerd_containerd_api_types_transfer_progress_proto_rawDesc = []byte{ @@ -122,20 +131,26 @@ var file_github_com_containerd_containerd_api_types_transfer_progress_proto_rawD 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x22, - 0x80, 0x01, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x1a, + 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x01, 0x0a, + 0x08, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x30, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x64, 0x65, 0x73, + 0x63, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -152,14 +167,16 @@ func file_github_com_containerd_containerd_api_types_transfer_progress_proto_raw var file_github_com_containerd_containerd_api_types_transfer_progress_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_github_com_containerd_containerd_api_types_transfer_progress_proto_goTypes = []interface{}{ - (*Progress)(nil), // 0: containerd.types.transfer.Progress + (*Progress)(nil), // 0: containerd.types.transfer.Progress + (*types.Descriptor)(nil), // 1: containerd.types.Descriptor } var file_github_com_containerd_containerd_api_types_transfer_progress_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 1, // 0: containerd.types.transfer.Progress.desc:type_name -> containerd.types.Descriptor + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_github_com_containerd_containerd_api_types_transfer_progress_proto_init() } diff --git a/api/types/transfer/progress.proto b/api/types/transfer/progress.proto index 3059bcbb12a4..094c363b2132 100644 --- a/api/types/transfer/progress.proto +++ b/api/types/transfer/progress.proto @@ -18,6 +18,8 @@ syntax = "proto3"; package containerd.types.transfer; +import "github.com/containerd/containerd/api/types/descriptor.proto"; + option go_package = "github.com/containerd/containerd/api/types/transfer"; message Progress { @@ -26,4 +28,5 @@ message Progress { repeated string parents = 3; int64 progress = 4; int64 total = 5; + containerd.types.Descriptor desc = 6; } diff --git a/api/types/transfer/registry.pb.go b/api/types/transfer/registry.pb.go index 57bb80bae9e5..1c67b7591dbf 100644 --- a/api/types/transfer/registry.pb.go +++ b/api/types/transfer/registry.pb.go @@ -159,7 +159,9 @@ type RegistryResolver struct { // made on. AuthStream string `protobuf:"bytes,1,opt,name=auth_stream,json=authStream,proto3" json:"auth_stream,omitempty"` // Headers - Headers map[string]string `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Headers map[string]string `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + HostDir string `protobuf:"bytes,3,opt,name=host_dir,json=hostDir,proto3" json:"host_dir,omitempty"` + DefaultScheme string `protobuf:"bytes,4,opt,name=default_scheme,json=defaultScheme,proto3" json:"default_scheme,omitempty"` } func (x *RegistryResolver) Reset() { @@ -208,6 +210,20 @@ func (x *RegistryResolver) GetHeaders() map[string]string { return nil } +func (x *RegistryResolver) GetHostDir() string { + if x != nil { + return x.HostDir + } + return "" +} + +func (x *RegistryResolver) GetDefaultScheme() string { + if x != nil { + return x.DefaultScheme + } + return "" +} + // AuthRequest is sent as a callback on a stream type AuthRequest struct { state protoimpl.MessageState @@ -364,7 +380,7 @@ var file_github_com_containerd_containerd_api_types_transfer_registry_proto_rawD 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x52, 0x08, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x22, 0xc3, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x22, 0x85, 0x02, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x52, 0x0a, 0x07, @@ -373,37 +389,41 @@ var file_github_com_containerd_containerd_api_types_transfer_registry_proto_rawD 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, - 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x69, 0x0a, 0x0b, - 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, - 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, - 0x0f, 0x77, 0x77, 0x77, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x77, 0x77, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xbc, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, - 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, - 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x65, 0x78, - 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x2a, 0x3e, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, - 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, - 0x07, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, - 0x41, 0x44, 0x45, 0x52, 0x10, 0x03, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x19, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x44, 0x69, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x65, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x69, + 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x28, 0x0a, 0x0f, 0x77, 0x77, 0x77, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x77, 0x77, 0x61, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xbc, 0x01, 0x0a, 0x0c, 0x41, 0x75, + 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x61, 0x75, + 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x37, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, + 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x41, 0x74, 0x2a, 0x3e, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0f, + 0x0a, 0x0b, 0x43, 0x52, 0x45, 0x44, 0x45, 0x4e, 0x54, 0x49, 0x41, 0x4c, 0x53, 0x10, 0x01, 0x12, + 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, + 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x03, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/types/transfer/registry.proto b/api/types/transfer/registry.proto index 0b3ce68b4c4b..3331ecb7820e 100644 --- a/api/types/transfer/registry.proto +++ b/api/types/transfer/registry.proto @@ -35,9 +35,10 @@ message RegistryResolver { // Headers map headers = 2; - // Allow custom hosts dir? + string host_dir = 3; + + string default_scheme = 4; // Force skip verify - // Force HTTP // CA callback? Client TLS callback? } diff --git a/archive/compression/benchmark_test.go b/archive/compression/benchmark_test.go deleted file mode 100644 index f8340802a757..000000000000 --- a/archive/compression/benchmark_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright The containerd Authors. - - 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. -*/ - -package compression - -import ( - "fmt" - "io" - "net/http" - "testing" - - "github.com/stretchr/testify/require" -) - -const benchmarkTestDataURL = "https://git.io/fADcl" - -func BenchmarkDecompression(b *testing.B) { - resp, err := http.Get(benchmarkTestDataURL) - require.NoError(b, err) - - data, err := io.ReadAll(resp.Body) - require.NoError(b, err) - resp.Body.Close() - - const mib = 1024 * 1024 - sizes := []int{32, 64, 128, 256} - - for _, sizeInMiB := range sizes { - size := sizeInMiB * mib - for len(data) < size { - data = append(data, data...) - } - data = data[0:size] - - gz := testCompress(b, data, Gzip) - zstd := testCompress(b, data, Zstd) - - b.Run(fmt.Sprintf("size=%dMiB", sizeInMiB), func(b *testing.B) { - b.Run("gzip", func(b *testing.B) { - testDecompress(b, gz) - }) - b.Run("zstd", func(b *testing.B) { - testDecompress(b, zstd) - }) - if unpigzPath != "" { - original := unpigzPath - unpigzPath = "" - b.Run("gzipPureGo", func(b *testing.B) { - testDecompress(b, gz) - }) - unpigzPath = original - } - }) - } -} diff --git a/archive/compression/compression.go b/archive/compression/compression.go deleted file mode 100644 index 06bc94d03261..000000000000 --- a/archive/compression/compression.go +++ /dev/null @@ -1,323 +0,0 @@ -/* - Copyright The containerd Authors. - - 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. -*/ - -package compression - -import ( - "bufio" - "bytes" - "compress/gzip" - "context" - "encoding/binary" - "fmt" - "io" - "os" - "strconv" - "sync" - - "github.com/containerd/containerd/log" - "github.com/klauspost/compress/zstd" - exec "golang.org/x/sys/execabs" -) - -type ( - // Compression is the state represents if compressed or not. - Compression int -) - -const ( - // Uncompressed represents the uncompressed. - Uncompressed Compression = iota - // Gzip is gzip compression algorithm. - Gzip - // Zstd is zstd compression algorithm. - Zstd -) - -const disablePigzEnv = "CONTAINERD_DISABLE_PIGZ" - -var ( - initPigz sync.Once - unpigzPath string -) - -var ( - bufioReader32KPool = &sync.Pool{ - New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) }, - } -) - -// DecompressReadCloser include the stream after decompress and the compress method detected. -type DecompressReadCloser interface { - io.ReadCloser - // GetCompression returns the compress method which is used before decompressing - GetCompression() Compression -} - -type readCloserWrapper struct { - io.Reader - compression Compression - closer func() error -} - -func (r *readCloserWrapper) Close() error { - if r.closer != nil { - return r.closer() - } - return nil -} - -func (r *readCloserWrapper) GetCompression() Compression { - return r.compression -} - -type writeCloserWrapper struct { - io.Writer - closer func() error -} - -func (w *writeCloserWrapper) Close() error { - if w.closer != nil { - w.closer() - } - return nil -} - -type bufferedReader struct { - buf *bufio.Reader -} - -func newBufferedReader(r io.Reader) *bufferedReader { - buf := bufioReader32KPool.Get().(*bufio.Reader) - buf.Reset(r) - return &bufferedReader{buf} -} - -func (r *bufferedReader) Read(p []byte) (n int, err error) { - if r.buf == nil { - return 0, io.EOF - } - n, err = r.buf.Read(p) - if err == io.EOF { - r.buf.Reset(nil) - bufioReader32KPool.Put(r.buf) - r.buf = nil - } - return -} - -func (r *bufferedReader) Peek(n int) ([]byte, error) { - if r.buf == nil { - return nil, io.EOF - } - return r.buf.Peek(n) -} - -const ( - zstdMagicSkippableStart = 0x184D2A50 - zstdMagicSkippableMask = 0xFFFFFFF0 -) - -var ( - gzipMagic = []byte{0x1F, 0x8B, 0x08} - zstdMagic = []byte{0x28, 0xb5, 0x2f, 0xfd} -) - -type matcher = func([]byte) bool - -func magicNumberMatcher(m []byte) matcher { - return func(source []byte) bool { - return bytes.HasPrefix(source, m) - } -} - -// zstdMatcher detects zstd compression algorithm. -// There are two frame formats defined by Zstandard: Zstandard frames and Skippable frames. -// See https://datatracker.ietf.org/doc/html/rfc8878#section-3 for more details. -func zstdMatcher() matcher { - return func(source []byte) bool { - if bytes.HasPrefix(source, zstdMagic) { - // Zstandard frame - return true - } - // skippable frame - if len(source) < 8 { - return false - } - // magic number from 0x184D2A50 to 0x184D2A5F. - if binary.LittleEndian.Uint32(source[:4])&zstdMagicSkippableMask == zstdMagicSkippableStart { - return true - } - return false - } -} - -// DetectCompression detects the compression algorithm of the source. -func DetectCompression(source []byte) Compression { - for compression, fn := range map[Compression]matcher{ - Gzip: magicNumberMatcher(gzipMagic), - Zstd: zstdMatcher(), - } { - if fn(source) { - return compression - } - } - return Uncompressed -} - -// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive. -func DecompressStream(archive io.Reader) (DecompressReadCloser, error) { - buf := newBufferedReader(archive) - bs, err := buf.Peek(10) - if err != nil && err != io.EOF { - // Note: we'll ignore any io.EOF error because there are some odd - // cases where the layer.tar file will be empty (zero bytes) and - // that results in an io.EOF from the Peek() call. So, in those - // cases we'll just treat it as a non-compressed stream and - // that means just create an empty layer. - // See Issue docker/docker#18170 - return nil, err - } - - switch compression := DetectCompression(bs); compression { - case Uncompressed: - return &readCloserWrapper{ - Reader: buf, - compression: compression, - }, nil - case Gzip: - ctx, cancel := context.WithCancel(context.Background()) - gzReader, err := gzipDecompress(ctx, buf) - if err != nil { - cancel() - return nil, err - } - - return &readCloserWrapper{ - Reader: gzReader, - compression: compression, - closer: func() error { - cancel() - return gzReader.Close() - }, - }, nil - case Zstd: - zstdReader, err := zstd.NewReader(buf) - if err != nil { - return nil, err - } - return &readCloserWrapper{ - Reader: zstdReader, - compression: compression, - closer: func() error { - zstdReader.Close() - return nil - }, - }, nil - - default: - return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension()) - } -} - -// CompressStream compresses the dest with specified compression algorithm. -func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, error) { - switch compression { - case Uncompressed: - return &writeCloserWrapper{dest, nil}, nil - case Gzip: - return gzip.NewWriter(dest), nil - case Zstd: - return zstd.NewWriter(dest) - default: - return nil, fmt.Errorf("unsupported compression format %s", (&compression).Extension()) - } -} - -// Extension returns the extension of a file that uses the specified compression algorithm. -func (compression *Compression) Extension() string { - switch *compression { - case Gzip: - return "gz" - case Zstd: - return "zst" - } - return "" -} - -func gzipDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) { - initPigz.Do(func() { - if unpigzPath = detectPigz(); unpigzPath != "" { - log.L.Debug("using pigz for decompression") - } - }) - - if unpigzPath == "" { - return gzip.NewReader(buf) - } - - return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf) -} - -func cmdStream(cmd *exec.Cmd, in io.Reader) (io.ReadCloser, error) { - reader, writer := io.Pipe() - - cmd.Stdin = in - cmd.Stdout = writer - - var errBuf bytes.Buffer - cmd.Stderr = &errBuf - - if err := cmd.Start(); err != nil { - return nil, err - } - - go func() { - if err := cmd.Wait(); err != nil { - writer.CloseWithError(fmt.Errorf("%s: %s", err, errBuf.String())) - } else { - writer.Close() - } - }() - - return reader, nil -} - -func detectPigz() string { - path, err := exec.LookPath("unpigz") - if err != nil { - log.L.WithError(err).Debug("unpigz not found, falling back to go gzip") - return "" - } - - // Check if pigz disabled via CONTAINERD_DISABLE_PIGZ env variable - value := os.Getenv(disablePigzEnv) - if value == "" { - return path - } - - disable, err := strconv.ParseBool(value) - if err != nil { - log.L.WithError(err).Warnf("could not parse %s: %s", disablePigzEnv, value) - return path - } - - if disable { - return "" - } - - return path -} diff --git a/archive/link_freebsd.go b/archive/link_freebsd.go deleted file mode 100644 index 2097db06bc7d..000000000000 --- a/archive/link_freebsd.go +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright The containerd Authors. - - 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. -*/ - -package archive - -import ( - "os" - "syscall" - - "golang.org/x/sys/unix" -) - -func link(oldname, newname string) error { - e := ignoringEINTR(func() error { - return unix.Linkat(unix.AT_FDCWD, oldname, unix.AT_FDCWD, newname, 0) - }) - if e != nil { - return &os.LinkError{Op: "link", Old: oldname, New: newname, Err: e} - } - return nil -} - -// The following contents were copied from Go 1.18.2. -// Use of this source code is governed by the following -// BSD-style license: -// -// Copyright (c) 2009 The Go Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// ignoringEINTR makes a function call and repeats it if it returns an -// EINTR error. This appears to be required even though we install all -// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846. -// Also #20400 and #36644 are issues in which a signal handler is -// installed without setting SA_RESTART. None of these are the common case, -// but there are enough of them that it seems that we can't avoid -// an EINTR loop. -func ignoringEINTR(fn func() error) error { - for { - err := fn() - if err != syscall.EINTR { - return err - } - } -} diff --git a/cio/io.go b/cio/io.go deleted file mode 100644 index 9c9b991fc074..000000000000 --- a/cio/io.go +++ /dev/null @@ -1,388 +0,0 @@ -/* - Copyright The containerd Authors. - - 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. -*/ - -package cio - -import ( - "context" - "fmt" - "io" - "net/url" - "os" - "path/filepath" - "strings" - "sync" - - "github.com/containerd/containerd/defaults" -) - -var bufPool = sync.Pool{ - New: func() interface{} { - buffer := make([]byte, 32<<10) - return &buffer - }, -} - -// Config holds the IO configurations. -type Config struct { - // Terminal is true if one has been allocated - Terminal bool - // Stdin path - Stdin string - // Stdout path - Stdout string - // Stderr path - Stderr string -} - -// IO holds the io information for a task or process -type IO interface { - // Config returns the IO configuration. - Config() Config - // Cancel aborts all current io operations. - Cancel() - // Wait blocks until all io copy operations have completed. - Wait() - // Close cleans up all open io resources. Cancel() is always called before - // Close() - Close() error -} - -// Creator creates new IO sets for a task -type Creator func(id string) (IO, error) - -// Attach allows callers to reattach to running tasks -// -// There should only be one reader for a task's IO set -// because fifo's can only be read from one reader or the output -// will be sent only to the first reads -type Attach func(*FIFOSet) (IO, error) - -// FIFOSet is a set of file paths to FIFOs for a task's standard IO streams -type FIFOSet struct { - Config - close func() error -} - -// Close the FIFOSet -func (f *FIFOSet) Close() error { - if f != nil && f.close != nil { - return f.close() - } - return nil -} - -// NewFIFOSet returns a new FIFOSet from a Config and a close function -func NewFIFOSet(config Config, close func() error) *FIFOSet { - return &FIFOSet{Config: config, close: close} -} - -// Streams used to configure a Creator or Attach -type Streams struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - Terminal bool - FIFODir string -} - -// Opt customize options for creating a Creator or Attach -type Opt func(*Streams) - -// WithStdio sets stream options to the standard input/output streams -func WithStdio(opt *Streams) { - WithStreams(os.Stdin, os.Stdout, os.Stderr)(opt) -} - -// WithTerminal sets the terminal option -func WithTerminal(opt *Streams) { - opt.Terminal = true -} - -// WithStreams sets the stream options to the specified Reader and Writers -func WithStreams(stdin io.Reader, stdout, stderr io.Writer) Opt { - return func(opt *Streams) { - opt.Stdin = stdin - opt.Stdout = stdout - opt.Stderr = stderr - } -} - -// WithFIFODir sets the fifo directory. -// e.g. "/run/containerd/fifo", "/run/users/1001/containerd/fifo" -func WithFIFODir(dir string) Opt { - return func(opt *Streams) { - opt.FIFODir = dir - } -} - -// NewCreator returns an IO creator from the options -func NewCreator(opts ...Opt) Creator { - streams := &Streams{} - for _, opt := range opts { - opt(streams) - } - if streams.FIFODir == "" { - streams.FIFODir = defaults.DefaultFIFODir - } - return func(id string) (IO, error) { - fifos, err := NewFIFOSetInDir(streams.FIFODir, id, streams.Terminal) - if err != nil { - return nil, err - } - if streams.Stdin == nil { - fifos.Stdin = "" - } - if streams.Stdout == nil { - fifos.Stdout = "" - } - if streams.Stderr == nil { - fifos.Stderr = "" - } - return copyIO(fifos, streams) - } -} - -// NewAttach attaches the existing io for a task to the provided io.Reader/Writers -func NewAttach(opts ...Opt) Attach { - streams := &Streams{} - for _, opt := range opts { - opt(streams) - } - return func(fifos *FIFOSet) (IO, error) { - if fifos == nil { - return nil, fmt.Errorf("cannot attach, missing fifos") - } - if streams.Stdin == nil { - fifos.Stdin = "" - } - if streams.Stdout == nil { - fifos.Stdout = "" - } - if streams.Stderr == nil { - fifos.Stderr = "" - } - return copyIO(fifos, streams) - } -} - -// NullIO redirects the container's IO into /dev/null -func NullIO(_ string) (IO, error) { - return &cio{}, nil -} - -// cio is a basic container IO implementation. -type cio struct { - config Config - wg *sync.WaitGroup - closers []io.Closer - cancel context.CancelFunc -} - -func (c *cio) Config() Config { - return c.config -} - -func (c *cio) Wait() { - if c.wg != nil { - c.wg.Wait() - } -} - -func (c *cio) Close() error { - var lastErr error - for _, closer := range c.closers { - if closer == nil { - continue - } - if err := closer.Close(); err != nil { - lastErr = err - } - } - return lastErr -} - -func (c *cio) Cancel() { - if c.cancel != nil { - c.cancel() - } -} - -type pipes struct { - Stdin io.WriteCloser - Stdout io.ReadCloser - Stderr io.ReadCloser -} - -// DirectIO allows task IO to be handled externally by the caller -type DirectIO struct { - pipes - cio -} - -var ( - _ IO = &DirectIO{} - _ IO = &logURI{} -) - -// LogURI provides the raw logging URI -func LogURI(uri *url.URL) Creator { - return func(_ string) (IO, error) { - return &logURI{ - config: Config{ - Stdout: uri.String(), - Stderr: uri.String(), - }, - }, nil - } -} - -// TerminalLogURI provides the raw logging URI -// as well as sets the terminal option to true. -func TerminalLogURI(uri *url.URL) Creator { - return func(_ string) (IO, error) { - return &logURI{ - config: Config{ - Stdout: uri.String(), - Stderr: uri.String(), - Terminal: true, - }, - }, nil - } -} - -// BinaryIO forwards container STDOUT|STDERR directly to a logging binary -func BinaryIO(binary string, args map[string]string) Creator { - return func(_ string) (IO, error) { - uri, err := LogURIGenerator("binary", binary, args) - if err != nil { - return nil, err - } - - res := uri.String() - return &logURI{ - config: Config{ - Stdout: res, - Stderr: res, - }, - }, nil - } -} - -// TerminalBinaryIO forwards container STDOUT|STDERR directly to a logging binary -// It also sets the terminal option to true -func TerminalBinaryIO(binary string, args map[string]string) Creator { - return func(_ string) (IO, error) { - uri, err := LogURIGenerator("binary", binary, args) - if err != nil { - return nil, err - } - - res := uri.String() - return &logURI{ - config: Config{ - Stdout: res, - Stderr: res, - Terminal: true, - }, - }, nil - } -} - -// LogFile creates a file on disk that logs the task's STDOUT,STDERR. -// If the log file already exists, the logs will be appended to the file. -func LogFile(path string) Creator { - return func(_ string) (IO, error) { - uri, err := LogURIGenerator("file", path, nil) - if err != nil { - return nil, err - } - - res := uri.String() - return &logURI{ - config: Config{ - Stdout: res, - Stderr: res, - }, - }, nil - } -} - -// LogURIGenerator is the helper to generate log uri with specific scheme. -func LogURIGenerator(scheme string, path string, args map[string]string) (*url.URL, error) { - path = filepath.Clean(path) - if !filepath.IsAbs(path) { - return nil, fmt.Errorf("%q must be absolute", path) - } - - // Without adding / here, C:\foo\bar.txt will become file://C:/foo/bar.txt - // which is invalid. The path must have three slashes. - // - // https://learn.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows - // > In the case of a local Windows file path, there is no hostname, - // > and thus another slash and the path immediately follow. - p := filepath.ToSlash(path) - if !strings.HasPrefix(path, "/") { - p = "/" + p - } - uri := &url.URL{Scheme: scheme, Path: p} - - if len(args) == 0 { - return uri, nil - } - - q := uri.Query() - for k, v := range args { - q.Set(k, v) - } - uri.RawQuery = q.Encode() - return uri, nil -} - -type logURI struct { - config Config -} - -func (l *logURI) Config() Config { - return l.config -} - -func (l *logURI) Cancel() { - -} - -func (l *logURI) Wait() { - -} - -func (l *logURI) Close() error { - return nil -} - -// Load the io for a container but do not attach -// -// Allows io to be loaded on the task for deletion without -// starting copy routines -func Load(set *FIFOSet) (IO, error) { - return &cio{ - config: set.Config, - closers: []io.Closer{set}, - }, nil -} - -func (p *pipes) closers() []io.Closer { - return []io.Closer{p.Stdin, p.Stdout, p.Stderr} -} diff --git a/client.go b/client.go deleted file mode 100644 index 505704985d46..000000000000 --- a/client.go +++ /dev/null @@ -1,874 +0,0 @@ -/* - Copyright The containerd Authors. - - 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. -*/ - -package containerd - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "runtime" - "strconv" - "strings" - "sync" - "time" - - containersapi "github.com/containerd/containerd/api/services/containers/v1" - contentapi "github.com/containerd/containerd/api/services/content/v1" - diffapi "github.com/containerd/containerd/api/services/diff/v1" - eventsapi "github.com/containerd/containerd/api/services/events/v1" - imagesapi "github.com/containerd/containerd/api/services/images/v1" - introspectionapi "github.com/containerd/containerd/api/services/introspection/v1" - leasesapi "github.com/containerd/containerd/api/services/leases/v1" - namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1" - sandboxsapi "github.com/containerd/containerd/api/services/sandbox/v1" - snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" - "github.com/containerd/containerd/api/services/tasks/v1" - versionservice "github.com/containerd/containerd/api/services/version/v1" - apitypes "github.com/containerd/containerd/api/types" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/content" - contentproxy "github.com/containerd/containerd/content/proxy" - "github.com/containerd/containerd/defaults" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/leases" - leasesproxy "github.com/containerd/containerd/leases/proxy" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/pkg/dialer" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/plugin" - ptypes "github.com/containerd/containerd/protobuf/types" - "github.com/containerd/containerd/remotes" - "github.com/containerd/containerd/remotes/docker" - "github.com/containerd/containerd/sandbox" - sandboxproxy "github.com/containerd/containerd/sandbox/proxy" - "github.com/containerd/containerd/services/introspection" - "github.com/containerd/containerd/snapshots" - snproxy "github.com/containerd/containerd/snapshots/proxy" - "github.com/containerd/typeurl/v2" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/opencontainers/runtime-spec/specs-go" - "golang.org/x/sync/semaphore" - "google.golang.org/grpc" - "google.golang.org/grpc/backoff" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/health/grpc_health_v1" -) - -func init() { - const prefix = "types.containerd.io" - // register TypeUrls for commonly marshaled external types - major := strconv.Itoa(specs.VersionMajor) - typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec") - typeurl.Register(&specs.Process{}, prefix, "opencontainers/runtime-spec", major, "Process") - typeurl.Register(&specs.LinuxResources{}, prefix, "opencontainers/runtime-spec", major, "LinuxResources") - typeurl.Register(&specs.WindowsResources{}, prefix, "opencontainers/runtime-spec", major, "WindowsResources") -} - -// New returns a new containerd client that is connected to the containerd -// instance provided by address -func New(address string, opts ...ClientOpt) (*Client, error) { - var copts clientOpts - for _, o := range opts { - if err := o(&copts); err != nil { - return nil, err - } - } - if copts.timeout == 0 { - copts.timeout = 10 * time.Second - } - - c := &Client{ - defaultns: copts.defaultns, - } - - if copts.defaultRuntime != "" { - c.runtime = copts.defaultRuntime - } else { - c.runtime = defaults.DefaultRuntime - } - - if copts.defaultPlatform != nil { - c.platform = copts.defaultPlatform - } else { - c.platform = platforms.Default() - } - - if copts.services != nil { - c.services = *copts.services - } - if address != "" { - backoffConfig := backoff.DefaultConfig - backoffConfig.MaxDelay = 3 * time.Second - connParams := grpc.ConnectParams{ - Backoff: backoffConfig, - } - gopts := []grpc.DialOption{ - grpc.WithBlock(), - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.FailOnNonTempDialError(true), - grpc.WithConnectParams(connParams), - grpc.WithContextDialer(dialer.ContextDialer), - grpc.WithReturnConnectionError(), - } - if len(copts.dialOptions) > 0 { - gopts = copts.dialOptions - } - gopts = append(gopts, grpc.WithDefaultCallOptions( - grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize), - grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize))) - if len(copts.callOptions) > 0 { - gopts = append(gopts, grpc.WithDefaultCallOptions(copts.callOptions...)) - } - if copts.defaultns != "" { - unary, stream := newNSInterceptors(copts.defaultns) - gopts = append(gopts, grpc.WithChainUnaryInterceptor(unary)) - gopts = append(gopts, grpc.WithChainStreamInterceptor(stream)) - } - - connector := func() (*grpc.ClientConn, error) { - ctx, cancel := context.WithTimeout(context.Background(), copts.timeout) - defer cancel() - conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...) - if err != nil { - return nil, fmt.Errorf("failed to dial %q: %w", address, err) - } - return conn, nil - } - conn, err := connector() - if err != nil { - return nil, err - } - c.conn, c.connector = conn, connector - } - if copts.services == nil && c.conn == nil { - return nil, fmt.Errorf("no grpc connection or services is available: %w", errdefs.ErrUnavailable) - } - - // check namespace labels for default runtime - if copts.defaultRuntime == "" && c.defaultns != "" { - if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { - return nil, err - } else if label != "" { - c.runtime = label - } - } - - return c, nil -} - -// NewWithConn returns a new containerd client that is connected to the containerd -// instance provided by the connection -func NewWithConn(conn *grpc.ClientConn, opts ...ClientOpt) (*Client, error) { - var copts clientOpts - for _, o := range opts { - if err := o(&copts); err != nil { - return nil, err - } - } - c := &Client{ - defaultns: copts.defaultns, - conn: conn, - runtime: plugin.RuntimePlugin.String() + "." + runtime.GOOS, - } - - if copts.defaultPlatform != nil { - c.platform = copts.defaultPlatform - } else { - c.platform = platforms.Default() - } - - // check namespace labels for default runtime - if copts.defaultRuntime == "" && c.defaultns != "" { - if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { - return nil, err - } else if label != "" { - c.runtime = label - } - } - - if copts.services != nil { - c.services = *copts.services - } - return c, nil -} - -// Client is the client to interact with containerd and its various services -// using a uniform interface -type Client struct { - services - connMu sync.Mutex - conn *grpc.ClientConn - runtime string - defaultns string - platform platforms.MatchComparer - connector func() (*grpc.ClientConn, error) -} - -// Reconnect re-establishes the GRPC connection to the containerd daemon -func (c *Client) Reconnect() error { - if c.connector == nil { - return fmt.Errorf("unable to reconnect to containerd, no connector available: %w", errdefs.ErrUnavailable) - } - c.connMu.Lock() - defer c.connMu.Unlock() - c.conn.Close() - conn, err := c.connector() - if err != nil { - return err - } - c.conn = conn - return nil -} - -// Runtime returns the name of the runtime being used -func (c *Client) Runtime() string { - return c.runtime -} - -// IsServing returns true if the client can successfully connect to the -// containerd daemon and the healthcheck service returns the SERVING -// response. -// This call will block if a transient error is encountered during -// connection. A timeout can be set in the context to ensure it returns -// early. -func (c *Client) IsServing(ctx context.Context) (bool, error) { - c.connMu.Lock() - if c.conn == nil { - c.connMu.Unlock() - return false, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) - } - c.connMu.Unlock() - r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true)) - if err != nil { - return false, err - } - return r.Status == grpc_health_v1.HealthCheckResponse_SERVING, nil -} - -// Containers returns all containers created in containerd -func (c *Client) Containers(ctx context.Context, filters ...string) ([]Container, error) { - r, err := c.ContainerService().List(ctx, filters...) - if err != nil { - return nil, err - } - var out []Container - for _, container := range r { - out = append(out, containerFromRecord(c, container)) - } - return out, nil -} - -// NewContainer will create a new container with the provided id. -// The id must be unique within the namespace. -func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) { - ctx, done, err := c.WithLease(ctx) - if err != nil { - return nil, err - } - defer done(ctx) - - container := containers.Container{ - ID: id, - Runtime: containers.RuntimeInfo{ - Name: c.runtime, - }, - } - for _, o := range opts { - if err := o(ctx, c, &container); err != nil { - return nil, err - } - } - r, err := c.ContainerService().Create(ctx, container) - if err != nil { - return nil, err - } - return containerFromRecord(c, r), nil -} - -// LoadContainer loads an existing container from metadata -func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error) { - r, err := c.ContainerService().Get(ctx, id) - if err != nil { - return nil, err - } - return containerFromRecord(c, r), nil -} - -// RemoteContext is used to configure object resolutions and transfers with -// remote content stores and image providers. -type RemoteContext struct { - // Resolver is used to resolve names to objects, fetchers, and pushers. - // If no resolver is provided, defaults to Docker registry resolver. - Resolver remotes.Resolver - - // PlatformMatcher is used to match the platforms for an image - // operation and define the preference when a single match is required - // from multiple platforms. - PlatformMatcher platforms.MatchComparer - - // Unpack is done after an image is pulled to extract into a snapshotter. - // It is done simultaneously for schema 2 images when they are pulled. - // If an image is not unpacked on pull, it can be unpacked any time - // afterwards. Unpacking is required to run an image. - Unpack bool - - // UnpackOpts handles options to the unpack call. - UnpackOpts []UnpackOpt - - // Snapshotter used for unpacking - Snapshotter string - - // SnapshotterOpts are additional options to be passed to a snapshotter during pull - SnapshotterOpts []snapshots.Opt - - // Labels to be applied to the created image - Labels map[string]string - - // BaseHandlers are a set of handlers which get are called on dispatch. - // These handlers always get called before any operation specific - // handlers. - BaseHandlers []images.Handler - - // HandlerWrapper wraps the handler which gets sent to dispatch. - // Unlike BaseHandlers, this can run before and after the built - // in handlers, allowing operations to run on the descriptor - // after it has completed transferring. - HandlerWrapper func(images.Handler) images.Handler - - // ConvertSchema1 is whether to convert Docker registry schema 1 - // manifests. If this option is false then any image which resolves - // to schema 1 will return an error since schema 1 is not supported. - // - // Deprecated: use Schema 2 or OCI images. - ConvertSchema1 bool - - // Platforms defines which platforms to handle when doing the image operation. - // Platforms is ignored when a PlatformMatcher is set, otherwise the - // platforms will be used to create a PlatformMatcher with no ordering - // preference. - Platforms []string - - // MaxConcurrentDownloads is the max concurrent content downloads for each pull. - MaxConcurrentDownloads int - - // MaxConcurrentUploadedLayers is the max concurrent uploaded layers for each push. - MaxConcurrentUploadedLayers int - - // AllMetadata downloads all manifests and known-configuration files - AllMetadata bool - - // ChildLabelMap sets the labels used to reference child objects in the content - // store. By default, all GC reference labels will be set for all fetched content. - ChildLabelMap func(ocispec.Descriptor) []string -} - -func defaultRemoteContext() *RemoteContext { - return &RemoteContext{ - Resolver: docker.NewResolver(docker.ResolverOptions{}), - } -} - -// Fetch downloads the provided content into containerd's content store -// and returns a non-platform specific image reference -func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (images.Image, error) { - fetchCtx := defaultRemoteContext() - for _, o := range opts { - if err := o(c, fetchCtx); err != nil { - return images.Image{}, err - } - } - - if fetchCtx.Unpack { - return images.Image{}, fmt.Errorf("unpack on fetch not supported, try pull: %w", errdefs.ErrNotImplemented) - } - - if fetchCtx.PlatformMatcher == nil { - if len(fetchCtx.Platforms) == 0 { - fetchCtx.PlatformMatcher = platforms.All - } else { - ps, err := platforms.ParseAll(fetchCtx.Platforms) - if err != nil { - return images.Image{}, err - } - - fetchCtx.PlatformMatcher = platforms.Any(ps...) - } - } - - ctx, done, err := c.WithLease(ctx) - if err != nil { - return images.Image{}, err - } - defer done(ctx) - - img, err := c.fetch(ctx, fetchCtx, ref, 0) - if err != nil { - return images.Image{}, err - } - return c.createNewImage(ctx, img) -} - -// Push uploads the provided content to a remote resource -func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpt) error { - pushCtx := defaultRemoteContext() - for _, o := range opts { - if err := o(c, pushCtx); err != nil { - return err - } - } - if pushCtx.PlatformMatcher == nil { - if len(pushCtx.Platforms) > 0 { - ps, err := platforms.ParseAll(pushCtx.Platforms) - if err != nil { - return err - } - pushCtx.PlatformMatcher = platforms.Any(ps...) - } else { - pushCtx.PlatformMatcher = platforms.All - } - } - - // Annotate ref with digest to push only push tag for single digest - if !strings.Contains(ref, "@") { - ref = ref + "@" + desc.Digest.String() - } - - pusher, err := pushCtx.Resolver.Pusher(ctx, ref) - if err != nil { - return err - } - - var wrapper func(images.Handler) images.Handler - - if len(pushCtx.BaseHandlers) > 0 { - wrapper = func(h images.Handler) images.Handler { - h = images.Handlers(append(pushCtx.BaseHandlers, h)...) - if pushCtx.HandlerWrapper != nil { - h = pushCtx.HandlerWrapper(h) - } - return h - } - } else if pushCtx.HandlerWrapper != nil { - wrapper = pushCtx.HandlerWrapper - } - - var limiter *semaphore.Weighted - if pushCtx.MaxConcurrentUploadedLayers > 0 { - limiter = semaphore.NewWeighted(int64(pushCtx.MaxConcurrentUploadedLayers)) - } - - return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), limiter, pushCtx.PlatformMatcher, wrapper) -} - -// GetImage returns an existing image -func (c *Client) GetImage(ctx context.Context, ref string) (Image, error) { - i, err := c.ImageService().Get(ctx, ref) - if err != nil { - return nil, err - } - return NewImage(c, i), nil -} - -// ListImages returns all existing images -func (c *Client) ListImages(ctx context.Context, filters ...string) ([]Image, error) { - imgs, err := c.ImageService().List(ctx, filters...) - if err != nil { - return nil, err - } - images := make([]Image, len(imgs)) - for i, img := range imgs { - images[i] = NewImage(c, img) - } - return images, nil -} - -// Restore restores a container from a checkpoint -func (c *Client) Restore(ctx context.Context, id string, checkpoint Image, opts ...RestoreOpts) (Container, error) { - store := c.ContentStore() - index, err := decodeIndex(ctx, store, checkpoint.Target()) - if err != nil { - return nil, err - } - - ctx, done, err := c.WithLease(ctx) - if err != nil { - return nil, err - } - defer done(ctx) - - copts := []NewContainerOpts{} - for _, o := range opts { - copts = append(copts, o(ctx, id, c, checkpoint, index)) - } - - ctr, err := c.NewContainer(ctx, id, copts...) - if err != nil { - return nil, err - } - - return ctr, nil -} - -func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) { - labels := map[string]string{} - for i, m := range index.Manifests { - labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String() - } - data, err := json.Marshal(index) - if err != nil { - return ocispec.Descriptor{}, err - } - return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) -} - -func decodeIndex(ctx context.Context, store content.Provider, desc ocispec.Descriptor) (*ocispec.Index, error) { - var index ocispec.Index - p, err := content.ReadBlob(ctx, store, desc) - if err != nil { - return nil, err - } - if err := json.Unmarshal(p, &index); err != nil { - return nil, err - } - - return &index, nil -} - -// GetLabel gets a label value from namespace store -// If there is no default label, an empty string returned with nil error -func (c *Client) GetLabel(ctx context.Context, label string) (string, error) { - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - if c.defaultns == "" { - return "", err - } - ns = c.defaultns - } - - srv := c.NamespaceService() - labels, err := srv.Labels(ctx, ns) - if err != nil { - return "", err - } - - value := labels[label] - return value, nil -} - -// Subscribe to events that match one or more of the provided filters. -// -// Callers should listen on both the envelope and errs channels. If the errs -// channel returns nil or an error, the subscriber should terminate. -// -// The subscriber can stop receiving events by canceling the provided context. -// The errs channel will be closed and return a nil error. -func (c *Client) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) { - return c.EventService().Subscribe(ctx, filters...) -} - -// Close closes the clients connection to containerd -func (c *Client) Close() error { - c.connMu.Lock() - defer c.connMu.Unlock() - if c.conn != nil { - return c.conn.Close() - } - return nil -} - -// NamespaceService returns the underlying Namespaces Store -func (c *Client) NamespaceService() namespaces.Store { - if c.namespaceStore != nil { - return c.namespaceStore - } - c.connMu.Lock() - defer c.connMu.Unlock() - return NewNamespaceStoreFromClient(namespacesapi.NewNamespacesClient(c.conn)) -} - -// ContainerService returns the underlying container Store -func (c *Client) ContainerService() containers.Store { - if c.containerStore != nil { - return c.containerStore - } - c.connMu.Lock() - defer c.connMu.Unlock() - return NewRemoteContainerStore(containersapi.NewContainersClient(c.conn)) -} - -// ContentStore returns the underlying content Store -func (c *Client) ContentStore() content.Store { - if c.contentStore != nil { - return c.contentStore - } - c.connMu.Lock() - defer c.connMu.Unlock() - return contentproxy.NewContentStore(contentapi.NewContentClient(c.conn)) -} - -// SnapshotService returns the underlying snapshotter for the provided snapshotter name -func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter { - snapshotterName, err := c.resolveSnapshotterName(context.Background(), snapshotterName) - if err != nil { - snapshotterName = DefaultSnapshotter - } - if c.snapshotters != nil { - return c.snapshotters[snapshotterName] - } - c.connMu.Lock() - defer c.connMu.Unlock() - return snproxy.NewSnapshotter(snapshotsapi.NewSnapshotsClient(c.conn), snapshotterName) -} - -// DefaultNamespace return the default namespace -func (c *Client) DefaultNamespace() string { - return c.defaultns -} - -// TaskService returns the underlying TasksClient -func (c *Client) TaskService() tasks.TasksClient { - if c.taskService != nil { - return c.taskService - } - c.connMu.Lock() - defer c.connMu.Unlock() - return tasks.NewTasksClient(c.conn) -} - -// ImageService returns the underlying image Store -func (c *Client) ImageService() images.Store { - if c.imageStore != nil { - return c.imageStore - } - c.connMu.Lock() - defer c.connMu.Unlock() - return NewImageStoreFromClient(imagesapi.NewImagesClient(c.conn)) -} - -// DiffService returns the underlying Differ -func (c *Client) DiffService() DiffService { - if c.diffService != nil { - return c.diffService - } - c.connMu.Lock() - defer c.connMu.Unlock() - return NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn)) -} - -// IntrospectionService returns the underlying Introspection Client -func (c *Client) IntrospectionService() introspection.Service { - if c.introspectionService != nil { - return c.introspectionService - } - c.connMu.Lock() - defer c.connMu.Unlock() - return introspection.NewIntrospectionServiceFromClient(introspectionapi.NewIntrospectionClient(c.conn)) -} - -// LeasesService returns the underlying Leases Client -func (c *Client) LeasesService() leases.Manager { - if c.leasesService != nil { - return c.leasesService - } - c.connMu.Lock() - defer c.connMu.Unlock() - return leasesproxy.NewLeaseManager(leasesapi.NewLeasesClient(c.conn)) -} - -// HealthService returns the underlying GRPC HealthClient -func (c *Client) HealthService() grpc_health_v1.HealthClient { - c.connMu.Lock() - defer c.connMu.Unlock() - return grpc_health_v1.NewHealthClient(c.conn) -} - -// EventService returns the underlying event service -func (c *Client) EventService() EventService { - if c.eventService != nil { - return c.eventService - } - c.connMu.Lock() - defer c.connMu.Unlock() - return NewEventServiceFromClient(eventsapi.NewEventsClient(c.conn)) -} - -// SandboxStore returns the underlying sandbox store client -func (c *Client) SandboxStore() sandbox.Store { - if c.sandboxStore != nil { - return c.sandboxStore - } - c.connMu.Lock() - defer c.connMu.Unlock() - return sandboxproxy.NewSandboxStore(sandboxsapi.NewStoreClient(c.conn)) -} - -// SandboxController returns the underlying sandbox controller client -func (c *Client) SandboxController() sandbox.Controller { - if c.sandboxController != nil { - return c.sandboxController - } - c.connMu.Lock() - defer c.connMu.Unlock() - return sandboxproxy.NewSandboxController(sandboxsapi.NewControllerClient(c.conn)) -} - -// VersionService returns the underlying VersionClient -func (c *Client) VersionService() versionservice.VersionClient { - c.connMu.Lock() - defer c.connMu.Unlock() - return versionservice.NewVersionClient(c.conn) -} - -// Conn returns the underlying GRPC connection object -func (c *Client) Conn() *grpc.ClientConn { - c.connMu.Lock() - defer c.connMu.Unlock() - return c.conn -} - -// Version of containerd -type Version struct { - // Version number - Version string - // Revision from git that was built - Revision string -} - -// Version returns the version of containerd that the client is connected to -func (c *Client) Version(ctx context.Context) (Version, error) { - c.connMu.Lock() - if c.conn == nil { - c.connMu.Unlock() - return Version{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) - } - c.connMu.Unlock() - response, err := c.VersionService().Version(ctx, &ptypes.Empty{}) - if err != nil { - return Version{}, err - } - return Version{ - Version: response.Version, - Revision: response.Revision, - }, nil -} - -// ServerInfo represents the introspected server information -type ServerInfo struct { - UUID string -} - -// Server returns server information from the introspection service -func (c *Client) Server(ctx context.Context) (ServerInfo, error) { - c.connMu.Lock() - if c.conn == nil { - c.connMu.Unlock() - return ServerInfo{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) - } - c.connMu.Unlock() - - response, err := c.IntrospectionService().Server(ctx, &ptypes.Empty{}) - if err != nil { - return ServerInfo{}, err - } - return ServerInfo{ - UUID: response.UUID, - }, nil -} - -func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) { - if name == "" { - label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel) - if err != nil { - return "", err - } - - if label != "" { - name = label - } else { - name = DefaultSnapshotter - } - } - - return name, nil -} - -func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { - name, err := c.resolveSnapshotterName(ctx, name) - if err != nil { - return nil, err - } - - s := c.SnapshotService(name) - if s == nil { - return nil, fmt.Errorf("snapshotter %s was not found: %w", name, errdefs.ErrNotFound) - } - - return s, nil -} - -// GetSnapshotterSupportedPlatforms returns a platform matchers which represents the -// supported platforms for the given snapshotters -func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshotterName string) (platforms.MatchComparer, error) { - filters := []string{fmt.Sprintf("type==%s, id==%s", plugin.SnapshotPlugin, snapshotterName)} - in := c.IntrospectionService() - - resp, err := in.Plugins(ctx, filters) - if err != nil { - return nil, err - } - - if len(resp.Plugins) <= 0 { - return nil, fmt.Errorf("inspection service could not find snapshotter %s plugin", snapshotterName) - } - - sn := resp.Plugins[0] - snPlatforms := toPlatforms(sn.Platforms) - return platforms.Any(snPlatforms...), nil -} - -func toPlatforms(pt []*apitypes.Platform) []ocispec.Platform { - platforms := make([]ocispec.Platform, len(pt)) - for i, p := range pt { - platforms[i] = ocispec.Platform{ - Architecture: p.Architecture, - OS: p.OS, - Variant: p.Variant, - } - } - return platforms -} - -// GetSnapshotterCapabilities returns the capabilities of a snapshotter. -func (c *Client) GetSnapshotterCapabilities(ctx context.Context, snapshotterName string) ([]string, error) { - filters := []string{fmt.Sprintf("type==%s, id==%s", plugin.SnapshotPlugin, snapshotterName)} - in := c.IntrospectionService() - - resp, err := in.Plugins(ctx, filters) - if err != nil { - return nil, err - } - - if len(resp.Plugins) <= 0 { - return nil, fmt.Errorf("inspection service could not find snapshotter %s plugin", snapshotterName) - } - - sn := resp.Plugins[0] - return sn.Capabilities, nil -} diff --git a/client/client.go b/client/client.go new file mode 100644 index 000000000000..c58459b214f3 --- /dev/null +++ b/client/client.go @@ -0,0 +1,965 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "google.golang.org/grpc/resolver" + + containersapi "github.com/containerd/containerd/api/services/containers/v1" + diffapi "github.com/containerd/containerd/api/services/diff/v1" + imagesapi "github.com/containerd/containerd/api/services/images/v1" + leasesapi "github.com/containerd/containerd/api/services/leases/v1" + namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1" + sandboxsapi "github.com/containerd/containerd/api/services/sandbox/v1" + snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1" + "github.com/containerd/containerd/api/services/tasks/v1" + versionservice "github.com/containerd/containerd/api/services/version/v1" + apitypes "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/content" + contentproxy "github.com/containerd/containerd/v2/core/content/proxy" + "github.com/containerd/containerd/v2/core/events" + eventsproxy "github.com/containerd/containerd/v2/core/events/proxy" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/introspection" + introspectionproxy "github.com/containerd/containerd/v2/core/introspection/proxy" + "github.com/containerd/containerd/v2/core/leases" + leasesproxy "github.com/containerd/containerd/v2/core/leases/proxy" + "github.com/containerd/containerd/v2/core/remotes" + "github.com/containerd/containerd/v2/core/remotes/docker" + "github.com/containerd/containerd/v2/core/sandbox" + sandboxproxy "github.com/containerd/containerd/v2/core/sandbox/proxy" + "github.com/containerd/containerd/v2/core/snapshots" + snproxy "github.com/containerd/containerd/v2/core/snapshots/proxy" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/dialer" + "github.com/containerd/containerd/v2/pkg/namespaces" + ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types" + "github.com/containerd/containerd/v2/pkg/tracing" + "github.com/containerd/containerd/v2/plugins" + "github.com/containerd/errdefs" + "github.com/containerd/platforms" + "github.com/containerd/typeurl/v2" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-spec/specs-go/features" + "golang.org/x/sync/semaphore" + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/health/grpc_health_v1" +) + +func init() { + const prefix = "types.containerd.io" + // register TypeUrls for commonly marshaled external types + major := strconv.Itoa(specs.VersionMajor) + typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec") + typeurl.Register(&specs.Process{}, prefix, "opencontainers/runtime-spec", major, "Process") + typeurl.Register(&specs.LinuxResources{}, prefix, "opencontainers/runtime-spec", major, "LinuxResources") + typeurl.Register(&specs.WindowsResources{}, prefix, "opencontainers/runtime-spec", major, "WindowsResources") + typeurl.Register(&features.Features{}, prefix, "opencontainers/runtime-spec", major, "features", "Features") + + if runtime.GOOS == "windows" { + // After bumping GRPC to 1.64, Windows tests started failing with: "name resolver error: produced zero addresses". + // This is happening because grpc.NewClient uses DNS resolver by default, which apparently not what we want + // when using socket paths on Windows. + // Using a workaround from https://github.com/grpc/grpc-go/issues/1786#issuecomment-2119088770 + resolver.SetDefaultScheme("passthrough") + } +} + +// New returns a new containerd client that is connected to the containerd +// instance provided by address +func New(address string, opts ...Opt) (*Client, error) { + var copts clientOpts + for _, o := range opts { + if err := o(&copts); err != nil { + return nil, err + } + } + if copts.timeout == 0 { + copts.timeout = 10 * time.Second + } + + c := &Client{ + defaultns: copts.defaultns, + } + + if copts.defaultRuntime != "" { + c.runtime = copts.defaultRuntime + } else { + c.runtime = defaults.DefaultRuntime + } + + if copts.defaultPlatform != nil { + c.platform = copts.defaultPlatform + } else { + c.platform = platforms.Default() + } + + if copts.services != nil { + c.services = *copts.services + } + if address != "" { + backoffConfig := backoff.DefaultConfig + backoffConfig.MaxDelay = copts.timeout + connParams := grpc.ConnectParams{ + Backoff: backoffConfig, + } + gopts := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithConnectParams(connParams), + grpc.WithContextDialer(dialer.ContextDialer), + } + if len(copts.dialOptions) > 0 { + gopts = copts.dialOptions + } + gopts = append(gopts, grpc.WithDefaultCallOptions( + grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize), + grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize))) + if len(copts.callOptions) > 0 { + gopts = append(gopts, grpc.WithDefaultCallOptions(copts.callOptions...)) + } + if copts.defaultns != "" { + unary, stream := newNSInterceptors(copts.defaultns) + gopts = append(gopts, grpc.WithChainUnaryInterceptor(unary)) + gopts = append(gopts, grpc.WithChainStreamInterceptor(stream)) + } + + connector := func() (*grpc.ClientConn, error) { + conn, err := grpc.NewClient(dialer.DialAddress(address), gopts...) + if err != nil { + return nil, fmt.Errorf("failed to dial %q: %w", address, err) + } + return conn, nil + } + conn, err := connector() + if err != nil { + return nil, err + } + c.conn, c.connector = conn, connector + } + if copts.services == nil && c.conn == nil { + return nil, fmt.Errorf("no grpc connection or services is available: %w", errdefs.ErrUnavailable) + } + + // check namespace labels for default runtime + if copts.defaultRuntime == "" && c.defaultns != "" { + if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { + return nil, err + } else if label != "" { + c.runtime = label + } + } + + return c, nil +} + +// NewWithConn returns a new containerd client that is connected to the containerd +// instance provided by the connection +func NewWithConn(conn *grpc.ClientConn, opts ...Opt) (*Client, error) { + var copts clientOpts + for _, o := range opts { + if err := o(&copts); err != nil { + return nil, err + } + } + c := &Client{ + defaultns: copts.defaultns, + conn: conn, + runtime: defaults.DefaultRuntime, + } + + if copts.defaultPlatform != nil { + c.platform = copts.defaultPlatform + } else { + c.platform = platforms.Default() + } + + // check namespace labels for default runtime + if copts.defaultRuntime == "" && c.defaultns != "" { + if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil { + return nil, err + } else if label != "" { + c.runtime = label + } + } + + if copts.services != nil { + c.services = *copts.services + } + return c, nil +} + +// Client is the client to interact with containerd and its various services +// using a uniform interface +type Client struct { + services + connMu sync.Mutex + conn *grpc.ClientConn + runtime string + defaultns string + platform platforms.MatchComparer + connector func() (*grpc.ClientConn, error) +} + +// Reconnect re-establishes the GRPC connection to the containerd daemon +func (c *Client) Reconnect() error { + if c.connector == nil { + return fmt.Errorf("unable to reconnect to containerd, no connector available: %w", errdefs.ErrUnavailable) + } + c.connMu.Lock() + defer c.connMu.Unlock() + c.conn.Close() + conn, err := c.connector() + if err != nil { + return err + } + c.conn = conn + return nil +} + +// Runtime returns the name of the runtime being used +func (c *Client) Runtime() string { + return c.runtime +} + +// IsServing returns true if the client can successfully connect to the +// containerd daemon and the healthcheck service returns the SERVING +// response. +// This call will block if a transient error is encountered during +// connection. A timeout can be set in the context to ensure it returns +// early. +func (c *Client) IsServing(ctx context.Context) (bool, error) { + c.connMu.Lock() + if c.conn == nil { + c.connMu.Unlock() + return false, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) + } + c.connMu.Unlock() + r, err := c.HealthService().Check(ctx, &grpc_health_v1.HealthCheckRequest{}, grpc.WaitForReady(true)) + if err != nil { + return false, err + } + return r.Status == grpc_health_v1.HealthCheckResponse_SERVING, nil +} + +// Containers returns all containers created in containerd +func (c *Client) Containers(ctx context.Context, filters ...string) ([]Container, error) { + r, err := c.ContainerService().List(ctx, filters...) + if err != nil { + return nil, err + } + out := make([]Container, len(r)) + for i, container := range r { + out[i] = containerFromRecord(c, container) + } + return out, nil +} + +// NewContainer will create a new container with the provided id. +// The id must be unique within the namespace. +func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) { + ctx, span := tracing.StartSpan(ctx, "client.NewContainer") + defer span.End() + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + container := containers.Container{ + ID: id, + Runtime: containers.RuntimeInfo{ + Name: c.runtime, + }, + } + for _, o := range opts { + if err := o(ctx, c, &container); err != nil { + return nil, err + } + } + + span.SetAttributes( + tracing.Attribute("container.id", container.ID), + tracing.Attribute("container.image.ref", container.Image), + tracing.Attribute("container.runtime.name", container.Runtime.Name), + tracing.Attribute("container.snapshotter.name", container.Snapshotter), + ) + r, err := c.ContainerService().Create(ctx, container) + if err != nil { + return nil, err + } + return containerFromRecord(c, r), nil +} + +// LoadContainer loads an existing container from metadata +func (c *Client) LoadContainer(ctx context.Context, id string) (Container, error) { + ctx, span := tracing.StartSpan(ctx, "client.LoadContainer") + defer span.End() + r, err := c.ContainerService().Get(ctx, id) + if err != nil { + return nil, err + } + + span.SetAttributes( + tracing.Attribute("container.id", r.ID), + tracing.Attribute("container.image.ref", r.Image), + tracing.Attribute("container.runtime.name", r.Runtime.Name), + tracing.Attribute("container.snapshotter.name", r.Snapshotter), + tracing.Attribute("container.createdAt", r.CreatedAt.Format(time.RFC3339)), + tracing.Attribute("container.updatedAt", r.UpdatedAt.Format(time.RFC3339)), + ) + return containerFromRecord(c, r), nil +} + +// RemoteContext is used to configure object resolutions and transfers with +// remote content stores and image providers. +type RemoteContext struct { + // Resolver is used to resolve names to objects, fetchers, and pushers. + // If no resolver is provided, defaults to Docker registry resolver. + Resolver remotes.Resolver + + // PlatformMatcher is used to match the platforms for an image + // operation and define the preference when a single match is required + // from multiple platforms. + PlatformMatcher platforms.MatchComparer + + // Unpack is done after an image is pulled to extract into a snapshotter. + // It is done simultaneously for schema 2 images when they are pulled. + // If an image is not unpacked on pull, it can be unpacked any time + // afterwards. Unpacking is required to run an image. + Unpack bool + + // UnpackOpts handles options to the unpack call. + UnpackOpts []UnpackOpt + + // Snapshotter used for unpacking + Snapshotter string + + // SnapshotterOpts are additional options to be passed to a snapshotter during pull + SnapshotterOpts []snapshots.Opt + + // Labels to be applied to the created image + Labels map[string]string + + // BaseHandlers are a set of handlers which get are called on dispatch. + // These handlers always get called before any operation specific + // handlers. + BaseHandlers []images.Handler + + // HandlerWrapper wraps the handler which gets sent to dispatch. + // Unlike BaseHandlers, this can run before and after the built + // in handlers, allowing operations to run on the descriptor + // after it has completed transferring. + HandlerWrapper func(images.Handler) images.Handler + + // ConvertSchema1 is whether to convert Docker registry schema 1 + // manifests. If this option is false then any image which resolves + // to schema 1 will return an error since schema 1 is not supported. + // + // Deprecated: use Schema 2 or OCI images. + ConvertSchema1 bool + + // Platforms defines which platforms to handle when doing the image operation. + // Platforms is ignored when a PlatformMatcher is set, otherwise the + // platforms will be used to create a PlatformMatcher with no ordering + // preference. + Platforms []string + + // MaxConcurrentDownloads is the max concurrent content downloads for each pull. + MaxConcurrentDownloads int + + // MaxConcurrentUploadedLayers is the max concurrent uploaded layers for each push. + MaxConcurrentUploadedLayers int + + // AllMetadata downloads all manifests and known-configuration files + AllMetadata bool + + // ChildLabelMap sets the labels used to reference child objects in the content + // store. By default, all GC reference labels will be set for all fetched content. + ChildLabelMap func(ocispec.Descriptor) []string +} + +func defaultRemoteContext() *RemoteContext { + return &RemoteContext{ + Resolver: docker.NewResolver(docker.ResolverOptions{}), + } +} + +// Fetch downloads the provided content into containerd's content store +// and returns a non-platform specific image reference +func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (images.Image, error) { + fetchCtx := defaultRemoteContext() + for _, o := range opts { + if err := o(c, fetchCtx); err != nil { + return images.Image{}, err + } + } + + if fetchCtx.Unpack { + return images.Image{}, fmt.Errorf("unpack on fetch not supported, try pull: %w", errdefs.ErrNotImplemented) + } + + if fetchCtx.PlatformMatcher == nil { + if len(fetchCtx.Platforms) == 0 { + fetchCtx.PlatformMatcher = platforms.All + } else { + ps, err := platforms.ParseAll(fetchCtx.Platforms) + if err != nil { + return images.Image{}, err + } + + fetchCtx.PlatformMatcher = platforms.Any(ps...) + } + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return images.Image{}, err + } + defer done(ctx) + + img, err := c.fetch(ctx, fetchCtx, ref, 0) + if err != nil { + return images.Image{}, err + } + return c.createNewImage(ctx, img) +} + +// Push uploads the provided content to a remote resource +func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpt) error { + pushCtx := defaultRemoteContext() + for _, o := range opts { + if err := o(c, pushCtx); err != nil { + return err + } + } + if pushCtx.PlatformMatcher == nil { + if len(pushCtx.Platforms) > 0 { + ps, err := platforms.ParseAll(pushCtx.Platforms) + if err != nil { + return err + } + pushCtx.PlatformMatcher = platforms.Any(ps...) + } else { + pushCtx.PlatformMatcher = platforms.All + } + } + + // Annotate ref with digest to push only push tag for single digest + if !strings.Contains(ref, "@") { + ref = ref + "@" + desc.Digest.String() + } + + pusher, err := pushCtx.Resolver.Pusher(ctx, ref) + if err != nil { + return err + } + + var wrapper func(images.Handler) images.Handler + + if len(pushCtx.BaseHandlers) > 0 { + wrapper = func(h images.Handler) images.Handler { + h = images.Handlers(append(pushCtx.BaseHandlers, h)...) + if pushCtx.HandlerWrapper != nil { + h = pushCtx.HandlerWrapper(h) + } + return h + } + } else if pushCtx.HandlerWrapper != nil { + wrapper = pushCtx.HandlerWrapper + } + + var limiter *semaphore.Weighted + if pushCtx.MaxConcurrentUploadedLayers > 0 { + limiter = semaphore.NewWeighted(int64(pushCtx.MaxConcurrentUploadedLayers)) + } + + return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), limiter, pushCtx.PlatformMatcher, wrapper) +} + +// GetImage returns an existing image +func (c *Client) GetImage(ctx context.Context, ref string) (Image, error) { + i, err := c.ImageService().Get(ctx, ref) + if err != nil { + return nil, err + } + return NewImage(c, i), nil +} + +// ListImages returns all existing images +func (c *Client) ListImages(ctx context.Context, filters ...string) ([]Image, error) { + imgs, err := c.ImageService().List(ctx, filters...) + if err != nil { + return nil, err + } + images := make([]Image, len(imgs)) + for i, img := range imgs { + images[i] = NewImage(c, img) + } + return images, nil +} + +// Restore restores a container from a checkpoint +func (c *Client) Restore(ctx context.Context, id string, checkpoint Image, opts ...RestoreOpts) (Container, error) { + store := c.ContentStore() + index, err := decodeIndex(ctx, store, checkpoint.Target()) + if err != nil { + return nil, err + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + copts := make([]NewContainerOpts, len(opts)) + for i, o := range opts { + copts[i] = o(ctx, id, c, checkpoint, index) + } + + ctr, err := c.NewContainer(ctx, id, copts...) + if err != nil { + return nil, err + } + + return ctr, nil +} + +func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) { + labels := map[string]string{} + for i, m := range index.Manifests { + labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String() + } + data, err := json.Marshal(index) + if err != nil { + return ocispec.Descriptor{}, err + } + return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels)) +} + +func decodeIndex(ctx context.Context, store content.Provider, desc ocispec.Descriptor) (*ocispec.Index, error) { + var index ocispec.Index + p, err := content.ReadBlob(ctx, store, desc) + if err != nil { + return nil, err + } + if err := json.Unmarshal(p, &index); err != nil { + return nil, err + } + + return &index, nil +} + +// GetLabel gets a label value from namespace store +// If there is no default label, an empty string returned with nil error +func (c *Client) GetLabel(ctx context.Context, label string) (string, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + if c.defaultns == "" { + return "", err + } + ns = c.defaultns + } + + srv := c.NamespaceService() + labels, err := srv.Labels(ctx, ns) + if err != nil { + return "", err + } + + value := labels[label] + return value, nil +} + +// Subscribe to events that match one or more of the provided filters. +// +// Callers should listen on both the envelope and errs channels. If the errs +// channel returns nil or an error, the subscriber should terminate. +// +// The subscriber can stop receiving events by canceling the provided context. +// The errs channel will be closed and return a nil error. +func (c *Client) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) { + return c.EventService().Subscribe(ctx, filters...) +} + +// Close closes the clients connection to containerd +func (c *Client) Close() error { + c.connMu.Lock() + defer c.connMu.Unlock() + if c.conn != nil { + return c.conn.Close() + } + return nil +} + +// NamespaceService returns the underlying Namespaces Store +func (c *Client) NamespaceService() namespaces.Store { + if c.namespaceStore != nil { + return c.namespaceStore + } + c.connMu.Lock() + defer c.connMu.Unlock() + return NewNamespaceStoreFromClient(namespacesapi.NewNamespacesClient(c.conn)) +} + +// ContainerService returns the underlying container Store +func (c *Client) ContainerService() containers.Store { + if c.containerStore != nil { + return c.containerStore + } + c.connMu.Lock() + defer c.connMu.Unlock() + return NewRemoteContainerStore(containersapi.NewContainersClient(c.conn)) +} + +// ContentStore returns the underlying content Store +func (c *Client) ContentStore() content.Store { + if c.contentStore != nil { + return c.contentStore + } + c.connMu.Lock() + defer c.connMu.Unlock() + return contentproxy.NewContentStore(c.conn) +} + +// SnapshotService returns the underlying snapshotter for the provided snapshotter name +func (c *Client) SnapshotService(snapshotterName string) snapshots.Snapshotter { + snapshotterName, err := c.resolveSnapshotterName(context.Background(), snapshotterName) + if err != nil { + snapshotterName = defaults.DefaultSnapshotter + } + if c.snapshotters != nil { + return c.snapshotters[snapshotterName] + } + c.connMu.Lock() + defer c.connMu.Unlock() + return snproxy.NewSnapshotter(snapshotsapi.NewSnapshotsClient(c.conn), snapshotterName) +} + +// DefaultNamespace return the default namespace +func (c *Client) DefaultNamespace() string { + return c.defaultns +} + +// TaskService returns the underlying TasksClient +func (c *Client) TaskService() tasks.TasksClient { + if c.taskService != nil { + return c.taskService + } + c.connMu.Lock() + defer c.connMu.Unlock() + return tasks.NewTasksClient(c.conn) +} + +// ImageService returns the underlying image Store +func (c *Client) ImageService() images.Store { + if c.imageStore != nil { + return c.imageStore + } + c.connMu.Lock() + defer c.connMu.Unlock() + return NewImageStoreFromClient(imagesapi.NewImagesClient(c.conn)) +} + +// DiffService returns the underlying Differ +func (c *Client) DiffService() DiffService { + if c.diffService != nil { + return c.diffService + } + c.connMu.Lock() + defer c.connMu.Unlock() + return NewDiffServiceFromClient(diffapi.NewDiffClient(c.conn)) +} + +// IntrospectionService returns the underlying Introspection Client +func (c *Client) IntrospectionService() introspection.Service { + if c.introspectionService != nil { + return c.introspectionService + } + c.connMu.Lock() + defer c.connMu.Unlock() + return introspectionproxy.NewIntrospectionProxy(c.conn) +} + +// LeasesService returns the underlying Leases Client +func (c *Client) LeasesService() leases.Manager { + if c.leasesService != nil { + return c.leasesService + } + c.connMu.Lock() + defer c.connMu.Unlock() + return leasesproxy.NewLeaseManager(leasesapi.NewLeasesClient(c.conn)) +} + +// HealthService returns the underlying GRPC HealthClient +func (c *Client) HealthService() grpc_health_v1.HealthClient { + c.connMu.Lock() + defer c.connMu.Unlock() + return grpc_health_v1.NewHealthClient(c.conn) +} + +// EventService returns the underlying event service +func (c *Client) EventService() EventService { + if c.eventService != nil { + return c.eventService + } + c.connMu.Lock() + defer c.connMu.Unlock() + return eventsproxy.NewRemoteEvents(c.conn) +} + +// SandboxStore returns the underlying sandbox store client +func (c *Client) SandboxStore() sandbox.Store { + if c.sandboxStore != nil { + return c.sandboxStore + } + c.connMu.Lock() + defer c.connMu.Unlock() + return sandboxproxy.NewSandboxStore(sandboxsapi.NewStoreClient(c.conn)) +} + +// SandboxController returns the underlying sandbox controller client +func (c *Client) SandboxController(name string) sandbox.Controller { + if c.sandboxers != nil { + return c.sandboxers[name] + } + c.connMu.Lock() + defer c.connMu.Unlock() + return sandboxproxy.NewSandboxController(sandboxsapi.NewControllerClient(c.conn), name) +} + +// VersionService returns the underlying VersionClient +func (c *Client) VersionService() versionservice.VersionClient { + c.connMu.Lock() + defer c.connMu.Unlock() + return versionservice.NewVersionClient(c.conn) +} + +// Conn returns the underlying RPC connection object +// Either *grpc.ClientConn or *ttrpc.Conn +func (c *Client) Conn() any { + c.connMu.Lock() + defer c.connMu.Unlock() + return c.conn +} + +// Version of containerd +type Version struct { + // Version number + Version string + // Revision from git that was built + Revision string +} + +// Version returns the version of containerd that the client is connected to +func (c *Client) Version(ctx context.Context) (Version, error) { + c.connMu.Lock() + if c.conn == nil { + c.connMu.Unlock() + return Version{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) + } + c.connMu.Unlock() + response, err := c.VersionService().Version(ctx, &ptypes.Empty{}) + if err != nil { + return Version{}, err + } + return Version{ + Version: response.Version, + Revision: response.Revision, + }, nil +} + +// ServerInfo represents the introspected server information +type ServerInfo struct { + UUID string +} + +// Server returns server information from the introspection service +func (c *Client) Server(ctx context.Context) (ServerInfo, error) { + c.connMu.Lock() + if c.conn == nil { + c.connMu.Unlock() + return ServerInfo{}, fmt.Errorf("no grpc connection available: %w", errdefs.ErrUnavailable) + } + c.connMu.Unlock() + + response, err := c.IntrospectionService().Server(ctx) + if err != nil { + return ServerInfo{}, err + } + return ServerInfo{ + UUID: response.UUID, + }, nil +} + +func (c *Client) resolveSnapshotterName(ctx context.Context, name string) (string, error) { + if name == "" { + label, err := c.GetLabel(ctx, defaults.DefaultSnapshotterNSLabel) + if err != nil { + return "", err + } + + if label != "" { + name = label + } else { + name = defaults.DefaultSnapshotter + } + } + + return name, nil +} + +func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Snapshotter, error) { + name, err := c.resolveSnapshotterName(ctx, name) + if err != nil { + return nil, err + } + + s := c.SnapshotService(name) + if s == nil { + return nil, fmt.Errorf("snapshotter %s was not found: %w", name, errdefs.ErrNotFound) + } + + return s, nil +} + +// GetSnapshotterSupportedPlatforms returns a platform matchers which represents the +// supported platforms for the given snapshotters +func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshotterName string) (platforms.MatchComparer, error) { + filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} + in := c.IntrospectionService() + + resp, err := in.Plugins(ctx, filters...) + if err != nil { + return nil, err + } + + if len(resp.Plugins) <= 0 { + return nil, fmt.Errorf("inspection service could not find snapshotter %s plugin", snapshotterName) + } + + sn := resp.Plugins[0] + snPlatforms := toPlatforms(sn.Platforms) + return platforms.Any(snPlatforms...), nil +} + +func toPlatforms(pt []*apitypes.Platform) []ocispec.Platform { + platforms := make([]ocispec.Platform, len(pt)) + for i, p := range pt { + platforms[i] = ocispec.Platform{ + Architecture: p.Architecture, + OS: p.OS, + Variant: p.Variant, + } + } + return platforms +} + +// GetSnapshotterCapabilities returns the capabilities of a snapshotter. +func (c *Client) GetSnapshotterCapabilities(ctx context.Context, snapshotterName string) ([]string, error) { + filters := []string{fmt.Sprintf("type==%s, id==%s", plugins.SnapshotPlugin, snapshotterName)} + in := c.IntrospectionService() + + resp, err := in.Plugins(ctx, filters...) + if err != nil { + return nil, err + } + + if len(resp.Plugins) <= 0 { + return nil, fmt.Errorf("inspection service could not find snapshotter %s plugin", snapshotterName) + } + + sn := resp.Plugins[0] + return sn.Capabilities, nil +} + +type RuntimeVersion struct { + Version string + Revision string +} + +type RuntimeInfo struct { + Name string + Version RuntimeVersion + Options interface{} + Features interface{} + Annotations map[string]string +} + +func (c *Client) RuntimeInfo(ctx context.Context, runtimePath string, runtimeOptions interface{}) (*RuntimeInfo, error) { + rt := c.runtime + if runtimePath != "" { + rt = runtimePath + } + rr := &apitypes.RuntimeRequest{ + RuntimePath: rt, + } + var err error + if runtimeOptions != nil { + rr.Options, err = typeurl.MarshalAnyToProto(runtimeOptions) + if err != nil { + return nil, fmt.Errorf("failed to marshal %T: %w", runtimeOptions, err) + } + } + + s := c.IntrospectionService() + + resp, err := s.PluginInfo(ctx, string(plugins.RuntimePluginV2), "task", rr) + if err != nil { + return nil, err + } + + var info apitypes.RuntimeInfo + if err := typeurl.UnmarshalTo(resp.Extra, &info); err != nil { + return nil, fmt.Errorf("failed to get runtime info from plugin info: %w", err) + } + + var result RuntimeInfo + result.Name = info.Name + if info.Version != nil { + result.Version.Version = info.Version.Version + result.Version.Revision = info.Version.Revision + } + if info.Options != nil { + result.Options, err = typeurl.UnmarshalAny(info.Options) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal RuntimeInfo.Options (%T): %w", info.Options, err) + } + } + if info.Features != nil { + result.Features, err = typeurl.UnmarshalAny(info.Features) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal RuntimeInfo.Features (%T): %w", info.Features, err) + } + } + result.Annotations = info.Annotations + return &result, nil +} diff --git a/client_opts.go b/client/client_opts.go similarity index 90% rename from client_opts.go rename to client/client_opts.go index 4e0a78a8a31d..54b37d4ca3a2 100644 --- a/client_opts.go +++ b/client/client_opts.go @@ -14,15 +14,15 @@ limitations under the License. */ -package containerd +package client import ( "time" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/remotes" - "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/remotes" + "github.com/containerd/containerd/v2/core/snapshots" + "github.com/containerd/platforms" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "google.golang.org/grpc" @@ -38,14 +38,14 @@ type clientOpts struct { timeout time.Duration } -// ClientOpt allows callers to set options on the containerd client -type ClientOpt func(c *clientOpts) error +// Opt allows callers to set options on the containerd client +type Opt func(c *clientOpts) error // WithDefaultNamespace sets the default namespace on the client // // Any operation that does not have a namespace set on the context will // be provided the default namespace -func WithDefaultNamespace(ns string) ClientOpt { +func WithDefaultNamespace(ns string) Opt { return func(c *clientOpts) error { c.defaultns = ns return nil @@ -53,7 +53,7 @@ func WithDefaultNamespace(ns string) ClientOpt { } // WithDefaultRuntime sets the default runtime on the client -func WithDefaultRuntime(rt string) ClientOpt { +func WithDefaultRuntime(rt string) Opt { return func(c *clientOpts) error { c.defaultRuntime = rt return nil @@ -61,7 +61,7 @@ func WithDefaultRuntime(rt string) ClientOpt { } // WithDefaultPlatform sets the default platform matcher on the client -func WithDefaultPlatform(platform platforms.MatchComparer) ClientOpt { +func WithDefaultPlatform(platform platforms.MatchComparer) Opt { return func(c *clientOpts) error { c.defaultPlatform = platform return nil @@ -69,7 +69,7 @@ func WithDefaultPlatform(platform platforms.MatchComparer) ClientOpt { } // WithDialOpts allows grpc.DialOptions to be set on the connection -func WithDialOpts(opts []grpc.DialOption) ClientOpt { +func WithDialOpts(opts []grpc.DialOption) Opt { return func(c *clientOpts) error { c.dialOptions = opts return nil @@ -77,7 +77,7 @@ func WithDialOpts(opts []grpc.DialOption) ClientOpt { } // WithCallOpts allows grpc.CallOptions to be set on the connection -func WithCallOpts(opts []grpc.CallOption) ClientOpt { +func WithCallOpts(opts []grpc.CallOption) Opt { return func(c *clientOpts) error { c.callOptions = opts return nil @@ -85,7 +85,7 @@ func WithCallOpts(opts []grpc.CallOption) ClientOpt { } // WithServices sets services used by the client. -func WithServices(opts ...ServicesOpt) ClientOpt { +func WithServices(opts ...ServicesOpt) Opt { return func(c *clientOpts) error { c.services = &services{} for _, o := range opts { @@ -96,7 +96,7 @@ func WithServices(opts ...ServicesOpt) ClientOpt { } // WithTimeout sets the connection timeout for the client -func WithTimeout(d time.Duration) ClientOpt { +func WithTimeout(d time.Duration) Opt { return func(c *clientOpts) error { c.timeout = d return nil diff --git a/client/container.go b/client/container.go new file mode 100644 index 000000000000..b9cf25e9370f --- /dev/null +++ b/client/container.go @@ -0,0 +1,489 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/api/types/runc/options" + tasktypes "github.com/containerd/containerd/api/types/task" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + "github.com/containerd/fifo" + "github.com/containerd/typeurl/v2" + ver "github.com/opencontainers/image-spec/specs-go" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/opencontainers/selinux/go-selinux/label" + + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/containerd/v2/pkg/tracing" +) + +const ( + checkpointRuntimeNameLabel = "io.containerd.checkpoint.runtime" + checkpointSnapshotterNameLabel = "io.containerd.checkpoint.snapshotter" +) + +// Container is a metadata object for container resources and task creation +type Container interface { + // ID identifies the container + ID() string + // Info returns the underlying container record type + Info(context.Context, ...InfoOpts) (containers.Container, error) + // Delete removes the container + Delete(context.Context, ...DeleteOpts) error + // NewTask creates a new task based on the container metadata + NewTask(context.Context, cio.Creator, ...NewTaskOpts) (Task, error) + // Spec returns the OCI runtime specification + Spec(context.Context) (*oci.Spec, error) + // Task returns the current task for the container + // + // If cio.Load options are passed the client will Load the IO for the running + // task. + // + // If cio.Attach options are passed the client will reattach to the IO for the running + // task. + // + // If no task exists for the container a NotFound error is returned + // + // Clients must make sure that only one reader is attached to the task and consuming + // the output from the task's fifos + Task(context.Context, cio.Attach) (Task, error) + // Image returns the image that the container is based on + Image(context.Context) (Image, error) + // Labels returns the labels set on the container + Labels(context.Context) (map[string]string, error) + // SetLabels sets the provided labels for the container and returns the final label set + SetLabels(context.Context, map[string]string) (map[string]string, error) + // Extensions returns the extensions set on the container + Extensions(context.Context) (map[string]typeurl.Any, error) + // Update a container + Update(context.Context, ...UpdateContainerOpts) error + // Checkpoint creates a checkpoint image of the current container + Checkpoint(context.Context, string, ...CheckpointOpts) (Image, error) +} + +func containerFromRecord(client *Client, c containers.Container) *container { + return &container{ + client: client, + id: c.ID, + metadata: c, + } +} + +var _ = (Container)(&container{}) + +type container struct { + client *Client + id string + metadata containers.Container +} + +// ID returns the container's unique id +func (c *container) ID() string { + return c.id +} + +func (c *container) Info(ctx context.Context, opts ...InfoOpts) (containers.Container, error) { + i := &InfoConfig{ + // default to refreshing the container's local metadata + Refresh: true, + } + for _, o := range opts { + o(i) + } + if i.Refresh { + metadata, err := c.get(ctx) + if err != nil { + return c.metadata, err + } + c.metadata = metadata + } + return c.metadata, nil +} + +func (c *container) Extensions(ctx context.Context) (map[string]typeurl.Any, error) { + r, err := c.get(ctx) + if err != nil { + return nil, err + } + return r.Extensions, nil +} + +func (c *container) Labels(ctx context.Context) (map[string]string, error) { + r, err := c.get(ctx) + if err != nil { + return nil, err + } + return r.Labels, nil +} + +func (c *container) SetLabels(ctx context.Context, labels map[string]string) (map[string]string, error) { + ctx, span := tracing.StartSpan(ctx, "container.SetLabels", + tracing.WithAttribute("container.id", c.id), + ) + defer span.End() + container := containers.Container{ + ID: c.id, + Labels: labels, + } + + var paths []string + // mask off paths so we only muck with the labels encountered in labels. + // Labels not in the passed in argument will be left alone. + for k := range labels { + paths = append(paths, strings.Join([]string{"labels", k}, ".")) + } + + r, err := c.client.ContainerService().Update(ctx, container, paths...) + if err != nil { + return nil, err + } + return r.Labels, nil +} + +// Spec returns the current OCI specification for the container +func (c *container) Spec(ctx context.Context) (*oci.Spec, error) { + r, err := c.get(ctx) + if err != nil { + return nil, err + } + var s oci.Spec + if err := json.Unmarshal(r.Spec.GetValue(), &s); err != nil { + return nil, err + } + return &s, nil +} + +// Delete deletes an existing container +// an error is returned if the container has running tasks +func (c *container) Delete(ctx context.Context, opts ...DeleteOpts) error { + ctx, span := tracing.StartSpan(ctx, "container.Delete", + tracing.WithAttribute("container.id", c.id), + ) + defer span.End() + if _, err := c.loadTask(ctx, nil); err == nil { + return fmt.Errorf("cannot delete running task %v: %w", c.id, errdefs.ErrFailedPrecondition) + } + r, err := c.get(ctx) + if err != nil { + return err + } + for _, o := range opts { + if err := o(ctx, c.client, r); err != nil { + return err + } + } + return c.client.ContainerService().Delete(ctx, c.id) +} + +func (c *container) Task(ctx context.Context, attach cio.Attach) (Task, error) { + return c.loadTask(ctx, attach) +} + +// Image returns the image that the container is based on +func (c *container) Image(ctx context.Context) (Image, error) { + r, err := c.get(ctx) + if err != nil { + return nil, err + } + if r.Image == "" { + return nil, fmt.Errorf("container not created from an image: %w", errdefs.ErrNotFound) + } + i, err := c.client.ImageService().Get(ctx, r.Image) + if err != nil { + return nil, fmt.Errorf("failed to get image %s for container: %w", r.Image, err) + } + return NewImage(c.client, i), nil +} + +func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...NewTaskOpts) (_ Task, err error) { + ctx, span := tracing.StartSpan(ctx, "container.NewTask") + defer span.End() + i, err := ioCreate(c.id) + if err != nil { + return nil, err + } + defer func() { + if err != nil && i != nil { + i.Cancel() + i.Close() + } + }() + cfg := i.Config() + request := &tasks.CreateTaskRequest{ + ContainerID: c.id, + Terminal: cfg.Terminal, + Stdin: cfg.Stdin, + Stdout: cfg.Stdout, + Stderr: cfg.Stderr, + } + r, err := c.get(ctx) + if err != nil { + return nil, err + } + if r.SnapshotKey != "" { + if r.Snapshotter == "" { + return nil, fmt.Errorf("unable to resolve rootfs mounts without snapshotter on container: %w", errdefs.ErrInvalidArgument) + } + + // get the rootfs from the snapshotter and add it to the request + s, err := c.client.getSnapshotter(ctx, r.Snapshotter) + if err != nil { + return nil, err + } + mounts, err := s.Mounts(ctx, r.SnapshotKey) + if err != nil { + return nil, err + } + spec, err := c.Spec(ctx) + if err != nil { + return nil, err + } + for _, m := range mounts { + if spec.Linux != nil && spec.Linux.MountLabel != "" { + if ml := label.FormatMountLabel("", spec.Linux.MountLabel); ml != "" { + m.Options = append(m.Options, ml) + } + } + request.Rootfs = append(request.Rootfs, &types.Mount{ + Type: m.Type, + Source: m.Source, + Target: m.Target, + Options: m.Options, + }) + } + } + info := TaskInfo{ + runtime: r.Runtime.Name, + } + for _, o := range opts { + if err := o(ctx, c.client, &info); err != nil { + return nil, err + } + } + for _, m := range info.RootFS { + request.Rootfs = append(request.Rootfs, &types.Mount{ + Type: m.Type, + Source: m.Source, + Target: m.Target, + Options: m.Options, + }) + } + request.RuntimePath = info.RuntimePath + if info.Options != nil { + o, err := typeurl.MarshalAny(info.Options) + if err != nil { + return nil, err + } + request.Options = typeurl.MarshalProto(o) + } + t := &task{ + client: c.client, + io: i, + id: c.id, + c: c, + } + if info.Checkpoint != nil { + request.Checkpoint = info.Checkpoint + } + + span.SetAttributes( + tracing.Attribute("task.container.id", request.ContainerID), + tracing.Attribute("task.request.options", request.Options.String()), + tracing.Attribute("task.runtime.name", info.runtime), + ) + response, err := c.client.TaskService().Create(ctx, request) + if err != nil { + return nil, errgrpc.ToNative(err) + } + + span.AddEvent("task created", + tracing.Attribute("task.process.id", int(response.Pid)), + ) + t.pid = response.Pid + return t, nil +} + +func (c *container) Update(ctx context.Context, opts ...UpdateContainerOpts) error { + // fetch the current container config before updating it + ctx, span := tracing.StartSpan(ctx, "container.Update") + defer span.End() + r, err := c.get(ctx) + if err != nil { + return err + } + for _, o := range opts { + if err := o(ctx, c.client, &r); err != nil { + return err + } + } + if _, err := c.client.ContainerService().Update(ctx, r); err != nil { + return errgrpc.ToNative(err) + } + return nil +} + +func (c *container) Checkpoint(ctx context.Context, ref string, opts ...CheckpointOpts) (Image, error) { + index := &ocispec.Index{ + Versioned: ver.Versioned{ + SchemaVersion: 2, + }, + Annotations: make(map[string]string), + } + copts := &options.CheckpointOptions{ + Exit: false, + OpenTcp: false, + ExternalUnixSockets: false, + Terminal: false, + FileLocks: true, + EmptyNamespaces: nil, + } + info, err := c.Info(ctx) + if err != nil { + return nil, err + } + + img, err := c.Image(ctx) + if err != nil { + return nil, err + } + + ctx, done, err := c.client.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + // add image name to manifest + index.Annotations[ocispec.AnnotationRefName] = img.Name() + // add runtime info to index + index.Annotations[checkpointRuntimeNameLabel] = info.Runtime.Name + // add snapshotter info to index + index.Annotations[checkpointSnapshotterNameLabel] = info.Snapshotter + + // process remaining opts + for _, o := range opts { + if err := o(ctx, c.client, &info, index, copts); err != nil { + err = errgrpc.ToNative(err) + if !errdefs.IsAlreadyExists(err) { + return nil, err + } + } + } + + desc, err := writeIndex(ctx, index, c.client, c.ID()+"index") + if err != nil { + return nil, err + } + i := images.Image{ + Name: ref, + Target: desc, + } + checkpoint, err := c.client.ImageService().Create(ctx, i) + if err != nil { + return nil, err + } + + return NewImage(c.client, checkpoint), nil +} + +func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, error) { + response, err := c.client.TaskService().Get(ctx, &tasks.GetRequest{ + ContainerID: c.id, + }) + if err != nil { + err = errgrpc.ToNative(err) + if errdefs.IsNotFound(err) { + return nil, fmt.Errorf("no running task found: %w", err) + } + return nil, err + } + var i cio.IO + if ioAttach != nil && response.Process.Status != tasktypes.Status_UNKNOWN { + // Do not attach IO for task in unknown state, because there + // are no fifo paths anyway. + if i, err = attachExistingIO(response, ioAttach); err != nil { + return nil, err + } + } + t := &task{ + client: c.client, + io: i, + id: response.Process.ID, + pid: response.Process.Pid, + c: c, + } + return t, nil +} + +func (c *container) get(ctx context.Context) (containers.Container, error) { + return c.client.ContainerService().Get(ctx, c.id) +} + +// get the existing fifo paths from the task information stored by the daemon +func attachExistingIO(response *tasks.GetResponse, ioAttach cio.Attach) (cio.IO, error) { + fifoSet := loadFifos(response) + return ioAttach(fifoSet) +} + +// loadFifos loads the containers fifos +func loadFifos(response *tasks.GetResponse) *cio.FIFOSet { + fifos := []string{ + response.Process.Stdin, + response.Process.Stdout, + response.Process.Stderr, + } + closer := func() error { + var ( + err error + dirs = map[string]struct{}{} + ) + for _, f := range fifos { + if isFifo, _ := fifo.IsFifo(f); isFifo { + if rerr := os.Remove(f); err == nil { + err = rerr + } + dirs[filepath.Dir(f)] = struct{}{} + } + } + for dir := range dirs { + // we ignore errors here because we don't + // want to remove the directory if it isn't + // empty + _ = os.Remove(dir) + } + return err + } + + return cio.NewFIFOSet(cio.Config{ + Stdin: response.Process.Stdin, + Stdout: response.Process.Stdout, + Stderr: response.Process.Stderr, + Terminal: response.Process.Terminal, + }, closer) +} diff --git a/container_checkpoint_opts.go b/client/container_checkpoint_opts.go similarity index 84% rename from container_checkpoint_opts.go rename to client/container_checkpoint_opts.go index c1d9fb8bd68a..4edb937f6261 100644 --- a/container_checkpoint_opts.go +++ b/client/container_checkpoint_opts.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client import ( "bytes" @@ -24,24 +24,20 @@ import ( "runtime" tasks "github.com/containerd/containerd/api/services/tasks/v1" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/diff" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/platforms" - "github.com/containerd/containerd/protobuf" - "github.com/containerd/containerd/protobuf/proto" - "github.com/containerd/containerd/rootfs" - "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/diff" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/protobuf/proto" + "github.com/containerd/containerd/v2/pkg/rootfs" + "github.com/containerd/platforms" + "github.com/containerd/typeurl/v2" "github.com/opencontainers/go-digest" imagespec "github.com/opencontainers/image-spec/specs-go/v1" ) -var ( - // ErrCheckpointRWUnsupported is returned if the container runtime does not support checkpoint - ErrCheckpointRWUnsupported = errors.New("rw checkpoint is only supported on v2 runtimes") - // ErrMediaTypeNotFound returns an error when a media type in the manifest is unknown - ErrMediaTypeNotFound = errors.New("media type not found") -) +// ErrMediaTypeNotFound returns an error when a media type in the manifest is unknown +var ErrMediaTypeNotFound = errors.New("media type not found") // CheckpointOpts are options to manage the checkpoint operation type CheckpointOpts func(context.Context, *Client, *containers.Container, *imagespec.Index, *options.CheckpointOptions) error @@ -58,7 +54,7 @@ func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Cont // WithCheckpointTask includes the running task func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { - opt, err := protobuf.MarshalAnyToProto(copts) + opt, err := typeurl.MarshalAnyToProto(copts) if err != nil { return nil } @@ -100,7 +96,7 @@ func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Conta // WithCheckpointRuntime includes the container runtime info func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error { if c.Runtime.Options != nil && c.Runtime.Options.GetValue() != nil { - opt := protobuf.FromAny(c.Runtime.Options) + opt := typeurl.MarshalProto(c.Runtime.Options) data, err := proto.Marshal(opt) if err != nil { return err diff --git a/container_opts.go b/client/container_opts.go similarity index 93% rename from container_opts.go rename to client/container_opts.go index d8105061f3f4..04f2a9062114 100644 --- a/container_opts.go +++ b/client/container_opts.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client import ( "context" @@ -22,14 +22,13 @@ import ( "errors" "fmt" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/oci" - "github.com/containerd/containerd/protobuf" - "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/snapshots" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/errdefs" "github.com/containerd/typeurl/v2" "github.com/opencontainers/image-spec/identity" v1 "github.com/opencontainers/image-spec/specs-go/v1" @@ -120,24 +119,24 @@ func WithImageConfigLabels(image Image) NewContainerOpts { if err != nil { return err } + if !images.IsConfigType(ic.MediaType) { + return fmt.Errorf("unknown image config media type %s", ic.MediaType) + } + var ( ociimage v1.Image config v1.ImageConfig ) - switch ic.MediaType { - case v1.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config: - p, err := content.ReadBlob(ctx, image.ContentStore(), ic) - if err != nil { - return err - } + p, err := content.ReadBlob(ctx, image.ContentStore(), ic) + if err != nil { + return err + } - if err := json.Unmarshal(p, &ociimage); err != nil { - return err - } - config = ociimage.Config - default: - return fmt.Errorf("unknown image config media type %s", ic.MediaType) + if err = json.Unmarshal(p, &ociimage); err != nil { + return err } + config = ociimage.Config + c.Labels = config.Labels return nil } @@ -321,7 +320,7 @@ func WithSpec(s *oci.Spec, opts ...oci.SpecOpts) NewContainerOpts { } var err error - c.Spec, err = protobuf.MarshalAnyToProto(s) + c.Spec, err = typeurl.MarshalAnyToProto(s) return err } } diff --git a/client/container_opts_unix.go b/client/container_opts_unix.go new file mode 100644 index 000000000000..fc562923920f --- /dev/null +++ b/client/container_opts_unix.go @@ -0,0 +1,147 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "fmt" + "os" + "path/filepath" + "syscall" + + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/internal/userns" + + "github.com/containerd/errdefs" + "github.com/opencontainers/image-spec/identity" + "github.com/opencontainers/runtime-spec/specs-go" +) + +// WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the +// filesystem to be used by a container with user namespaces +func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts { + uidmaps := []specs.LinuxIDMapping{{ContainerID: 0, HostID: uid, Size: 65536}} + gidmaps := []specs.LinuxIDMapping{{ContainerID: 0, HostID: gid, Size: 65536}} + return withRemappedSnapshotBase(id, i, uidmaps, gidmaps, false) +} + +// WithUserNSRemappedSnapshot creates a new snapshot and remaps the uid/gid for the +// filesystem to be used by a container with user namespaces +func WithUserNSRemappedSnapshot(id string, i Image, uidmaps, gidmaps []specs.LinuxIDMapping) NewContainerOpts { + return withRemappedSnapshotBase(id, i, uidmaps, gidmaps, false) +} + +// WithRemappedSnapshotView is similar to WithRemappedSnapshot but rootfs is mounted as read-only. +func WithRemappedSnapshotView(id string, i Image, uid, gid uint32) NewContainerOpts { + uidmaps := []specs.LinuxIDMapping{{ContainerID: 0, HostID: uid, Size: 65536}} + gidmaps := []specs.LinuxIDMapping{{ContainerID: 0, HostID: gid, Size: 65536}} + return withRemappedSnapshotBase(id, i, uidmaps, gidmaps, true) +} + +// WithUserNSRemappedSnapshotView is similar to WithUserNSRemappedSnapshot but rootfs is mounted as read-only. +func WithUserNSRemappedSnapshotView(id string, i Image, uidmaps, gidmaps []specs.LinuxIDMapping) NewContainerOpts { + return withRemappedSnapshotBase(id, i, uidmaps, gidmaps, true) +} + +func withRemappedSnapshotBase(id string, i Image, uidmaps, gidmaps []specs.LinuxIDMapping, readonly bool) NewContainerOpts { + return func(ctx context.Context, client *Client, c *containers.Container) error { + diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform) + if err != nil { + return err + } + + rsn := remappedSnapshot{ + Parent: identity.ChainID(diffIDs).String(), + IDMap: userns.IDMap{UidMap: uidmaps, GidMap: gidmaps}, + } + usernsID, err := rsn.ID() + if err != nil { + return fmt.Errorf("failed to remap snapshot: %w", err) + } + + c.Snapshotter, err = client.resolveSnapshotterName(ctx, c.Snapshotter) + if err != nil { + return err + } + snapshotter, err := client.getSnapshotter(ctx, c.Snapshotter) + if err != nil { + return err + } + if _, err := snapshotter.Stat(ctx, usernsID); err == nil { + if _, err := snapshotter.Prepare(ctx, id, usernsID); err == nil { + c.SnapshotKey = id + c.Image = i.Name() + return nil + } else if !errdefs.IsNotFound(err) { + return err + } + } + mounts, err := snapshotter.Prepare(ctx, usernsID+"-remap", rsn.Parent) + if err != nil { + return err + } + if err := remapRootFS(ctx, mounts, rsn.IDMap); err != nil { + snapshotter.Remove(ctx, usernsID) + return err + } + if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil { + return err + } + if readonly { + _, err = snapshotter.View(ctx, id, usernsID) + } else { + _, err = snapshotter.Prepare(ctx, id, usernsID) + } + if err != nil { + return err + } + c.SnapshotKey = id + c.Image = i.Name() + return nil + } +} + +func remapRootFS(ctx context.Context, mounts []mount.Mount, idMap userns.IDMap) error { + return mount.WithTempMount(ctx, mounts, func(root string) error { + return filepath.Walk(root, chown(root, idMap)) + }) +} + +func chown(root string, idMap userns.IDMap) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + stat := info.Sys().(*syscall.Stat_t) + h, cerr := idMap.ToHost(userns.User{Uid: stat.Uid, Gid: stat.Gid}) + if cerr != nil { + return cerr + } + // be sure the lchown the path as to not de-reference the symlink to a host file + if cerr = os.Lchown(path, int(h.Uid), int(h.Gid)); cerr != nil { + return cerr + } + // we must retain special permissions such as setuid, setgid and sticky bits + if mode := info.Mode(); mode&os.ModeSymlink == 0 && mode&(os.ModeSetuid|os.ModeSetgid|os.ModeSticky) != 0 { + return os.Chmod(path, mode) + } + return nil + } +} diff --git a/container_restore_opts.go b/client/container_restore_opts.go similarity index 92% rename from container_restore_opts.go rename to client/container_restore_opts.go index 2afc18701386..174ae89d1254 100644 --- a/container_restore_opts.go +++ b/client/container_restore_opts.go @@ -14,18 +14,18 @@ limitations under the License. */ -package containerd +package client import ( "context" "errors" "fmt" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/protobuf/proto" - ptypes "github.com/containerd/containerd/protobuf/types" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/protobuf/proto" + ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types" "github.com/opencontainers/image-spec/identity" imagespec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -45,7 +45,7 @@ type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) // WithRestoreImage restores the image for the container func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts { return func(ctx context.Context, client *Client, c *containers.Container) error { - name, ok := index.Annotations[checkpointImageNameLabel] + name, ok := index.Annotations[imagespec.AnnotationRefName] if !ok || name == "" { return ErrImageNameNotFoundInIndex } diff --git a/containerstore.go b/client/containerstore.go similarity index 88% rename from containerstore.go rename to client/containerstore.go index 331a6f41de04..a908737c98fb 100644 --- a/containerstore.go +++ b/client/containerstore.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client import ( "context" @@ -22,13 +22,14 @@ import ( "io" containersapi "github.com/containerd/containerd/api/services/containers/v1" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/protobuf" - ptypes "github.com/containerd/containerd/protobuf/types" + "github.com/containerd/errdefs/pkg/errgrpc" "github.com/containerd/typeurl/v2" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/pkg/protobuf" + ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types" ) type remoteContainers struct { @@ -49,7 +50,7 @@ func (r *remoteContainers) Get(ctx context.Context, id string) (containers.Conta ID: id, }) if err != nil { - return containers.Container{}, errdefs.FromGRPC(err) + return containers.Container{}, errgrpc.ToNative(err) } return containerFromProto(resp.Container), nil @@ -71,7 +72,7 @@ func (r *remoteContainers) list(ctx context.Context, filters ...string) ([]conta Filters: filters, }) if err != nil { - return nil, errdefs.FromGRPC(err) + return nil, errgrpc.ToNative(err) } return containersFromProto(resp.Containers), nil } @@ -83,7 +84,7 @@ func (r *remoteContainers) stream(ctx context.Context, filters ...string) ([]con Filters: filters, }) if err != nil { - return nil, errdefs.FromGRPC(err) + return nil, errgrpc.ToNative(err) } var containers []containers.Container for { @@ -97,7 +98,7 @@ func (r *remoteContainers) stream(ctx context.Context, filters ...string) ([]con return nil, errStreamNotAvailable } } - return nil, errdefs.FromGRPC(err) + return nil, errgrpc.ToNative(err) } select { case <-ctx.Done(): @@ -113,7 +114,7 @@ func (r *remoteContainers) Create(ctx context.Context, container containers.Cont Container: containerToProto(&container), }) if err != nil { - return containers.Container{}, errdefs.FromGRPC(err) + return containers.Container{}, errgrpc.ToNative(err) } return containerFromProto(created.Container), nil @@ -133,7 +134,7 @@ func (r *remoteContainers) Update(ctx context.Context, container containers.Cont UpdateMask: updateMask, }) if err != nil { - return containers.Container{}, errdefs.FromGRPC(err) + return containers.Container{}, errgrpc.ToNative(err) } return containerFromProto(updated.Container), nil @@ -145,14 +146,14 @@ func (r *remoteContainers) Delete(ctx context.Context, id string) error { ID: id, }) - return errdefs.FromGRPC(err) + return errgrpc.ToNative(err) } func containerToProto(container *containers.Container) *containersapi.Container { extensions := make(map[string]*ptypes.Any) for k, v := range container.Extensions { - extensions[k] = protobuf.FromAny(v) + extensions[k] = typeurl.MarshalProto(v) } return &containersapi.Container{ ID: container.ID, @@ -160,9 +161,9 @@ func containerToProto(container *containers.Container) *containersapi.Container Image: container.Image, Runtime: &containersapi.Container_Runtime{ Name: container.Runtime.Name, - Options: protobuf.FromAny(container.Runtime.Options), + Options: typeurl.MarshalProto(container.Runtime.Options), }, - Spec: protobuf.FromAny(container.Spec), + Spec: typeurl.MarshalProto(container.Spec), Snapshotter: container.Snapshotter, SnapshotKey: container.SnapshotKey, Extensions: extensions, diff --git a/client/diff.go b/client/diff.go new file mode 100644 index 000000000000..2af19d4a7a08 --- /dev/null +++ b/client/diff.go @@ -0,0 +1,35 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + diffapi "github.com/containerd/containerd/api/services/diff/v1" + "github.com/containerd/containerd/v2/core/diff" + "github.com/containerd/containerd/v2/core/diff/proxy" +) + +// DiffService handles the computation and application of diffs +type DiffService interface { + diff.Comparer + diff.Applier +} + +// NewDiffServiceFromClient returns a new diff service which communicates +// over a GRPC connection. +func NewDiffServiceFromClient(client diffapi.DiffClient) DiffService { + return proxy.NewDiffApplier(client).(DiffService) +} diff --git a/client/events.go b/client/events.go new file mode 100644 index 000000000000..3f6e252b37c2 --- /dev/null +++ b/client/events.go @@ -0,0 +1,125 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + + eventsapi "github.com/containerd/containerd/api/services/events/v1" + "github.com/containerd/containerd/api/types" + "github.com/containerd/errdefs/pkg/errgrpc" + "github.com/containerd/typeurl/v2" + + "github.com/containerd/containerd/v2/core/events" + "github.com/containerd/containerd/v2/pkg/protobuf" +) + +// EventService handles the publish, forward and subscribe of events. +type EventService interface { + events.Publisher + events.Forwarder + events.Subscriber +} + +// NewEventServiceFromClient returns a new event service which communicates +// over a GRPC connection. +func NewEventServiceFromClient(client eventsapi.EventsClient) EventService { + return &eventRemote{ + client: client, + } +} + +type eventRemote struct { + client eventsapi.EventsClient +} + +func (e *eventRemote) Publish(ctx context.Context, topic string, event events.Event) error { + evt, err := typeurl.MarshalAny(event) + if err != nil { + return err + } + req := &eventsapi.PublishRequest{ + Topic: topic, + Event: typeurl.MarshalProto(evt), + } + if _, err := e.client.Publish(ctx, req); err != nil { + return errgrpc.ToNative(err) + } + return nil +} + +func (e *eventRemote) Forward(ctx context.Context, envelope *events.Envelope) error { + req := &eventsapi.ForwardRequest{ + Envelope: &types.Envelope{ + Timestamp: protobuf.ToTimestamp(envelope.Timestamp), + Namespace: envelope.Namespace, + Topic: envelope.Topic, + Event: typeurl.MarshalProto(envelope.Event), + }, + } + if _, err := e.client.Forward(ctx, req); err != nil { + return errgrpc.ToNative(err) + } + return nil +} + +func (e *eventRemote) Subscribe(ctx context.Context, filters ...string) (ch <-chan *events.Envelope, errs <-chan error) { + var ( + evq = make(chan *events.Envelope) + errq = make(chan error, 1) + ) + + errs = errq + ch = evq + + session, err := e.client.Subscribe(ctx, &eventsapi.SubscribeRequest{ + Filters: filters, + }) + if err != nil { + errq <- err + close(errq) + return + } + + go func() { + defer close(errq) + + for { + ev, err := session.Recv() + if err != nil { + errq <- err + return + } + + select { + case evq <- &events.Envelope{ + Timestamp: protobuf.FromTimestamp(ev.Timestamp), + Namespace: ev.Namespace, + Topic: ev.Topic, + Event: ev.Event, + }: + case <-ctx.Done(): + if cerr := ctx.Err(); cerr != context.Canceled { + errq <- cerr + } + return + } + } + }() + + return ch, errs +} diff --git a/client/export.go b/client/export.go new file mode 100644 index 000000000000..bd34c65d4244 --- /dev/null +++ b/client/export.go @@ -0,0 +1,31 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "io" + + "github.com/containerd/containerd/v2/core/images/archive" +) + +// Export exports images to a Tar stream. +// The tar archive is in OCI format with a Docker compatible manifest +// when a single target platform is given. +func (c *Client) Export(ctx context.Context, w io.Writer, opts ...archive.ExportOpt) error { + return archive.Export(ctx, c.ContentStore(), w, opts...) +} diff --git a/client/grpc.go b/client/grpc.go new file mode 100644 index 000000000000..99325094a926 --- /dev/null +++ b/client/grpc.go @@ -0,0 +1,52 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + + "github.com/containerd/containerd/v2/pkg/namespaces" + "google.golang.org/grpc" +) + +type namespaceInterceptor struct { + namespace string +} + +func (ni namespaceInterceptor) unary(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + _, ok := namespaces.Namespace(ctx) + if !ok { + ctx = namespaces.WithNamespace(ctx, ni.namespace) + } + return invoker(ctx, method, req, reply, cc, opts...) +} + +func (ni namespaceInterceptor) stream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + _, ok := namespaces.Namespace(ctx) + if !ok { + ctx = namespaces.WithNamespace(ctx, ni.namespace) + } + + return streamer(ctx, desc, cc, method, opts...) +} + +func newNSInterceptors(ns string) (grpc.UnaryClientInterceptor, grpc.StreamClientInterceptor) { + ni := namespaceInterceptor{ + namespace: ns, + } + return grpc.UnaryClientInterceptor(ni.unary), grpc.StreamClientInterceptor(ni.stream) +} diff --git a/client/image.go b/client/image.go new file mode 100644 index 000000000000..355bcba73e6d --- /dev/null +++ b/client/image.go @@ -0,0 +1,436 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "sync" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/diff" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/images/usage" + "github.com/containerd/containerd/v2/core/snapshots" + "github.com/containerd/containerd/v2/internal/kmutex" + "github.com/containerd/containerd/v2/pkg/labels" + "github.com/containerd/containerd/v2/pkg/rootfs" + "github.com/containerd/errdefs" + "github.com/containerd/platforms" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/image-spec/identity" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// Image describes an image used by containers +type Image interface { + // Name of the image + Name() string + // Target descriptor for the image content + Target() ocispec.Descriptor + // Labels of the image + Labels() map[string]string + // Unpack unpacks the image's content into a snapshot + Unpack(context.Context, string, ...UnpackOpt) error + // RootFS returns the unpacked diffids that make up images rootfs. + RootFS(ctx context.Context) ([]digest.Digest, error) + // Size returns the total size of the image's packed resources. + Size(ctx context.Context) (int64, error) + // Usage returns a usage calculation for the image. + Usage(context.Context, ...UsageOpt) (int64, error) + // Config descriptor for the image. + Config(ctx context.Context) (ocispec.Descriptor, error) + // IsUnpacked returns whether an image is unpacked. + IsUnpacked(context.Context, string) (bool, error) + // ContentStore provides a content store which contains image blob data + ContentStore() content.Store + // Metadata returns the underlying image metadata + Metadata() images.Image + // Platform returns the platform match comparer. Can be nil. + Platform() platforms.MatchComparer + // Spec returns the OCI image spec for a given image. + Spec(ctx context.Context) (ocispec.Image, error) +} + +type usageOptions struct { + manifestLimit *int + manifestOnly bool + snapshots bool +} + +// UsageOpt is used to configure the usage calculation +type UsageOpt func(*usageOptions) error + +// WithUsageManifestLimit sets the limit to the number of manifests which will +// be walked for usage. Setting this value to 0 will require all manifests to +// be walked, returning ErrNotFound if manifests are missing. +// NOTE: By default all manifests which exist will be walked +// and any non-existent manifests and their subobjects will be ignored. +func WithUsageManifestLimit(i int) UsageOpt { + // If 0 then don't filter any manifests + // By default limits to current platform + return func(o *usageOptions) error { + o.manifestLimit = &i + return nil + } +} + +// WithSnapshotUsage will check for referenced snapshots from the image objects +// and include the snapshot size in the total usage. +func WithSnapshotUsage() UsageOpt { + return func(o *usageOptions) error { + o.snapshots = true + return nil + } +} + +// WithManifestUsage is used to get the usage for an image based on what is +// reported by the manifests rather than what exists in the content store. +// NOTE: This function is best used with the manifest limit set to get a +// consistent value, otherwise non-existent manifests will be excluded. +func WithManifestUsage() UsageOpt { + return func(o *usageOptions) error { + o.manifestOnly = true + return nil + } +} + +var _ = (Image)(&image{}) + +// NewImage returns a client image object from the metadata image +func NewImage(client *Client, i images.Image) Image { + return &image{ + client: client, + i: i, + platform: client.platform, + } +} + +// NewImageWithPlatform returns a client image object from the metadata image +func NewImageWithPlatform(client *Client, i images.Image, platform platforms.MatchComparer) Image { + return &image{ + client: client, + i: i, + platform: platform, + } +} + +type image struct { + client *Client + + i images.Image + platform platforms.MatchComparer + diffIDs []digest.Digest + + mu sync.Mutex +} + +func (i *image) Metadata() images.Image { + return i.i +} + +func (i *image) Name() string { + return i.i.Name +} + +func (i *image) Target() ocispec.Descriptor { + return i.i.Target +} + +func (i *image) Labels() map[string]string { + return i.i.Labels +} + +func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) { + i.mu.Lock() + defer i.mu.Unlock() + if i.diffIDs != nil { + return i.diffIDs, nil + } + + provider := i.client.ContentStore() + diffIDs, err := i.i.RootFS(ctx, provider, i.platform) + if err != nil { + return nil, err + } + i.diffIDs = diffIDs + return diffIDs, nil +} + +func (i *image) Size(ctx context.Context) (int64, error) { + return usage.CalculateImageUsage(ctx, i.i, i.client.ContentStore(), usage.WithManifestLimit(i.platform, 1), usage.WithManifestUsage()) +} + +func (i *image) Usage(ctx context.Context, opts ...UsageOpt) (int64, error) { + var config usageOptions + for _, opt := range opts { + if err := opt(&config); err != nil { + return 0, err + } + } + + var usageOpts []usage.Opt + if config.manifestLimit != nil { + usageOpts = append(usageOpts, usage.WithManifestLimit(i.platform, *config.manifestLimit)) + } + if config.snapshots { + usageOpts = append(usageOpts, usage.WithSnapshotters(i.client.SnapshotService)) + } + if config.manifestOnly { + usageOpts = append(usageOpts, usage.WithManifestUsage()) + } + + return usage.CalculateImageUsage(ctx, i.i, i.client.ContentStore(), usageOpts...) +} + +func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { + provider := i.client.ContentStore() + return i.i.Config(ctx, provider, i.platform) +} + +func (i *image) IsUnpacked(ctx context.Context, snapshotterName string) (bool, error) { + sn, err := i.client.getSnapshotter(ctx, snapshotterName) + if err != nil { + return false, err + } + + diffs, err := i.RootFS(ctx) + if err != nil { + return false, err + } + + if _, err := sn.Stat(ctx, identity.ChainID(diffs).String()); err != nil { + if errdefs.IsNotFound(err) { + return false, nil + } + return false, err + } + + return true, nil +} + +func (i *image) Spec(ctx context.Context) (ocispec.Image, error) { + var ociImage ocispec.Image + + desc, err := i.Config(ctx) + if err != nil { + return ociImage, fmt.Errorf("get image config descriptor: %w", err) + } + + blob, err := content.ReadBlob(ctx, i.ContentStore(), desc) + if err != nil { + return ociImage, fmt.Errorf("read image config from content store: %w", err) + } + + if err := json.Unmarshal(blob, &ociImage); err != nil { + return ociImage, fmt.Errorf("unmarshal image config %s: %w", blob, err) + } + + return ociImage, nil +} + +// UnpackConfig provides configuration for the unpack of an image +type UnpackConfig struct { + // ApplyOpts for applying a diff to a snapshotter + ApplyOpts []diff.ApplyOpt + // SnapshotOpts for configuring a snapshotter + SnapshotOpts []snapshots.Opt + // CheckPlatformSupported is whether to validate that a snapshotter + // supports an image's platform before unpacking + CheckPlatformSupported bool + // DuplicationSuppressor is used to make sure that there is only one + // in-flight fetch request or unpack handler for a given descriptor's + // digest or chain ID. + DuplicationSuppressor kmutex.KeyedLocker +} + +// UnpackOpt provides configuration for unpack +type UnpackOpt func(context.Context, *UnpackConfig) error + +// WithSnapshotterPlatformCheck sets `CheckPlatformSupported` on the UnpackConfig +func WithSnapshotterPlatformCheck() UnpackOpt { + return func(ctx context.Context, uc *UnpackConfig) error { + uc.CheckPlatformSupported = true + return nil + } +} + +// WithUnpackDuplicationSuppressor sets `DuplicationSuppressor` on the UnpackConfig. +func WithUnpackDuplicationSuppressor(suppressor kmutex.KeyedLocker) UnpackOpt { + return func(ctx context.Context, uc *UnpackConfig) error { + uc.DuplicationSuppressor = suppressor + return nil + } +} + +// WithUnpackApplyOpts appends new apply options on the UnpackConfig. +func WithUnpackApplyOpts(opts ...diff.ApplyOpt) UnpackOpt { + return func(ctx context.Context, uc *UnpackConfig) error { + uc.ApplyOpts = append(uc.ApplyOpts, opts...) + return nil + } +} + +func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...UnpackOpt) error { + ctx, done, err := i.client.WithLease(ctx) + if err != nil { + return err + } + defer done(ctx) + + var config UnpackConfig + for _, o := range opts { + if err := o(ctx, &config); err != nil { + return err + } + } + + manifest, err := i.getManifest(ctx, i.platform) + if err != nil { + return err + } + + layers, err := i.getLayers(ctx, manifest) + if err != nil { + return err + } + + var ( + a = i.client.DiffService() + cs = i.client.ContentStore() + + chain []digest.Digest + unpacked bool + ) + snapshotterName, err = i.client.resolveSnapshotterName(ctx, snapshotterName) + if err != nil { + return err + } + sn, err := i.client.getSnapshotter(ctx, snapshotterName) + if err != nil { + return err + } + if config.CheckPlatformSupported { + if err := i.checkSnapshotterSupport(ctx, snapshotterName, manifest); err != nil { + return err + } + } + + for _, layer := range layers { + unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts) + if err != nil { + return fmt.Errorf("apply layer error for %q: %w", i.Name(), err) + } + + if unpacked { + // Set the uncompressed label after the uncompressed + // digest has been verified through apply. + cinfo := content.Info{ + Digest: layer.Blob.Digest, + Labels: map[string]string{ + labels.LabelUncompressed: layer.Diff.Digest.String(), + }, + } + if _, err := cs.Update(ctx, cinfo, "labels."+labels.LabelUncompressed); err != nil { + return err + } + } + + chain = append(chain, layer.Diff.Digest) + } + + desc, err := i.i.Config(ctx, cs, i.platform) + if err != nil { + return err + } + + rootFS := identity.ChainID(chain).String() + + cinfo := content.Info{ + Digest: desc.Digest, + Labels: map[string]string{ + fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootFS, + }, + } + + _, err = cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName)) + return err +} + +func (i *image) getManifest(ctx context.Context, platform platforms.MatchComparer) (ocispec.Manifest, error) { + cs := i.ContentStore() + manifest, err := images.Manifest(ctx, cs, i.i.Target, platform) + if err != nil { + return ocispec.Manifest{}, err + } + return manifest, nil +} + +func (i *image) getLayers(ctx context.Context, manifest ocispec.Manifest) ([]rootfs.Layer, error) { + diffIDs, err := i.RootFS(ctx) + if err != nil { + return nil, fmt.Errorf("failed to resolve rootfs: %w", err) + } + + // parse out the image layers from oci artifact layers + imageLayers := []ocispec.Descriptor{} + for _, ociLayer := range manifest.Layers { + if images.IsLayerType(ociLayer.MediaType) { + imageLayers = append(imageLayers, ociLayer) + } + } + if len(diffIDs) != len(imageLayers) { + return nil, errors.New("mismatched image rootfs and manifest layers") + } + layers := make([]rootfs.Layer, len(diffIDs)) + for i := range diffIDs { + layers[i].Diff = ocispec.Descriptor{ + // TODO: derive media type from compressed type + MediaType: ocispec.MediaTypeImageLayer, + Digest: diffIDs[i], + } + layers[i].Blob = imageLayers[i] + } + return layers, nil +} + +func (i *image) checkSnapshotterSupport(ctx context.Context, snapshotterName string, manifest ocispec.Manifest) error { + snapshotterPlatformMatcher, err := i.client.GetSnapshotterSupportedPlatforms(ctx, snapshotterName) + if err != nil { + return err + } + + manifestPlatform, err := images.ConfigPlatform(ctx, i.ContentStore(), manifest.Config) + if err != nil { + return err + } + + if snapshotterPlatformMatcher.Match(manifestPlatform) { + return nil + } + return fmt.Errorf("snapshotter %s does not support platform %s for image %s", snapshotterName, manifestPlatform, manifest.Config.Digest) +} + +func (i *image) ContentStore() content.Store { + return i.client.ContentStore() +} + +func (i *image) Platform() platforms.MatchComparer { + return i.platform +} diff --git a/client/image_store.go b/client/image_store.go new file mode 100644 index 000000000000..c52e99ea1ab7 --- /dev/null +++ b/client/image_store.go @@ -0,0 +1,150 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + + imagesapi "github.com/containerd/containerd/api/services/images/v1" + "github.com/containerd/errdefs/pkg/errgrpc" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/epoch" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/containerd/v2/pkg/protobuf" + ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types" +) + +type remoteImages struct { + client imagesapi.ImagesClient +} + +// NewImageStoreFromClient returns a new image store client +func NewImageStoreFromClient(client imagesapi.ImagesClient) images.Store { + return &remoteImages{ + client: client, + } +} + +func (s *remoteImages) Get(ctx context.Context, name string) (images.Image, error) { + resp, err := s.client.Get(ctx, &imagesapi.GetImageRequest{ + Name: name, + }) + if err != nil { + return images.Image{}, errgrpc.ToNative(err) + } + + return imageFromProto(resp.Image), nil +} + +func (s *remoteImages) List(ctx context.Context, filters ...string) ([]images.Image, error) { + resp, err := s.client.List(ctx, &imagesapi.ListImagesRequest{ + Filters: filters, + }) + if err != nil { + return nil, errgrpc.ToNative(err) + } + + return imagesFromProto(resp.Images), nil +} + +func (s *remoteImages) Create(ctx context.Context, image images.Image) (images.Image, error) { + req := &imagesapi.CreateImageRequest{ + Image: imageToProto(&image), + } + if tm := epoch.FromContext(ctx); tm != nil { + req.SourceDateEpoch = timestamppb.New(*tm) + } + created, err := s.client.Create(ctx, req) + if err != nil { + return images.Image{}, errgrpc.ToNative(err) + } + + return imageFromProto(created.Image), nil +} + +func (s *remoteImages) Update(ctx context.Context, image images.Image, fieldpaths ...string) (images.Image, error) { + var updateMask *ptypes.FieldMask + if len(fieldpaths) > 0 { + updateMask = &ptypes.FieldMask{ + Paths: fieldpaths, + } + } + req := &imagesapi.UpdateImageRequest{ + Image: imageToProto(&image), + UpdateMask: updateMask, + } + if tm := epoch.FromContext(ctx); tm != nil { + req.SourceDateEpoch = timestamppb.New(*tm) + } + updated, err := s.client.Update(ctx, req) + if err != nil { + return images.Image{}, errgrpc.ToNative(err) + } + + return imageFromProto(updated.Image), nil +} + +func (s *remoteImages) Delete(ctx context.Context, name string, opts ...images.DeleteOpt) error { + var do images.DeleteOptions + for _, opt := range opts { + if err := opt(ctx, &do); err != nil { + return err + } + } + req := &imagesapi.DeleteImageRequest{ + Name: name, + Sync: do.Synchronous, + } + if do.Target != nil { + req.Target = oci.DescriptorToProto(*do.Target) + } + _, err := s.client.Delete(ctx, req) + return errgrpc.ToNative(err) +} + +func imageToProto(image *images.Image) *imagesapi.Image { + return &imagesapi.Image{ + Name: image.Name, + Labels: image.Labels, + Target: oci.DescriptorToProto(image.Target), + CreatedAt: protobuf.ToTimestamp(image.CreatedAt), + UpdatedAt: protobuf.ToTimestamp(image.UpdatedAt), + } +} + +func imageFromProto(imagepb *imagesapi.Image) images.Image { + return images.Image{ + Name: imagepb.Name, + Labels: imagepb.Labels, + Target: oci.DescriptorFromProto(imagepb.Target), + CreatedAt: protobuf.FromTimestamp(imagepb.CreatedAt), + UpdatedAt: protobuf.FromTimestamp(imagepb.UpdatedAt), + } +} + +func imagesFromProto(imagespb []*imagesapi.Image) []images.Image { + var images []images.Image + + for _, image := range imagespb { + image := image + images = append(images, imageFromProto(image)) + } + + return images +} diff --git a/client/import.go b/client/import.go new file mode 100644 index 000000000000..65ae95e22d64 --- /dev/null +++ b/client/import.go @@ -0,0 +1,269 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "io" + + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/images/archive" + "github.com/containerd/errdefs" + "github.com/containerd/platforms" + digest "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +type importOpts struct { + indexName string + imageRefT func(string) string + dgstRefT func(digest.Digest) string + skipDgstRef func(string) bool + allPlatforms bool + platformMatcher platforms.MatchComparer + compress bool + discardLayers bool + skipMissing bool + imageLabels map[string]string +} + +// ImportOpt allows the caller to specify import specific options +type ImportOpt func(*importOpts) error + +// WithImageRefTranslator is used to translate the index reference +// to an image reference for the image store. +func WithImageRefTranslator(f func(string) string) ImportOpt { + return func(c *importOpts) error { + c.imageRefT = f + return nil + } +} + +// WithImageLabels are the image labels to apply to a new image +func WithImageLabels(labels map[string]string) ImportOpt { + return func(c *importOpts) error { + c.imageLabels = labels + return nil + } +} + +// WithDigestRef is used to create digest images for each +// manifest in the index. +func WithDigestRef(f func(digest.Digest) string) ImportOpt { + return func(c *importOpts) error { + c.dgstRefT = f + return nil + } +} + +// WithSkipDigestRef is used to specify when to skip applying +// WithDigestRef. The callback receives an image reference (or an empty +// string if not specified in the image). When the callback returns true, +// the skip occurs. +func WithSkipDigestRef(f func(string) bool) ImportOpt { + return func(c *importOpts) error { + c.skipDgstRef = f + return nil + } +} + +// WithIndexName creates a tag pointing to the imported index +func WithIndexName(name string) ImportOpt { + return func(c *importOpts) error { + c.indexName = name + return nil + } +} + +// WithAllPlatforms is used to import content for all platforms. +func WithAllPlatforms(allPlatforms bool) ImportOpt { + return func(c *importOpts) error { + c.allPlatforms = allPlatforms + return nil + } +} + +// WithImportPlatform is used to import content for specific platform. +func WithImportPlatform(platformMacher platforms.MatchComparer) ImportOpt { + return func(c *importOpts) error { + c.platformMatcher = platformMacher + return nil + } +} + +// WithImportCompression compresses uncompressed layers on import. +// This is used for import formats which do not include the manifest. +func WithImportCompression() ImportOpt { + return func(c *importOpts) error { + c.compress = true + return nil + } +} + +// WithDiscardUnpackedLayers allows the garbage collector to clean up +// layers from content store after unpacking. +func WithDiscardUnpackedLayers() ImportOpt { + return func(c *importOpts) error { + c.discardLayers = true + return nil + } +} + +// WithSkipMissing allows to import an archive which doesn't contain all the +// referenced blobs. +func WithSkipMissing() ImportOpt { + return func(c *importOpts) error { + c.skipMissing = true + return nil + } +} + +// Import imports an image from a Tar stream using reader. +// Caller needs to specify importer. Future version may use oci.v1 as the default. +// Note that unreferenced blobs may be imported to the content store as well. +func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt) ([]images.Image, error) { + var iopts importOpts + for _, o := range opts { + if err := o(&iopts); err != nil { + return nil, err + } + } + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + var aio []archive.ImportOpt + if iopts.compress { + aio = append(aio, archive.WithImportCompression()) + } + + index, err := archive.ImportIndex(ctx, c.ContentStore(), reader, aio...) + if err != nil { + return nil, err + } + + var ( + imgs []images.Image + cs = c.ContentStore() + is = c.ImageService() + ) + + if iopts.indexName != "" { + imgs = append(imgs, images.Image{ + Name: iopts.indexName, + Target: index, + }) + } + var platformMatcher = c.platform + if iopts.allPlatforms { + platformMatcher = platforms.All + } else if iopts.platformMatcher != nil { + platformMatcher = iopts.platformMatcher + } + + var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + // Only save images at top level + if desc.Digest != index.Digest { + // Don't set labels on missing content. + children, err := images.Children(ctx, cs, desc) + if iopts.skipMissing && errdefs.IsNotFound(err) { + return nil, images.ErrSkipDesc + } + return children, err + } + + idx, err := decodeIndex(ctx, cs, desc) + if err != nil { + return nil, err + } + + for _, m := range idx.Manifests { + name := imageName(m.Annotations, iopts.imageRefT) + if name != "" { + imgs = append(imgs, images.Image{ + Name: name, + Target: m, + }) + } + if iopts.skipDgstRef != nil { + if iopts.skipDgstRef(name) { + continue + } + } + if iopts.dgstRefT != nil { + ref := iopts.dgstRefT(m.Digest) + if ref != "" { + imgs = append(imgs, images.Image{ + Name: ref, + Target: m, + }) + } + } + } + + return idx.Manifests, nil + } + + handler = images.FilterPlatforms(handler, platformMatcher) + if iopts.discardLayers { + handler = images.SetChildrenMappedLabels(cs, handler, images.ChildGCLabelsFilterLayers) + } else { + handler = images.SetChildrenLabels(cs, handler) + } + if err := images.WalkNotEmpty(ctx, handler, index); err != nil { + return nil, err + } + + for i := range imgs { + fieldsPath := []string{"target"} + if iopts.imageLabels != nil { + fieldsPath = append(fieldsPath, "labels") + imgs[i].Labels = iopts.imageLabels + } + img, err := is.Update(ctx, imgs[i], fieldsPath...) + if err != nil { + if !errdefs.IsNotFound(err) { + return nil, err + } + + img, err = is.Create(ctx, imgs[i]) + if err != nil { + return nil, err + } + } + imgs[i] = img + } + + return imgs, nil +} + +func imageName(annotations map[string]string, ociCleanup func(string) string) string { + name := annotations[images.AnnotationImageName] + if name != "" { + return name + } + name = annotations[ocispec.AnnotationRefName] + if name != "" { + if ociCleanup != nil { + name = ociCleanup(name) + } + } + return name +} diff --git a/install.go b/client/install.go similarity index 90% rename from install.go rename to client/install.go index a307960b8c35..2f636b277cd9 100644 --- a/install.go +++ b/client/install.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client import ( "archive/tar" @@ -26,10 +26,10 @@ import ( "runtime" "strings" - "github.com/containerd/containerd/archive" - "github.com/containerd/containerd/archive/compression" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/images" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/archive" + "github.com/containerd/containerd/v2/pkg/archive/compression" ) // Install a binary image into the opt service. @@ -112,8 +112,7 @@ func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (stri if config.Path != "" { return config.Path, nil } - filters := []string{"id==opt"} - resp, err := c.IntrospectionService().Plugins(ctx, filters) + resp, err := c.IntrospectionService().Plugins(ctx, "id==opt") if err != nil { return "", err } diff --git a/install_opts.go b/client/install_opts.go similarity index 98% rename from install_opts.go rename to client/install_opts.go index b0c9213cb277..c42d910e8784 100644 --- a/install_opts.go +++ b/client/install_opts.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client // InstallOpts configures binary installs type InstallOpts func(*InstallConfig) diff --git a/client/lease.go b/client/lease.go new file mode 100644 index 000000000000..e0608a7c6c55 --- /dev/null +++ b/client/lease.go @@ -0,0 +1,54 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "time" + + "github.com/containerd/containerd/v2/core/leases" +) + +// WithLease attaches a lease on the context +func (c *Client) WithLease(ctx context.Context, opts ...leases.Opt) (context.Context, func(context.Context) error, error) { + nop := func(context.Context) error { return nil } + + _, ok := leases.FromContext(ctx) + if ok { + return ctx, nop, nil + } + + ls := c.LeasesService() + + if len(opts) == 0 { + // Use default lease configuration if no options provided + opts = []leases.Opt{ + leases.WithRandomID(), + leases.WithExpiration(24 * time.Hour), + } + } + + l, err := ls.Create(ctx, opts...) + if err != nil { + return ctx, nop, err + } + + ctx = leases.WithLease(ctx, l.ID) + return ctx, func(ctx context.Context) error { + return ls.Delete(ctx, l) + }, nil +} diff --git a/client/namespaces.go b/client/namespaces.go new file mode 100644 index 000000000000..ca93e80f62c6 --- /dev/null +++ b/client/namespaces.go @@ -0,0 +1,122 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "strings" + + api "github.com/containerd/containerd/api/services/namespaces/v1" + "github.com/containerd/errdefs/pkg/errgrpc" + + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/protobuf/types" +) + +// NewNamespaceStoreFromClient returns a new namespace store +func NewNamespaceStoreFromClient(client api.NamespacesClient) namespaces.Store { + return &remoteNamespaces{client: client} +} + +type remoteNamespaces struct { + client api.NamespacesClient +} + +func (r *remoteNamespaces) Create(ctx context.Context, namespace string, labels map[string]string) error { + var req api.CreateNamespaceRequest + + req.Namespace = &api.Namespace{ + Name: namespace, + Labels: labels, + } + + _, err := r.client.Create(ctx, &req) + if err != nil { + return errgrpc.ToNative(err) + } + + return nil +} + +func (r *remoteNamespaces) Labels(ctx context.Context, namespace string) (map[string]string, error) { + var req api.GetNamespaceRequest + req.Name = namespace + + resp, err := r.client.Get(ctx, &req) + if err != nil { + return nil, errgrpc.ToNative(err) + } + + return resp.Namespace.Labels, nil +} + +func (r *remoteNamespaces) SetLabel(ctx context.Context, namespace, key, value string) error { + var req api.UpdateNamespaceRequest + + req.Namespace = &api.Namespace{ + Name: namespace, + Labels: map[string]string{key: value}, + } + + req.UpdateMask = &types.FieldMask{ + Paths: []string{strings.Join([]string{"labels", key}, ".")}, + } + + _, err := r.client.Update(ctx, &req) + if err != nil { + return errgrpc.ToNative(err) + } + + return nil +} + +func (r *remoteNamespaces) List(ctx context.Context) ([]string, error) { + var req api.ListNamespacesRequest + + resp, err := r.client.List(ctx, &req) + if err != nil { + return nil, errgrpc.ToNative(err) + } + + var namespaces []string + + for _, ns := range resp.Namespaces { + namespaces = append(namespaces, ns.Name) + } + + return namespaces, nil +} + +func (r *remoteNamespaces) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error { + i := namespaces.DeleteInfo{ + Name: namespace, + } + for _, o := range opts { + if err := o(ctx, &i); err != nil { + return err + } + } + req := api.DeleteNamespaceRequest{ + Name: namespace, + } + _, err := r.client.Delete(ctx, &req) + if err != nil { + return errgrpc.ToNative(err) + } + + return nil +} diff --git a/oss_fuzz.go b/client/oss_fuzz.go similarity index 97% rename from oss_fuzz.go rename to client/oss_fuzz.go index 8d1def4f09c3..429592667d75 100644 --- a/oss_fuzz.go +++ b/client/oss_fuzz.go @@ -16,7 +16,7 @@ limitations under the License. */ -package containerd +package client import ( "github.com/AdamKorcz/go-118-fuzz-build/testing" diff --git a/client/process.go b/client/process.go new file mode 100644 index 000000000000..e451eaa7d169 --- /dev/null +++ b/client/process.go @@ -0,0 +1,280 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "fmt" + "strings" + "syscall" + "time" + + "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/protobuf" + "github.com/containerd/containerd/v2/pkg/tracing" +) + +// Process represents a system process +type Process interface { + // ID of the process + ID() string + // Pid is the system specific process id + Pid() uint32 + // Start starts the process executing the user's defined binary + Start(context.Context) error + // Delete removes the process and any resources allocated returning the exit status + Delete(context.Context, ...ProcessDeleteOpts) (*ExitStatus, error) + // Kill sends the provided signal to the process + Kill(context.Context, syscall.Signal, ...KillOpts) error + // Wait asynchronously waits for the process to exit, and sends the exit code to the returned channel + Wait(context.Context) (<-chan ExitStatus, error) + // CloseIO allows various pipes to be closed on the process + CloseIO(context.Context, ...IOCloserOpts) error + // Resize changes the width and height of the process's terminal + Resize(ctx context.Context, w, h uint32) error + // IO returns the io set for the process + IO() cio.IO + // Status returns the executing status of the process + Status(context.Context) (Status, error) +} + +// NewExitStatus populates an ExitStatus +func NewExitStatus(code uint32, t time.Time, err error) *ExitStatus { + return &ExitStatus{ + code: code, + exitedAt: t, + err: err, + } +} + +// ExitStatus encapsulates a process's exit status. +// It is used by `Wait()` to return either a process exit code or an error +type ExitStatus struct { + code uint32 + exitedAt time.Time + err error +} + +// Result returns the exit code and time of the exit status. +// An error may be returned here to which indicates there was an error +// +// at some point while waiting for the exit status. It does not signify +// an error with the process itself. +// +// If an error is returned, the process may still be running. +func (s ExitStatus) Result() (uint32, time.Time, error) { + return s.code, s.exitedAt, s.err +} + +// ExitCode returns the exit code of the process. +// This is only valid if Error() returns nil. +func (s ExitStatus) ExitCode() uint32 { + return s.code +} + +// ExitTime returns the exit time of the process +// This is only valid if Error() returns nil. +func (s ExitStatus) ExitTime() time.Time { + return s.exitedAt +} + +// Error returns the error, if any, that occurred while waiting for the +// process. +func (s ExitStatus) Error() error { + return s.err +} + +type process struct { + id string + task *task + pid uint32 + io cio.IO +} + +func (p *process) ID() string { + return p.id +} + +// Pid returns the pid of the process +// The pid is not set until start is called and returns +func (p *process) Pid() uint32 { + return p.pid +} + +// Start starts the exec process +func (p *process) Start(ctx context.Context) error { + ctx, span := tracing.StartSpan(ctx, "process.Start", + tracing.WithAttribute("process.id", p.ID()), + tracing.WithAttribute("process.task.id", p.task.ID()), + ) + defer span.End() + r, err := p.task.client.TaskService().Start(ctx, &tasks.StartRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + if p.io != nil { + p.io.Cancel() + p.io.Wait() + p.io.Close() + } + return errgrpc.ToNative(err) + } + span.SetAttributes(tracing.Attribute("process.pid", int(r.Pid))) + p.pid = r.Pid + return nil +} + +func (p *process) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error { + ctx, span := tracing.StartSpan(ctx, "process.Kill", + tracing.WithAttribute("process.id", p.ID()), + tracing.WithAttribute("process.pid", int(p.Pid())), + tracing.WithAttribute("process.task.id", p.task.ID()), + ) + defer span.End() + var i KillInfo + for _, o := range opts { + if err := o(ctx, &i); err != nil { + return err + } + } + _, err := p.task.client.TaskService().Kill(ctx, &tasks.KillRequest{ + Signal: uint32(s), + ContainerID: p.task.id, + ExecID: p.id, + All: i.All, + }) + return errgrpc.ToNative(err) +} + +func (p *process) Wait(ctx context.Context) (<-chan ExitStatus, error) { + c := make(chan ExitStatus, 1) + go func() { + defer close(c) + ctx, span := tracing.StartSpan(ctx, "process.Wait", + tracing.WithAttribute("process.id", p.ID()), + tracing.WithAttribute("process.task.id", p.task.ID()), + ) + defer span.End() + r, err := p.task.client.TaskService().Wait(ctx, &tasks.WaitRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + c <- ExitStatus{ + code: UnknownExitStatus, + err: err, + } + return + } + c <- ExitStatus{ + code: r.ExitStatus, + exitedAt: protobuf.FromTimestamp(r.ExitedAt), + } + }() + return c, nil +} + +func (p *process) CloseIO(ctx context.Context, opts ...IOCloserOpts) error { + ctx, span := tracing.StartSpan(ctx, "process.CloseIO", + tracing.WithAttribute("process.id", p.ID()), + ) + defer span.End() + r := &tasks.CloseIORequest{ + ContainerID: p.task.id, + ExecID: p.id, + } + var i IOCloseInfo + for _, o := range opts { + o(&i) + } + r.Stdin = i.Stdin + _, err := p.task.client.TaskService().CloseIO(ctx, r) + return errgrpc.ToNative(err) +} + +func (p *process) IO() cio.IO { + return p.io +} + +func (p *process) Resize(ctx context.Context, w, h uint32) error { + ctx, span := tracing.StartSpan(ctx, "process.Resize", + tracing.WithAttribute("process.id", p.ID()), + ) + defer span.End() + _, err := p.task.client.TaskService().ResizePty(ctx, &tasks.ResizePtyRequest{ + ContainerID: p.task.id, + Width: w, + Height: h, + ExecID: p.id, + }) + return errgrpc.ToNative(err) +} + +func (p *process) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) { + ctx, span := tracing.StartSpan(ctx, "process.Delete", + tracing.WithAttribute("process.id", p.ID()), + ) + defer span.End() + for _, o := range opts { + if err := o(ctx, p); err != nil { + return nil, err + } + } + status, err := p.Status(ctx) + if err != nil { + return nil, err + } + switch status.Status { + case Running, Paused, Pausing: + return nil, fmt.Errorf("current process state: %s, process must be stopped before deletion: %w", status.Status, errdefs.ErrFailedPrecondition) + } + r, err := p.task.client.TaskService().DeleteProcess(ctx, &tasks.DeleteProcessRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + return nil, errgrpc.ToNative(err) + } + if p.io != nil { + p.io.Cancel() + p.io.Wait() + p.io.Close() + } + return &ExitStatus{code: r.ExitStatus, exitedAt: protobuf.FromTimestamp(r.ExitedAt)}, nil +} + +func (p *process) Status(ctx context.Context) (Status, error) { + r, err := p.task.client.TaskService().Get(ctx, &tasks.GetRequest{ + ContainerID: p.task.id, + ExecID: p.id, + }) + if err != nil { + return Status{}, errgrpc.ToNative(err) + } + status := ProcessStatus(strings.ToLower(r.Process.Status.String())) + exitStatus := r.Process.ExitStatus + + return Status{ + Status: status, + ExitStatus: exitStatus, + }, nil +} diff --git a/client/pull.go b/client/pull.go new file mode 100644 index 000000000000..060c729dfea1 --- /dev/null +++ b/client/pull.go @@ -0,0 +1,320 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "errors" + "fmt" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/sync/semaphore" + + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/remotes" + "github.com/containerd/containerd/v2/core/remotes/docker" + "github.com/containerd/containerd/v2/core/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. + "github.com/containerd/containerd/v2/core/unpack" + "github.com/containerd/containerd/v2/pkg/tracing" + "github.com/containerd/errdefs" + "github.com/containerd/platforms" +) + +const ( + pullSpanPrefix = "pull" +) + +// Pull downloads the provided content into containerd's content store +// and returns a platform specific image object +func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (_ Image, retErr error) { + ctx, span := tracing.StartSpan(ctx, tracing.Name(pullSpanPrefix, "Pull")) + defer span.End() + + pullCtx := defaultRemoteContext() + + for _, o := range opts { + if err := o(c, pullCtx); err != nil { + return nil, err + } + } + + if pullCtx.PlatformMatcher == nil { + if len(pullCtx.Platforms) > 1 { + return nil, errors.New("cannot pull multiplatform image locally, try Fetch") + } else if len(pullCtx.Platforms) == 0 { + pullCtx.PlatformMatcher = c.platform + } else { + p, err := platforms.Parse(pullCtx.Platforms[0]) + if err != nil { + return nil, fmt.Errorf("invalid platform %s: %w", pullCtx.Platforms[0], err) + } + + pullCtx.PlatformMatcher = platforms.Only(p) + } + } + + span.SetAttributes( + tracing.Attribute("image.ref", ref), + tracing.Attribute("unpack", pullCtx.Unpack), + tracing.Attribute("max.concurrent.downloads", pullCtx.MaxConcurrentDownloads), + tracing.Attribute("platforms.count", len(pullCtx.Platforms)), + ) + + ctx, done, err := c.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + + var unpacker *unpack.Unpacker + + if pullCtx.Unpack { + snapshotterName, err := c.resolveSnapshotterName(ctx, pullCtx.Snapshotter) + if err != nil { + return nil, fmt.Errorf("unable to resolve snapshotter: %w", err) + } + span.SetAttributes(tracing.Attribute("snapshotter.name", snapshotterName)) + var uconfig UnpackConfig + for _, opt := range pullCtx.UnpackOpts { + if err := opt(ctx, &uconfig); err != nil { + return nil, err + } + } + var platformMatcher platforms.Matcher + if !uconfig.CheckPlatformSupported { + platformMatcher = platforms.All + } + + // Check client Unpack config + platform := unpack.Platform{ + Platform: platformMatcher, + SnapshotterKey: snapshotterName, + Snapshotter: c.SnapshotService(snapshotterName), + SnapshotOpts: append(pullCtx.SnapshotterOpts, uconfig.SnapshotOpts...), + Applier: c.DiffService(), + ApplyOpts: uconfig.ApplyOpts, + } + uopts := []unpack.UnpackerOpt{unpack.WithUnpackPlatform(platform)} + if pullCtx.MaxConcurrentDownloads > 0 { + uopts = append(uopts, unpack.WithLimiter(semaphore.NewWeighted(int64(pullCtx.MaxConcurrentDownloads)))) + } + if uconfig.DuplicationSuppressor != nil { + uopts = append(uopts, unpack.WithDuplicationSuppressor(uconfig.DuplicationSuppressor)) + } + unpacker, err = unpack.NewUnpacker(ctx, c.ContentStore(), uopts...) + if err != nil { + return nil, fmt.Errorf("unable to initialize unpacker: %w", err) + } + defer func() { + if _, err := unpacker.Wait(); err != nil { + if retErr == nil { + retErr = fmt.Errorf("unpack: %w", err) + } + } + }() + wrapper := pullCtx.HandlerWrapper + pullCtx.HandlerWrapper = func(h images.Handler) images.Handler { + if wrapper == nil { + return unpacker.Unpack(h) + } + return unpacker.Unpack(wrapper(h)) + } + } + + img, err := c.fetch(ctx, pullCtx, ref, 1) + if err != nil { + return nil, err + } + + // NOTE(fuweid): unpacker defers blobs download. before create image + // record in ImageService, should wait for unpacking(including blobs + // download). + var ur unpack.Result + if unpacker != nil { + _, unpackSpan := tracing.StartSpan(ctx, tracing.Name(pullSpanPrefix, "UnpackWait")) + if ur, err = unpacker.Wait(); err != nil { + unpackSpan.SetStatus(err) + unpackSpan.End() + return nil, err + } + unpackSpan.End() + } + + img, err = c.createNewImage(ctx, img) + if err != nil { + return nil, err + } + + i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher) + span.SetAttributes(tracing.Attribute("image.ref", i.Name())) + + if unpacker != nil && ur.Unpacks == 0 { + // Unpack was tried previously but nothing was unpacked + // This is at least required for schema 1 image. + if err := i.Unpack(ctx, pullCtx.Snapshotter, pullCtx.UnpackOpts...); err != nil { + return nil, fmt.Errorf("failed to unpack image on snapshotter %s: %w", pullCtx.Snapshotter, err) + } + } + + return i, nil +} + +func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) { + ctx, span := tracing.StartSpan(ctx, tracing.Name(pullSpanPrefix, "fetch")) + defer span.End() + store := c.ContentStore() + name, desc, err := rCtx.Resolver.Resolve(ctx, ref) + if err != nil { + return images.Image{}, fmt.Errorf("failed to resolve reference %q: %w", ref, err) + } + + fetcher, err := rCtx.Resolver.Fetcher(ctx, name) + if err != nil { + return images.Image{}, fmt.Errorf("failed to get fetcher for %q: %w", name, err) + } + + var ( + handler images.Handler + + isConvertible bool + originalSchema1Digest string + converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error) + limiter *semaphore.Weighted + ) + + if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 { + schema1Converter, err := schema1.NewConverter(store, fetcher) + if err != nil { + return images.Image{}, fmt.Errorf("failed to get converter for %q: %w", ref, err) + } + + handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...) + + isConvertible = true + + converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) { + return schema1Converter.Convert(ctx) + } + + originalSchema1Digest = desc.Digest.String() + } else { + // Get all the children for a descriptor + childrenHandler := images.ChildrenHandler(store) + // Set any children labels for that content + childrenHandler = images.SetChildrenMappedLabels(store, childrenHandler, rCtx.ChildLabelMap) + if rCtx.AllMetadata { + // Filter manifests by platforms but allow to handle manifest + // and configuration for not-target platforms + childrenHandler = remotes.FilterManifestByPlatformHandler(childrenHandler, rCtx.PlatformMatcher) + } else { + // Filter children by platforms if specified. + childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher) + } + // Sort and limit manifests if a finite number is needed + if limit > 0 { + childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) + } + + // set isConvertible to true if there is application/octet-stream media type + convertibleHandler := images.HandlerFunc( + func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + if desc.MediaType == docker.LegacyConfigMediaType { + isConvertible = true + } + + return []ocispec.Descriptor{}, nil + }, + ) + + appendDistSrcLabelHandler, err := docker.AppendDistributionSourceLabel(store, ref) + if err != nil { + return images.Image{}, err + } + + handlers := append(rCtx.BaseHandlers, + remotes.FetchHandler(store, fetcher), + convertibleHandler, + childrenHandler, + appendDistSrcLabelHandler, + ) + + handler = images.Handlers(handlers...) + + converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) { + return docker.ConvertManifest(ctx, store, desc) + } + } + + if rCtx.HandlerWrapper != nil { + handler = rCtx.HandlerWrapper(handler) + } + + if rCtx.MaxConcurrentDownloads > 0 { + limiter = semaphore.NewWeighted(int64(rCtx.MaxConcurrentDownloads)) + } + + if err := images.Dispatch(ctx, handler, limiter, desc); err != nil { + return images.Image{}, err + } + + if isConvertible { + if desc, err = converterFunc(ctx, desc); err != nil { + return images.Image{}, err + } + } + + if originalSchema1Digest != "" { + if rCtx.Labels == nil { + rCtx.Labels = make(map[string]string) + } + rCtx.Labels[images.ConvertedDockerSchema1LabelKey] = originalSchema1Digest + } + + return images.Image{ + Name: name, + Target: desc, + Labels: rCtx.Labels, + }, nil +} + +func (c *Client) createNewImage(ctx context.Context, img images.Image) (images.Image, error) { + ctx, span := tracing.StartSpan(ctx, tracing.Name(pullSpanPrefix, "pull.createNewImage")) + defer span.End() + is := c.ImageService() + for { + if created, err := is.Create(ctx, img); err != nil { + if !errdefs.IsAlreadyExists(err) { + return images.Image{}, err + } + + updated, err := is.Update(ctx, img) + if err != nil { + // if image was removed, try create again + if errdefs.IsNotFound(err) { + continue + } + return images.Image{}, err + } + + img = updated + } else { + img = created + } + + return img, nil + } +} diff --git a/client/sandbox.go b/client/sandbox.go new file mode 100644 index 000000000000..335debe226ef --- /dev/null +++ b/client/sandbox.go @@ -0,0 +1,236 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/containerd/errdefs" + "github.com/containerd/typeurl/v2" + + "github.com/containerd/containerd/v2/core/containers" + api "github.com/containerd/containerd/v2/core/sandbox" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/containerd/v2/pkg/protobuf/types" +) + +// Sandbox is a high level client to containerd's sandboxes. +type Sandbox interface { + // ID is a sandbox identifier + ID() string + // Metadata returns metadata of the sandbox + Metadata() api.Sandbox + // NewContainer creates new container that will belong to this sandbox + NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) + // Labels returns the labels set on the sandbox + Labels(ctx context.Context) (map[string]string, error) + // Start starts new sandbox instance + Start(ctx context.Context) error + // Stop sends stop request to the shim instance. + Stop(ctx context.Context) error + // Wait blocks until sandbox process exits. + Wait(ctx context.Context) (<-chan ExitStatus, error) + // Shutdown removes sandbox from the metadata store and shutdowns shim instance. + Shutdown(ctx context.Context) error +} + +type sandboxClient struct { + client *Client + metadata api.Sandbox +} + +func (s *sandboxClient) ID() string { + return s.metadata.ID +} + +func (s *sandboxClient) Metadata() api.Sandbox { + return s.metadata +} + +func (s *sandboxClient) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) { + return s.client.NewContainer(ctx, id, append(opts, WithSandbox(s.ID()))...) +} + +func (s *sandboxClient) Labels(ctx context.Context) (map[string]string, error) { + sandbox, err := s.client.SandboxStore().Get(ctx, s.ID()) + if err != nil { + return nil, err + } + + return sandbox.Labels, nil +} + +func (s *sandboxClient) Start(ctx context.Context) error { + _, err := s.client.SandboxController(s.metadata.Sandboxer).Start(ctx, s.ID()) + if err != nil { + return err + } + + return nil +} + +func (s *sandboxClient) Wait(ctx context.Context) (<-chan ExitStatus, error) { + c := make(chan ExitStatus, 1) + go func() { + defer close(c) + + exitStatus, err := s.client.SandboxController(s.metadata.Sandboxer).Wait(ctx, s.ID()) + if err != nil { + c <- ExitStatus{ + code: UnknownExitStatus, + err: err, + } + return + } + + c <- ExitStatus{ + code: exitStatus.ExitStatus, + exitedAt: exitStatus.ExitedAt, + } + }() + + return c, nil +} + +func (s *sandboxClient) Stop(ctx context.Context) error { + return s.client.SandboxController(s.metadata.Sandboxer).Stop(ctx, s.ID()) +} + +func (s *sandboxClient) Shutdown(ctx context.Context) error { + if err := s.client.SandboxController(s.metadata.Sandboxer).Shutdown(ctx, s.ID()); err != nil && errdefs.IsNotFound(err) { + return fmt.Errorf("failed to shutdown sandbox: %w", err) + } + + if err := s.client.SandboxStore().Delete(ctx, s.ID()); err != nil && !errdefs.IsNotFound(err) { + return fmt.Errorf("failed to delete sandbox from store: %w", err) + } + + return nil +} + +// NewSandbox creates new sandbox client +func (c *Client) NewSandbox(ctx context.Context, sandboxID string, opts ...NewSandboxOpts) (Sandbox, error) { + if sandboxID == "" { + return nil, errors.New("sandbox ID must be specified") + } + + newSandbox := api.Sandbox{ + ID: sandboxID, + CreatedAt: time.Now().UTC(), + UpdatedAt: time.Now().UTC(), + } + + for _, opt := range opts { + if err := opt(ctx, c, &newSandbox); err != nil { + return nil, err + } + } + + metadata, err := c.SandboxStore().Create(ctx, newSandbox) + if err != nil { + return nil, err + } + + return &sandboxClient{ + client: c, + metadata: metadata, + }, nil +} + +// LoadSandbox laods existing sandbox metadata object using the id +func (c *Client) LoadSandbox(ctx context.Context, id string) (Sandbox, error) { + sandbox, err := c.SandboxStore().Get(ctx, id) + if err != nil { + return nil, err + } + + return &sandboxClient{ + client: c, + metadata: sandbox, + }, nil +} + +// NewSandboxOpts is a sandbox options and extensions to be provided by client +type NewSandboxOpts func(ctx context.Context, client *Client, sandbox *api.Sandbox) error + +// WithSandboxRuntime allows a user to specify the runtime to be used to run a sandbox +func WithSandboxRuntime(name string, options interface{}) NewSandboxOpts { + return func(ctx context.Context, client *Client, s *api.Sandbox) error { + if options == nil { + options = &types.Empty{} + } + + opts, err := typeurl.MarshalAny(options) + if err != nil { + return fmt.Errorf("failed to marshal sandbox runtime options: %w", err) + } + + s.Runtime = api.RuntimeOpts{ + Name: name, + Options: opts, + } + + return nil + } +} + +// WithSandboxSpec will provide the sandbox runtime spec +func WithSandboxSpec(s *oci.Spec, opts ...oci.SpecOpts) NewSandboxOpts { + return func(ctx context.Context, client *Client, sandbox *api.Sandbox) error { + c := &containers.Container{ID: sandbox.ID} + + if err := oci.ApplyOpts(ctx, client, c, s, opts...); err != nil { + return err + } + + spec, err := typeurl.MarshalAny(s) + if err != nil { + return fmt.Errorf("failed to marshal spec: %w", err) + } + + sandbox.Spec = spec + return nil + } +} + +// WithSandboxExtension attaches an extension to sandbox +func WithSandboxExtension(name string, extension interface{}) NewSandboxOpts { + return func(ctx context.Context, client *Client, s *api.Sandbox) error { + if s.Extensions == nil { + s.Extensions = make(map[string]typeurl.Any) + } + + ext, err := typeurl.MarshalAny(extension) + if err != nil { + return fmt.Errorf("failed to marshal sandbox extension: %w", err) + } + + s.Extensions[name] = ext + return nil + } +} + +// WithSandboxLabels attaches map of labels to sandbox +func WithSandboxLabels(labels map[string]string) NewSandboxOpts { + return func(ctx context.Context, client *Client, sandbox *api.Sandbox) error { + sandbox.Labels = labels + return nil + } +} diff --git a/client/services.go b/client/services.go new file mode 100644 index 000000000000..d2e69a1cee77 --- /dev/null +++ b/client/services.go @@ -0,0 +1,232 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "fmt" + + containersapi "github.com/containerd/containerd/api/services/containers/v1" + "github.com/containerd/containerd/api/services/diff/v1" + imagesapi "github.com/containerd/containerd/api/services/images/v1" + namespacesapi "github.com/containerd/containerd/api/services/namespaces/v1" + "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/introspection" + "github.com/containerd/containerd/v2/core/leases" + "github.com/containerd/containerd/v2/core/sandbox" + "github.com/containerd/containerd/v2/core/snapshots" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/plugins" + srv "github.com/containerd/containerd/v2/plugins/services" + "github.com/containerd/plugin" +) + +type services struct { + contentStore content.Store + imageStore images.Store + containerStore containers.Store + namespaceStore namespaces.Store + snapshotters map[string]snapshots.Snapshotter + taskService tasks.TasksClient + diffService DiffService + eventService EventService + leasesService leases.Manager + introspectionService introspection.Service + sandboxStore sandbox.Store + sandboxers map[string]sandbox.Controller +} + +// ServicesOpt allows callers to set options on the services +type ServicesOpt func(c *services) + +// WithContentStore sets the content store. +func WithContentStore(contentStore content.Store) ServicesOpt { + return func(s *services) { + s.contentStore = contentStore + } +} + +// WithImageClient sets the image service to use using an images client. +func WithImageClient(imageService imagesapi.ImagesClient) ServicesOpt { + return func(s *services) { + s.imageStore = NewImageStoreFromClient(imageService) + } +} + +// WithImageStore sets the image store. +func WithImageStore(imageStore images.Store) ServicesOpt { + return func(s *services) { + s.imageStore = imageStore + } +} + +// WithSnapshotters sets the snapshotters. +func WithSnapshotters(snapshotters map[string]snapshots.Snapshotter) ServicesOpt { + return func(s *services) { + s.snapshotters = make(map[string]snapshots.Snapshotter) + for n, sn := range snapshotters { + s.snapshotters[n] = sn + } + } +} + +// WithContainerClient sets the container service to use using a containers client. +func WithContainerClient(containerService containersapi.ContainersClient) ServicesOpt { + return func(s *services) { + s.containerStore = NewRemoteContainerStore(containerService) + } +} + +// WithContainerStore sets the container store. +func WithContainerStore(containerStore containers.Store) ServicesOpt { + return func(s *services) { + s.containerStore = containerStore + } +} + +// WithTaskClient sets the task service to use from a tasks client. +func WithTaskClient(taskService tasks.TasksClient) ServicesOpt { + return func(s *services) { + s.taskService = taskService + } +} + +// WithDiffClient sets the diff service to use from a diff client. +func WithDiffClient(diffService diff.DiffClient) ServicesOpt { + return func(s *services) { + s.diffService = NewDiffServiceFromClient(diffService) + } +} + +// WithDiffService sets the diff store. +func WithDiffService(diffService DiffService) ServicesOpt { + return func(s *services) { + s.diffService = diffService + } +} + +// WithEventService sets the event service. +func WithEventService(eventService EventService) ServicesOpt { + return func(s *services) { + s.eventService = eventService + } +} + +// WithNamespaceClient sets the namespace service using a namespaces client. +func WithNamespaceClient(namespaceService namespacesapi.NamespacesClient) ServicesOpt { + return func(s *services) { + s.namespaceStore = NewNamespaceStoreFromClient(namespaceService) + } +} + +// WithNamespaceService sets the namespace service. +func WithNamespaceService(namespaceService namespaces.Store) ServicesOpt { + return func(s *services) { + s.namespaceStore = namespaceService + } +} + +// WithLeasesService sets the lease service. +func WithLeasesService(leasesService leases.Manager) ServicesOpt { + return func(s *services) { + s.leasesService = leasesService + } +} + +// WithIntrospectionService sets the introspection service. +func WithIntrospectionService(in introspection.Service) ServicesOpt { + return func(s *services) { + s.introspectionService = in + } +} + +// WithSandboxStore sets the sandbox store. +func WithSandboxStore(client sandbox.Store) ServicesOpt { + return func(s *services) { + s.sandboxStore = client + } +} + +// WithInMemoryServices is suitable for cases when there is need to use containerd's client from +// another (in-memory) containerd plugin (such as CRI). +func WithInMemoryServices(ic *plugin.InitContext) Opt { + return func(c *clientOpts) error { + var opts []ServicesOpt + for t, fn := range map[plugin.Type]func(interface{}) ServicesOpt{ + plugins.EventPlugin: func(i interface{}) ServicesOpt { + return WithEventService(i.(EventService)) + }, + plugins.LeasePlugin: func(i interface{}) ServicesOpt { + return WithLeasesService(i.(leases.Manager)) + }, + plugins.SandboxStorePlugin: func(i interface{}) ServicesOpt { + return WithSandboxStore(i.(sandbox.Store)) + }, + } { + i, err := ic.GetSingle(t) + if err != nil { + return fmt.Errorf("failed to get %q plugin: %w", t, err) + } + opts = append(opts, fn(i)) + } + + plugins, err := ic.GetByType(plugins.ServicePlugin) + if err != nil { + return fmt.Errorf("failed to get service plugin: %w", err) + } + for s, fn := range map[string]func(interface{}) ServicesOpt{ + srv.ContentService: func(s interface{}) ServicesOpt { + return WithContentStore(s.(content.Store)) + }, + srv.ImagesService: func(s interface{}) ServicesOpt { + return WithImageClient(s.(imagesapi.ImagesClient)) + }, + srv.SnapshotsService: func(s interface{}) ServicesOpt { + return WithSnapshotters(s.(map[string]snapshots.Snapshotter)) + }, + srv.ContainersService: func(s interface{}) ServicesOpt { + return WithContainerClient(s.(containersapi.ContainersClient)) + }, + srv.TasksService: func(s interface{}) ServicesOpt { + return WithTaskClient(s.(tasks.TasksClient)) + }, + srv.DiffService: func(s interface{}) ServicesOpt { + return WithDiffClient(s.(diff.DiffClient)) + }, + srv.NamespacesService: func(s interface{}) ServicesOpt { + return WithNamespaceClient(s.(namespacesapi.NamespacesClient)) + }, + srv.IntrospectionService: func(s interface{}) ServicesOpt { + return WithIntrospectionService(s.(introspection.Service)) + }, + } { + i := plugins[s] + if i == nil { + return fmt.Errorf("service %q not found", s) + } + opts = append(opts, fn(i)) + } + + c.services = &services{} + for _, o := range opts { + o(c.services) + } + return nil + } +} diff --git a/client/signals.go b/client/signals.go new file mode 100644 index 000000000000..9488b22996f3 --- /dev/null +++ b/client/signals.go @@ -0,0 +1,83 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "encoding/json" + "fmt" + "syscall" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images" + "github.com/moby/sys/signal" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +// StopSignalLabel is a well-known containerd label for storing the stop +// signal specified in the OCI image config +const StopSignalLabel = "io.containerd.image.config.stop-signal" + +// GetStopSignal retrieves the container stop signal, specified by the +// well-known containerd label (StopSignalLabel) +func GetStopSignal(ctx context.Context, container Container, defaultSignal syscall.Signal) (syscall.Signal, error) { + labels, err := container.Labels(ctx) + if err != nil { + return -1, err + } + + if stopSignal, ok := labels[StopSignalLabel]; ok { + return signal.ParseSignal(stopSignal) + } + + return defaultSignal, nil +} + +// GetOCIStopSignal retrieves the stop signal specified in the OCI image config +func GetOCIStopSignal(ctx context.Context, image Image, defaultSignal string) (string, error) { + _, err := signal.ParseSignal(defaultSignal) + if err != nil { + return "", err + } + ic, err := image.Config(ctx) + if err != nil { + return "", err + } + if !images.IsConfigType(ic.MediaType) { + return "", fmt.Errorf("unknown image config media type %s", ic.MediaType) + } + + var ( + ociimage v1.Image + config v1.ImageConfig + ) + p, err := content.ReadBlob(ctx, image.ContentStore(), ic) + if err != nil { + return "", err + } + + if err = json.Unmarshal(p, &ociimage); err != nil { + return "", err + } + config = ociimage.Config + + if config.StopSignal == "" { + return defaultSignal, nil + } + + return config.StopSignal, nil +} diff --git a/client/snapshotter_opts_unix.go b/client/snapshotter_opts_unix.go new file mode 100644 index 000000000000..5984b2176dbd --- /dev/null +++ b/client/snapshotter_opts_unix.go @@ -0,0 +1,159 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "encoding/json" + "fmt" + "slices" + + "github.com/containerd/containerd/v2/core/snapshots" + "github.com/containerd/containerd/v2/internal/userns" + "github.com/opencontainers/go-digest" + "github.com/opencontainers/runtime-spec/specs-go" +) + +const ( + capaRemapIDs = "remap-ids" + capaOnlyRemapIDs = "only-remap-ids" +) + +// WithRemapperLabels creates the labels used by any supporting snapshotter +// to shift the filesystem ownership (user namespace mapping) automatically; currently +// supported by the fuse-overlayfs and overlay snapshotters +func WithRemapperLabels(ctrUID, hostUID, ctrGID, hostGID, length uint32) snapshots.Opt { + return snapshots.WithLabels(map[string]string{ + snapshots.LabelSnapshotUIDMapping: fmt.Sprintf("%d:%d:%d", ctrUID, hostUID, length), + snapshots.LabelSnapshotGIDMapping: fmt.Sprintf("%d:%d:%d", ctrGID, hostGID, length)}) +} + +func resolveSnapshotOptions(ctx context.Context, client *Client, snapshotterName string, snapshotter snapshots.Snapshotter, parent string, opts ...snapshots.Opt) (string, error) { + capabs, err := client.GetSnapshotterCapabilities(ctx, snapshotterName) + if err != nil { + return "", err + } + + for _, capab := range capabs { + if capab == capaRemapIDs { + // Snapshotter supports ID remapping, we don't need to do anything. + return parent, nil + } + } + + var local snapshots.Info + for _, opt := range opts { + opt(&local) + } + + needsRemap := false + var uidMapLabel, gidMapLabel string + + if value, ok := local.Labels[snapshots.LabelSnapshotUIDMapping]; ok { + needsRemap = true + uidMapLabel = value + } + if value, ok := local.Labels[snapshots.LabelSnapshotGIDMapping]; ok { + needsRemap = true + gidMapLabel = value + } + + if !needsRemap { + return parent, nil + } + + capaOnlyRemap := false + for _, capa := range capabs { + if capa == capaOnlyRemapIDs { + capaOnlyRemap = true + } + } + + if capaOnlyRemap { + return "", fmt.Errorf("snapshotter %q doesn't support idmap mounts on this host, configure `slow_chown` to allow a slower and expensive fallback", snapshotterName) + } + + var uidMap, gidMap specs.LinuxIDMapping + _, err = fmt.Sscanf(uidMapLabel, "%d:%d:%d", &uidMap.ContainerID, &uidMap.HostID, &uidMap.Size) + if err != nil { + return "", fmt.Errorf("uidMapLabel unparsable: %w", err) + } + _, err = fmt.Sscanf(gidMapLabel, "%d:%d:%d", &gidMap.ContainerID, &gidMap.HostID, &gidMap.Size) + if err != nil { + return "", fmt.Errorf("gidMapLabel unparsable: %w", err) + } + + if uidMap.ContainerID != 0 || gidMap.ContainerID != 0 { + return "", fmt.Errorf("Container UID/GID of 0 only supported currently (%d/%d)", uidMap.ContainerID, gidMap.ContainerID) + } + + rsn := remappedSnapshot{ + Parent: parent, + IDMap: userns.IDMap{ + UidMap: []specs.LinuxIDMapping{uidMap}, + GidMap: []specs.LinuxIDMapping{gidMap}, + }, + } + usernsID, err := rsn.ID() + if err != nil { + return "", fmt.Errorf("failed to remap snapshot: %w", err) + } + + if _, err := snapshotter.Stat(ctx, usernsID); err == nil { + return usernsID, nil + } + mounts, err := snapshotter.Prepare(ctx, usernsID+"-remap", parent) + if err != nil { + return "", err + } + + if err := remapRootFS(ctx, mounts, rsn.IDMap); err != nil { + snapshotter.Remove(ctx, usernsID+"-remap") + return "", err + } + if err := snapshotter.Commit(ctx, usernsID, usernsID+"-remap"); err != nil { + return "", err + } + + return usernsID, nil +} + +type remappedSnapshot struct { + Parent string `json:"Parent"` + IDMap userns.IDMap `json:"IDMap"` +} + +func (s *remappedSnapshot) ID() (string, error) { + compare := func(a, b specs.LinuxIDMapping) int { + if a.ContainerID < b.ContainerID { + return -1 + } else if a.ContainerID == b.ContainerID { + return 0 + } + return 1 + } + slices.SortStableFunc(s.IDMap.UidMap, compare) + slices.SortStableFunc(s.IDMap.GidMap, compare) + + buf, err := json.Marshal(s) + if err != nil { + return "", err + } + return digest.FromBytes(buf).String(), nil +} diff --git a/snapshotter_opts_windows.go b/client/snapshotter_opts_windows.go similarity index 92% rename from snapshotter_opts_windows.go rename to client/snapshotter_opts_windows.go index 540bcb3130ab..ab78663c5157 100644 --- a/snapshotter_opts_windows.go +++ b/client/snapshotter_opts_windows.go @@ -14,12 +14,12 @@ limitations under the License. */ -package containerd +package client import ( "context" - "github.com/containerd/containerd/snapshots" + "github.com/containerd/containerd/v2/core/snapshots" ) func resolveSnapshotOptions(ctx context.Context, client *Client, snapshotterName string, snapshotter snapshots.Snapshotter, parent string, opts ...snapshots.Opt) (string, error) { diff --git a/client/task.go b/client/task.go new file mode 100644 index 000000000000..20312a922a88 --- /dev/null +++ b/client/task.go @@ -0,0 +1,757 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + "errors" + "fmt" + "io" + goruntime "runtime" + "strings" + "syscall" + "time" + + "github.com/containerd/containerd/api/services/tasks/v1" + "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + "github.com/containerd/typeurl/v2" + digest "github.com/opencontainers/go-digest" + is "github.com/opencontainers/image-spec/specs-go" + v1 "github.com/opencontainers/image-spec/specs-go/v1" + specs "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/diff" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/containerd/v2/pkg/protobuf" + google_protobuf "github.com/containerd/containerd/v2/pkg/protobuf/types" + "github.com/containerd/containerd/v2/pkg/rootfs" + "github.com/containerd/containerd/v2/pkg/tracing" + "github.com/containerd/containerd/v2/plugins" +) + +// UnknownExitStatus is returned when containerd is unable to +// determine the exit status of a process. This can happen if the process never starts +// or if an error was encountered when obtaining the exit status, it is set to 255. +const UnknownExitStatus = 255 + +const ( + checkpointDateFormat = "01-02-2006-15:04:05" + checkpointNameFormat = "containerd.io/checkpoint/%s:%s" +) + +// Status returns process status and exit information +type Status struct { + // Status of the process + Status ProcessStatus + // ExitStatus returned by the process + ExitStatus uint32 + // ExitedTime is the time at which the process died + ExitTime time.Time +} + +// ProcessInfo provides platform specific process information +type ProcessInfo struct { + // Pid is the process ID + Pid uint32 + // Info includes additional process information + // Info varies by platform + Info *google_protobuf.Any +} + +// ProcessStatus returns a human readable status for the Process representing its current status +type ProcessStatus string + +const ( + // Running indicates the process is currently executing + Running ProcessStatus = "running" + // Created indicates the process has been created within containerd but the + // user's defined process has not started + Created ProcessStatus = "created" + // Stopped indicates that the process has ran and exited + Stopped ProcessStatus = "stopped" + // Paused indicates that the process is currently paused + Paused ProcessStatus = "paused" + // Pausing indicates that the process is currently switching from a + // running state into a paused state + Pausing ProcessStatus = "pausing" + // Unknown indicates that we could not determine the status from the runtime + Unknown ProcessStatus = "unknown" +) + +// IOCloseInfo allows specific io pipes to be closed on a process +type IOCloseInfo struct { + Stdin bool +} + +// IOCloserOpts allows the caller to set specific pipes as closed on a process +type IOCloserOpts func(*IOCloseInfo) + +// WithStdinCloser closes the stdin of a process +func WithStdinCloser(r *IOCloseInfo) { + r.Stdin = true +} + +// CheckpointTaskInfo allows specific checkpoint information to be set for the task +type CheckpointTaskInfo struct { + Name string + // ParentCheckpoint is the digest of a parent checkpoint + ParentCheckpoint digest.Digest + // Options hold runtime specific settings for checkpointing a task + Options interface{} + + runtime string +} + +// Runtime name for the container +func (i *CheckpointTaskInfo) Runtime() string { + return i.runtime +} + +// CheckpointTaskOpts allows the caller to set checkpoint options +type CheckpointTaskOpts func(*CheckpointTaskInfo) error + +// TaskInfo sets options for task creation +type TaskInfo struct { + // Checkpoint is the Descriptor for an existing checkpoint that can be used + // to restore a task's runtime and memory state + Checkpoint *types.Descriptor + // RootFS is a list of mounts to use as the task's root filesystem + RootFS []mount.Mount + // Options hold runtime specific settings for task creation + Options interface{} + // RuntimePath is an absolute path that can be used to overwrite path + // to a shim runtime binary. + RuntimePath string + + // runtime is the runtime name for the container, and cannot be changed. + runtime string +} + +// Runtime name for the container +func (i *TaskInfo) Runtime() string { + return i.runtime +} + +// Task is the executable object within containerd +type Task interface { + Process + + // Pause suspends the execution of the task + Pause(context.Context) error + // Resume the execution of the task + Resume(context.Context) error + // Exec creates a new process inside the task + Exec(context.Context, string, *specs.Process, cio.Creator) (Process, error) + // Pids returns a list of system specific process ids inside the task + Pids(context.Context) ([]ProcessInfo, error) + // Checkpoint serializes the runtime and memory information of a task into an + // OCI Index that can be pushed and pulled from a remote resource. + // + // Additional software like CRIU maybe required to checkpoint and restore tasks + // NOTE: Checkpoint supports to dump task information to a directory, in this way, + // an empty OCI Index will be returned. + Checkpoint(context.Context, ...CheckpointTaskOpts) (Image, error) + // Update modifies executing tasks with updated settings + Update(context.Context, ...UpdateTaskOpts) error + // LoadProcess loads a previously created exec'd process + LoadProcess(context.Context, string, cio.Attach) (Process, error) + // Metrics returns task metrics for runtime specific metrics + // + // The metric types are generic to containerd and change depending on the runtime + // For the built in Linux runtime, github.com/containerd/cgroups.Metrics + // are returned in protobuf format + Metrics(context.Context) (*types.Metric, error) + // Spec returns the current OCI specification for the task + Spec(context.Context) (*oci.Spec, error) +} + +var _ = (Task)(&task{}) + +type task struct { + client *Client + c Container + + io cio.IO + id string + pid uint32 +} + +// Spec returns the current OCI specification for the task +func (t *task) Spec(ctx context.Context) (*oci.Spec, error) { + return t.c.Spec(ctx) +} + +// ID of the task +func (t *task) ID() string { + return t.id +} + +// Pid returns the pid or process id for the task +func (t *task) Pid() uint32 { + return t.pid +} + +func (t *task) Start(ctx context.Context) error { + ctx, span := tracing.StartSpan(ctx, "task.Start", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + r, err := t.client.TaskService().Start(ctx, &tasks.StartRequest{ + ContainerID: t.id, + }) + if err != nil { + if t.io != nil { + t.io.Cancel() + t.io.Close() + } + return errgrpc.ToNative(err) + } + span.SetAttributes(tracing.Attribute("task.pid", r.Pid)) + t.pid = r.Pid + return nil +} + +func (t *task) Kill(ctx context.Context, s syscall.Signal, opts ...KillOpts) error { + ctx, span := tracing.StartSpan(ctx, "task.Kill", + tracing.WithAttribute("task.id", t.ID()), + tracing.WithAttribute("task.pid", int(t.Pid())), + ) + defer span.End() + var i KillInfo + for _, o := range opts { + if err := o(ctx, &i); err != nil { + return err + } + } + + span.SetAttributes( + tracing.Attribute("task.exec.id", i.ExecID), + tracing.Attribute("task.exec.killall", i.All), + ) + _, err := t.client.TaskService().Kill(ctx, &tasks.KillRequest{ + Signal: uint32(s), + ContainerID: t.id, + ExecID: i.ExecID, + All: i.All, + }) + if err != nil { + return errgrpc.ToNative(err) + } + return nil +} + +func (t *task) Pause(ctx context.Context) error { + ctx, span := tracing.StartSpan(ctx, "task.Pause", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + _, err := t.client.TaskService().Pause(ctx, &tasks.PauseTaskRequest{ + ContainerID: t.id, + }) + return errgrpc.ToNative(err) +} + +func (t *task) Resume(ctx context.Context) error { + ctx, span := tracing.StartSpan(ctx, "task.Resume", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + _, err := t.client.TaskService().Resume(ctx, &tasks.ResumeTaskRequest{ + ContainerID: t.id, + }) + return errgrpc.ToNative(err) +} + +func (t *task) Status(ctx context.Context) (Status, error) { + r, err := t.client.TaskService().Get(ctx, &tasks.GetRequest{ + ContainerID: t.id, + }) + if err != nil { + return Status{}, errgrpc.ToNative(err) + } + status := ProcessStatus(strings.ToLower(r.Process.Status.String())) + exitStatus := r.Process.ExitStatus + exitTime := protobuf.FromTimestamp(r.Process.ExitedAt) + + return Status{ + Status: status, + ExitStatus: exitStatus, + ExitTime: exitTime, + }, nil +} + +func (t *task) Wait(ctx context.Context) (<-chan ExitStatus, error) { + c := make(chan ExitStatus, 1) + go func() { + defer close(c) + ctx, span := tracing.StartSpan(ctx, "task.Wait", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + r, err := t.client.TaskService().Wait(ctx, &tasks.WaitRequest{ + ContainerID: t.id, + }) + if err != nil { + c <- ExitStatus{ + code: UnknownExitStatus, + err: err, + } + return + } + c <- ExitStatus{ + code: r.ExitStatus, + exitedAt: protobuf.FromTimestamp(r.ExitedAt), + } + }() + return c, nil +} + +// Delete deletes the task and its runtime state +// it returns the exit status of the task and any errors that were encountered +// during cleanup +func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStatus, error) { + ctx, span := tracing.StartSpan(ctx, "task.Delete", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + for _, o := range opts { + if err := o(ctx, t); err != nil { + return nil, err + } + } + status, err := t.Status(ctx) + if err != nil && errdefs.IsNotFound(err) { + return nil, err + } + + switch status.Status { + case Stopped, Unknown, "": + case Created: + if t.client.runtime == plugins.RuntimePlugin.String()+".windows" { + // On windows Created is akin to Stopped + break + } + if t.pid == 0 { + // allow for deletion of created tasks with PID 0 + // https://github.com/containerd/containerd/issues/7357 + break + } + fallthrough + default: + return nil, fmt.Errorf("task must be stopped before deletion: %s: %w", status.Status, errdefs.ErrFailedPrecondition) + } + if t.io != nil { + // io.Wait locks for restored tasks on Windows unless we call + // io.Close first (https://github.com/containerd/containerd/issues/5621) + // in other cases, preserve the contract and let IO finish before closing + if t.client.runtime == plugins.RuntimePlugin.String()+".windows" { + t.io.Close() + } + // io.Cancel is used to cancel the io goroutine while it is in + // fifo-opening state. It does not stop the pipes since these + // should be closed on the shim's side, otherwise we might lose + // data from the container! + t.io.Cancel() + t.io.Wait() + } + r, err := t.client.TaskService().Delete(ctx, &tasks.DeleteTaskRequest{ + ContainerID: t.id, + }) + if err != nil { + return nil, errgrpc.ToNative(err) + } + // Only cleanup the IO after a successful Delete + if t.io != nil { + t.io.Close() + } + return &ExitStatus{code: r.ExitStatus, exitedAt: protobuf.FromTimestamp(r.ExitedAt)}, nil +} + +func (t *task) Exec(ctx context.Context, id string, spec *specs.Process, ioCreate cio.Creator) (_ Process, err error) { + ctx, span := tracing.StartSpan(ctx, "task.Exec", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + if id == "" { + return nil, fmt.Errorf("exec id must not be empty: %w", errdefs.ErrInvalidArgument) + } + span.SetAttributes(tracing.Attribute("task.exec.id", id)) + i, err := ioCreate(id) + if err != nil { + return nil, err + } + defer func() { + if err != nil && i != nil { + i.Cancel() + i.Close() + } + }() + pSpec, err := typeurl.MarshalAnyToProto(spec) + if err != nil { + return nil, err + } + cfg := i.Config() + request := &tasks.ExecProcessRequest{ + ContainerID: t.id, + ExecID: id, + Terminal: cfg.Terminal, + Stdin: cfg.Stdin, + Stdout: cfg.Stdout, + Stderr: cfg.Stderr, + Spec: pSpec, + } + if _, err := t.client.TaskService().Exec(ctx, request); err != nil { + i.Cancel() + i.Wait() + i.Close() + return nil, errgrpc.ToNative(err) + } + return &process{ + id: id, + task: t, + io: i, + }, nil +} + +func (t *task) Pids(ctx context.Context) ([]ProcessInfo, error) { + response, err := t.client.TaskService().ListPids(ctx, &tasks.ListPidsRequest{ + ContainerID: t.id, + }) + if err != nil { + return nil, errgrpc.ToNative(err) + } + var processList []ProcessInfo + for _, p := range response.Processes { + processList = append(processList, ProcessInfo{ + Pid: p.Pid, + Info: p.Info, + }) + } + return processList, nil +} + +func (t *task) CloseIO(ctx context.Context, opts ...IOCloserOpts) error { + ctx, span := tracing.StartSpan(ctx, "task.CloseIO", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + r := &tasks.CloseIORequest{ + ContainerID: t.id, + } + var i IOCloseInfo + for _, o := range opts { + o(&i) + } + r.Stdin = i.Stdin + + _, err := t.client.TaskService().CloseIO(ctx, r) + return errgrpc.ToNative(err) +} + +func (t *task) IO() cio.IO { + return t.io +} + +func (t *task) Resize(ctx context.Context, w, h uint32) error { + ctx, span := tracing.StartSpan(ctx, "task.Resize", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + _, err := t.client.TaskService().ResizePty(ctx, &tasks.ResizePtyRequest{ + ContainerID: t.id, + Width: w, + Height: h, + }) + return errgrpc.ToNative(err) +} + +// NOTE: Checkpoint supports to dump task information to a directory, in this way, an empty +// OCI Index will be returned. +func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Image, error) { + ctx, done, err := t.client.WithLease(ctx) + if err != nil { + return nil, err + } + defer done(ctx) + cr, err := t.client.ContainerService().Get(ctx, t.id) + if err != nil { + return nil, err + } + + request := &tasks.CheckpointTaskRequest{ + ContainerID: t.id, + } + i := CheckpointTaskInfo{ + runtime: cr.Runtime.Name, + } + for _, o := range opts { + if err := o(&i); err != nil { + return nil, err + } + } + // set a default name + if i.Name == "" { + i.Name = fmt.Sprintf(checkpointNameFormat, t.id, time.Now().Format(checkpointDateFormat)) + } + request.ParentCheckpoint = i.ParentCheckpoint.String() + if i.Options != nil { + o, err := typeurl.MarshalAnyToProto(i.Options) + if err != nil { + return nil, err + } + request.Options = o + } + + status, err := t.Status(ctx) + if err != nil { + return nil, err + } + + if status.Status != Paused { + // make sure we pause it and resume after all other filesystem operations are completed + if err := t.Pause(ctx); err != nil { + return nil, err + } + defer t.Resume(ctx) + } + + index := v1.Index{ + Versioned: is.Versioned{ + SchemaVersion: 2, + }, + Annotations: make(map[string]string), + } + if err := t.checkpointTask(ctx, &index, request); err != nil { + return nil, err + } + // if checkpoint image path passed, jump checkpoint image, + // return an empty image + if isCheckpointPathExist(cr.Runtime.Name, i.Options) { + return NewImage(t.client, images.Image{}), nil + } + + if cr.Image != "" { + if err := t.checkpointImage(ctx, &index, cr.Image); err != nil { + return nil, err + } + index.Annotations["image.name"] = cr.Image + } + if cr.SnapshotKey != "" { + if err := t.checkpointRWSnapshot(ctx, &index, cr.Snapshotter, cr.SnapshotKey); err != nil { + return nil, err + } + } + desc, err := writeIndex(ctx, &index, t.client, t.id) + if err != nil { + return nil, err + } + im := images.Image{ + Name: i.Name, + Target: desc, + Labels: map[string]string{ + "containerd.io/checkpoint": "true", + }, + } + if im, err = t.client.ImageService().Create(ctx, im); err != nil { + return nil, err + } + return NewImage(t.client, im), nil +} + +// UpdateTaskInfo allows updated specific settings to be changed on a task +type UpdateTaskInfo struct { + // Resources updates a tasks resource constraints + Resources interface{} + // Annotations allows arbitrary and/or experimental resource constraints for task update + Annotations map[string]string +} + +// UpdateTaskOpts allows a caller to update task settings +type UpdateTaskOpts func(context.Context, *Client, *UpdateTaskInfo) error + +func (t *task) Update(ctx context.Context, opts ...UpdateTaskOpts) error { + ctx, span := tracing.StartSpan(ctx, "task.Update", + tracing.WithAttribute("task.id", t.ID()), + ) + defer span.End() + request := &tasks.UpdateTaskRequest{ + ContainerID: t.id, + } + var i UpdateTaskInfo + for _, o := range opts { + if err := o(ctx, t.client, &i); err != nil { + return err + } + } + if i.Resources != nil { + r, err := typeurl.MarshalAny(i.Resources) + if err != nil { + return err + } + request.Resources = typeurl.MarshalProto(r) + } + if i.Annotations != nil { + request.Annotations = i.Annotations + } + _, err := t.client.TaskService().Update(ctx, request) + return errgrpc.ToNative(err) +} + +func (t *task) LoadProcess(ctx context.Context, id string, ioAttach cio.Attach) (Process, error) { + if id == t.id && ioAttach == nil { + return t, nil + } + response, err := t.client.TaskService().Get(ctx, &tasks.GetRequest{ + ContainerID: t.id, + ExecID: id, + }) + if err != nil { + err = errgrpc.ToNative(err) + if errdefs.IsNotFound(err) { + return nil, fmt.Errorf("no running process found: %w", err) + } + return nil, err + } + var i cio.IO + if ioAttach != nil { + if i, err = attachExistingIO(response, ioAttach); err != nil { + return nil, err + } + } + return &process{ + id: id, + task: t, + io: i, + }, nil +} + +func (t *task) Metrics(ctx context.Context) (*types.Metric, error) { + response, err := t.client.TaskService().Metrics(ctx, &tasks.MetricsRequest{ + Filters: []string{ + "id==" + t.id, + }, + }) + if err != nil { + return nil, errgrpc.ToNative(err) + } + + if response.Metrics == nil { + _, err := t.Status(ctx) + if err != nil && errdefs.IsNotFound(err) { + return nil, err + } + return nil, errors.New("no metrics received") + } + + return response.Metrics[0], nil +} + +func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tasks.CheckpointTaskRequest) error { + response, err := t.client.TaskService().Checkpoint(ctx, request) + if err != nil { + return errgrpc.ToNative(err) + } + // NOTE: response.Descriptors can be an empty slice if checkpoint image is jumped + // add the checkpoint descriptors to the index + for _, d := range response.Descriptors { + index.Manifests = append(index.Manifests, v1.Descriptor{ + MediaType: d.MediaType, + Size: d.Size, + Digest: digest.Digest(d.Digest), + Platform: &v1.Platform{ + OS: goruntime.GOOS, + Architecture: goruntime.GOARCH, + }, + Annotations: d.Annotations, + }) + } + return nil +} + +func (t *task) checkpointRWSnapshot(ctx context.Context, index *v1.Index, snapshotterName string, id string) error { + opts := []diff.Opt{ + diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", id)), + } + rw, err := rootfs.CreateDiff(ctx, id, t.client.SnapshotService(snapshotterName), t.client.DiffService(), opts...) + if err != nil { + return err + } + rw.Platform = &v1.Platform{ + OS: goruntime.GOOS, + Architecture: goruntime.GOARCH, + } + index.Manifests = append(index.Manifests, rw) + return nil +} + +func (t *task) checkpointImage(ctx context.Context, index *v1.Index, image string) error { + if image == "" { + return fmt.Errorf("cannot checkpoint image with empty name") + } + ir, err := t.client.ImageService().Get(ctx, image) + if err != nil { + return err + } + index.Manifests = append(index.Manifests, ir.Target) + return nil +} + +func writeContent(ctx context.Context, store content.Ingester, mediaType, ref string, r io.Reader, opts ...content.Opt) (d v1.Descriptor, err error) { + writer, err := store.Writer(ctx, content.WithRef(ref)) + if err != nil { + return d, err + } + defer writer.Close() + size, err := io.Copy(writer, r) + if err != nil { + return d, err + } + + if err := writer.Commit(ctx, size, "", opts...); err != nil { + if !errdefs.IsAlreadyExists(err) { + return d, err + } + } + return v1.Descriptor{ + MediaType: mediaType, + Digest: writer.Digest(), + Size: size, + }, nil +} + +// isCheckpointPathExist only suitable for runc runtime now +func isCheckpointPathExist(runtime string, v interface{}) bool { + if v == nil { + return false + } + + switch runtime { + case plugins.RuntimeRuncV2: + if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" { + return true + } + } + + return false +} diff --git a/task_opts.go b/client/task_opts.go similarity index 86% rename from task_opts.go rename to client/task_opts.go index 9dd8fcd0226b..8e94d4c5978a 100644 --- a/task_opts.go +++ b/client/task_opts.go @@ -14,7 +14,7 @@ limitations under the License. */ -package containerd +package client import ( "context" @@ -23,10 +23,10 @@ import ( "syscall" "github.com/containerd/containerd/api/types" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/errdefs" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -50,6 +50,23 @@ func WithRuntimePath(absRuntimePath string) NewTaskOpts { } } +// WithTaskAPIEndpoint allow task service to manage a task through a given endpoint, +// usually it is served inside a sandbox, and we can get it from sandbox status. +func WithTaskAPIEndpoint(address string, version uint32) NewTaskOpts { + return func(ctx context.Context, client *Client, info *TaskInfo) error { + if info.Options == nil { + info.Options = &options.Options{} + } + opts, ok := info.Options.(*options.Options) + if !ok { + return errors.New("invalid runtime v2 options format") + } + opts.TaskApiAddress = address + opts.TaskApiVersion = version + return nil + } +} + // WithTaskCheckpoint allows a task to be created with live runtime and memory data from a // previous checkpoint. Additional software such as CRIU may be required to // restore a task from a checkpoint @@ -134,6 +151,12 @@ type ProcessDeleteOpts func(context.Context, Process) error // WithProcessKill will forcefully kill and delete a process func WithProcessKill(ctx context.Context, p Process) error { + // Skip killing tasks with PID 0 + // https://github.com/containerd/containerd/issues/10441 + if p.Pid() == 0 { + return nil + } + ctx, cancel := context.WithCancel(ctx) defer cancel() // ignore errors to wait and kill as we are forcefully killing diff --git a/task_opts_unix.go b/client/task_opts_unix.go similarity index 97% rename from task_opts_unix.go rename to client/task_opts_unix.go index ae8282c3a3b0..d33e30284e4c 100644 --- a/task_opts_unix.go +++ b/client/task_opts_unix.go @@ -16,13 +16,13 @@ limitations under the License. */ -package containerd +package client import ( "context" "errors" - "github.com/containerd/containerd/runtime/v2/runc/options" + "github.com/containerd/containerd/api/types/runc/options" ) // WithNoNewKeyring causes tasks not to be created with a new keyring for secret storage. diff --git a/client/transfer.go b/client/transfer.go new file mode 100644 index 000000000000..5bd02aa6d2d3 --- /dev/null +++ b/client/transfer.go @@ -0,0 +1,40 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package client + +import ( + "context" + + "github.com/containerd/containerd/v2/core/streaming" + streamproxy "github.com/containerd/containerd/v2/core/streaming/proxy" + "github.com/containerd/containerd/v2/core/transfer" + "github.com/containerd/containerd/v2/core/transfer/proxy" +) + +func (c *Client) Transfer(ctx context.Context, src interface{}, dest interface{}, opts ...transfer.Opt) error { + ctx, done, err := c.WithLease(ctx) + if err != nil { + return err + } + defer done(ctx) + + return proxy.NewTransferrer(c.conn, c.streamCreator()).Transfer(ctx, src, dest, opts...) +} + +func (c *Client) streamCreator() streaming.StreamCreator { + return streamproxy.NewStreamCreator(c.conn) +} diff --git a/cmd/containerd-shim-runc-v2/main.go b/cmd/containerd-shim-runc-v2/main.go index 7b80310f05e8..d6f11990c211 100644 --- a/cmd/containerd-shim-runc-v2/main.go +++ b/cmd/containerd-shim-runc-v2/main.go @@ -21,10 +21,9 @@ package main import ( "context" - "github.com/containerd/containerd/runtime/v2/runc/manager" - _ "github.com/containerd/containerd/runtime/v2/runc/pause" - _ "github.com/containerd/containerd/runtime/v2/runc/task/plugin" - "github.com/containerd/containerd/runtime/v2/shim" + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/manager" + _ "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/task/plugin" + "github.com/containerd/containerd/v2/pkg/shim" ) func main() { diff --git a/cmd/containerd-shim-runc-v2/main_tracing.go b/cmd/containerd-shim-runc-v2/main_tracing.go new file mode 100644 index 000000000000..45be0c67824d --- /dev/null +++ b/cmd/containerd-shim-runc-v2/main_tracing.go @@ -0,0 +1,24 @@ +//go:build shim_tracing + +/* + Copyright The containerd Authors. + + 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. +*/ + +package main + +import ( + _ "github.com/containerd/containerd/v2/internal/pprof" + _ "github.com/containerd/containerd/v2/pkg/tracing/plugin" +) diff --git a/cmd/containerd-shim-runc-v2/manager/manager_linux.go b/cmd/containerd-shim-runc-v2/manager/manager_linux.go new file mode 100644 index 000000000000..7955ce0e53e8 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/manager/manager_linux.go @@ -0,0 +1,387 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package manager + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "os" + "os/exec" + "path/filepath" + goruntime "runtime" + "syscall" + "time" + + "github.com/containerd/cgroups/v3" + "github.com/containerd/cgroups/v3/cgroup1" + cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2" + "github.com/containerd/containerd/api/types" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/process" + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/runc" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/schedcore" + "github.com/containerd/containerd/v2/pkg/shim" + "github.com/containerd/containerd/v2/version" + "github.com/containerd/errdefs" + runcC "github.com/containerd/go-runc" + "github.com/containerd/log" + "github.com/containerd/typeurl/v2" + "github.com/opencontainers/runtime-spec/specs-go/features" + "golang.org/x/sys/unix" +) + +// NewShimManager returns an implementation of the shim manager +// using runc +func NewShimManager(name string) shim.Manager { + return &manager{ + name: name, + } +} + +// group labels specifies how the shim groups services. +// currently supports a runc.v2 specific .group label and the +// standard k8s pod label. Order matters in this list +var groupLabels = []string{ + "io.containerd.runc.v2.group", + "io.kubernetes.cri.sandbox-id", +} + +// spec is a shallow version of [oci.Spec] containing only the +// fields we need for the hook. We use a shallow struct to reduce +// the overhead of unmarshaling. +type spec struct { + // Annotations contains arbitrary metadata for the container. + Annotations map[string]string `json:"annotations,omitempty"` +} + +type manager struct { + name string +} + +func newCommand(ctx context.Context, id, containerdAddress, containerdTTRPCAddress string, debug bool) (*exec.Cmd, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + self, err := os.Executable() + if err != nil { + return nil, err + } + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + args := []string{ + "-namespace", ns, + "-id", id, + "-address", containerdAddress, + } + if debug { + args = append(args, "-debug") + } + cmd := exec.Command(self, args...) + cmd.Dir = cwd + cmd.Env = append(os.Environ(), "GOMAXPROCS=4") + cmd.Env = append(cmd.Env, "OTEL_SERVICE_NAME=containerd-shim-"+id) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + } + return cmd, nil +} + +func readSpec() (*spec, error) { + const configFileName = "config.json" + f, err := os.Open(configFileName) + if err != nil { + return nil, err + } + defer f.Close() + var s spec + if err := json.NewDecoder(f).Decode(&s); err != nil { + return nil, err + } + return &s, nil +} + +func (m manager) Name() string { + return m.name +} + +type shimSocket struct { + addr string + s *net.UnixListener + f *os.File +} + +func (s *shimSocket) Close() { + if s.s != nil { + s.s.Close() + } + if s.f != nil { + s.f.Close() + } + _ = shim.RemoveSocket(s.addr) +} + +func newShimSocket(ctx context.Context, path, id string, debug bool) (*shimSocket, error) { + address, err := shim.SocketAddress(ctx, path, id, debug) + if err != nil { + return nil, err + } + socket, err := shim.NewSocket(address) + if err != nil { + // the only time where this would happen is if there is a bug and the socket + // was not cleaned up in the cleanup method of the shim or we are using the + // grouping functionality where the new process should be run with the same + // shim as an existing container + if !shim.SocketEaddrinuse(err) { + return nil, fmt.Errorf("create new shim socket: %w", err) + } + if !debug && shim.CanConnect(address) { + return &shimSocket{addr: address}, errdefs.ErrAlreadyExists + } + if err := shim.RemoveSocket(address); err != nil { + return nil, fmt.Errorf("remove pre-existing socket: %w", err) + } + if socket, err = shim.NewSocket(address); err != nil { + return nil, fmt.Errorf("try create new shim socket 2x: %w", err) + } + } + s := &shimSocket{ + addr: address, + s: socket, + } + f, err := socket.File() + if err != nil { + s.Close() + return nil, err + } + s.f = f + return s, nil +} + +func (manager) Start(ctx context.Context, id string, opts shim.StartOpts) (_ shim.BootstrapParams, retErr error) { + var params shim.BootstrapParams + params.Version = 3 + params.Protocol = "ttrpc" + + cmd, err := newCommand(ctx, id, opts.Address, opts.TTRPCAddress, opts.Debug) + if err != nil { + return params, err + } + grouping := id + spec, err := readSpec() + if err != nil { + return params, err + } + for _, group := range groupLabels { + if groupID, ok := spec.Annotations[group]; ok { + grouping = groupID + break + } + } + + var sockets []*shimSocket + defer func() { + if retErr != nil { + for _, s := range sockets { + s.Close() + } + } + }() + + s, err := newShimSocket(ctx, opts.Address, grouping, false) + if err != nil { + if errdefs.IsAlreadyExists(err) { + params.Address = s.addr + return params, nil + } + return params, err + } + sockets = append(sockets, s) + cmd.ExtraFiles = append(cmd.ExtraFiles, s.f) + + if opts.Debug { + s, err = newShimSocket(ctx, opts.Address, grouping, true) + if err != nil { + return params, err + } + sockets = append(sockets, s) + cmd.ExtraFiles = append(cmd.ExtraFiles, s.f) + } + + goruntime.LockOSThread() + if os.Getenv("SCHED_CORE") != "" { + if err := schedcore.Create(schedcore.ProcessGroup); err != nil { + return params, fmt.Errorf("enable sched core support: %w", err) + } + } + + if err := cmd.Start(); err != nil { + return params, err + } + + goruntime.UnlockOSThread() + + defer func() { + if retErr != nil { + cmd.Process.Kill() + } + }() + // make sure to wait after start + go cmd.Wait() + + if opts, err := shim.ReadRuntimeOptions[*options.Options](os.Stdin); err == nil { + if opts.ShimCgroup != "" { + if cgroups.Mode() == cgroups.Unified { + cg, err := cgroupsv2.Load(opts.ShimCgroup) + if err != nil { + return params, fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) + } + if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { + return params, fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) + } + } else { + cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup)) + if err != nil { + return params, fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) + } + if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { + return params, fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) + } + } + } + } + + if err := shim.AdjustOOMScore(cmd.Process.Pid); err != nil { + return params, fmt.Errorf("failed to adjust OOM score for shim: %w", err) + } + + params.Address = sockets[0].addr + return params, nil +} + +func (manager) Stop(ctx context.Context, id string) (shim.StopStatus, error) { + cwd, err := os.Getwd() + if err != nil { + return shim.StopStatus{}, err + } + + path := filepath.Join(filepath.Dir(cwd), id) + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return shim.StopStatus{}, err + } + runtime, err := runc.ReadRuntime(path) + if err != nil { + return shim.StopStatus{}, err + } + opts, err := runc.ReadOptions(path) + if err != nil { + return shim.StopStatus{}, err + } + root := process.RuncRoot + if opts != nil && opts.Root != "" { + root = opts.Root + } + + r := process.NewRunc(root, path, ns, runtime, false) + if err := r.Delete(ctx, id, &runcC.DeleteOpts{ + Force: true, + }); err != nil { + log.G(ctx).WithError(err).Warn("failed to remove runc container") + } + if err := mount.UnmountRecursive(filepath.Join(path, "rootfs"), 0); err != nil { + log.G(ctx).WithError(err).Warn("failed to cleanup rootfs mount") + } + pid, err := runcC.ReadPidFile(filepath.Join(path, process.InitPidFile)) + if err != nil { + log.G(ctx).WithError(err).Warn("failed to read init pid file") + } + return shim.StopStatus{ + ExitedAt: time.Now(), + ExitStatus: 128 + int(unix.SIGKILL), + Pid: pid, + }, nil +} + +func (m manager) Info(ctx context.Context, optionsR io.Reader) (*types.RuntimeInfo, error) { + info := &types.RuntimeInfo{ + Name: m.name, + Version: &types.RuntimeVersion{ + Version: version.Version, + Revision: version.Revision, + }, + Annotations: nil, + } + binaryName := runcC.DefaultCommand + opts, err := shim.ReadRuntimeOptions[*options.Options](optionsR) + if err != nil { + if !errors.Is(err, errdefs.ErrNotFound) { + return nil, fmt.Errorf("failed to read runtime options (*options.Options): %w", err) + } + } + if opts != nil { + info.Options, err = typeurl.MarshalAnyToProto(opts) + if err != nil { + return nil, fmt.Errorf("failed to marshal %T: %w", opts, err) + } + if opts.BinaryName != "" { + binaryName = opts.BinaryName + } + + } + absBinary, err := exec.LookPath(binaryName) + if err != nil { + return nil, fmt.Errorf("failed to look up the path of %q: %w", binaryName, err) + } + features, err := m.features(ctx, absBinary, opts) + if err != nil { + // youki does not implement `runc features` yet, at the time of writing this (Sep 2023) + // https://github.com/containers/youki/issues/815 + log.G(ctx).WithError(err).Debug("Failed to get the runtime features. The runc binary does not implement `runc features` command?") + } + if features != nil { + info.Features, err = typeurl.MarshalAnyToProto(features) + if err != nil { + return nil, fmt.Errorf("failed to marshal %T: %w", features, err) + } + } + return info, nil +} + +func (m manager) features(ctx context.Context, absBinary string, opts *options.Options) (*features.Features, error) { + var stderr bytes.Buffer + cmd := exec.CommandContext(ctx, absBinary, "features") + cmd.Stderr = &stderr + stdout, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("failed to execute %v: %w (stderr: %q)", cmd.Args, err, stderr.String()) + } + var feat features.Features + if err := json.Unmarshal(stdout, &feat); err != nil { + return nil, err + } + return &feat, nil +} diff --git a/pkg/process/deleted_state.go b/cmd/containerd-shim-runc-v2/process/deleted_state.go similarity index 94% rename from pkg/process/deleted_state.go rename to cmd/containerd-shim-runc-v2/process/deleted_state.go index 30852104b231..3bb4f88d6056 100644 --- a/pkg/process/deleted_state.go +++ b/cmd/containerd-shim-runc-v2/process/deleted_state.go @@ -24,8 +24,8 @@ import ( "fmt" "github.com/containerd/console" - "github.com/containerd/containerd/errdefs" - google_protobuf "github.com/containerd/containerd/protobuf/types" + google_protobuf "github.com/containerd/containerd/v2/pkg/protobuf/types" + "github.com/containerd/errdefs" ) type deletedState struct { diff --git a/cmd/containerd-shim-runc-v2/process/exec.go b/cmd/containerd-shim-runc-v2/process/exec.go new file mode 100644 index 000000000000..40344c13d8b0 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/exec.go @@ -0,0 +1,263 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + "context" + "fmt" + "io" + "os" + "path/filepath" + "sync" + "syscall" + "time" + + "golang.org/x/sys/unix" + + "github.com/containerd/console" + "github.com/containerd/containerd/v2/pkg/stdio" + "github.com/containerd/errdefs" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + specs "github.com/opencontainers/runtime-spec/specs-go" +) + +type execProcess struct { + wg sync.WaitGroup + + execState execState + + mu sync.Mutex + id string + console console.Console + io *processIO + status int + exited time.Time + pid safePid + closers []io.Closer + stdin io.Closer + stdio stdio.Stdio + path string + spec specs.Process + + parent *Init + waitBlock chan struct{} +} + +func (e *execProcess) Wait() { + <-e.waitBlock +} + +func (e *execProcess) ID() string { + return e.id +} + +func (e *execProcess) Pid() int { + return e.pid.get() +} + +func (e *execProcess) ExitStatus() int { + e.mu.Lock() + defer e.mu.Unlock() + return e.status +} + +func (e *execProcess) ExitedAt() time.Time { + e.mu.Lock() + defer e.mu.Unlock() + return e.exited +} + +func (e *execProcess) SetExited(status int) { + e.mu.Lock() + defer e.mu.Unlock() + + e.execState.SetExited(status) +} + +func (e *execProcess) setExited(status int) { + e.status = status + e.exited = time.Now() + e.parent.Platform.ShutdownConsole(context.Background(), e.console) + close(e.waitBlock) +} + +func (e *execProcess) Delete(ctx context.Context) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Delete(ctx) +} + +func (e *execProcess) delete(ctx context.Context) error { + waitTimeout(ctx, &e.wg, 2*time.Second) + if e.io != nil { + for _, c := range e.closers { + c.Close() + } + e.io.Close() + } + pidfile := filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id)) + // silently ignore error + os.Remove(pidfile) + return nil +} + +func (e *execProcess) Resize(ws console.WinSize) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Resize(ws) +} + +func (e *execProcess) resize(ws console.WinSize) error { + if e.console == nil { + return nil + } + return e.console.Resize(ws) +} + +func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Kill(ctx, sig, false) +} + +func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error { + pid := e.pid.get() + switch { + case pid == 0: + return fmt.Errorf("process not created: %w", errdefs.ErrFailedPrecondition) + case !e.exited.IsZero(): + return fmt.Errorf("process already finished: %w", errdefs.ErrNotFound) + default: + if err := unix.Kill(pid, syscall.Signal(sig)); err != nil { + return fmt.Errorf("exec kill error: %w", checkKillError(err)) + } + } + return nil +} + +func (e *execProcess) Stdin() io.Closer { + return e.stdin +} + +func (e *execProcess) Stdio() stdio.Stdio { + return e.stdio +} + +func (e *execProcess) Start(ctx context.Context) error { + e.mu.Lock() + defer e.mu.Unlock() + + return e.execState.Start(ctx) +} + +func (e *execProcess) start(ctx context.Context) (err error) { + // The reaper may receive exit signal right after + // the container is started, before the e.pid is updated. + // In that case, we want to block the signal handler to + // access e.pid until it is updated. + e.pid.Lock() + defer e.pid.Unlock() + + var ( + socket *runc.Socket + pio *processIO + pidFile = newExecPidFile(e.path, e.id) + ) + if e.stdio.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return fmt.Errorf("failed to create runc console socket: %w", err) + } + defer socket.Close() + } else { + if pio, err = createIO(ctx, e.id, e.parent.IoUID, e.parent.IoGID, e.stdio); err != nil { + return fmt.Errorf("failed to create init process I/O: %w", err) + } + e.io = pio + } + opts := &runc.ExecOpts{ + PidFile: pidFile.Path(), + Detach: true, + } + if pio != nil { + opts.IO = pio.IO() + } + if socket != nil { + opts.ConsoleSocket = socket + } + if err := e.parent.runtime.Exec(ctx, e.parent.id, e.spec, opts); err != nil { + close(e.waitBlock) + return e.parent.runtimeError(err, "OCI runtime exec failed") + } + if e.stdio.Stdin != "" { + if err := e.openStdin(e.stdio.Stdin); err != nil { + return err + } + } + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return fmt.Errorf("failed to retrieve console master: %w", err) + } + if e.console, err = e.parent.Platform.CopyConsole(ctx, console, e.id, e.stdio.Stdin, e.stdio.Stdout, e.stdio.Stderr, &e.wg); err != nil { + return fmt.Errorf("failed to start console copy: %w", err) + } + } else { + if err := pio.Copy(ctx, &e.wg); err != nil { + return fmt.Errorf("failed to start io pipe copy: %w", err) + } + } + pid, err := pidFile.Read() + if err != nil { + return fmt.Errorf("failed to retrieve OCI runtime exec pi: %wd", err) + } + e.pid.pid = pid + return nil +} + +func (e *execProcess) openStdin(path string) error { + sc, err := fifo.OpenFifo(context.Background(), path, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return fmt.Errorf("failed to open stdin fifo %s: %w", path, err) + } + e.stdin = sc + e.closers = append(e.closers, sc) + return nil +} + +func (e *execProcess) Status(ctx context.Context) (string, error) { + s, err := e.parent.Status(ctx) + if err != nil { + return "", err + } + // if the container as a whole is in the pausing/paused state, so are all + // other processes inside the container, use container state here + switch s { + case "paused", "pausing": + return s, nil + } + e.mu.Lock() + defer e.mu.Unlock() + return e.execState.Status(ctx) +} diff --git a/pkg/process/exec_state.go b/cmd/containerd-shim-runc-v2/process/exec_state.go similarity index 100% rename from pkg/process/exec_state.go rename to cmd/containerd-shim-runc-v2/process/exec_state.go diff --git a/cmd/containerd-shim-runc-v2/process/init.go b/cmd/containerd-shim-runc-v2/process/init.go new file mode 100644 index 000000000000..e7c668ad0328 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/init.go @@ -0,0 +1,497 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/containerd/console" + "github.com/containerd/containerd/v2/core/mount" + google_protobuf "github.com/containerd/containerd/v2/pkg/protobuf/types" + "github.com/containerd/containerd/v2/pkg/stdio" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + "github.com/containerd/log" + specs "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/sys/unix" +) + +// Init represents an initial process for a container +type Init struct { + wg sync.WaitGroup + initState initState + + // mu is used to ensure that `Start()` and `Exited()` calls return in + // the right order when invoked in separate goroutines. + // This is the case within the shim implementation as it makes use of + // the reaper interface. + mu sync.Mutex + + waitBlock chan struct{} + + WorkDir string + + id string + Bundle string + console console.Console + Platform stdio.Platform + io *processIO + runtime *runc.Runc + // pausing preserves the pausing state. + pausing atomic.Bool + status int + exited time.Time + pid int + closers []io.Closer + stdin io.Closer + stdio stdio.Stdio + Rootfs string + IoUID int + IoGID int + NoPivotRoot bool + NoNewKeyring bool + CriuWorkPath string +} + +// NewRunc returns a new runc instance for a process +func NewRunc(root, path, namespace, runtime string, systemd bool) *runc.Runc { + if root == "" { + root = RuncRoot + } + return &runc.Runc{ + Command: runtime, + Log: filepath.Join(path, "log.json"), + LogFormat: runc.JSON, + PdeathSignal: unix.SIGKILL, + Root: filepath.Join(root, namespace), + SystemdCgroup: systemd, + } +} + +// New returns a new process +func New(id string, runtime *runc.Runc, stdio stdio.Stdio) *Init { + p := &Init{ + id: id, + runtime: runtime, + stdio: stdio, + status: 0, + waitBlock: make(chan struct{}), + } + p.initState = &createdState{p: p} + return p +} + +// Create the process with the provided config +func (p *Init) Create(ctx context.Context, r *CreateConfig) error { + var ( + err error + socket *runc.Socket + pio *processIO + pidFile = newPidFile(p.Bundle) + ) + + if r.Terminal { + if socket, err = runc.NewTempConsoleSocket(); err != nil { + return fmt.Errorf("failed to create OCI runtime console socket: %w", err) + } + defer socket.Close() + } else { + if pio, err = createIO(ctx, p.id, p.IoUID, p.IoGID, p.stdio); err != nil { + return fmt.Errorf("failed to create init process I/O: %w", err) + } + p.io = pio + } + if r.Checkpoint != "" { + return p.createCheckpointedState(r, pidFile) + } + opts := &runc.CreateOpts{ + PidFile: pidFile.Path(), + NoPivot: p.NoPivotRoot, + NoNewKeyring: p.NoNewKeyring, + } + if p.io != nil { + opts.IO = p.io.IO() + } + if socket != nil { + opts.ConsoleSocket = socket + } + + if err := p.runtime.Create(ctx, r.ID, r.Bundle, opts); err != nil { + return p.runtimeError(err, "OCI runtime create failed") + } + if r.Stdin != "" { + if err := p.openStdin(r.Stdin); err != nil { + return err + } + } + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + if socket != nil { + console, err := socket.ReceiveMaster() + if err != nil { + return fmt.Errorf("failed to retrieve console master: %w", err) + } + console, err = p.Platform.CopyConsole(ctx, console, p.id, r.Stdin, r.Stdout, r.Stderr, &p.wg) + if err != nil { + return fmt.Errorf("failed to start console copy: %w", err) + } + p.console = console + } else { + if err := pio.Copy(ctx, &p.wg); err != nil { + return fmt.Errorf("failed to start io pipe copy: %w", err) + } + } + pid, err := pidFile.Read() + if err != nil { + return fmt.Errorf("failed to retrieve OCI runtime container pid: %w", err) + } + p.pid = pid + return nil +} + +func (p *Init) openStdin(path string) error { + sc, err := fifo.OpenFifo(context.Background(), path, unix.O_WRONLY|unix.O_NONBLOCK, 0) + if err != nil { + return fmt.Errorf("failed to open stdin fifo %s: %w", path, err) + } + p.stdin = sc + p.closers = append(p.closers, sc) + return nil +} + +func (p *Init) createCheckpointedState(r *CreateConfig, pidFile *pidFile) error { + opts := &runc.RestoreOpts{ + CheckpointOpts: runc.CheckpointOpts{ + ImagePath: r.Checkpoint, + WorkDir: p.CriuWorkPath, + ParentPath: r.ParentCheckpoint, + }, + PidFile: pidFile.Path(), + NoPivot: p.NoPivotRoot, + Detach: true, + NoSubreaper: true, + } + + if p.io != nil { + opts.IO = p.io.IO() + } + + p.initState = &createdCheckpointState{ + p: p, + opts: opts, + } + return nil +} + +// Wait for the process to exit +func (p *Init) Wait() { + <-p.waitBlock +} + +// ID of the process +func (p *Init) ID() string { + return p.id +} + +// Pid of the process +func (p *Init) Pid() int { + return p.pid +} + +// ExitStatus of the process +func (p *Init) ExitStatus() int { + p.mu.Lock() + defer p.mu.Unlock() + + return p.status +} + +// ExitedAt at time when the process exited +func (p *Init) ExitedAt() time.Time { + p.mu.Lock() + defer p.mu.Unlock() + + return p.exited +} + +// Status of the process +func (p *Init) Status(ctx context.Context) (string, error) { + if p.pausing.Load() { + return "pausing", nil + } + + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Status(ctx) +} + +// Start the init process +func (p *Init) Start(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Start(ctx) +} + +func (p *Init) start(ctx context.Context) error { + err := p.runtime.Start(ctx, p.id) + return p.runtimeError(err, "OCI runtime start failed") +} + +// SetExited of the init process with the next status +func (p *Init) SetExited(status int) { + p.mu.Lock() + defer p.mu.Unlock() + + p.initState.SetExited(status) +} + +func (p *Init) setExited(status int) { + p.exited = time.Now() + p.status = status + p.Platform.ShutdownConsole(context.Background(), p.console) + close(p.waitBlock) +} + +// Delete the init process +func (p *Init) Delete(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Delete(ctx) +} + +func (p *Init) delete(ctx context.Context) error { + waitTimeout(ctx, &p.wg, 2*time.Second) + err := p.runtime.Delete(ctx, p.id, nil) + // ignore errors if a runtime has already deleted the process + // but we still hold metadata and pipes + // + // this is common during a checkpoint, runc will delete the container state + // after a checkpoint and the container will no longer exist within runc + if err != nil { + if strings.Contains(err.Error(), "does not exist") { + err = nil + } else { + err = p.runtimeError(err, "failed to delete task") + } + } + if p.io != nil { + for _, c := range p.closers { + c.Close() + } + p.io.Close() + } + if err2 := mount.UnmountRecursive(p.Rootfs, 0); err2 != nil { + log.G(ctx).WithError(err2).Warn("failed to cleanup rootfs mount") + if err == nil { + err = fmt.Errorf("failed rootfs umount: %w", err2) + } + } + return err +} + +// Resize the init processes console +func (p *Init) Resize(ws console.WinSize) error { + p.mu.Lock() + defer p.mu.Unlock() + + if p.console == nil { + return nil + } + return p.console.Resize(ws) +} + +// Pause the init process and all its child processes +func (p *Init) Pause(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Pause(ctx) +} + +// Resume the init process and all its child processes +func (p *Init) Resume(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Resume(ctx) +} + +// Kill the init process +func (p *Init) Kill(ctx context.Context, signal uint32, all bool) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Kill(ctx, signal, all) +} + +func (p *Init) kill(ctx context.Context, signal uint32, all bool) error { + err := p.runtime.Kill(ctx, p.id, int(signal), &runc.KillOpts{ + All: all, + }) + return checkKillError(err) +} + +// KillAll processes belonging to the init process +func (p *Init) KillAll(ctx context.Context) error { + p.mu.Lock() + defer p.mu.Unlock() + + err := p.runtime.Kill(ctx, p.id, int(unix.SIGKILL), &runc.KillOpts{ + All: true, + }) + return p.runtimeError(err, "OCI runtime killall failed") +} + +// Stdin of the process +func (p *Init) Stdin() io.Closer { + return p.stdin +} + +// Runtime returns the OCI runtime configured for the init process +func (p *Init) Runtime() *runc.Runc { + return p.runtime +} + +// Exec returns a new child process +func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Exec(ctx, path, r) +} + +// exec returns a new exec'd process +func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (Process, error) { + // process exec request + var spec specs.Process + if err := json.Unmarshal(r.Spec.Value, &spec); err != nil { + return nil, err + } + spec.Terminal = r.Terminal + + e := &execProcess{ + id: r.ID, + path: path, + parent: p, + spec: spec, + stdio: stdio.Stdio{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }, + waitBlock: make(chan struct{}), + } + e.execState = &execCreatedState{p: e} + return e, nil +} + +// Checkpoint the init process +func (p *Init) Checkpoint(ctx context.Context, r *CheckpointConfig) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Checkpoint(ctx, r) +} + +func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error { + var actions []runc.CheckpointAction + if !r.Exit { + actions = append(actions, runc.LeaveRunning) + } + // keep criu work directory if criu work dir is set + work := r.WorkDir + if work == "" { + work = filepath.Join(p.WorkDir, "criu-work") + defer os.RemoveAll(work) + } + if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{ + WorkDir: work, + ImagePath: r.Path, + AllowOpenTCP: r.AllowOpenTCP, + AllowExternalUnixSockets: r.AllowExternalUnixSockets, + AllowTerminal: r.AllowTerminal, + FileLocks: r.FileLocks, + EmptyNamespaces: r.EmptyNamespaces, + }, actions...); err != nil { + dumpLog := filepath.Join(p.Bundle, "criu-dump.log") + if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil { + log.G(ctx).WithError(cerr).Error("failed to copy dump.log to criu-dump.log") + } + return fmt.Errorf("%s path= %s", criuError(err), dumpLog) + } + return nil +} + +// Update the processes resource configuration +func (p *Init) Update(ctx context.Context, r *google_protobuf.Any) error { + p.mu.Lock() + defer p.mu.Unlock() + + return p.initState.Update(ctx, r) +} + +func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error { + var resources specs.LinuxResources + if err := json.Unmarshal(r.Value, &resources); err != nil { + return err + } + return p.runtime.Update(ctx, p.id, &resources) +} + +// Stdio of the process +func (p *Init) Stdio() stdio.Stdio { + return p.stdio +} + +func (p *Init) runtimeError(rErr error, msg string) error { + if rErr == nil { + return nil + } + + rMsg, err := getLastRuntimeError(p.runtime) + switch { + case err != nil: + return fmt.Errorf("%s: %s (%s): %w", msg, "unable to retrieve OCI runtime error", err.Error(), rErr) + case rMsg == "": + return fmt.Errorf("%s: %w", msg, rErr) + default: + return fmt.Errorf("%s: %s", msg, rMsg) + } +} + +func withConditionalIO(c stdio.Stdio) runc.IOOpt { + return func(o *runc.IOOption) { + o.OpenStdin = c.Stdin != "" + o.OpenStdout = c.Stdout != "" + o.OpenStderr = c.Stderr != "" + } +} diff --git a/pkg/process/init_state.go b/cmd/containerd-shim-runc-v2/process/init_state.go similarity index 99% rename from pkg/process/init_state.go rename to cmd/containerd-shim-runc-v2/process/init_state.go index 3c74a0870217..01f5d3e21ff1 100644 --- a/pkg/process/init_state.go +++ b/cmd/containerd-shim-runc-v2/process/init_state.go @@ -23,9 +23,9 @@ import ( "errors" "fmt" - "github.com/containerd/containerd/log" - google_protobuf "github.com/containerd/containerd/protobuf/types" + google_protobuf "github.com/containerd/containerd/v2/pkg/protobuf/types" runc "github.com/containerd/go-runc" + "github.com/containerd/log" ) type initState interface { diff --git a/cmd/containerd-shim-runc-v2/process/io.go b/cmd/containerd-shim-runc-v2/process/io.go new file mode 100644 index 000000000000..466b506b18c6 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/io.go @@ -0,0 +1,434 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + "context" + "errors" + "fmt" + "io" + "net/url" + "os" + "os/exec" + "path/filepath" + "sync" + "sync/atomic" + "syscall" + "time" + + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/stdio" + "github.com/containerd/fifo" + runc "github.com/containerd/go-runc" + "github.com/containerd/log" +) + +const binaryIOProcTermTimeout = 12 * time.Second // Give logger process solid 10 seconds for cleanup + +var bufPool = sync.Pool{ + New: func() interface{} { + // setting to 4096 to align with PIPE_BUF + // http://man7.org/linux/man-pages/man7/pipe.7.html + buffer := make([]byte, 4096) + return &buffer + }, +} + +type processIO struct { + io runc.IO + + uri *url.URL + copy bool + stdio stdio.Stdio +} + +func (p *processIO) Close() error { + if p.io != nil { + return p.io.Close() + } + return nil +} + +func (p *processIO) IO() runc.IO { + return p.io +} + +func (p *processIO) Copy(ctx context.Context, wg *sync.WaitGroup) error { + if !p.copy { + return nil + } + var cwg sync.WaitGroup + if err := copyPipes(ctx, p.IO(), p.stdio.Stdin, p.stdio.Stdout, p.stdio.Stderr, wg, &cwg); err != nil { + return fmt.Errorf("unable to copy pipes: %w", err) + } + cwg.Wait() + return nil +} + +func createIO(ctx context.Context, id string, ioUID, ioGID int, stdio stdio.Stdio) (*processIO, error) { + pio := &processIO{ + stdio: stdio, + } + if stdio.IsNull() { + i, err := runc.NewNullIO() + if err != nil { + return nil, err + } + pio.io = i + return pio, nil + } + u, err := url.Parse(stdio.Stdout) + if err != nil { + return nil, fmt.Errorf("unable to parse stdout uri: %w", err) + } + if u.Scheme == "" { + u.Scheme = "fifo" + } + pio.uri = u + switch u.Scheme { + case "fifo": + pio.copy = true + pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio)) + case "binary": + pio.io, err = NewBinaryIO(ctx, id, u) + case "file": + filePath := u.Path + if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil { + return nil, err + } + var f *os.File + f, err = os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, err + } + f.Close() + pio.stdio.Stdout = filePath + pio.stdio.Stderr = filePath + pio.copy = true + pio.io, err = runc.NewPipeIO(ioUID, ioGID, withConditionalIO(stdio)) + default: + return nil, fmt.Errorf("unknown STDIO scheme %s", u.Scheme) + } + if err != nil { + return nil, err + } + return pio, nil +} + +func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, wg, cwg *sync.WaitGroup) error { + var sameFile *countingWriteCloser + for _, i := range []struct { + name string + dest func(wc io.WriteCloser, rc io.Closer) + }{ + { + name: stdout, + dest: func(wc io.WriteCloser, rc io.Closer) { + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + if _, err := io.CopyBuffer(wc, rio.Stdout(), *p); err != nil { + log.G(ctx).Warn("error copying stdout") + } + wg.Done() + wc.Close() + if rc != nil { + rc.Close() + } + }() + }, + }, { + name: stderr, + dest: func(wc io.WriteCloser, rc io.Closer) { + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + if _, err := io.CopyBuffer(wc, rio.Stderr(), *p); err != nil { + log.G(ctx).Warn("error copying stderr") + } + wg.Done() + wc.Close() + if rc != nil { + rc.Close() + } + }() + }, + }, + } { + ok, err := fifo.IsFifo(i.name) + if err != nil { + return err + } + var ( + fw io.WriteCloser + fr io.Closer + ) + if ok { + if fw, err = fifo.OpenFifo(ctx, i.name, syscall.O_WRONLY, 0); err != nil { + return fmt.Errorf("containerd-shim: opening w/o fifo %q failed: %w", i.name, err) + } + if fr, err = fifo.OpenFifo(ctx, i.name, syscall.O_RDONLY, 0); err != nil { + return fmt.Errorf("containerd-shim: opening r/o fifo %q failed: %w", i.name, err) + } + } else { + if sameFile != nil { + sameFile.count++ + i.dest(sameFile, nil) + continue + } + if fw, err = os.OpenFile(i.name, syscall.O_WRONLY|syscall.O_APPEND, 0); err != nil { + return fmt.Errorf("containerd-shim: opening file %q failed: %w", i.name, err) + } + if stdout == stderr { + sameFile = &countingWriteCloser{ + WriteCloser: fw, + count: 1, + } + } + } + i.dest(fw, fr) + } + if stdin == "" { + return nil + } + f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err) + } + cwg.Add(1) + go func() { + cwg.Done() + p := bufPool.Get().(*[]byte) + defer bufPool.Put(p) + + io.CopyBuffer(rio.Stdin(), f, *p) + rio.Stdin().Close() + f.Close() + }() + return nil +} + +// countingWriteCloser masks io.Closer() until close has been invoked a certain number of times. +type countingWriteCloser struct { + io.WriteCloser + count int64 +} + +func (c *countingWriteCloser) Close() error { + if atomic.AddInt64(&c.count, -1) > 0 { + return nil + } + return c.WriteCloser.Close() +} + +// NewBinaryIO runs a custom binary process for pluggable shim logging +func NewBinaryIO(ctx context.Context, id string, uri *url.URL) (_ runc.IO, err error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + var closers []func() error + defer func() { + if err == nil { + return + } + result := []error{err} + for _, fn := range closers { + result = append(result, fn()) + } + err = errors.Join(result...) + }() + + out, err := newPipe() + if err != nil { + return nil, fmt.Errorf("failed to create stdout pipes: %w", err) + } + closers = append(closers, out.Close) + + serr, err := newPipe() + if err != nil { + return nil, fmt.Errorf("failed to create stderr pipes: %w", err) + } + closers = append(closers, serr.Close) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + closers = append(closers, r.Close, w.Close) + + cmd := NewBinaryCmd(uri, id, ns) + cmd.ExtraFiles = append(cmd.ExtraFiles, out.r, serr.r, w) + // don't need to register this with the reaper or wait when + // running inside a shim + if err := cmd.Start(); err != nil { + return nil, fmt.Errorf("failed to start binary process: %w", err) + } + closers = append(closers, func() error { return cmd.Process.Kill() }) + + // close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, fmt.Errorf("failed to close write pipe after start: %w", err) + } + + // wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, fmt.Errorf("failed to read from logging binary: %w", err) + } + + return &binaryIO{ + cmd: cmd, + out: out, + err: serr, + }, nil +} + +type binaryIO struct { + cmd *exec.Cmd + out, err *pipe +} + +func (b *binaryIO) CloseAfterStart() error { + var result []error + + for _, v := range []*pipe{b.out, b.err} { + if v != nil { + if err := v.r.Close(); err != nil { + result = append(result, err) + } + } + } + + return errors.Join(result...) +} + +func (b *binaryIO) Close() error { + var result []error + + for _, v := range []*pipe{b.out, b.err} { + if v != nil { + if err := v.Close(); err != nil { + result = append(result, err) + } + } + } + + if err := b.cancel(); err != nil { + result = append(result, err) + } + + return errors.Join(result...) +} + +func (b *binaryIO) cancel() error { + if b.cmd == nil || b.cmd.Process == nil { + return nil + } + + // Send SIGTERM first, so logger process has a chance to flush and exit properly + if err := b.cmd.Process.Signal(syscall.SIGTERM); err != nil { + result := []error{fmt.Errorf("failed to send SIGTERM: %w", err)} + + log.L.WithError(err).Warn("failed to send SIGTERM signal, killing logging shim") + + if err := b.cmd.Process.Kill(); err != nil { + result = append(result, fmt.Errorf("failed to kill process after faulty SIGTERM: %w", err)) + } + + return errors.Join(result...) + } + + done := make(chan error, 1) + go func() { + done <- b.cmd.Wait() + }() + + select { + case err := <-done: + return err + case <-time.After(binaryIOProcTermTimeout): + log.L.Warn("failed to wait for shim logger process to exit, killing") + + err := b.cmd.Process.Kill() + if err != nil { + return fmt.Errorf("failed to kill shim logger process: %w", err) + } + + return nil + } +} + +func (b *binaryIO) Stdin() io.WriteCloser { + return nil +} + +func (b *binaryIO) Stdout() io.ReadCloser { + return nil +} + +func (b *binaryIO) Stderr() io.ReadCloser { + return nil +} + +func (b *binaryIO) Set(cmd *exec.Cmd) { + if b.out != nil { + cmd.Stdout = b.out.w + } + if b.err != nil { + cmd.Stderr = b.err.w + } +} + +func newPipe() (*pipe, error) { + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + return &pipe{ + r: r, + w: w, + }, nil +} + +type pipe struct { + r *os.File + w *os.File +} + +func (p *pipe) Close() error { + var result []error + + if err := p.w.Close(); err != nil { + result = append(result, fmt.Errorf("pipe: failed to close write pipe: %w", err)) + } + + if err := p.r.Close(); err != nil { + result = append(result, fmt.Errorf("pipe: failed to close read pipe: %w", err)) + } + + return errors.Join(result...) +} diff --git a/cmd/containerd-shim-runc-v2/process/io_test.go b/cmd/containerd-shim-runc-v2/process/io_test.go new file mode 100644 index 000000000000..6bb38ba4a73d --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/io_test.go @@ -0,0 +1,97 @@ +//go:build linux + +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + "context" + "net/url" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/containerd/containerd/v2/pkg/namespaces" +) + +func TestNewBinaryIO(t *testing.T) { + ctx := namespaces.WithNamespace(context.Background(), "test") + uri, _ := url.Parse("binary:///bin/echo?test") + + before := descriptorCount(t) + + io, err := NewBinaryIO(ctx, "1", uri) + if err != nil { + t.Fatal(err) + } + + err = io.Close() + if err != nil { + t.Fatal(err) + } + + after := descriptorCount(t) + if before != after-1 { // one descriptor must be closed from shim logger side + t.Fatalf("some descriptors weren't closed (%d != %d -1)", before, after) + } +} + +func TestNewBinaryIOCleanup(t *testing.T) { + ctx := namespaces.WithNamespace(context.Background(), "test") + uri, _ := url.Parse("binary:///not/existing") + + before := descriptorCount(t) + _, err := NewBinaryIO(ctx, "2", uri) + if err == nil { + t.Fatal("error expected for invalid binary") + } + + after := descriptorCount(t) + if before != after { + t.Fatalf("some descriptors weren't closed (%d != %d)", before, after) + } +} + +func descriptorCount(t *testing.T) int { + t.Helper() + const dir = "/proc/self/fd" + files, _ := os.ReadDir(dir) + + // Go 1.23+ uses pidfd instead of PID for processes started by a user, + // if possible (see https://go.dev/cl/570036). As a side effect, every + // os.StartProcess or os.FindProcess call results in an extra opened + // file descriptor, which is only closed in p.Wait or p.Release. + // + // To retain compatibility with previous Go versions (or Go 1.23+ + // behavior on older kernels), let's not count pidfds. + // + // TODO: if the proposal to check for internal file descriptors + // (https://go.dev/issues/67639) is accepted, we can use that + // instead to detect internal fds in use by the Go runtime. + count := 0 + for _, file := range files { + sym, err := os.Readlink(filepath.Join(dir, file.Name())) + // Either pidfd:[70517] or anon_inode:[pidfd] (on Linux 5.4). + if err == nil && strings.Contains(sym, "pidfd") { + continue + } + count++ + } + + return count +} diff --git a/pkg/process/io_util.go b/cmd/containerd-shim-runc-v2/process/io_util.go similarity index 97% rename from pkg/process/io_util.go rename to cmd/containerd-shim-runc-v2/process/io_util.go index e814c114b9d0..72bbf9233f8f 100644 --- a/pkg/process/io_util.go +++ b/cmd/containerd-shim-runc-v2/process/io_util.go @@ -19,8 +19,7 @@ package process import ( "net/url" "os" - - exec "golang.org/x/sys/execabs" + "os/exec" ) // NewBinaryCmd returns a Cmd to be used to start a logging binary. diff --git a/cmd/containerd-shim-runc-v2/process/process.go b/cmd/containerd-shim-runc-v2/process/process.go new file mode 100644 index 000000000000..7c1de346d32b --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/process.go @@ -0,0 +1,56 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + "context" + "io" + "time" + + "github.com/containerd/console" + "github.com/containerd/containerd/v2/pkg/stdio" +) + +// Process on a system +type Process interface { + // ID returns the id for the process + ID() string + // Pid returns the pid for the process + Pid() int + // ExitStatus returns the exit status + ExitStatus() int + // ExitedAt is the time the process exited + ExitedAt() time.Time + // Stdin returns the process STDIN + Stdin() io.Closer + // Stdio returns io information for the container + Stdio() stdio.Stdio + // Status returns the process status + Status(context.Context) (string, error) + // Wait blocks until the process has exited + Wait() + // Resize resizes the process console + Resize(ws console.WinSize) error + // Start execution of the process + Start(context.Context) error + // Delete deletes the process and its resourcess + Delete(context.Context) error + // Kill kills the process + Kill(context.Context, uint32, bool) error + // SetExited sets the exit status for the process + SetExited(status int) +} diff --git a/cmd/containerd-shim-runc-v2/process/types.go b/cmd/containerd-shim-runc-v2/process/types.go new file mode 100644 index 000000000000..2d9bd5f6be4d --- /dev/null +++ b/cmd/containerd-shim-runc-v2/process/types.go @@ -0,0 +1,66 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package process + +import ( + google_protobuf "github.com/containerd/containerd/v2/pkg/protobuf/types" +) + +// Mount holds filesystem mount configuration +type Mount struct { + Type string + Source string + Target string + Options []string +} + +// CreateConfig hold task creation configuration +type CreateConfig struct { + ID string + Bundle string + Runtime string + Rootfs []Mount + Terminal bool + Stdin string + Stdout string + Stderr string + Checkpoint string + ParentCheckpoint string + Options *google_protobuf.Any +} + +// ExecConfig holds exec creation configuration +type ExecConfig struct { + ID string + Terminal bool + Stdin string + Stdout string + Stderr string + Spec *google_protobuf.Any +} + +// CheckpointConfig holds task checkpoint configuration +type CheckpointConfig struct { + WorkDir string + Path string + Exit bool + AllowOpenTCP bool + AllowExternalUnixSockets bool + AllowTerminal bool + FileLocks bool + EmptyNamespaces []string +} diff --git a/pkg/process/utils.go b/cmd/containerd-shim-runc-v2/process/utils.go similarity index 98% rename from pkg/process/utils.go rename to cmd/containerd-shim-runc-v2/process/utils.go index 34b1f633da62..848ce8cc1319 100644 --- a/pkg/process/utils.go +++ b/cmd/containerd-shim-runc-v2/process/utils.go @@ -29,7 +29,7 @@ import ( "sync" "time" - "github.com/containerd/containerd/errdefs" + "github.com/containerd/errdefs" runc "github.com/containerd/go-runc" "golang.org/x/sys/unix" ) diff --git a/cmd/containerd-shim-runc-v2/runc/container.go b/cmd/containerd-shim-runc-v2/runc/container.go new file mode 100644 index 000000000000..d5b4a1f80d2b --- /dev/null +++ b/cmd/containerd-shim-runc-v2/runc/container.go @@ -0,0 +1,514 @@ +//go:build linux + +/* + Copyright The containerd Authors. + + 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. +*/ + +package runc + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "sync" + + "github.com/containerd/cgroups/v3" + "github.com/containerd/cgroups/v3/cgroup1" + cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2" + "github.com/containerd/console" + "github.com/containerd/containerd/api/runtime/task/v3" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + "github.com/containerd/log" + "github.com/containerd/typeurl/v2" + + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/process" + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/stdio" +) + +// NewContainer returns a new runc container +func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTaskRequest) (_ *Container, retErr error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, fmt.Errorf("create namespace: %w", err) + } + + opts := &options.Options{} + if r.Options.GetValue() != nil { + v, err := typeurl.UnmarshalAny(r.Options) + if err != nil { + return nil, err + } + if v != nil { + opts = v.(*options.Options) + } + } + + var pmounts []process.Mount + for _, m := range r.Rootfs { + pmounts = append(pmounts, process.Mount{ + Type: m.Type, + Source: m.Source, + Target: m.Target, + Options: m.Options, + }) + } + + rootfs := "" + if len(pmounts) > 0 { + rootfs = filepath.Join(r.Bundle, "rootfs") + if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) { + return nil, err + } + } + + config := &process.CreateConfig{ + ID: r.ID, + Bundle: r.Bundle, + Runtime: opts.BinaryName, + Rootfs: pmounts, + Terminal: r.Terminal, + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Checkpoint: r.Checkpoint, + ParentCheckpoint: r.ParentCheckpoint, + Options: r.Options, + } + + if err := WriteOptions(r.Bundle, opts); err != nil { + return nil, err + } + // For historical reason, we write opts.BinaryName as well as the entire opts + if err := WriteRuntime(r.Bundle, opts.BinaryName); err != nil { + return nil, err + } + + var mounts []mount.Mount + for _, pm := range pmounts { + mounts = append(mounts, mount.Mount{ + Type: pm.Type, + Source: pm.Source, + Target: pm.Target, + Options: pm.Options, + }) + } + defer func() { + if retErr != nil { + if err := mount.UnmountMounts(mounts, rootfs, 0); err != nil { + log.G(ctx).WithError(err).Warn("failed to cleanup rootfs mount") + } + } + }() + if err := mount.All(mounts, rootfs); err != nil { + return nil, fmt.Errorf("failed to mount rootfs component: %w", err) + } + + p, err := newInit( + ctx, + r.Bundle, + filepath.Join(r.Bundle, "work"), + ns, + platform, + config, + opts, + rootfs, + ) + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + if err := p.Create(ctx, config); err != nil { + return nil, errgrpc.ToGRPC(err) + } + container := &Container{ + ID: r.ID, + Bundle: r.Bundle, + process: p, + processes: make(map[string]process.Process), + reservedProcess: make(map[string]struct{}), + } + pid := p.Pid() + if pid > 0 { + var cg interface{} + if cgroups.Mode() == cgroups.Unified { + g, err := cgroupsv2.PidGroupPath(pid) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup2 for %d", pid) + return container, nil + } + cg, err = cgroupsv2.Load(g) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup2 for %d", pid) + } + } else { + cg, err = cgroup1.Load(cgroup1.PidPath(pid)) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup for %d", pid) + } + } + container.cgroup = cg + } + return container, nil +} + +const optionsFilename = "options.json" + +// ReadOptions reads the option information from the path. +// When the file does not exist, ReadOptions returns nil without an error. +func ReadOptions(path string) (*options.Options, error) { + filePath := filepath.Join(path, optionsFilename) + if _, err := os.Stat(filePath); err != nil { + if os.IsNotExist(err) { + return nil, nil + } + return nil, err + } + + data, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + var opts options.Options + if err := json.Unmarshal(data, &opts); err != nil { + return nil, err + } + return &opts, nil +} + +// WriteOptions writes the options information into the path +func WriteOptions(path string, opts *options.Options) error { + data, err := json.Marshal(opts) + if err != nil { + return err + } + return os.WriteFile(filepath.Join(path, optionsFilename), data, 0600) +} + +// ReadRuntime reads the runtime information from the path +func ReadRuntime(path string) (string, error) { + data, err := os.ReadFile(filepath.Join(path, "runtime")) + if err != nil { + return "", err + } + return string(data), nil +} + +// WriteRuntime writes the runtime information into the path +func WriteRuntime(path, runtime string) error { + return os.WriteFile(filepath.Join(path, "runtime"), []byte(runtime), 0600) +} + +func newInit(ctx context.Context, path, workDir, namespace string, platform stdio.Platform, + r *process.CreateConfig, options *options.Options, rootfs string) (*process.Init, error) { + runtime := process.NewRunc(options.Root, path, namespace, options.BinaryName, options.SystemdCgroup) + p := process.New(r.ID, runtime, stdio.Stdio{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }) + p.Bundle = r.Bundle + p.Platform = platform + p.Rootfs = rootfs + p.WorkDir = workDir + p.IoUID = int(options.IoUid) + p.IoGID = int(options.IoGid) + p.NoPivotRoot = options.NoPivotRoot + p.NoNewKeyring = options.NoNewKeyring + p.CriuWorkPath = options.CriuWorkPath + if p.CriuWorkPath == "" { + // if criu work path not set, use container WorkDir + p.CriuWorkPath = p.WorkDir + } + return p, nil +} + +// Container for operating on a runc container and its processes +type Container struct { + mu sync.Mutex + + // ID of the container + ID string + // Bundle path + Bundle string + + // cgroup is either cgroups.Cgroup or *cgroupsv2.Manager + cgroup interface{} + process process.Process + processes map[string]process.Process + reservedProcess map[string]struct{} +} + +// All processes in the container +func (c *Container) All() (o []process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + + for _, p := range c.processes { + o = append(o, p) + } + if c.process != nil { + o = append(o, c.process) + } + return o +} + +// ExecdProcesses added to the container +func (c *Container) ExecdProcesses() (o []process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + for _, p := range c.processes { + o = append(o, p) + } + return o +} + +// Pid of the main process of a container +func (c *Container) Pid() int { + c.mu.Lock() + defer c.mu.Unlock() + return c.process.Pid() +} + +// Cgroup of the container +func (c *Container) Cgroup() interface{} { + c.mu.Lock() + defer c.mu.Unlock() + return c.cgroup +} + +// CgroupSet sets the cgroup to the container +func (c *Container) CgroupSet(cg interface{}) { + c.mu.Lock() + c.cgroup = cg + c.mu.Unlock() +} + +// Process returns the process by id +func (c *Container) Process(id string) (process.Process, error) { + c.mu.Lock() + defer c.mu.Unlock() + if id == "" { + if c.process == nil { + return nil, fmt.Errorf("container must be created: %w", errdefs.ErrFailedPrecondition) + } + return c.process, nil + } + p, ok := c.processes[id] + if !ok { + return nil, fmt.Errorf("process does not exist %s: %w", id, errdefs.ErrNotFound) + } + return p, nil +} + +// ReserveProcess checks for the existence of an id and atomically +// reserves the process id if it does not already exist +// +// Returns true if the process id was successfully reserved and a +// cancel func to release the reservation +func (c *Container) ReserveProcess(id string) (bool, func()) { + c.mu.Lock() + defer c.mu.Unlock() + + if _, ok := c.processes[id]; ok { + return false, nil + } + if _, ok := c.reservedProcess[id]; ok { + return false, nil + } + c.reservedProcess[id] = struct{}{} + return true, func() { + c.mu.Lock() + defer c.mu.Unlock() + delete(c.reservedProcess, id) + } +} + +// ProcessAdd adds a new process to the container +func (c *Container) ProcessAdd(process process.Process) { + c.mu.Lock() + defer c.mu.Unlock() + + delete(c.reservedProcess, process.ID()) + c.processes[process.ID()] = process +} + +// ProcessRemove removes the process by id from the container +func (c *Container) ProcessRemove(id string) { + c.mu.Lock() + defer c.mu.Unlock() + delete(c.processes, id) +} + +// Start a container process +func (c *Container) Start(ctx context.Context, r *task.StartRequest) (process.Process, error) { + p, err := c.Process(r.ExecID) + if err != nil { + return nil, err + } + if err := p.Start(ctx); err != nil { + return p, err + } + if c.Cgroup() == nil && p.Pid() > 0 { + var cg interface{} + if cgroups.Mode() == cgroups.Unified { + g, err := cgroupsv2.PidGroupPath(p.Pid()) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup2 for %d", p.Pid()) + } + cg, err = cgroupsv2.Load(g) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup2 for %d", p.Pid()) + } + } else { + cg, err = cgroup1.Load(cgroup1.PidPath(p.Pid())) + if err != nil { + log.G(ctx).WithError(err).Errorf("loading cgroup for %d", p.Pid()) + } + } + c.cgroup = cg + } + return p, nil +} + +// Delete the container or a process by id +func (c *Container) Delete(ctx context.Context, r *task.DeleteRequest) (process.Process, error) { + p, err := c.Process(r.ExecID) + if err != nil { + return nil, err + } + if err := p.Delete(ctx); err != nil { + return nil, err + } + if r.ExecID != "" { + c.ProcessRemove(r.ExecID) + } + return p, nil +} + +// Exec an additional process +func (c *Container) Exec(ctx context.Context, r *task.ExecProcessRequest) (process.Process, error) { + process, err := c.process.(*process.Init).Exec(ctx, c.Bundle, &process.ExecConfig{ + ID: r.ExecID, + Terminal: r.Terminal, + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Spec: r.Spec, + }) + if err != nil { + return nil, err + } + c.ProcessAdd(process) + return process, nil +} + +// Pause the container +func (c *Container) Pause(ctx context.Context) error { + return c.process.(*process.Init).Pause(ctx) +} + +// Resume the container +func (c *Container) Resume(ctx context.Context) error { + return c.process.(*process.Init).Resume(ctx) +} + +// ResizePty of a process +func (c *Container) ResizePty(ctx context.Context, r *task.ResizePtyRequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + ws := console.WinSize{ + Width: uint16(r.Width), + Height: uint16(r.Height), + } + return p.Resize(ws) +} + +// Kill a process +func (c *Container) Kill(ctx context.Context, r *task.KillRequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + return p.Kill(ctx, r.Signal, r.All) +} + +// CloseIO of a process +func (c *Container) CloseIO(ctx context.Context, r *task.CloseIORequest) error { + p, err := c.Process(r.ExecID) + if err != nil { + return err + } + if stdin := p.Stdin(); stdin != nil { + if err := stdin.Close(); err != nil { + return fmt.Errorf("close stdin: %w", err) + } + } + return nil +} + +// Checkpoint the container +func (c *Container) Checkpoint(ctx context.Context, r *task.CheckpointTaskRequest) error { + p, err := c.Process("") + if err != nil { + return err + } + + var opts options.CheckpointOptions + if r.Options != nil { + if err := typeurl.UnmarshalTo(r.Options, &opts); err != nil { + return err + } + } + return p.(*process.Init).Checkpoint(ctx, &process.CheckpointConfig{ + Path: r.Path, + Exit: opts.Exit, + AllowOpenTCP: opts.OpenTcp, + AllowExternalUnixSockets: opts.ExternalUnixSockets, + AllowTerminal: opts.Terminal, + FileLocks: opts.FileLocks, + EmptyNamespaces: opts.EmptyNamespaces, + WorkDir: opts.WorkPath, + }) +} + +// Update the resource information of a running container +func (c *Container) Update(ctx context.Context, r *task.UpdateTaskRequest) error { + p, err := c.Process("") + if err != nil { + return err + } + return p.(*process.Init).Update(ctx, r.Resources) +} + +// HasPid returns true if the container owns a specific pid +func (c *Container) HasPid(pid int) bool { + if c.Pid() == pid { + return true + } + for _, p := range c.All() { + if p.Pid() == pid { + return true + } + } + return false +} diff --git a/cmd/containerd-shim-runc-v2/runc/platform.go b/cmd/containerd-shim-runc-v2/runc/platform.go new file mode 100644 index 000000000000..68b00ab676cd --- /dev/null +++ b/cmd/containerd-shim-runc-v2/runc/platform.go @@ -0,0 +1,202 @@ +//go:build linux + +/* + Copyright The containerd Authors. + + 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. +*/ + +package runc + +import ( + "context" + "errors" + "fmt" + "io" + "net/url" + "os" + "sync" + "syscall" + + "github.com/containerd/console" + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/process" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/stdio" + "github.com/containerd/fifo" +) + +var bufPool = sync.Pool{ + New: func() interface{} { + // setting to 4096 to align with PIPE_BUF + // http://man7.org/linux/man-pages/man7/pipe.7.html + buffer := make([]byte, 4096) + return &buffer + }, +} + +// NewPlatform returns a linux platform for use with I/O operations +func NewPlatform() (stdio.Platform, error) { + epoller, err := console.NewEpoller() + if err != nil { + return nil, fmt.Errorf("failed to initialize epoller: %w", err) + } + go epoller.Wait() + return &linuxPlatform{ + epoller: epoller, + }, nil +} + +type linuxPlatform struct { + epoller *console.Epoller +} + +func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { + if p.epoller == nil { + return nil, errors.New("uninitialized epoller") + } + + epollConsole, err := p.epoller.Add(console) + if err != nil { + return nil, err + } + + var cwg sync.WaitGroup + if stdin != "" { + in, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return nil, err + } + cwg.Add(1) + go func() { + cwg.Done() + bp := bufPool.Get().(*[]byte) + defer bufPool.Put(bp) + io.CopyBuffer(epollConsole, in, *bp) + // we need to shutdown epollConsole when pipe broken + epollConsole.Shutdown(p.epoller.CloseConsole) + epollConsole.Close() + in.Close() + }() + } + + uri, err := url.Parse(stdout) + if err != nil { + return nil, fmt.Errorf("unable to parse stdout uri: %w", err) + } + + switch uri.Scheme { + case "binary": + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return nil, err + } + + cmd := process.NewBinaryCmd(uri, id, ns) + + // In case of unexpected errors during logging binary start, close open pipes + var filesToClose []*os.File + + defer func() { + if retErr != nil { + process.CloseFiles(filesToClose...) + } + }() + + // Create pipe to be used by logging binary for Stdout + outR, outW, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create stdout pipes: %w", err) + } + filesToClose = append(filesToClose, outR) + + // Stderr is created for logging binary but unused when terminal is true + serrR, _, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("failed to create stderr pipes: %w", err) + } + filesToClose = append(filesToClose, serrR) + + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + filesToClose = append(filesToClose, r) + + cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) + + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + io.Copy(outW, epollConsole) + outW.Close() + wg.Done() + }() + + if err := cmd.Start(); err != nil { + return nil, fmt.Errorf("failed to start logging binary process: %w", err) + } + + // Close our side of the pipe after start + if err := w.Close(); err != nil { + return nil, fmt.Errorf("failed to close write pipe after start: %w", err) + } + + // Wait for the logging binary to be ready + b := make([]byte, 1) + if _, err := r.Read(b); err != nil && err != io.EOF { + return nil, fmt.Errorf("failed to read from logging binary: %w", err) + } + cwg.Wait() + + default: + outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) + if err != nil { + return nil, err + } + outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) + if err != nil { + return nil, err + } + wg.Add(1) + cwg.Add(1) + go func() { + cwg.Done() + buf := bufPool.Get().(*[]byte) + defer bufPool.Put(buf) + io.CopyBuffer(outw, epollConsole, *buf) + + outw.Close() + outr.Close() + wg.Done() + }() + cwg.Wait() + } + + return epollConsole, nil +} + +func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { + if p.epoller == nil { + return errors.New("uninitialized epoller") + } + epollConsole, ok := cons.(*console.EpollConsole) + if !ok { + return fmt.Errorf("expected EpollConsole, got %#v", cons) + } + return epollConsole.Shutdown(p.epoller.CloseConsole) +} + +func (p *linuxPlatform) Close() error { + return p.epoller.Close() +} diff --git a/cmd/containerd-shim-runc-v2/runc/util.go b/cmd/containerd-shim-runc-v2/runc/util.go new file mode 100644 index 000000000000..7a3d88dff544 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/runc/util.go @@ -0,0 +1,62 @@ +//go:build linux + +/* + Copyright The containerd Authors. + + 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. +*/ + +package runc + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + + "github.com/containerd/log" + "github.com/opencontainers/runtime-spec/specs-go" +) + +// ShouldKillAllOnExit reads the bundle's OCI spec and returns true if +// there is an error reading the spec or if the container has a private PID namespace +func ShouldKillAllOnExit(ctx context.Context, bundlePath string) bool { + spec, err := readSpec(bundlePath) + if err != nil { + log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to read config.json") + return true + } + + if spec.Linux != nil { + for _, ns := range spec.Linux.Namespaces { + if ns.Type == specs.PIDNamespace && ns.Path == "" { + return false + } + } + } + return true +} + +func readSpec(p string) (*specs.Spec, error) { + const configFileName = "config.json" + f, err := os.Open(filepath.Join(p, configFileName)) + if err != nil { + return nil, err + } + defer f.Close() + var s specs.Spec + if err := json.NewDecoder(f).Decode(&s); err != nil { + return nil, err + } + return &s, nil +} diff --git a/cmd/containerd-shim-runc-v2/task/plugin/plugin_linux.go b/cmd/containerd-shim-runc-v2/task/plugin/plugin_linux.go new file mode 100644 index 000000000000..31edccd443d5 --- /dev/null +++ b/cmd/containerd-shim-runc-v2/task/plugin/plugin_linux.go @@ -0,0 +1,49 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package plugin + +import ( + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/task" + "github.com/containerd/containerd/v2/pkg/shim" + "github.com/containerd/containerd/v2/pkg/shutdown" + "github.com/containerd/containerd/v2/plugins" + "github.com/containerd/plugin" + "github.com/containerd/plugin/registry" +) + +func init() { + registry.Register(&plugin.Registration{ + Type: plugins.TTRPCPlugin, + ID: "task", + Requires: []plugin.Type{ + plugins.EventPlugin, + plugins.InternalPlugin, + }, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + pp, err := ic.GetByID(plugins.EventPlugin, "publisher") + if err != nil { + return nil, err + } + ss, err := ic.GetByID(plugins.InternalPlugin, "shutdown") + if err != nil { + return nil, err + } + return task.NewTaskService(ic.Context, pp.(shim.Publisher), ss.(shutdown.Service)) + }, + }) + +} diff --git a/cmd/containerd-shim-runc-v2/task/service.go b/cmd/containerd-shim-runc-v2/task/service.go new file mode 100644 index 000000000000..373b6881ed0b --- /dev/null +++ b/cmd/containerd-shim-runc-v2/task/service.go @@ -0,0 +1,817 @@ +//go:build linux + +/* + Copyright The containerd Authors. + + 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. +*/ + +package task + +import ( + "context" + "fmt" + "os" + "sync" + + "github.com/moby/sys/userns" + + "github.com/containerd/cgroups/v3" + "github.com/containerd/cgroups/v3/cgroup1" + cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2" + eventstypes "github.com/containerd/containerd/api/events" + taskAPI "github.com/containerd/containerd/api/runtime/task/v3" + "github.com/containerd/containerd/api/types/runc/options" + "github.com/containerd/containerd/api/types/task" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + runcC "github.com/containerd/go-runc" + "github.com/containerd/log" + "github.com/containerd/ttrpc" + "github.com/containerd/typeurl/v2" + + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/process" + "github.com/containerd/containerd/v2/cmd/containerd-shim-runc-v2/runc" + "github.com/containerd/containerd/v2/core/runtime" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/oom" + oomv1 "github.com/containerd/containerd/v2/pkg/oom/v1" + oomv2 "github.com/containerd/containerd/v2/pkg/oom/v2" + "github.com/containerd/containerd/v2/pkg/protobuf" + ptypes "github.com/containerd/containerd/v2/pkg/protobuf/types" + "github.com/containerd/containerd/v2/pkg/shim" + "github.com/containerd/containerd/v2/pkg/shutdown" + "github.com/containerd/containerd/v2/pkg/stdio" + "github.com/containerd/containerd/v2/pkg/sys/reaper" +) + +var ( + _ = shim.TTRPCService(&service{}) + empty = &ptypes.Empty{} +) + +// NewTaskService creates a new instance of a task service +func NewTaskService(ctx context.Context, publisher shim.Publisher, sd shutdown.Service) (taskAPI.TTRPCTaskService, error) { + var ( + ep oom.Watcher + err error + ) + if cgroups.Mode() == cgroups.Unified { + ep, err = oomv2.New(publisher) + } else { + ep, err = oomv1.New(publisher) + } + if err != nil { + return nil, err + } + go ep.Run(ctx) + s := &service{ + context: ctx, + events: make(chan interface{}, 128), + ec: reaper.Default.Subscribe(), + ep: ep, + shutdown: sd, + containers: make(map[string]*runc.Container), + running: make(map[int][]containerProcess), + runningExecs: make(map[*runc.Container]int), + execCountSubscribers: make(map[*runc.Container]chan<- int), + containerInitExit: make(map[*runc.Container]runcC.Exit), + exitSubscribers: make(map[*map[int][]runcC.Exit]struct{}), + } + go s.processExits() + runcC.Monitor = reaper.Default + if err := s.initPlatform(); err != nil { + return nil, fmt.Errorf("failed to initialized platform behavior: %w", err) + } + go s.forward(ctx, publisher) + sd.RegisterCallback(func(context.Context) error { + close(s.events) + return nil + }) + + if address, err := shim.ReadAddress("address"); err == nil { + sd.RegisterCallback(func(context.Context) error { + return shim.RemoveSocket(address) + }) + } + return s, nil +} + +// service is the shim implementation of a remote shim over GRPC +type service struct { + mu sync.Mutex + + context context.Context + events chan interface{} + platform stdio.Platform + ec chan runcC.Exit + ep oom.Watcher + + containers map[string]*runc.Container + + lifecycleMu sync.Mutex + running map[int][]containerProcess // pid -> running process, guarded by lifecycleMu + runningExecs map[*runc.Container]int // container -> num running execs, guarded by lifecycleMu + // container -> subscription to exec exits/changes to s.runningExecs[container], + // guarded by lifecycleMu + execCountSubscribers map[*runc.Container]chan<- int + // container -> init exits, guarded by lifecycleMu + // Used to stash container init process exits, so that we can hold them + // until after we've made sure to publish all the container's exec exits. + // Also used to prevent starting new execs from being started if the + // container's init process (read: pid, not [process.Init]) has already been + // reaped by the shim. + // Note that this flag gets updated before the container's [process.Init.Status] + // is transitioned to "stopped". + containerInitExit map[*runc.Container]runcC.Exit + // Subscriptions to exits for PIDs. Adding/deleting subscriptions and + // dereferencing the subscription pointers must only be done while holding + // lifecycleMu. + exitSubscribers map[*map[int][]runcC.Exit]struct{} + + shutdown shutdown.Service +} + +type containerProcess struct { + Container *runc.Container + Process process.Process +} + +// preStart prepares for starting a container process and handling its exit. +// The container being started should be passed in as c when starting the container +// init process for an already-created container. c should be nil when creating a +// container or when starting an exec. +// +// The returned handleStarted closure records that the process has started so +// that its exit can be handled efficiently. If the process has already exited, +// it handles the exit immediately. +// handleStarted should be called after the event announcing the start of the +// process has been published. Note that s.lifecycleMu must not be held when +// calling handleStarted. +// +// The returned cleanup closure releases resources used to handle early exits. +// It must be called before the caller of preStart returns, otherwise severe +// memory leaks will occur. +func (s *service) preStart(c *runc.Container) (handleStarted func(*runc.Container, process.Process), cleanup func()) { + exits := make(map[int][]runcC.Exit) + s.exitSubscribers[&exits] = struct{}{} + + if c != nil { + // Remove container init process from s.running so it will once again be + // treated as an early exit if it exits before handleStarted is called. + pid := c.Pid() + var newRunning []containerProcess + for _, cp := range s.running[pid] { + if cp.Container != c { + newRunning = append(newRunning, cp) + } + } + if len(newRunning) > 0 { + s.running[pid] = newRunning + } else { + delete(s.running, pid) + } + } + + handleStarted = func(c *runc.Container, p process.Process) { + var pid int + if p != nil { + pid = p.Pid() + } + + s.lifecycleMu.Lock() + + ees, exited := exits[pid] + delete(s.exitSubscribers, &exits) + exits = nil + if pid == 0 || exited { + s.lifecycleMu.Unlock() + for _, ee := range ees { + s.handleProcessExit(ee, c, p) + } + } else { + // Process start was successful, add to `s.running`. + s.running[pid] = append(s.running[pid], containerProcess{ + Container: c, + Process: p, + }) + s.lifecycleMu.Unlock() + } + } + + cleanup = func() { + if exits != nil { + s.lifecycleMu.Lock() + defer s.lifecycleMu.Unlock() + delete(s.exitSubscribers, &exits) + } + } + + return handleStarted, cleanup +} + +// Create a new initial process and container with the underlying OCI runtime +func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { + s.mu.Lock() + defer s.mu.Unlock() + + s.lifecycleMu.Lock() + handleStarted, cleanup := s.preStart(nil) + s.lifecycleMu.Unlock() + defer cleanup() + + container, err := runc.NewContainer(ctx, s.platform, r) + if err != nil { + return nil, err + } + + s.containers[r.ID] = container + + s.send(&eventstypes.TaskCreate{ + ContainerID: r.ID, + Bundle: r.Bundle, + Rootfs: r.Rootfs, + IO: &eventstypes.TaskIO{ + Stdin: r.Stdin, + Stdout: r.Stdout, + Stderr: r.Stderr, + Terminal: r.Terminal, + }, + Checkpoint: r.Checkpoint, + Pid: uint32(container.Pid()), + }) + + // The following line cannot return an error as the only state in which that + // could happen would also cause the container.Pid() call above to + // nil-deference panic. + proc, _ := container.Process("") + handleStarted(container, proc) + + return &taskAPI.CreateTaskResponse{ + Pid: uint32(container.Pid()), + }, nil +} + +func (s *service) RegisterTTRPC(server *ttrpc.Server) error { + taskAPI.RegisterTTRPCTaskService(server, s) + return nil +} + +// Start a process +func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + + var cinit *runc.Container + s.lifecycleMu.Lock() + if r.ExecID == "" { + cinit = container + } else { + if _, initExited := s.containerInitExit[container]; initExited { + s.lifecycleMu.Unlock() + return nil, errgrpc.ToGRPCf(errdefs.ErrFailedPrecondition, "container %s init process is not running", container.ID) + } + s.runningExecs[container]++ + } + handleStarted, cleanup := s.preStart(cinit) + s.lifecycleMu.Unlock() + defer cleanup() + + p, err := container.Start(ctx, r) + if err != nil { + // If we failed to even start the process, s.runningExecs + // won't get decremented in s.handleProcessExit. We still need + // to update it. + if r.ExecID != "" { + s.lifecycleMu.Lock() + s.runningExecs[container]-- + if ch, ok := s.execCountSubscribers[container]; ok { + ch <- s.runningExecs[container] + } + s.lifecycleMu.Unlock() + } + handleStarted(container, p) + return nil, errgrpc.ToGRPC(err) + } + + switch r.ExecID { + case "": + switch cg := container.Cgroup().(type) { + case cgroup1.Cgroup: + if err := s.ep.Add(container.ID, cg); err != nil { + log.G(ctx).WithError(err).Error("add cg to OOM monitor") + } + case *cgroupsv2.Manager: + allControllers, err := cg.RootControllers() + if err != nil { + log.G(ctx).WithError(err).Error("failed to get root controllers") + } else { + if err := cg.ToggleControllers(allControllers, cgroupsv2.Enable); err != nil { + if userns.RunningInUserNS() { + log.G(ctx).WithError(err).Debugf("failed to enable controllers (%v)", allControllers) + } else { + log.G(ctx).WithError(err).Errorf("failed to enable controllers (%v)", allControllers) + } + } + } + if err := s.ep.Add(container.ID, cg); err != nil { + log.G(ctx).WithError(err).Error("add cg to OOM monitor") + } + } + + s.send(&eventstypes.TaskStart{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + }) + default: + s.send(&eventstypes.TaskExecStarted{ + ContainerID: container.ID, + ExecID: r.ExecID, + Pid: uint32(p.Pid()), + }) + } + handleStarted(container, p) + return &taskAPI.StartResponse{ + Pid: uint32(p.Pid()), + }, nil +} + +// Delete the initial process and container +func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Delete(ctx, r) + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + // if we deleted an init task, send the task delete event + if r.ExecID == "" { + s.mu.Lock() + delete(s.containers, r.ID) + s.mu.Unlock() + s.send(&eventstypes.TaskDelete{ + ContainerID: container.ID, + Pid: uint32(p.Pid()), + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: protobuf.ToTimestamp(p.ExitedAt()), + }) + } + return &taskAPI.DeleteResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: protobuf.ToTimestamp(p.ExitedAt()), + Pid: uint32(p.Pid()), + }, nil +} + +// Exec an additional process inside the container +func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + ok, cancel := container.ReserveProcess(r.ExecID) + if !ok { + return nil, errgrpc.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID) + } + process, err := container.Exec(ctx, r) + if err != nil { + cancel() + return nil, errgrpc.ToGRPC(err) + } + + s.send(&eventstypes.TaskExecAdded{ + ContainerID: container.ID, + ExecID: process.ID(), + }) + return empty, nil +} + +// ResizePty of a process +func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.ResizePty(ctx, r); err != nil { + return nil, errgrpc.ToGRPC(err) + } + return empty, nil +} + +// State returns runtime state information for a process +func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Process(r.ExecID) + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + st, err := p.Status(ctx) + if err != nil { + return nil, err + } + status := task.Status_UNKNOWN + switch st { + case "created": + status = task.Status_CREATED + case "running": + status = task.Status_RUNNING + case "stopped": + status = task.Status_STOPPED + case "paused": + status = task.Status_PAUSED + case "pausing": + status = task.Status_PAUSING + } + sio := p.Stdio() + return &taskAPI.StateResponse{ + ID: p.ID(), + Bundle: container.Bundle, + Pid: uint32(p.Pid()), + Status: status, + Stdin: sio.Stdin, + Stdout: sio.Stdout, + Stderr: sio.Stderr, + Terminal: sio.Terminal, + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: protobuf.ToTimestamp(p.ExitedAt()), + }, nil +} + +// Pause the container +func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Pause(ctx); err != nil { + return nil, errgrpc.ToGRPC(err) + } + s.send(&eventstypes.TaskPaused{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Resume the container +func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Resume(ctx); err != nil { + return nil, errgrpc.ToGRPC(err) + } + s.send(&eventstypes.TaskResumed{ + ContainerID: container.ID, + }) + return empty, nil +} + +// Kill a process with the provided signal +func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Kill(ctx, r); err != nil { + return nil, errgrpc.ToGRPC(err) + } + return empty, nil +} + +// Pids returns all pids inside the container +func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + pids, err := s.getContainerPids(ctx, container) + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + var processes []*task.ProcessInfo + for _, pid := range pids { + pInfo := task.ProcessInfo{ + Pid: pid, + } + for _, p := range container.ExecdProcesses() { + if p.Pid() == int(pid) { + d := &options.ProcessDetails{ + ExecID: p.ID(), + } + a, err := typeurl.MarshalAnyToProto(d) + if err != nil { + return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err) + } + pInfo.Info = a + break + } + } + processes = append(processes, &pInfo) + } + return &taskAPI.PidsResponse{ + Processes: processes, + }, nil +} + +// CloseIO of a process +func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.CloseIO(ctx, r); err != nil { + return nil, err + } + return empty, nil +} + +// Checkpoint the container +func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Checkpoint(ctx, r); err != nil { + return nil, errgrpc.ToGRPC(err) + } + return empty, nil +} + +// Update a running container +func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + if err := container.Update(ctx, r); err != nil { + return nil, errgrpc.ToGRPC(err) + } + return empty, nil +} + +// Wait for a process to exit +func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + p, err := container.Process(r.ExecID) + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + p.Wait() + + return &taskAPI.WaitResponse{ + ExitStatus: uint32(p.ExitStatus()), + ExitedAt: protobuf.ToTimestamp(p.ExitedAt()), + }, nil +} + +// Connect returns shim information such as the shim's pid +func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { + var pid int + if container, err := s.getContainer(r.ID); err == nil { + pid = container.Pid() + } + return &taskAPI.ConnectResponse{ + ShimPid: uint32(os.Getpid()), + TaskPid: uint32(pid), + }, nil +} + +func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + + // return out if the shim is still servicing containers + if len(s.containers) > 0 { + return empty, nil + } + + // please make sure that temporary resource has been cleanup or registered + // for cleanup before calling shutdown + s.shutdown.Shutdown() + + return empty, nil +} + +func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + container, err := s.getContainer(r.ID) + if err != nil { + return nil, err + } + cgx := container.Cgroup() + if cgx == nil { + return nil, errgrpc.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") + } + var statsx interface{} + switch cg := cgx.(type) { + case cgroup1.Cgroup: + stats, err := cg.Stat(cgroup1.IgnoreNotExist) + if err != nil { + return nil, err + } + statsx = stats + case *cgroupsv2.Manager: + stats, err := cg.Stat() + if err != nil { + return nil, err + } + statsx = stats + default: + return nil, errgrpc.ToGRPCf(errdefs.ErrNotImplemented, "unsupported cgroup type %T", cg) + } + data, err := typeurl.MarshalAny(statsx) + if err != nil { + return nil, err + } + return &taskAPI.StatsResponse{ + Stats: typeurl.MarshalProto(data), + }, nil +} + +func (s *service) processExits() { + for e := range s.ec { + // While unlikely, it is not impossible for a container process to exit + // and have its PID be recycled for a new container process before we + // have a chance to process the first exit. As we have no way to tell + // for sure which of the processes the exit event corresponds to (until + // pidfd support is implemented) there is no way for us to handle the + // exit correctly in that case. + + s.lifecycleMu.Lock() + // Inform any concurrent s.Start() calls so they can handle the exit + // if the PID belongs to them. + for subscriber := range s.exitSubscribers { + (*subscriber)[e.Pid] = append((*subscriber)[e.Pid], e) + } + // Handle the exit for a created/started process. If there's more than + // one, assume they've all exited. One of them will be the correct + // process. + var cps []containerProcess + for _, cp := range s.running[e.Pid] { + _, init := cp.Process.(*process.Init) + if init { + s.containerInitExit[cp.Container] = e + } + cps = append(cps, cp) + } + delete(s.running, e.Pid) + s.lifecycleMu.Unlock() + + for _, cp := range cps { + if ip, ok := cp.Process.(*process.Init); ok { + s.handleInitExit(e, cp.Container, ip) + } else { + s.handleProcessExit(e, cp.Container, cp.Process) + } + } + } +} + +func (s *service) send(evt interface{}) { + s.events <- evt +} + +// handleInitExit processes container init process exits. +// This is handled separately from non-init exits, because there +// are some extra invariants we want to ensure in this case, namely: +// - for a given container, the init process exit MUST be the last exit published +// This is achieved by: +// - killing all running container processes (if the container has a shared pid +// namespace, otherwise all other processes have been reaped already). +// - waiting for the container's running exec counter to reach 0. +// - finally, publishing the init exit. +func (s *service) handleInitExit(e runcC.Exit, c *runc.Container, p *process.Init) { + // kill all running container processes + if runc.ShouldKillAllOnExit(s.context, c.Bundle) { + if err := p.KillAll(s.context); err != nil { + log.G(s.context).WithError(err).WithField("id", p.ID()). + Error("failed to kill init's children") + } + } + + s.lifecycleMu.Lock() + numRunningExecs := s.runningExecs[c] + if numRunningExecs == 0 { + delete(s.runningExecs, c) + s.lifecycleMu.Unlock() + s.handleProcessExit(e, c, p) + return + } + + events := make(chan int, numRunningExecs) + s.execCountSubscribers[c] = events + + s.lifecycleMu.Unlock() + + go func() { + defer func() { + s.lifecycleMu.Lock() + defer s.lifecycleMu.Unlock() + delete(s.execCountSubscribers, c) + delete(s.runningExecs, c) + }() + + // wait for running processes to exit + for { + if runningExecs := <-events; runningExecs == 0 { + break + } + } + + // all running processes have exited now, and no new + // ones can start, so we can publish the init exit + s.handleProcessExit(e, c, p) + }() +} + +func (s *service) handleProcessExit(e runcC.Exit, c *runc.Container, p process.Process) { + p.SetExited(e.Status) + s.send(&eventstypes.TaskExit{ + ContainerID: c.ID, + ID: p.ID(), + Pid: uint32(e.Pid), + ExitStatus: uint32(e.Status), + ExitedAt: protobuf.ToTimestamp(p.ExitedAt()), + }) + if _, init := p.(*process.Init); !init { + s.lifecycleMu.Lock() + s.runningExecs[c]-- + if ch, ok := s.execCountSubscribers[c]; ok { + ch <- s.runningExecs[c] + } + s.lifecycleMu.Unlock() + } +} + +func (s *service) getContainerPids(ctx context.Context, container *runc.Container) ([]uint32, error) { + p, err := container.Process("") + if err != nil { + return nil, errgrpc.ToGRPC(err) + } + ps, err := p.(*process.Init).Runtime().Ps(ctx, container.ID) + if err != nil { + return nil, err + } + pids := make([]uint32, 0, len(ps)) + for _, pid := range ps { + pids = append(pids, uint32(pid)) + } + return pids, nil +} + +func (s *service) forward(ctx context.Context, publisher shim.Publisher) { + ns, _ := namespaces.Namespace(ctx) + ctx = namespaces.WithNamespace(context.Background(), ns) + for e := range s.events { + err := publisher.Publish(ctx, runtime.GetTopic(e), e) + if err != nil { + log.G(ctx).WithError(err).Error("post event") + } + } + publisher.Close() +} + +func (s *service) getContainer(id string) (*runc.Container, error) { + s.mu.Lock() + container := s.containers[id] + s.mu.Unlock() + if container == nil { + return nil, errgrpc.ToGRPCf(errdefs.ErrNotFound, "container not created") + } + return container, nil +} + +// initialize a single epoll fd to manage our consoles. `initPlatform` should +// only be called once. +func (s *service) initPlatform() error { + if s.platform != nil { + return nil + } + p, err := runc.NewPlatform() + if err != nil { + return err + } + s.platform = p + s.shutdown.RegisterCallback(func(context.Context) error { return s.platform.Close() }) + return nil +} diff --git a/cmd/containerd-stress/cri_worker.go b/cmd/containerd-stress/cri_worker.go index 99c5fbeac224..332227cfb485 100644 --- a/cmd/containerd-stress/cri_worker.go +++ b/cmd/containerd-stress/cri_worker.go @@ -23,9 +23,9 @@ import ( "sync" "time" - internalapi "github.com/containerd/containerd/integration/cri-api/pkg/apis" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/pkg/cri/util" + internalapi "github.com/containerd/containerd/v2/integration/cri-api/pkg/apis" + "github.com/containerd/containerd/v2/internal/cri/util" + "github.com/containerd/log" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" ) @@ -117,23 +117,19 @@ func (w *criWorker) runSandbox(tctx, ctx context.Context, id string) (err error) // verify it is running ? ticker := time.NewTicker(250 * time.Millisecond) - quit := make(chan struct{}) go func() { for { select { case <-tctx.Done(): - close(quit) + ticker.Stop() return case <-ticker.C: // do stuff status, err := w.client.PodSandboxStatus(sb) if err != nil && status.GetState() == runtime.PodSandboxState_SANDBOX_READY { - close(quit) + ticker.Stop() return } - case <-quit: - ticker.Stop() - return } } }() diff --git a/cmd/containerd-stress/density.go b/cmd/containerd-stress/density.go index 757b0247117c..a48928fe92f5 100644 --- a/cmd/containerd-stress/density.go +++ b/cmd/containerd-stress/density.go @@ -29,19 +29,19 @@ import ( "strings" "syscall" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/oci" - "github.com/urfave/cli" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/log" + "github.com/urfave/cli/v2" ) -var densityCommand = cli.Command{ +var densityCommand = &cli.Command{ Name: "density", Usage: "Stress tests density of containers running on a system", Flags: []cli.Flag{ - cli.IntFlag{ + &cli.IntFlag{ Name: "count", Usage: "Number of containers to run", Value: 10, @@ -58,14 +58,14 @@ var densityCommand = cli.Command{ } config := config{ - Address: cliContext.GlobalString("address"), - Duration: cliContext.GlobalDuration("duration"), - Concurrency: cliContext.GlobalInt("concurrent"), - Exec: cliContext.GlobalBool("exec"), - Image: cliContext.GlobalString("image"), - JSON: cliContext.GlobalBool("json"), - Metrics: cliContext.GlobalString("metrics"), - Snapshotter: cliContext.GlobalString("snapshotter"), + Address: cliContext.String("address"), + Duration: cliContext.Duration("duration"), + Concurrency: cliContext.Int("concurrent"), + Exec: cliContext.Bool("exec"), + Image: cliContext.String("image"), + JSON: cliContext.Bool("json"), + Metrics: cliContext.String("metrics"), + Snapshotter: cliContext.String("snapshotter"), } client, err := config.newClient() if err != nil { diff --git a/cmd/containerd-stress/exec_worker.go b/cmd/containerd-stress/exec_worker.go index 0980b14c017d..145fa99f59aa 100644 --- a/cmd/containerd-stress/exec_worker.go +++ b/cmd/containerd-stress/exec_worker.go @@ -23,10 +23,10 @@ import ( "syscall" "time" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/oci" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/log" specs "github.com/opencontainers/runtime-spec/specs-go" ) diff --git a/cmd/containerd-stress/main.go b/cmd/containerd-stress/main.go index e8ae9c8db947..5739b0f2de4c 100644 --- a/cmd/containerd-stress/main.go +++ b/cmd/containerd-stress/main.go @@ -28,13 +28,14 @@ import ( "syscall" "time" - "github.com/containerd/containerd" - "github.com/containerd/containerd/integration/remote" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/plugin" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/integration/remote" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/plugins" + "github.com/containerd/log" metrics "github.com/docker/go-metrics" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( @@ -62,6 +63,12 @@ func init() { if err := setRlimit(); err != nil { panic(err) } + + cli.HelpFlag = &cli.BoolFlag{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Show help", + } } type worker interface { @@ -124,85 +131,91 @@ func main() { app.Name = "containerd-stress" app.Description = "stress test a containerd daemon" app.Flags = []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", Usage: "Set debug output in the logs", }, - cli.StringFlag{ - Name: "address,a", - Value: "/run/containerd/containerd.sock", - Usage: "Path to the containerd socket", + &cli.StringFlag{ + Name: "address", + Aliases: []string{"a"}, + Value: defaults.DefaultAddress, + Usage: "Path to the containerd socket", }, - cli.IntFlag{ - Name: "concurrent,c", - Value: 1, - Usage: "Set the concurrency of the stress test", + &cli.IntFlag{ + Name: "concurrent", + Aliases: []string{"c"}, + Value: 1, + Usage: "Set the concurrency of the stress test", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "cri", Usage: "Utilize CRI to create pods for the stress test. This requires a runtime that matches CRI runtime handler. Example: --runtime runc", }, - cli.DurationFlag{ - Name: "duration,d", - Value: 1 * time.Minute, - Usage: "Set the duration of the stress test", + &cli.DurationFlag{ + Name: "duration", + Aliases: []string{"d"}, + Value: 1 * time.Minute, + Usage: "Set the duration of the stress test", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "exec", Usage: "Add execs to the stress tests (non-CRI only)", }, - cli.StringFlag{ - Name: "image,i", - Value: "docker.io/library/alpine:latest", - Usage: "Image to be utilized for testing", + &cli.StringFlag{ + Name: "image", + Aliases: []string{"i"}, + Value: "docker.io/library/alpine:latest", + Usage: "Image to be utilized for testing", }, - cli.BoolFlag{ - Name: "json,j", - Usage: "Output results in json format", + &cli.BoolFlag{ + Name: "json", + Aliases: []string{"j"}, + Usage: "Output results in json format", }, - cli.StringFlag{ - Name: "metrics,m", - Usage: "Address to serve the metrics API", + &cli.StringFlag{ + Name: "metrics", + Aliases: []string{"m"}, + Usage: "Address to serve the metrics API", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "runtime", Usage: "Set the runtime to stress test", - Value: plugin.RuntimeRuncV2, + Value: plugins.RuntimeRuncV2, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "snapshotter", Usage: "Set the snapshotter to use", Value: "overlayfs", }, } - app.Before = func(context *cli.Context) error { - if context.GlobalBool("json") { + app.Before = func(cliContext *cli.Context) error { + if cliContext.Bool("json") { if err := log.SetLevel("warn"); err != nil { return err } } - if context.GlobalBool("debug") { + if cliContext.Bool("debug") { if err := log.SetLevel("debug"); err != nil { return err } } return nil } - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ densityCommand, } - app.Action = func(context *cli.Context) error { + app.Action = func(cliContext *cli.Context) error { config := config{ - Address: context.GlobalString("address"), - Duration: context.GlobalDuration("duration"), - Concurrency: context.GlobalInt("concurrent"), - CRI: context.GlobalBool("cri"), - Exec: context.GlobalBool("exec"), - Image: context.GlobalString("image"), - JSON: context.GlobalBool("json"), - Metrics: context.GlobalString("metrics"), - Runtime: context.GlobalString("runtime"), - Snapshotter: context.GlobalString("snapshotter"), + Address: cliContext.String("address"), + Duration: cliContext.Duration("duration"), + Concurrency: cliContext.Int("concurrent"), + CRI: cliContext.Bool("cri"), + Exec: cliContext.Bool("exec"), + Image: cliContext.String("image"), + JSON: cliContext.Bool("json"), + Metrics: cliContext.String("metrics"), + Runtime: cliContext.String("runtime"), + Snapshotter: cliContext.String("snapshotter"), } if config.Metrics != "" { return serve(config) @@ -259,13 +272,12 @@ func serve(c config) error { func criTest(c config) error { var ( - timeout = 1 * time.Minute - wg sync.WaitGroup - ctx = namespaces.WithNamespace(context.Background(), stressNs) - criEndpoint = "unix:///run/containerd/containerd.sock" + timeout = 1 * time.Minute + wg sync.WaitGroup + ctx = namespaces.WithNamespace(context.Background(), stressNs) ) - client, err := remote.NewRuntimeService(criEndpoint, timeout) + client, err := remote.NewRuntimeService(c.Address, timeout) if err != nil { return fmt.Errorf("failed to create runtime service: %w", err) } diff --git a/cmd/containerd-stress/size.go b/cmd/containerd-stress/size.go index 02908a8640a1..113ba6aa4a77 100644 --- a/cmd/containerd-stress/size.go +++ b/cmd/containerd-stress/size.go @@ -19,7 +19,7 @@ package main import ( "os" - "github.com/containerd/containerd/log" + "github.com/containerd/log" ) const defaultPath = "/usr/local/bin/" diff --git a/cmd/containerd-stress/worker.go b/cmd/containerd-stress/worker.go index d8bf742b9870..27fed37031cc 100644 --- a/cmd/containerd-stress/worker.go +++ b/cmd/containerd-stress/worker.go @@ -23,10 +23,10 @@ import ( "sync" "time" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/oci" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/containerd/v2/pkg/oci" + "github.com/containerd/log" ) type ctrWorker struct { diff --git a/cmd/containerd/builtins/btrfs_linux.go b/cmd/containerd/builtins/btrfs_linux.go index 17bf8dfe95a0..00bd9314a725 100644 --- a/cmd/containerd/builtins/btrfs_linux.go +++ b/cmd/containerd/builtins/btrfs_linux.go @@ -18,4 +18,4 @@ package builtins -import _ "github.com/containerd/containerd/snapshots/btrfs/plugin" +import _ "github.com/containerd/containerd/v2/plugins/snapshots/btrfs/plugin" diff --git a/cmd/containerd/builtins/builtins.go b/cmd/containerd/builtins/builtins.go index 6ed9f3b0a6bc..17c8b4e5f969 100644 --- a/cmd/containerd/builtins/builtins.go +++ b/cmd/containerd/builtins/builtins.go @@ -18,31 +18,33 @@ package builtins // register containerd builtins here import ( - _ "github.com/containerd/containerd/diff/walking/plugin" - _ "github.com/containerd/containerd/events/plugin" - _ "github.com/containerd/containerd/gc/scheduler" - _ "github.com/containerd/containerd/leases/plugin" - _ "github.com/containerd/containerd/metadata/plugin" - _ "github.com/containerd/containerd/pkg/nri/plugin" - _ "github.com/containerd/containerd/plugins/sandbox" - _ "github.com/containerd/containerd/plugins/streaming" - _ "github.com/containerd/containerd/plugins/transfer" - _ "github.com/containerd/containerd/runtime/restart/monitor" - _ "github.com/containerd/containerd/runtime/v2" - _ "github.com/containerd/containerd/services/containers" - _ "github.com/containerd/containerd/services/content" - _ "github.com/containerd/containerd/services/diff" - _ "github.com/containerd/containerd/services/events" - _ "github.com/containerd/containerd/services/healthcheck" - _ "github.com/containerd/containerd/services/images" - _ "github.com/containerd/containerd/services/introspection" - _ "github.com/containerd/containerd/services/leases" - _ "github.com/containerd/containerd/services/namespaces" - _ "github.com/containerd/containerd/services/opt" - _ "github.com/containerd/containerd/services/sandbox" - _ "github.com/containerd/containerd/services/snapshots" - _ "github.com/containerd/containerd/services/streaming" - _ "github.com/containerd/containerd/services/tasks" - _ "github.com/containerd/containerd/services/transfer" - _ "github.com/containerd/containerd/services/version" + _ "github.com/containerd/containerd/v2/core/runtime/v2" + _ "github.com/containerd/containerd/v2/plugins/content/local/plugin" + _ "github.com/containerd/containerd/v2/plugins/events" + _ "github.com/containerd/containerd/v2/plugins/gc" + _ "github.com/containerd/containerd/v2/plugins/imageverifier" + _ "github.com/containerd/containerd/v2/plugins/leases" + _ "github.com/containerd/containerd/v2/plugins/metadata" + _ "github.com/containerd/containerd/v2/plugins/nri" + _ "github.com/containerd/containerd/v2/plugins/restart" + _ "github.com/containerd/containerd/v2/plugins/sandbox" + _ "github.com/containerd/containerd/v2/plugins/services/containers" + _ "github.com/containerd/containerd/v2/plugins/services/content" + _ "github.com/containerd/containerd/v2/plugins/services/diff" + _ "github.com/containerd/containerd/v2/plugins/services/events" + _ "github.com/containerd/containerd/v2/plugins/services/healthcheck" + _ "github.com/containerd/containerd/v2/plugins/services/images" + _ "github.com/containerd/containerd/v2/plugins/services/introspection" + _ "github.com/containerd/containerd/v2/plugins/services/leases" + _ "github.com/containerd/containerd/v2/plugins/services/namespaces" + _ "github.com/containerd/containerd/v2/plugins/services/opt" + _ "github.com/containerd/containerd/v2/plugins/services/sandbox" + _ "github.com/containerd/containerd/v2/plugins/services/snapshots" + _ "github.com/containerd/containerd/v2/plugins/services/streaming" + _ "github.com/containerd/containerd/v2/plugins/services/tasks" + _ "github.com/containerd/containerd/v2/plugins/services/transfer" + _ "github.com/containerd/containerd/v2/plugins/services/version" + _ "github.com/containerd/containerd/v2/plugins/services/warning" + _ "github.com/containerd/containerd/v2/plugins/streaming" + _ "github.com/containerd/containerd/v2/plugins/transfer" ) diff --git a/cmd/containerd/builtins/builtins_freebsd.go b/cmd/containerd/builtins/builtins_freebsd.go index c7fdbe190e9d..2201896bba49 100644 --- a/cmd/containerd/builtins/builtins_freebsd.go +++ b/cmd/containerd/builtins/builtins_freebsd.go @@ -16,4 +16,7 @@ package builtins -import _ "github.com/containerd/zfs/plugin" +import ( + _ "github.com/containerd/containerd/v2/plugins/diff/walking/plugin" + _ "github.com/containerd/zfs/v2/plugin" +) diff --git a/cmd/containerd/builtins/builtins_linux.go b/cmd/containerd/builtins/builtins_linux.go index fead87916ba5..deed083b843c 100644 --- a/cmd/containerd/builtins/builtins_linux.go +++ b/cmd/containerd/builtins/builtins_linux.go @@ -17,10 +17,11 @@ package builtins import ( - _ "github.com/containerd/containerd/metrics/cgroups" - _ "github.com/containerd/containerd/metrics/cgroups/v2" - _ "github.com/containerd/containerd/runtime/v2/runc/options" - _ "github.com/containerd/containerd/snapshots/blockfile/plugin" - _ "github.com/containerd/containerd/snapshots/native/plugin" - _ "github.com/containerd/containerd/snapshots/overlay/plugin" + _ "github.com/containerd/containerd/api/types/runc/options" + _ "github.com/containerd/containerd/v2/core/metrics/cgroups" + _ "github.com/containerd/containerd/v2/core/metrics/cgroups/v2" + _ "github.com/containerd/containerd/v2/plugins/diff/walking/plugin" + _ "github.com/containerd/containerd/v2/plugins/snapshots/blockfile/plugin" + _ "github.com/containerd/containerd/v2/plugins/snapshots/native/plugin" + _ "github.com/containerd/containerd/v2/plugins/snapshots/overlay/plugin" ) diff --git a/cmd/containerd/builtins/builtins_unix.go b/cmd/containerd/builtins/builtins_unix.go index 348e2ccbbc4c..d2f6a4d85235 100644 --- a/cmd/containerd/builtins/builtins_unix.go +++ b/cmd/containerd/builtins/builtins_unix.go @@ -19,6 +19,7 @@ package builtins import ( - _ "github.com/containerd/containerd/snapshots/blockfile/plugin" - _ "github.com/containerd/containerd/snapshots/native/plugin" + _ "github.com/containerd/containerd/v2/plugins/diff/walking/plugin" + _ "github.com/containerd/containerd/v2/plugins/snapshots/blockfile/plugin" + _ "github.com/containerd/containerd/v2/plugins/snapshots/native/plugin" ) diff --git a/cmd/containerd/builtins/builtins_windows.go b/cmd/containerd/builtins/builtins_windows.go index 3ba975a1ac2d..5600624e2e19 100644 --- a/cmd/containerd/builtins/builtins_windows.go +++ b/cmd/containerd/builtins/builtins_windows.go @@ -17,8 +17,8 @@ package builtins import ( - _ "github.com/containerd/containerd/diff/lcow" - _ "github.com/containerd/containerd/diff/windows" - _ "github.com/containerd/containerd/snapshots/lcow" - _ "github.com/containerd/containerd/snapshots/windows" + _ "github.com/containerd/containerd/v2/plugins/diff/lcow" + _ "github.com/containerd/containerd/v2/plugins/diff/windows" + _ "github.com/containerd/containerd/v2/plugins/snapshots/lcow" + _ "github.com/containerd/containerd/v2/plugins/snapshots/windows" ) diff --git a/cmd/containerd/builtins/cri.go b/cmd/containerd/builtins/cri.go index b7b31384de19..4e68b40dda31 100644 --- a/cmd/containerd/builtins/cri.go +++ b/cmd/containerd/builtins/cri.go @@ -19,5 +19,7 @@ package builtins import ( - _ "github.com/containerd/containerd/pkg/cri" + _ "github.com/containerd/containerd/v2/plugins/cri" + _ "github.com/containerd/containerd/v2/plugins/cri/images" + _ "github.com/containerd/containerd/v2/plugins/cri/runtime" ) diff --git a/cmd/containerd/builtins/devmapper_linux.go b/cmd/containerd/builtins/devmapper_linux.go index 818ae1282786..1492cef9ea3c 100644 --- a/cmd/containerd/builtins/devmapper_linux.go +++ b/cmd/containerd/builtins/devmapper_linux.go @@ -18,4 +18,4 @@ package builtins -import _ "github.com/containerd/containerd/snapshots/devmapper/plugin" +import _ "github.com/containerd/containerd/v2/plugins/snapshots/devmapper/plugin" diff --git a/cmd/containerd/builtins/tracing.go b/cmd/containerd/builtins/tracing.go index 9354bc7a7909..0926cd52d2e7 100644 --- a/cmd/containerd/builtins/tracing.go +++ b/cmd/containerd/builtins/tracing.go @@ -19,5 +19,5 @@ package builtins import ( - _ "github.com/containerd/containerd/tracing/plugin" + _ "github.com/containerd/containerd/v2/pkg/tracing/plugin" ) diff --git a/cmd/containerd/builtins/zfs_linux.go b/cmd/containerd/builtins/zfs_linux.go index 5cd0869d18db..8b4be027be9b 100644 --- a/cmd/containerd/builtins/zfs_linux.go +++ b/cmd/containerd/builtins/zfs_linux.go @@ -18,4 +18,4 @@ package builtins -import _ "github.com/containerd/zfs/plugin" +import _ "github.com/containerd/zfs/v2/plugin" diff --git a/cmd/containerd/command/config.go b/cmd/containerd/command/config.go index b121df0c6ca8..350af9d44b42 100644 --- a/cmd/containerd/command/config.go +++ b/cmd/containerd/command/config.go @@ -17,50 +17,37 @@ package command import ( - gocontext "context" - "io" + "context" "os" "path/filepath" - "github.com/containerd/containerd/defaults" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/pkg/timeout" - "github.com/containerd/containerd/services/server" - srvconfig "github.com/containerd/containerd/services/server/config" + "github.com/containerd/containerd/v2/cmd/containerd/server" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/timeout" + "github.com/containerd/containerd/v2/version" + "github.com/containerd/plugin/registry" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/pelletier/go-toml" - "github.com/urfave/cli" + "github.com/pelletier/go-toml/v2" + "github.com/urfave/cli/v2" ) -// Config is a wrapper of server config for printing out. -type Config struct { - *srvconfig.Config - // Plugins overrides `Plugins map[string]toml.Tree` in server config. - Plugins map[string]interface{} `toml:"plugins"` -} - -// WriteTo marshals the config to the provided writer -func (c *Config) WriteTo(w io.Writer) (int64, error) { - return 0, toml.NewEncoder(w).Encode(c) -} - -func outputConfig(cfg *srvconfig.Config) error { - config := &Config{ - Config: cfg, - } - - plugins, err := server.LoadPlugins(gocontext.Background(), config.Config) +func outputConfig(ctx context.Context, config *srvconfig.Config) error { + plugins, err := server.LoadPlugins(ctx, config) if err != nil { return err } if len(plugins) != 0 { - config.Plugins = make(map[string]interface{}) + if config.Plugins == nil { + config.Plugins = make(map[string]interface{}) + } for _, p := range plugins { if p.Config == nil { continue } - pc, err := config.Decode(p) + pc, err := config.Decode(ctx, p.URI(), p.Config) if err != nil { return err } @@ -82,41 +69,87 @@ func outputConfig(cfg *srvconfig.Config) error { // for the time being, keep the defaultConfig's version set at 1 so that // when a config without a version is loaded from disk and has no version // set, we assume it's a v1 config. But when generating new configs via - // this command, generate the v2 config - config.Config.Version = 2 - - // remove overridden Plugins type to avoid duplication in output - config.Config.Plugins = nil + // this command, generate the max configuration version + config.Version = version.ConfigVersion - _, err = config.WriteTo(os.Stdout) - return err + return toml.NewEncoder(os.Stdout).SetIndentTables(true).Encode(config) } func defaultConfig() *srvconfig.Config { return platformAgnosticDefaultConfig() } -var configCommand = cli.Command{ +var configCommand = &cli.Command{ Name: "config", Usage: "Information on the containerd config", - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ { Name: "default", Usage: "See the output of the default config", - Action: func(context *cli.Context) error { - return outputConfig(defaultConfig()) + Action: func(cliContext *cli.Context) error { + ctx := cliContext.Context + return outputConfig(ctx, defaultConfig()) }, }, { Name: "dump", Usage: "See the output of the final main config with imported in subconfig files", - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { + config := defaultConfig() + ctx := cliContext.Context + if err := srvconfig.LoadConfig(ctx, cliContext.String("config"), config); err != nil && !os.IsNotExist(err) { + return err + } + + return outputConfig(ctx, config) + }, + }, + { + Name: "migrate", + Usage: "Migrate the current configuration file to the latest version (does not migrate subconfig files)", + Action: func(cliContext *cli.Context) error { config := defaultConfig() - if err := srvconfig.LoadConfig(context.GlobalString("config"), config); err != nil && !os.IsNotExist(err) { + ctx := cliContext.Context + if err := srvconfig.LoadConfig(ctx, cliContext.String("config"), config); err != nil && !os.IsNotExist(err) { return err } - return outputConfig(config) + if config.Version < version.ConfigVersion { + plugins := registry.Graph(srvconfig.V2DisabledFilter(config.DisabledPlugins)) + for _, p := range plugins { + if p.ConfigMigration != nil { + if err := p.ConfigMigration(ctx, config.Version, config.Plugins); err != nil { + return err + } + } + } + } + + plugins, err := server.LoadPlugins(ctx, config) + if err != nil { + return err + } + if len(plugins) != 0 { + if config.Plugins == nil { + config.Plugins = make(map[string]interface{}) + } + for _, p := range plugins { + if p.Config == nil { + continue + } + + pc, err := config.Decode(ctx, p.URI(), p.Config) + if err != nil { + return err + } + + config.Plugins[p.URI()] = pc + } + } + + config.Version = version.ConfigVersion + + return toml.NewEncoder(os.Stdout).SetIndentTables(true).Encode(config) }, }, }, @@ -124,11 +157,7 @@ var configCommand = cli.Command{ func platformAgnosticDefaultConfig() *srvconfig.Config { return &srvconfig.Config{ - // see: https://github.com/containerd/containerd/blob/5c6ea7fdc1247939edaddb1eba62a94527418687/RELEASES.md#daemon-configuration - // this version MUST remain set to 1 until either there exists a means to - // override / configure the default at the containerd cli .. or when - // version 1 is no longer supported - Version: 1, + Version: version.ConfigVersion, Root: defaults.DefaultRootDir, State: defaults.DefaultStateDir, GRPC: srvconfig.GRPCConfig{ diff --git a/cmd/containerd/command/main.go b/cmd/containerd/command/main.go index 3b8e9739ee78..c18794a9c81f 100644 --- a/cmd/containerd/command/main.go +++ b/cmd/containerd/command/main.go @@ -17,7 +17,7 @@ package command import ( - gocontext "context" + "context" "fmt" "io" "net" @@ -27,16 +27,16 @@ import ( "runtime" "time" - "github.com/containerd/containerd/defaults" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/log" - _ "github.com/containerd/containerd/metrics" // import containerd build info - "github.com/containerd/containerd/mount" - "github.com/containerd/containerd/services/server" - srvconfig "github.com/containerd/containerd/services/server/config" - "github.com/containerd/containerd/sys" - "github.com/containerd/containerd/version" - "github.com/urfave/cli" + "github.com/containerd/containerd/v2/cmd/containerd/server" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + _ "github.com/containerd/containerd/v2/core/metrics" // import containerd build info + "github.com/containerd/containerd/v2/core/mount" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/sys" + "github.com/containerd/containerd/v2/version" + "github.com/containerd/errdefs" + "github.com/containerd/log" + "github.com/urfave/cli/v2" "google.golang.org/grpc/grpclog" ) @@ -54,8 +54,18 @@ func init() { // Discard grpc logs so that they don't mess with our stdio grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard)) - cli.VersionPrinter = func(c *cli.Context) { - fmt.Println(c.App.Name, version.Package, c.App.Version, version.Revision) + cli.VersionPrinter = func(cliContext *cli.Context) { + fmt.Println(cliContext.App.Name, version.Package, cliContext.App.Version, version.Revision) + } + cli.VersionFlag = &cli.BoolFlag{ + Name: "version", + Aliases: []string{"v"}, + Usage: "Print the version", + } + cli.HelpFlag = &cli.BoolFlag{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Show help", } } @@ -77,40 +87,43 @@ at the default file location. The *containerd config* command can be used to generate the default configuration for containerd. The output of that command can be used and modified as necessary as a custom configuration.` app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "config,c", - Usage: "Path to the configuration file", - Value: filepath.Join(defaults.DefaultConfigDir, "config.toml"), + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "Path to the configuration file", + Value: filepath.Join(defaults.DefaultConfigDir, "config.toml"), }, - cli.StringFlag{ - Name: "log-level,l", - Usage: "Set the logging level [trace, debug, info, warn, error, fatal, panic]", + &cli.StringFlag{ + Name: "log-level", + Aliases: []string{"l"}, + Usage: "Set the logging level [trace, debug, info, warn, error, fatal, panic]", }, - cli.StringFlag{ - Name: "address,a", - Usage: "Address for containerd's GRPC server", + &cli.StringFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address for containerd's GRPC server", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "root", Usage: "containerd root directory", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "state", Usage: "containerd state directory", }, } app.Flags = append(app.Flags, serviceFlags()...) - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ configCommand, publishCommand, ociHook, } - app.Action = func(context *cli.Context) error { + app.Action = func(cliContext *cli.Context) error { var ( start = time.Now() signals = make(chan os.Signal, 2048) serverC = make(chan *server.Server, 1) - ctx, cancel = gocontext.WithCancel(gocontext.Background()) + ctx, cancel = context.WithCancel(cliContext.Context) config = defaultConfig() ) @@ -118,16 +131,16 @@ can be used and modified as necessary as a custom configuration.` // Only try to load the config if it either exists, or the user explicitly // told us to load this path. - configPath := context.GlobalString("config") + configPath := cliContext.String("config") _, err := os.Stat(configPath) - if !os.IsNotExist(err) || context.GlobalIsSet("config") { - if err := srvconfig.LoadConfig(configPath, config); err != nil { + if !os.IsNotExist(err) || cliContext.IsSet("config") { + if err := srvconfig.LoadConfig(ctx, configPath, config); err != nil { return err } } // Apply flags to the config - if err := applyFlags(context, config); err != nil { + if err := applyFlags(cliContext, config); err != nil { return err } @@ -290,7 +303,7 @@ can be used and modified as necessary as a custom configuration.` return app } -func serve(ctx gocontext.Context, l net.Listener, serveFunc func(net.Listener) error) { +func serve(ctx context.Context, l net.Listener, serveFunc func(net.Listener) error) { path := l.Addr().String() log.G(ctx).WithField("address", path).Info("serving...") go func() { @@ -301,10 +314,10 @@ func serve(ctx gocontext.Context, l net.Listener, serveFunc func(net.Listener) e }() } -func applyFlags(context *cli.Context, config *srvconfig.Config) error { +func applyFlags(cliContext *cli.Context, config *srvconfig.Config) error { // the order for config vs flag values is that flags will always override // the config values if they are set - if err := setLogLevel(context, config); err != nil { + if err := setLogLevel(cliContext, config); err != nil { return err } if err := setLogFormat(config); err != nil { @@ -328,7 +341,7 @@ func applyFlags(context *cli.Context, config *srvconfig.Config) error { d: &config.GRPC.Address, }, } { - if s := context.GlobalString(v.name); s != "" { + if s := cliContext.String(v.name); s != "" { *v.d = s if v.name == "root" || v.name == "state" { absPath, err := filepath.Abs(s) @@ -340,13 +353,13 @@ func applyFlags(context *cli.Context, config *srvconfig.Config) error { } } - applyPlatformFlags(context) + applyPlatformFlags(cliContext) return nil } -func setLogLevel(context *cli.Context, config *srvconfig.Config) error { - l := context.GlobalString("log-level") +func setLogLevel(cliContext *cli.Context, config *srvconfig.Config) error { + l := cliContext.String("log-level") if l == "" { l = config.Debug.Level } diff --git a/cmd/containerd/command/main_unix.go b/cmd/containerd/command/main_unix.go index 927865a8d219..e160c7b9b3fa 100644 --- a/cmd/containerd/command/main_unix.go +++ b/cmd/containerd/command/main_unix.go @@ -23,8 +23,8 @@ import ( "os" "path/filepath" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/services/server" + "github.com/containerd/containerd/v2/cmd/containerd/server" + "github.com/containerd/log" "golang.org/x/sys/unix" ) diff --git a/cmd/containerd/command/main_windows.go b/cmd/containerd/command/main_windows.go index 182f4c007310..ff583f4be465 100644 --- a/cmd/containerd/command/main_windows.go +++ b/cmd/containerd/command/main_windows.go @@ -26,8 +26,8 @@ import ( "github.com/Microsoft/go-winio/pkg/etw" "github.com/Microsoft/go-winio/pkg/etwlogrus" "github.com/Microsoft/go-winio/pkg/guid" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/services/server" + "github.com/containerd/containerd/v2/cmd/containerd/server" + "github.com/containerd/log" "github.com/sirupsen/logrus" "golang.org/x/sys/windows" ) diff --git a/cmd/containerd/command/notify_systemd.go b/cmd/containerd/command/notify_systemd.go index 101db5f72fd8..6dc1ca3f96e6 100644 --- a/cmd/containerd/command/notify_systemd.go +++ b/cmd/containerd/command/notify_systemd.go @@ -23,7 +23,7 @@ import ( sd "github.com/coreos/go-systemd/v22/daemon" - "github.com/containerd/containerd/log" + "github.com/containerd/log" ) // notifyReady notifies systemd that the daemon is ready to serve requests diff --git a/cmd/containerd/command/oci-hook.go b/cmd/containerd/command/oci-hook.go index 361ecacfcc1b..6863356cc4e4 100644 --- a/cmd/containerd/command/oci-hook.go +++ b/cmd/containerd/command/oci-hook.go @@ -25,15 +25,15 @@ import ( "syscall" "text/template" - "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/v2/pkg/oci" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var ociHook = cli.Command{ +var ociHook = &cli.Command{ Name: "oci-hook", Usage: "Provides a base for OCI runtime hooks to allow arguments to be injected.", - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { state, err := loadHookState(os.Stdin) if err != nil { return err @@ -45,7 +45,7 @@ var ociHook = cli.Command{ } var ( ctx = newTemplateContext(state, spec) - args = []string(context.Args()) + args = cliContext.Args().Slice() env = os.Environ() ) if err := newList(&args).render(ctx); err != nil { diff --git a/cmd/containerd/command/publish.go b/cmd/containerd/command/publish.go index 27ae9a3076b9..ddd60e7dbd3a 100644 --- a/cmd/containerd/command/publish.go +++ b/cmd/containerd/command/publish.go @@ -17,7 +17,7 @@ package command import ( - gocontext "context" + "context" "fmt" "io" "net" @@ -25,33 +25,35 @@ import ( "time" eventsapi "github.com/containerd/containerd/api/services/events/v1" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/pkg/dialer" - "github.com/containerd/containerd/protobuf/proto" - "github.com/containerd/containerd/protobuf/types" - "github.com/urfave/cli" + "github.com/containerd/errdefs" + "github.com/containerd/errdefs/pkg/errgrpc" + "github.com/urfave/cli/v2" "google.golang.org/grpc" "google.golang.org/grpc/backoff" "google.golang.org/grpc/credentials/insecure" + + "github.com/containerd/containerd/v2/pkg/dialer" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/pkg/protobuf/proto" + "github.com/containerd/containerd/v2/pkg/protobuf/types" ) -var publishCommand = cli.Command{ +var publishCommand = &cli.Command{ Name: "publish", Usage: "Binary to publish events to containerd", Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "namespace", Usage: "Namespace to publish to", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "topic", Usage: "Topic of the event", }, }, - Action: func(context *cli.Context) error { - ctx := namespaces.WithNamespace(gocontext.Background(), context.String("namespace")) - topic := context.String("topic") + Action: func(cliContext *cli.Context) error { + ctx := namespaces.WithNamespace(cliContext.Context, cliContext.String("namespace")) + topic := cliContext.String("topic") if topic == "" { return fmt.Errorf("topic required to publish event: %w", errdefs.ErrInvalidArgument) } @@ -59,7 +61,7 @@ var publishCommand = cli.Command{ if err != nil { return err } - client, err := connectEvents(context.GlobalString("address")) + client, err := connectEvents(cliContext.String("address")) if err != nil { return err } @@ -67,7 +69,7 @@ var publishCommand = cli.Command{ Topic: topic, Event: payload, }); err != nil { - return errdefs.FromGRPC(err) + return errgrpc.ToNative(err) } return nil }, @@ -93,22 +95,18 @@ func connectEvents(address string) (eventsapi.EventsClient, error) { return eventsapi.NewEventsClient(conn), nil } -func connect(address string, d func(gocontext.Context, string) (net.Conn, error)) (*grpc.ClientConn, error) { +func connect(address string, d func(context.Context, string) (net.Conn, error)) (*grpc.ClientConn, error) { backoffConfig := backoff.DefaultConfig backoffConfig.MaxDelay = 3 * time.Second connParams := grpc.ConnectParams{ Backoff: backoffConfig, } gopts := []grpc.DialOption{ - grpc.WithBlock(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(d), - grpc.FailOnNonTempDialError(true), grpc.WithConnectParams(connParams), } - ctx, cancel := gocontext.WithTimeout(gocontext.Background(), 2*time.Second) - defer cancel() - conn, err := grpc.DialContext(ctx, dialer.DialAddress(address), gopts...) + conn, err := grpc.NewClient(dialer.DialAddress(address), gopts...) if err != nil { return nil, fmt.Errorf("failed to dial %q: %w", address, err) } diff --git a/cmd/containerd/command/service_unsupported.go b/cmd/containerd/command/service_unsupported.go index 9cd0114681b1..e275132dd4d2 100644 --- a/cmd/containerd/command/service_unsupported.go +++ b/cmd/containerd/command/service_unsupported.go @@ -19,8 +19,8 @@ package command import ( - "github.com/containerd/containerd/services/server" - "github.com/urfave/cli" + "github.com/containerd/containerd/v2/cmd/containerd/server" + "github.com/urfave/cli/v2" ) // serviceFlags returns an array of flags for configuring containerd to run @@ -30,7 +30,7 @@ func serviceFlags() []cli.Flag { } // applyPlatformFlags applies platform-specific flags. -func applyPlatformFlags(context *cli.Context) { +func applyPlatformFlags(cliContext *cli.Context) { } // registerUnregisterService is only relevant on Windows. diff --git a/cmd/containerd/command/service_windows.go b/cmd/containerd/command/service_windows.go index e5a830586f6b..6243e9379ebf 100644 --- a/cmd/containerd/command/service_windows.go +++ b/cmd/containerd/command/service_windows.go @@ -20,14 +20,14 @@ import ( "fmt" "log" "os" + "os/exec" "path/filepath" "time" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/services/server" + "github.com/containerd/containerd/v2/cmd/containerd/server" + "github.com/containerd/errdefs" "github.com/sirupsen/logrus" - "github.com/urfave/cli" - exec "golang.org/x/sys/execabs" + "github.com/urfave/cli/v2" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/debug" @@ -53,25 +53,25 @@ const defaultServiceName = "containerd" // as a Windows service under control of SCM. func serviceFlags() []cli.Flag { return []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "service-name", Usage: "Set the Windows service name", Value: defaultServiceName, }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "register-service", Usage: "Register the service and exit", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "unregister-service", Usage: "Unregister the service and exit", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "run-service", Usage: "", Hidden: true, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "log-file", Usage: "Path to the containerd log file", }, @@ -79,8 +79,8 @@ func serviceFlags() []cli.Flag { } // applyPlatformFlags applies platform-specific flags. -func applyPlatformFlags(context *cli.Context) { - serviceNameFlag = context.GlobalString("service-name") +func applyPlatformFlags(cliContext *cli.Context) { + serviceNameFlag = cliContext.String("service-name") if serviceNameFlag == "" { serviceNameFlag = defaultServiceName } @@ -101,9 +101,9 @@ func applyPlatformFlags(context *cli.Context) { d: &runServiceFlag, }, } { - *v.d = context.GlobalBool(v.name) + *v.d = cliContext.Bool(v.name) } - logFileFlag = context.GlobalString("log-file") + logFileFlag = cliContext.String("log-file") } type handler struct { diff --git a/cmd/containerd/main.go b/cmd/containerd/main.go index ccd41c3c0999..04cdf1f88a6c 100644 --- a/cmd/containerd/main.go +++ b/cmd/containerd/main.go @@ -17,23 +17,14 @@ package main import ( - "crypto" "fmt" "os" - "github.com/containerd/containerd/cmd/containerd/command" - "github.com/containerd/containerd/pkg/hasher" - "github.com/containerd/containerd/pkg/seed" //nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies + "github.com/containerd/containerd/v2/cmd/containerd/command" - _ "github.com/containerd/containerd/cmd/containerd/builtins" + _ "github.com/containerd/containerd/v2/cmd/containerd/builtins" ) -func init() { - //nolint:staticcheck // Global math/rand seed is deprecated, but still used by external dependencies - seed.WithTimeAndRand() - crypto.RegisterHash(crypto.SHA256, hasher.NewSHA256) -} - func main() { app := command.App() if err := app.Run(os.Args); err != nil { diff --git a/cmd/containerd/server/config/config.go b/cmd/containerd/server/config/config.go new file mode 100644 index 000000000000..b9aacf6fea50 --- /dev/null +++ b/cmd/containerd/server/config/config.go @@ -0,0 +1,501 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +// config is the global configuration for containerd +// +// Version History +// 1: Deprecated and removed in containerd 2.0 +// 2: Uses fully qualified plugin names +// 3: Added support for migration and warning on unknown fields +package config + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "reflect" + "strings" + + "dario.cat/mergo" + "github.com/pelletier/go-toml/v2" + + "github.com/containerd/containerd/v2/version" + "github.com/containerd/errdefs" + "github.com/containerd/log" + "github.com/containerd/plugin" +) + +// migrations hold the migration functions for every prior containerd config version +var migrations = []func(context.Context, *Config) error{ + nil, // Version 0 is not defined, treated at version 1 + v1Migrate, // Version 1 plugins renamed to URI for version 2 + nil, // Version 2 has only plugin changes to version 3 +} + +// NOTE: Any new map fields added also need to be handled in mergeConfig. + +// Config provides containerd configuration data for the server +type Config struct { + // Version of the config file + Version int `toml:"version"` + // Root is the path to a directory where containerd will store persistent data + Root string `toml:"root"` + // State is the path to a directory where containerd will store transient data + State string `toml:"state"` + // TempDir is the path to a directory where to place containerd temporary files + TempDir string `toml:"temp"` + // PluginDir is the directory for dynamic plugins to be stored + // + // Deprecated: Please use proxy or binary external plugins. + PluginDir string `toml:"plugin_dir"` + // GRPC configuration settings + GRPC GRPCConfig `toml:"grpc"` + // TTRPC configuration settings + TTRPC TTRPCConfig `toml:"ttrpc"` + // Debug and profiling settings + Debug Debug `toml:"debug"` + // Metrics and monitoring settings + Metrics MetricsConfig `toml:"metrics"` + // DisabledPlugins are IDs of plugins to disable. Disabled plugins won't be + // initialized and started. + // DisabledPlugins must use a fully qualified plugin URI. + DisabledPlugins []string `toml:"disabled_plugins"` + // RequiredPlugins are IDs of required plugins. Containerd exits if any + // required plugin doesn't exist or fails to be initialized or started. + // RequiredPlugins must use a fully qualified plugin URI. + RequiredPlugins []string `toml:"required_plugins"` + // Plugins provides plugin specific configuration for the initialization of a plugin + Plugins map[string]interface{} `toml:"plugins"` + // OOMScore adjust the containerd's oom score + OOMScore int `toml:"oom_score"` + // Cgroup specifies cgroup information for the containerd daemon process + Cgroup CgroupConfig `toml:"cgroup"` + // ProxyPlugins configures plugins which are communicated to over GRPC + ProxyPlugins map[string]ProxyPlugin `toml:"proxy_plugins"` + // Timeouts specified as a duration + Timeouts map[string]string `toml:"timeouts"` + // Imports are additional file path list to config files that can overwrite main config file fields + Imports []string `toml:"imports"` + // StreamProcessors configuration + StreamProcessors map[string]StreamProcessor `toml:"stream_processors"` +} + +// StreamProcessor provides configuration for diff content processors +type StreamProcessor struct { + // Accepts specific media-types + Accepts []string `toml:"accepts"` + // Returns the media-type + Returns string `toml:"returns"` + // Path or name of the binary + Path string `toml:"path"` + // Args to the binary + Args []string `toml:"args"` + // Environment variables for the binary + Env []string `toml:"env"` +} + +// ValidateVersion validates the config for a v2 file +func (c *Config) ValidateVersion() error { + if c.Version > version.ConfigVersion { + return fmt.Errorf("expected containerd config version equal to or less than `%d`, got `%d`", version.ConfigVersion, c.Version) + } + + for _, p := range c.DisabledPlugins { + if !strings.ContainsAny(p, ".") { + return fmt.Errorf("invalid disabled plugin URI %q expect io.containerd.x.vx", p) + } + } + for _, p := range c.RequiredPlugins { + if !strings.ContainsAny(p, ".") { + return fmt.Errorf("invalid required plugin URI %q expect io.containerd.x.vx", p) + } + } + + return nil +} + +// MigrateConfig will convert the config to the latest version before using +func (c *Config) MigrateConfig(ctx context.Context) error { + return c.MigrateConfigTo(ctx, version.ConfigVersion) +} + +// MigrateConfigTo will convert the config to the target version before using +func (c *Config) MigrateConfigTo(ctx context.Context, targetVersion int) error { + for c.Version < targetVersion { + if m := migrations[c.Version]; m != nil { + if err := m(ctx, c); err != nil { + return err + } + } + c.Version++ + } + return nil +} + +func v1MigratePluginName(ctx context.Context, plugin string) string { + // corePlugins is the list of used plugins before v1 was deprecated + corePlugins := map[string]string{ + "cri": "io.containerd.grpc.v1.cri", + "cgroups": "io.containerd.monitor.v1.cgroups", + "linux": "io.containerd.runtime.v1.linux", + "scheduler": "io.containerd.gc.v1.scheduler", + "bolt": "io.containerd.metadata.v1.bolt", + "task": "io.containerd.runtime.v2.task", + "opt": "io.containerd.internal.v1.opt", + "restart": "io.containerd.internal.v1.restart", + "tracing": "io.containerd.internal.v1.tracing", + "otlp": "io.containerd.tracing.processor.v1.otlp", + "aufs": "io.containerd.snapshotter.v1.aufs", + "btrfs": "io.containerd.snapshotter.v1.btrfs", + "devmapper": "io.containerd.snapshotter.v1.devmapper", + "native": "io.containerd.snapshotter.v1.native", + "overlayfs": "io.containerd.snapshotter.v1.overlayfs", + "zfs": "io.containerd.snapshotter.v1.zfs", + } + if !strings.ContainsAny(plugin, ".") { + var ambiguous string + if full, ok := corePlugins[plugin]; ok { + plugin = full + } else if strings.HasSuffix(plugin, "-service") { + plugin = "io.containerd.service.v1." + plugin + } else if plugin == "windows" || plugin == "windows-lcow" { + // runtime, differ, and snapshotter plugins do not have configs for v1 + ambiguous = plugin + plugin = "io.containerd.snapshotter.v1." + plugin + } else { + ambiguous = plugin + plugin = "io.containerd.grpc.v1." + plugin + } + if ambiguous != "" { + log.G(ctx).Warnf("Ambiguous %s plugin in v1 config, treating as %s", ambiguous, plugin) + } + } + return plugin +} + +func v1Migrate(ctx context.Context, c *Config) error { + plugins := make(map[string]interface{}, len(c.Plugins)) + for plugin, value := range c.Plugins { + plugins[v1MigratePluginName(ctx, plugin)] = value + } + c.Plugins = plugins + for i, plugin := range c.DisabledPlugins { + c.DisabledPlugins[i] = v1MigratePluginName(ctx, plugin) + } + for i, plugin := range c.RequiredPlugins { + c.RequiredPlugins[i] = v1MigratePluginName(ctx, plugin) + } + // No change in c.ProxyPlugins + return nil +} + +// GRPCConfig provides GRPC configuration for the socket +type GRPCConfig struct { + Address string `toml:"address"` + TCPAddress string `toml:"tcp_address"` + TCPTLSCA string `toml:"tcp_tls_ca"` + TCPTLSCert string `toml:"tcp_tls_cert"` + TCPTLSKey string `toml:"tcp_tls_key"` + UID int `toml:"uid"` + GID int `toml:"gid"` + MaxRecvMsgSize int `toml:"max_recv_message_size"` + MaxSendMsgSize int `toml:"max_send_message_size"` +} + +// TTRPCConfig provides TTRPC configuration for the socket +type TTRPCConfig struct { + Address string `toml:"address"` + UID int `toml:"uid"` + GID int `toml:"gid"` +} + +// Debug provides debug configuration +type Debug struct { + Address string `toml:"address"` + UID int `toml:"uid"` + GID int `toml:"gid"` + Level string `toml:"level"` + // Format represents the logging format. Supported values are 'text' and 'json'. + Format string `toml:"format"` +} + +// MetricsConfig provides metrics configuration +type MetricsConfig struct { + Address string `toml:"address"` + GRPCHistogram bool `toml:"grpc_histogram"` +} + +// CgroupConfig provides cgroup configuration +type CgroupConfig struct { + Path string `toml:"path"` +} + +// ProxyPlugin provides a proxy plugin configuration +type ProxyPlugin struct { + Type string `toml:"type"` + Address string `toml:"address"` + Platform string `toml:"platform"` + Exports map[string]string `toml:"exports"` + Capabilities []string `toml:"capabilities"` +} + +// Decode unmarshals a plugin specific configuration by plugin id +func (c *Config) Decode(ctx context.Context, id string, config interface{}) (interface{}, error) { + data, ok := c.Plugins[id] + if !ok { + return config, nil + } + + b, err := toml.Marshal(data) + if err != nil { + return nil, err + } + + if err := toml.NewDecoder(bytes.NewReader(b)).DisallowUnknownFields().Decode(config); err != nil { + var serr *toml.StrictMissingError + if errors.As(err, &serr) { + for _, derr := range serr.Errors { + log.G(ctx).WithFields(log.Fields{ + "plugin": id, + "key": strings.Join(derr.Key(), " "), + }).WithError(err).Warn("Ignoring unknown key in TOML for plugin") + } + err = toml.Unmarshal(b, config) + } + if err != nil { + return nil, err + } + + } + + return config, nil +} + +// LoadConfig loads the containerd server config from the provided path +func LoadConfig(ctx context.Context, path string, out *Config) error { + if out == nil { + return fmt.Errorf("argument out must not be nil: %w", errdefs.ErrInvalidArgument) + } + + var ( + loaded = map[string]bool{} + pending = []string{path} + ) + + for len(pending) > 0 { + path, pending = pending[0], pending[1:] + + // Check if a file at the given path already loaded to prevent circular imports + if _, ok := loaded[path]; ok { + continue + } + + config, err := loadConfigFile(ctx, path) + if err != nil { + return err + } + + switch config.Version { + case 0, 1: + if err := config.MigrateConfigTo(ctx, out.Version); err != nil { + return err + } + default: + // NOP + } + + if err := mergeConfig(out, config); err != nil { + return err + } + + imports, err := resolveImports(path, config.Imports) + if err != nil { + return err + } + + loaded[path] = true + pending = append(pending, imports...) + } + + err := out.ValidateVersion() + if err != nil { + return fmt.Errorf("failed to load TOML from %s: %w", path, err) + } + return nil +} + +// loadConfigFile decodes a TOML file at the given path +func loadConfigFile(ctx context.Context, path string) (*Config, error) { + config := &Config{} + + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + if err := toml.NewDecoder(f).DisallowUnknownFields().Decode(config); err != nil { + var serr *toml.StrictMissingError + if errors.As(err, &serr) { + for _, derr := range serr.Errors { + row, col := derr.Position() + log.G(ctx).WithFields(log.Fields{ + "file": path, + "row": row, + "column": col, + "key": strings.Join(derr.Key(), " "), + }).WithError(err).Warn("Ignoring unknown key in TOML") + } + + // Try decoding again with unknown fields + config = &Config{} + if _, seekerr := f.Seek(0, io.SeekStart); seekerr != nil { + return nil, fmt.Errorf("unable to seek file to start %w: failed to unmarshal TOML with unknown fields: %w", seekerr, err) + } + err = toml.NewDecoder(f).Decode(config) + } + if err != nil { + var derr *toml.DecodeError + if errors.As(err, &derr) { + row, column := derr.Position() + log.G(ctx).WithFields(log.Fields{ + "file": path, + "row": row, + "column": column, + }).WithError(err).Error("Failure unmarshaling TOML") + return nil, fmt.Errorf("failed to unmarshal TOML at row %d column %d: %w", row, column, err) + } + return nil, fmt.Errorf("failed to unmarshal TOML: %w", err) + } + + } + + return config, nil +} + +// resolveImports resolves import strings list to absolute paths list: +// - If path contains *, glob pattern matching applied +// - Non abs path is relative to parent config file directory +// - Abs paths returned as is +func resolveImports(parent string, imports []string) ([]string, error) { + var out []string + + for _, path := range imports { + path = filepath.Clean(path) + if !filepath.IsAbs(path) { + path = filepath.Join(filepath.Dir(parent), path) + } + + if strings.Contains(path, "*") { + matches, err := filepath.Glob(path) + if err != nil { + return nil, err + } + + out = append(out, matches...) + } else { + out = append(out, path) + } + } + + return out, nil +} + +// mergeConfig merges Config structs with the following rules: +// 'to' 'from' 'result' +// "" "value" "value" +// "value" "" "value" +// 1 0 1 +// 0 1 1 +// []{"1"} []{"2"} []{"1","2"} +// []{"1"} []{} []{"1"} +// []{"1", "2"} []{"1"} []{"1","2"} +// []{} []{"2"} []{"2"} +// Maps merged by keys, but values are replaced entirely. +func mergeConfig(to, from *Config) error { + err := mergo.Merge(to, from, mergo.WithOverride, mergo.WithTransformers(sliceTransformer{})) + if err != nil { + return err + } + + // Replace entire sections instead of merging map's values. + for k, v := range from.StreamProcessors { + to.StreamProcessors[k] = v + } + + for k, v := range from.ProxyPlugins { + to.ProxyPlugins[k] = v + } + + for k, v := range from.Timeouts { + to.Timeouts[k] = v + } + + return nil +} + +type sliceTransformer struct{} + +func (sliceTransformer) Transformer(t reflect.Type) func(dst, src reflect.Value) error { + if t.Kind() != reflect.Slice { + return nil + } + return func(dst, src reflect.Value) error { + if !dst.CanSet() { + return nil + } + if src.Type() != dst.Type() { + return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type()) + } + for i := 0; i < src.Len(); i++ { + found := false + for j := 0; j < dst.Len(); j++ { + srcv := src.Index(i) + dstv := dst.Index(j) + if !srcv.CanInterface() || !dstv.CanInterface() { + if srcv.Equal(dstv) { + found = true + break + } + } else if reflect.DeepEqual(srcv.Interface(), dstv.Interface()) { + found = true + break + } + } + if !found { + dst.Set(reflect.Append(dst, src.Index(i))) + } + } + + return nil + } +} + +// V2DisabledFilter matches based on URI +func V2DisabledFilter(list []string) plugin.DisableFilter { + set := make(map[string]struct{}, len(list)) + for _, l := range list { + set[l] = struct{}{} + } + return func(r *plugin.Registration) bool { + _, ok := set[r.URI()] + return ok + } +} diff --git a/cmd/containerd/server/config/config_test.go b/cmd/containerd/server/config/config_test.go new file mode 100644 index 000000000000..bfaf8faf331d --- /dev/null +++ b/cmd/containerd/server/config/config_test.go @@ -0,0 +1,448 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package config + +import ( + "bytes" + "context" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + "testing" + + "github.com/pelletier/go-toml/v2" + + "github.com/stretchr/testify/assert" + + "github.com/containerd/containerd/v2/version" + "github.com/containerd/log/logtest" +) + +func TestMigrations(t *testing.T) { + if len(migrations) != version.ConfigVersion { + t.Fatalf("Migration missing, expected %d migrations, only %d defined", version.ConfigVersion, len(migrations)) + } +} + +func TestMergeConfigs(t *testing.T) { + a := &Config{ + Version: 2, + Root: "old_root", + RequiredPlugins: []string{"io.containerd.old_plugin.v1"}, + DisabledPlugins: []string{"io.containerd.old_plugin.v1"}, + State: "old_state", + OOMScore: 1, + Timeouts: map[string]string{"a": "1"}, + StreamProcessors: map[string]StreamProcessor{"1": {Path: "2", Returns: "4"}, "2": {Path: "5"}}, + } + + b := &Config{ + Version: 2, + Root: "new_root", + RequiredPlugins: []string{"io.containerd.new_plugin1.v1", "io.containerd.new_plugin2.v1"}, + DisabledPlugins: []string{"io.containerd.old_plugin.v1"}, + OOMScore: 2, + Timeouts: map[string]string{"b": "2"}, + StreamProcessors: map[string]StreamProcessor{"1": {Path: "3"}}, + } + + err := mergeConfig(a, b) + assert.NoError(t, err) + + assert.Equal(t, 2, a.Version) + assert.Equal(t, "new_root", a.Root) + assert.Equal(t, "old_state", a.State) + assert.Equal(t, 2, a.OOMScore) + assert.Equal(t, []string{"io.containerd.old_plugin.v1", "io.containerd.new_plugin1.v1", "io.containerd.new_plugin2.v1"}, a.RequiredPlugins) + assert.Equal(t, []string{"io.containerd.old_plugin.v1"}, a.DisabledPlugins) + assert.Equal(t, map[string]string{"a": "1", "b": "2"}, a.Timeouts) + assert.Equal(t, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}}, a.StreamProcessors) + + // Verify overrides for integers + // https://github.com/containerd/containerd/blob/v1.6.0/services/server/config/config.go#L322-L323 + a = &Config{Version: 2, OOMScore: 1} + b = &Config{Version: 2, OOMScore: 0} // OOMScore "not set / default" + err = mergeConfig(a, b) + assert.NoError(t, err) + assert.Equal(t, 1, a.OOMScore) + + a = &Config{Version: 2, OOMScore: 1} + b = &Config{Version: 2, OOMScore: 0} // OOMScore "not set / default" + err = mergeConfig(a, b) + assert.NoError(t, err) + assert.Equal(t, 1, a.OOMScore) +} + +func TestResolveImports(t *testing.T) { + tempDir := t.TempDir() + + for _, filename := range []string{"config_1.toml", "config_2.toml", "test.toml"} { + err := os.WriteFile(filepath.Join(tempDir, filename), []byte(""), 0o600) + assert.NoError(t, err) + } + + imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{ + filepath.Join(tempDir, "config_*.toml"), // Glob + filepath.Join(tempDir, "./test.toml"), // Path clean up + "current.toml", // Resolve current working dir + }) + assert.NoError(t, err) + + assert.Equal(t, imports, []string{ + filepath.Join(tempDir, "config_1.toml"), + filepath.Join(tempDir, "config_2.toml"), + filepath.Join(tempDir, "test.toml"), + filepath.Join(tempDir, "current.toml"), + }) + + t.Run("GlobRelativePath", func(t *testing.T) { + imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{ + "config_*.toml", // Glob files from working dir + }) + assert.NoError(t, err) + assert.Equal(t, imports, []string{ + filepath.Join(tempDir, "config_1.toml"), + filepath.Join(tempDir, "config_2.toml"), + }) + }) +} + +func TestLoadSingleConfig(t *testing.T) { + data := ` +version = 2 +root = "/var/lib/containerd" + +[stream_processors] + [stream_processors."io.containerd.processor.v1.pigz"] + accepts = ["application/vnd.docker.image.rootfs.diff.tar.gzip"] + path = "unpigz" +` + tempDir := t.TempDir() + + path := filepath.Join(tempDir, "config.toml") + err := os.WriteFile(path, []byte(data), 0o600) + assert.NoError(t, err) + + var out Config + err = LoadConfig(context.Background(), path, &out) + assert.NoError(t, err) + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.Equal(t, map[string]StreamProcessor{ + "io.containerd.processor.v1.pigz": { + Accepts: []string{"application/vnd.docker.image.rootfs.diff.tar.gzip"}, + Path: "unpigz", + }, + }, out.StreamProcessors) +} + +func TestLoadConfigWithImports(t *testing.T) { + data1 := ` +version = 2 +root = "/var/lib/containerd" +imports = ["data2.toml"] +` + + data2 := ` +disabled_plugins = ["io.containerd.v1.xyz"] +` + + tempDir := t.TempDir() + + err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0o600) + assert.NoError(t, err) + + err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0o600) + assert.NoError(t, err) + + var out Config + err = LoadConfig(context.Background(), filepath.Join(tempDir, "data1.toml"), &out) + assert.NoError(t, err) + + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins) +} + +func TestLoadConfigWithCircularImports(t *testing.T) { + data1 := ` +version = 2 +root = "/var/lib/containerd" +imports = ["data2.toml", "data1.toml"] +` + + data2 := ` +disabled_plugins = ["io.containerd.v1.xyz"] +imports = ["data1.toml", "data2.toml"] +` + tempDir := t.TempDir() + + err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0o600) + assert.NoError(t, err) + + err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0o600) + assert.NoError(t, err) + + var out Config + err = LoadConfig(context.Background(), filepath.Join(tempDir, "data1.toml"), &out) + assert.NoError(t, err) + + assert.Equal(t, 2, out.Version) + assert.Equal(t, "/var/lib/containerd", out.Root) + assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins) + + sort.Strings(out.Imports) + assert.Equal(t, []string{ + "data1.toml", + "data2.toml", + }, out.Imports) +} + +// https://github.com/containerd/containerd/issues/10905 +func TestLoadConfigWithDefaultConfigVersion(t *testing.T) { + data1 := ` +disabled_plugins=["cri"] +` + tempDir := t.TempDir() + + err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0o600) + assert.NoError(t, err) + + var out Config + out.Version = version.ConfigVersion + err = LoadConfig(context.Background(), filepath.Join(tempDir, "data1.toml"), &out) + assert.NoError(t, err) + + assert.Equal(t, version.ConfigVersion, out.Version) + assert.Equal(t, []string{"io.containerd.grpc.v1.cri"}, out.DisabledPlugins) +} + +func TestDecodePlugin(t *testing.T) { + ctx := logtest.WithT(context.Background(), t) + data := ` +version = 2 +[plugins."io.containerd.runtime.v2.task"] + shim_debug = true +` + + tempDir := t.TempDir() + + path := filepath.Join(tempDir, "config.toml") + err := os.WriteFile(path, []byte(data), 0o600) + assert.NoError(t, err) + + var out Config + err = LoadConfig(context.Background(), path, &out) + assert.NoError(t, err) + + pluginConfig := map[string]interface{}{} + _, err = out.Decode(ctx, "io.containerd.runtime.v2.task", &pluginConfig) + assert.NoError(t, err) + assert.Equal(t, true, pluginConfig["shim_debug"]) +} + +// TestDecodePluginInV1Config tests decoding non-versioned config +// (should be parsed as V1 config) and migrated to latest. +func TestDecodePluginInV1Config(t *testing.T) { + ctx := logtest.WithT(context.Background(), t) + data := ` +[plugins.task] + shim_debug = true +` + + path := filepath.Join(t.TempDir(), "config.toml") + err := os.WriteFile(path, []byte(data), 0o600) + assert.NoError(t, err) + + var out Config + err = LoadConfig(context.Background(), path, &out) + assert.NoError(t, err) + assert.Equal(t, 0, out.Version) + + err = out.MigrateConfig(ctx) + assert.NoError(t, err) + assert.Equal(t, 3, out.Version) + + pluginConfig := map[string]interface{}{} + _, err = out.Decode(ctx, "io.containerd.runtime.v2.task", &pluginConfig) + assert.NoError(t, err) + assert.Equal(t, true, pluginConfig["shim_debug"]) +} + +func TestMergingPluginsWithTwoCriDropInConfigs(t *testing.T) { + data1 := ` +[plugins."io.containerd.grpc.v1.cri".cni] + bin_dir = "/cm/local/apps/kubernetes/current/bin/cni" +` + data2 := ` +[plugins."io.containerd.grpc.v1.cri".registry] + config_path = "/cm/local/apps/containerd/var/etc/certs.d" +` + expected := ` +[cni] + bin_dir = '/cm/local/apps/kubernetes/current/bin/cni' + +[registry] + config_path = '/cm/local/apps/containerd/var/etc/certs.d' +` + + testMergeConfig(t, []string{data1, data2}, expected, "io.containerd.grpc.v1.cri") + testMergeConfig(t, []string{data2, data1}, expected, "io.containerd.grpc.v1.cri") +} + +func TestMergingPluginsWithTwoCriCniDropInConfigs(t *testing.T) { + data1 := ` +[plugins."io.containerd.grpc.v1.cri".cni] + bin_dir = "/cm/local/apps/kubernetes/current/bin/cni" +` + data2 := ` +[plugins."io.containerd.grpc.v1.cri".cni] + conf_dir = "/tmp" +` + expected := ` +[cni] + bin_dir = '/cm/local/apps/kubernetes/current/bin/cni' + conf_dir = '/tmp' +` + testMergeConfig(t, []string{data1, data2}, expected, "io.containerd.grpc.v1.cri") +} + +func TestMergingPluginsWithTwoCriRuntimeDropInConfigs(t *testing.T) { + runcRuntime := ` +[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + runtime_type = "io.containerd.runc.v2" + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] + SystemdCgroup = true +` + nvidiaRuntime := ` +[plugins] + [plugins."io.containerd.grpc.v1.cri"] + [plugins."io.containerd.grpc.v1.cri".containerd] + default_runtime_name = "nvidia" + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia] + privileged_without_host_devices = false + runtime_engine = "" + runtime_root = "" + runtime_type = "io.containerd.runc.v2" + [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options] + BinaryName = "/usr/bin/nvidia-container-runtime" + SystemdCgroup = true +` + expected := ` +[containerd] + default_runtime_name = 'nvidia' + + [containerd.runtimes] + [containerd.runtimes.nvidia] + privileged_without_host_devices = false + runtime_engine = '' + runtime_root = '' + runtime_type = 'io.containerd.runc.v2' + + [containerd.runtimes.nvidia.options] + BinaryName = '/usr/bin/nvidia-container-runtime' + SystemdCgroup = true + + [containerd.runtimes.runc] + runtime_type = 'io.containerd.runc.v2' + + [containerd.runtimes.runc.options] + SystemdCgroup = true +` + testMergeConfig(t, []string{runcRuntime, nvidiaRuntime}, expected, "io.containerd.grpc.v1.cri") + + // Merging a third config that customizes only the default_runtime_name should result in mostly identical result + runcDefault := ` + [plugins."io.containerd.grpc.v1.cri".containerd] + default_runtime_name = "runc" +` + // This will then be the only difference in our expected TOML + expected2 := strings.Replace(expected, "default_runtime_name = 'nvidia'", "default_runtime_name = 'runc'", 1) + + testMergeConfig(t, []string{runcRuntime, nvidiaRuntime, runcDefault}, expected2, "io.containerd.grpc.v1.cri") + + // Mixing up the order will again result in 'nvidia' being the default runtime + testMergeConfig(t, []string{runcRuntime, runcDefault, nvidiaRuntime}, expected, "io.containerd.grpc.v1.cri") +} + +func TestMergingPluginsWithTwoCriRuntimeWithPodAnnotationsDropInConfigs(t *testing.T) { + runc1 := ` +[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + runtime_type = "io.containerd.runc.v2" + cni_conf_dir = "/foo" + pod_annotations = ["a", "b", "c"] +` + runc2 := ` +[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] + runtime_type = "io.containerd.runc.v2" + cni_conf_dir = "/bar" + pod_annotations = ["d", "e", "f"] +` + expected := ` +[containerd] + [containerd.runtimes] + [containerd.runtimes.runc] + cni_conf_dir = '/bar' + pod_annotations = ['d', 'e', 'f'] + runtime_type = 'io.containerd.runc.v2' +` + testMergeConfig(t, []string{runc1, runc2}, expected, "io.containerd.grpc.v1.cri") + + // The other way around: runc1 over runc2 + expected = ` +[containerd] + [containerd.runtimes] + [containerd.runtimes.runc] + cni_conf_dir = '/foo' + pod_annotations = ['a', 'b', 'c'] + runtime_type = 'io.containerd.runc.v2' +` + testMergeConfig(t, []string{runc2, runc1}, expected, "io.containerd.grpc.v1.cri") +} + +func testMergeConfig(t *testing.T, inputs []string, expected string, comparePlugin string) { + tempDir := t.TempDir() + var result Config + + for i, data := range inputs { + filename := fmt.Sprintf("data%d.toml", i+1) + filepath := filepath.Join(tempDir, filename) + err := os.WriteFile(filepath, []byte(data), 0600) + assert.NoError(t, err) + + var tempOut Config + err = LoadConfig(context.Background(), filepath, &tempOut) + assert.NoError(t, err) + + if i == 0 { + result = tempOut + } else { + err = mergeConfig(&result, &tempOut) + assert.NoError(t, err) + } + } + + criPlugin := result.Plugins[comparePlugin] + var buf bytes.Buffer + if err := toml.NewEncoder(&buf).SetIndentTables(true).Encode(criPlugin); err != nil { + panic(err) + } + assert.Equal(t, strings.TrimLeft(expected, "\n"), buf.String()) +} diff --git a/services/server/namespace.go b/cmd/containerd/server/namespace.go similarity index 96% rename from services/server/namespace.go rename to cmd/containerd/server/namespace.go index 99f5e33e4a34..82870b2d2b7d 100644 --- a/services/server/namespace.go +++ b/cmd/containerd/server/namespace.go @@ -19,7 +19,7 @@ package server import ( "context" - "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/v2/pkg/namespaces" "google.golang.org/grpc" ) diff --git a/cmd/containerd/server/server.go b/cmd/containerd/server/server.go new file mode 100644 index 000000000000..9f38cb3a64fd --- /dev/null +++ b/cmd/containerd/server/server.go @@ -0,0 +1,604 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package server + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "expvar" + "fmt" + "io" + "net" + "net/http" + "net/http/pprof" + "os" + "path/filepath" + "runtime" + "sync" + "sync/atomic" + "time" + + "github.com/containerd/log" + "github.com/containerd/ttrpc" + "github.com/docker/go-metrics" + grpc_prometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" + v1 "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + + diffapi "github.com/containerd/containerd/api/services/diff/v1" + sbapi "github.com/containerd/containerd/api/services/sandbox/v1" + ssapi "github.com/containerd/containerd/api/services/snapshots/v1" + "github.com/containerd/platforms" + "github.com/containerd/plugin" + "github.com/containerd/plugin/dynamic" + "github.com/containerd/plugin/registry" + + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + csproxy "github.com/containerd/containerd/v2/core/content/proxy" + "github.com/containerd/containerd/v2/core/diff" + diffproxy "github.com/containerd/containerd/v2/core/diff/proxy" + sbproxy "github.com/containerd/containerd/v2/core/sandbox/proxy" + ssproxy "github.com/containerd/containerd/v2/core/snapshots/proxy" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/deprecation" + "github.com/containerd/containerd/v2/pkg/dialer" + "github.com/containerd/containerd/v2/pkg/sys" + "github.com/containerd/containerd/v2/pkg/timeout" + "github.com/containerd/containerd/v2/plugins" + "github.com/containerd/containerd/v2/plugins/services/warning" + "github.com/containerd/containerd/v2/version" +) + +// CreateTopLevelDirectories creates the top-level root and state directories. +func CreateTopLevelDirectories(config *srvconfig.Config) error { + switch { + case config.Root == "": + return errors.New("root must be specified") + case config.State == "": + return errors.New("state must be specified") + case config.Root == config.State: + return errors.New("root and state must be different paths") + } + + if err := sys.MkdirAllWithACL(config.Root, 0o711); err != nil { + return err + } + + if err := sys.MkdirAllWithACL(config.State, 0o711); err != nil { + return err + } + if config.State != defaults.DefaultStateDir { + // XXX: socketRoot in pkg/shim is hard-coded to the default state directory. + // See https://github.com/containerd/containerd/issues/10502#issuecomment-2249268582 for why it's set up that way. + // The default fifo directory in pkg/cio is also configured separately and defaults to the default state directory instead of the configured state directory. + // Make sure the default state directory is created with the correct permissions. + if err := sys.MkdirAllWithACL(defaults.DefaultStateDir, 0o711); err != nil { + return err + } + } + + if config.TempDir != "" { + if err := sys.MkdirAllWithACL(config.TempDir, 0o711); err != nil { + return err + } + if runtime.GOOS == "windows" { + // On Windows, the Host Compute Service (vmcompute) will read the + // TEMP/TMP setting from the calling process when creating the + // tempdir to extract an image layer to. This allows the + // administrator to align the tempdir location with the same volume + // as the snapshot dir to avoid a copy operation when moving the + // extracted layer to the snapshot dir location. + os.Setenv("TEMP", config.TempDir) + os.Setenv("TMP", config.TempDir) + } else { + os.Setenv("TMPDIR", config.TempDir) + } + } + return nil +} + +// New creates and initializes a new containerd server +func New(ctx context.Context, config *srvconfig.Config) (*Server, error) { + var ( + currentVersion = config.Version + migrationT time.Duration + ) + if currentVersion < version.ConfigVersion { + // Migrate config to latest version + t1 := time.Now() + err := config.MigrateConfig(ctx) + if err != nil { + return nil, err + } + migrationT = time.Since(t1) + } + + if err := apply(ctx, config); err != nil { + return nil, err + } + for key, sec := range config.Timeouts { + d, err := time.ParseDuration(sec) + if err != nil { + return nil, fmt.Errorf("unable to parse %s into a time duration", sec) + } + timeout.Set(key, d) + } + loaded, err := LoadPlugins(ctx, config) + if err != nil { + return nil, err + } + for id, p := range config.StreamProcessors { + diff.RegisterProcessor(diff.BinaryHandler(id, p.Returns, p.Accepts, p.Path, p.Args, p.Env)) + } + + var prometheusServerMetricsOpts []grpc_prometheus.ServerMetricsOption + if config.Metrics.GRPCHistogram { + // Enable grpc time histograms to measure rpc latencies + prometheusServerMetricsOpts = append(prometheusServerMetricsOpts, grpc_prometheus.WithServerHandlingTimeHistogram()) + } + + prometheusServerMetrics := grpc_prometheus.NewServerMetrics(prometheusServerMetricsOpts...) + prometheus.MustRegister(prometheusServerMetrics) + + serverOpts := []grpc.ServerOption{ + grpc.StatsHandler(otelgrpc.NewServerHandler()), + grpc.ChainStreamInterceptor( + streamNamespaceInterceptor, + prometheusServerMetrics.StreamServerInterceptor(), + ), + grpc.ChainUnaryInterceptor( + unaryNamespaceInterceptor, + prometheusServerMetrics.UnaryServerInterceptor(), + ), + } + if config.GRPC.MaxRecvMsgSize > 0 { + serverOpts = append(serverOpts, grpc.MaxRecvMsgSize(config.GRPC.MaxRecvMsgSize)) + } + if config.GRPC.MaxSendMsgSize > 0 { + serverOpts = append(serverOpts, grpc.MaxSendMsgSize(config.GRPC.MaxSendMsgSize)) + } + ttrpcServer, err := newTTRPCServer() + if err != nil { + return nil, err + } + tcpServerOpts := serverOpts + if config.GRPC.TCPTLSCert != "" { + log.G(ctx).Info("setting up tls on tcp GRPC services...") + + tlsCert, err := tls.LoadX509KeyPair(config.GRPC.TCPTLSCert, config.GRPC.TCPTLSKey) + if err != nil { + return nil, err + } + tlsConfig := &tls.Config{Certificates: []tls.Certificate{tlsCert}} + + if config.GRPC.TCPTLSCA != "" { + caCertPool := x509.NewCertPool() + caCert, err := os.ReadFile(config.GRPC.TCPTLSCA) + if err != nil { + return nil, fmt.Errorf("failed to load CA file: %w", err) + } + caCertPool.AppendCertsFromPEM(caCert) + tlsConfig.ClientCAs = caCertPool + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + } + + tcpServerOpts = append(tcpServerOpts, grpc.Creds(credentials.NewTLS(tlsConfig))) + } + + // grpcService allows GRPC services to be registered with the underlying server + type grpcService interface { + Register(*grpc.Server) error + } + + // tcpService allows GRPC services to be registered with the underlying tcp server + type tcpService interface { + RegisterTCP(*grpc.Server) error + } + + // ttrpcService allows TTRPC services to be registered with the underlying server + type ttrpcService interface { + RegisterTTRPC(*ttrpc.Server) error + } + + var ( + grpcServer = grpc.NewServer(serverOpts...) + tcpServer = grpc.NewServer(tcpServerOpts...) + + grpcServices []grpcService + tcpServices []tcpService + ttrpcServices []ttrpcService + + s = &Server{ + prometheusServerMetrics: prometheusServerMetrics, + grpcServer: grpcServer, + tcpServer: tcpServer, + ttrpcServer: ttrpcServer, + config: config, + } + initialized = plugin.NewPluginSet() + required = make(map[string]struct{}) + ) + for _, r := range config.RequiredPlugins { + required[r] = struct{}{} + } + + if currentVersion < version.ConfigVersion { + t1 := time.Now() + // Run migration for each configuration version + // Run each plugin migration for each version to ensure that migration logic is simple and + // focused on upgrading from one version at a time. + for v := currentVersion; v < version.ConfigVersion; v++ { + for _, p := range loaded { + if p.ConfigMigration != nil { + if err := p.ConfigMigration(ctx, v, config.Plugins); err != nil { + return nil, err + } + } + } + } + migrationT = migrationT + time.Since(t1) + } + if migrationT > 0 { + log.G(ctx).WithField("t", migrationT).Warnf("Configuration migrated from version %d, use `containerd config migrate` to avoid migration", currentVersion) + } + + for _, p := range loaded { + id := p.URI() + log.G(ctx).WithFields(log.Fields{"id": id, "type": p.Type}).Info("loading plugin") + var mustSucceed int32 + + initContext := plugin.NewContext( + ctx, + initialized, + map[string]string{ + plugins.PropertyRootDir: filepath.Join(config.Root, id), + plugins.PropertyStateDir: filepath.Join(config.State, id), + plugins.PropertyGRPCAddress: config.GRPC.Address, + plugins.PropertyTTRPCAddress: config.TTRPC.Address, + }, + ) + initContext.RegisterReadiness = func() func() { + atomic.StoreInt32(&mustSucceed, 1) + return s.RegisterReadiness() + } + + // load the plugin specific configuration if it is provided + if p.Config != nil { + pc, err := config.Decode(ctx, id, p.Config) + if err != nil { + return nil, err + } + initContext.Config = pc + } + result := p.Init(initContext) + if err := initialized.Add(result); err != nil { + return nil, fmt.Errorf("could not add plugin result to plugin set: %w", err) + } + + instance, err := result.Instance() + if err != nil { + if plugin.IsSkipPlugin(err) { + log.G(ctx).WithFields(log.Fields{"error": err, "id": id, "type": p.Type}).Info("skip loading plugin") + } else { + log.G(ctx).WithFields(log.Fields{"error": err, "id": id, "type": p.Type}).Warn("failed to load plugin") + } + if _, ok := required[id]; ok { + return nil, fmt.Errorf("load required plugin %s: %w", id, err) + } + // If readiness was registered during initialization, the plugin cannot fail + if atomic.LoadInt32(&mustSucceed) != 0 { + return nil, fmt.Errorf("plugin failed after registering readiness %s: %w", id, err) + } + continue + } + + delete(required, id) + // check for grpc services that should be registered with the server + if src, ok := instance.(grpcService); ok { + grpcServices = append(grpcServices, src) + } + if src, ok := instance.(ttrpcService); ok { + ttrpcServices = append(ttrpcServices, src) + } + if service, ok := instance.(tcpService); ok { + tcpServices = append(tcpServices, service) + } + + s.plugins = append(s.plugins, result) + } + if len(required) != 0 { + var missing []string + for id := range required { + missing = append(missing, id) + } + return nil, fmt.Errorf("required plugin %s not included", missing) + } + + // register services after all plugins have been initialized + for _, service := range grpcServices { + if err := service.Register(grpcServer); err != nil { + return nil, err + } + } + for _, service := range ttrpcServices { + if err := service.RegisterTTRPC(ttrpcServer); err != nil { + return nil, err + } + } + for _, service := range tcpServices { + if err := service.RegisterTCP(tcpServer); err != nil { + return nil, err + } + } + + recordConfigDeprecations(ctx, config, initialized) + return s, nil +} + +// recordConfigDeprecations attempts to record use of any deprecated config field. Failures are logged and ignored. +func recordConfigDeprecations(ctx context.Context, config *srvconfig.Config, set *plugin.Set) { + // record any detected deprecations without blocking server startup + p := set.Get(plugins.WarningPlugin, plugins.DeprecationsPlugin) + if p == nil { + log.G(ctx).Warn("failed to find warning service to record deprecations") + return + } + instance, err := p.Instance() + if err != nil { + log.G(ctx).WithError(err).Warn("failed to load warning service to record deprecations") + return + } + warn, ok := instance.(warning.Service) + if !ok { + log.G(ctx).WithError(err).Warn("failed to load warning service to record deprecations, unexpected plugin type") + return + } + + if config.PluginDir != "" { //nolint:staticcheck + warn.Emit(ctx, deprecation.GoPluginLibrary) + } +} + +// Server is the containerd main daemon +type Server struct { + prometheusServerMetrics *grpc_prometheus.ServerMetrics + grpcServer *grpc.Server + ttrpcServer *ttrpc.Server + tcpServer *grpc.Server + config *srvconfig.Config + plugins []*plugin.Plugin + ready sync.WaitGroup +} + +// ServeGRPC provides the containerd grpc APIs on the provided listener +func (s *Server) ServeGRPC(l net.Listener) error { + s.prometheusServerMetrics.InitializeMetrics(s.grpcServer) + return trapClosedConnErr(s.grpcServer.Serve(l)) +} + +// ServeTTRPC provides the containerd ttrpc APIs on the provided listener +func (s *Server) ServeTTRPC(l net.Listener) error { + return trapClosedConnErr(s.ttrpcServer.Serve(context.Background(), l)) +} + +// ServeMetrics provides a prometheus endpoint for exposing metrics +func (s *Server) ServeMetrics(l net.Listener) error { + m := http.NewServeMux() + m.Handle("/v1/metrics", metrics.Handler()) + srv := &http.Server{ + Handler: m, + ReadHeaderTimeout: 5 * time.Minute, // "G112: Potential Slowloris Attack (gosec)"; not a real concern for our use, so setting a long timeout. + } + return trapClosedConnErr(srv.Serve(l)) +} + +// ServeTCP allows services to serve over tcp +func (s *Server) ServeTCP(l net.Listener) error { + s.prometheusServerMetrics.InitializeMetrics(s.tcpServer) + return trapClosedConnErr(s.tcpServer.Serve(l)) +} + +// ServeDebug provides a debug endpoint +func (s *Server) ServeDebug(l net.Listener) error { + // don't use the default http server mux to make sure nothing gets registered + // that we don't want to expose via containerd + m := http.NewServeMux() + m.Handle("/debug/vars", expvar.Handler()) + m.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index)) + m.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline)) + m.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) + m.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) + m.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace)) + srv := &http.Server{ + Handler: m, + ReadHeaderTimeout: 5 * time.Minute, // "G112: Potential Slowloris Attack (gosec)"; not a real concern for our use, so setting a long timeout. + } + return trapClosedConnErr(srv.Serve(l)) +} + +// Stop the containerd server canceling any open connections +func (s *Server) Stop() { + s.grpcServer.Stop() + for i := len(s.plugins) - 1; i >= 0; i-- { + p := s.plugins[i] + instance, err := p.Instance() + if err != nil { + log.L.WithFields(log.Fields{"error": err, "id": p.Registration.URI()}).Error("could not get plugin instance") + continue + } + closer, ok := instance.(io.Closer) + if !ok { + continue + } + if err := closer.Close(); err != nil { + log.L.WithFields(log.Fields{"error": err, "id": p.Registration.URI()}).Error("failed to close plugin") + } + } +} + +func (s *Server) RegisterReadiness() func() { + s.ready.Add(1) + return func() { + s.ready.Done() + } +} + +func (s *Server) Wait() { + s.ready.Wait() +} + +// LoadPlugins loads all plugins into containerd and generates an ordered graph +// of all plugins. +func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]plugin.Registration, error) { + // load all plugins into containerd + path := config.PluginDir //nolint:staticcheck + if path == "" { + path = filepath.Join(config.Root, "plugins") + } + if count, err := dynamic.Load(path); err != nil { + return nil, err + } else if count > 0 || config.PluginDir != "" { //nolint:staticcheck + config.PluginDir = path //nolint:staticcheck + log.G(ctx).Warningf("loaded %d dynamic plugins. `go_plugin` is deprecated, please use `external plugins` instead", count) + } + + clients := &proxyClients{} + for name, pp := range config.ProxyPlugins { + var ( + t plugin.Type + f func(*grpc.ClientConn) interface{} + + address = pp.Address + p v1.Platform + err error + ) + + switch pp.Type { + case string(plugins.SnapshotPlugin), "snapshot": + t = plugins.SnapshotPlugin + ssname := name + f = func(conn *grpc.ClientConn) interface{} { + return ssproxy.NewSnapshotter(ssapi.NewSnapshotsClient(conn), ssname) + } + + case string(plugins.ContentPlugin), "content": + t = plugins.ContentPlugin + f = func(conn *grpc.ClientConn) interface{} { + return csproxy.NewContentStore(conn) + } + case string(plugins.SandboxControllerPlugin), "sandbox": + t = plugins.SandboxControllerPlugin + f = func(conn *grpc.ClientConn) interface{} { + return sbproxy.NewSandboxController(sbapi.NewControllerClient(conn), name) + } + case string(plugins.DiffPlugin), "diff": + t = plugins.DiffPlugin + f = func(conn *grpc.ClientConn) interface{} { + return diffproxy.NewDiffApplier(diffapi.NewDiffClient(conn)) + } + default: + log.G(ctx).WithField("type", pp.Type).Warn("unknown proxy plugin type") + } + if pp.Platform != "" { + p, err = platforms.Parse(pp.Platform) + if err != nil { + log.G(ctx).WithFields(log.Fields{"error": err, "plugin": name}).Warn("skipping proxy platform with bad platform") + } + } else { + p = platforms.DefaultSpec() + } + + exports := pp.Exports + if exports == nil { + exports = map[string]string{} + } + exports["address"] = address + + registry.Register(&plugin.Registration{ + Type: t, + ID: name, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + ic.Meta.Exports = exports + ic.Meta.Platforms = append(ic.Meta.Platforms, p) + ic.Meta.Capabilities = pp.Capabilities + conn, err := clients.getClient(address) + if err != nil { + return nil, err + } + return f(conn), nil + }, + }) + + } + + filter := srvconfig.V2DisabledFilter + // return the ordered graph for plugins + return registry.Graph(filter(config.DisabledPlugins)), nil +} + +type proxyClients struct { + m sync.Mutex + clients map[string]*grpc.ClientConn +} + +func (pc *proxyClients) getClient(address string) (*grpc.ClientConn, error) { + pc.m.Lock() + defer pc.m.Unlock() + if pc.clients == nil { + pc.clients = map[string]*grpc.ClientConn{} + } else if c, ok := pc.clients[address]; ok { + return c, nil + } + + backoffConfig := backoff.DefaultConfig + backoffConfig.MaxDelay = 3 * time.Second + connParams := grpc.ConnectParams{ + Backoff: backoffConfig, + } + gopts := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithConnectParams(connParams), + grpc.WithContextDialer(dialer.ContextDialer), + + // TODO(stevvooe): We may need to allow configuration of this on the client. + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), + } + + conn, err := grpc.NewClient(dialer.DialAddress(address), gopts...) + if err != nil { + return nil, fmt.Errorf("failed to dial %q: %w", address, err) + } + + pc.clients[address] = conn + + return conn, nil +} + +func trapClosedConnErr(err error) error { + if err == nil || errors.Is(err, net.ErrClosed) { + return nil + } + return err +} diff --git a/services/server/server_linux.go b/cmd/containerd/server/server_linux.go similarity index 84% rename from services/server/server_linux.go rename to cmd/containerd/server/server_linux.go index 63cf36a31fb1..de22cf149ec4 100644 --- a/services/server/server_linux.go +++ b/cmd/containerd/server/server_linux.go @@ -23,9 +23,10 @@ import ( "github.com/containerd/cgroups/v3" cgroup1 "github.com/containerd/cgroups/v3/cgroup1" cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2" - "github.com/containerd/containerd/log" - srvconfig "github.com/containerd/containerd/services/server/config" - "github.com/containerd/containerd/sys" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + "github.com/containerd/containerd/v2/pkg/sys" + "github.com/containerd/log" + "github.com/containerd/otelttrpc" "github.com/containerd/ttrpc" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -66,5 +67,8 @@ func apply(ctx context.Context, config *srvconfig.Config) error { } func newTTRPCServer() (*ttrpc.Server, error) { - return ttrpc.NewServer(ttrpc.WithServerHandshaker(ttrpc.UnixSocketRequireSameUser())) + return ttrpc.NewServer( + ttrpc.WithServerHandshaker(ttrpc.UnixSocketRequireSameUser()), + ttrpc.WithUnaryServerInterceptor(otelttrpc.UnaryServerInterceptor()), + ) } diff --git a/services/server/server_solaris.go b/cmd/containerd/server/server_solaris.go similarity index 90% rename from services/server/server_solaris.go rename to cmd/containerd/server/server_solaris.go index 35a637021d8f..8677710e5ff3 100644 --- a/services/server/server_solaris.go +++ b/cmd/containerd/server/server_solaris.go @@ -19,7 +19,7 @@ package server import ( "context" - srvconfig "github.com/containerd/containerd/services/server/config" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" ) func apply(_ context.Context, _ *srvconfig.Config) error { diff --git a/cmd/containerd/server/server_test.go b/cmd/containerd/server/server_test.go new file mode 100644 index 000000000000..5d8fb0d67bfb --- /dev/null +++ b/cmd/containerd/server/server_test.go @@ -0,0 +1,150 @@ +/* + Copyright The containerd Authors. + + 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. +*/ + +package server + +import ( + "context" + "testing" + + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + "github.com/containerd/containerd/v2/version" + "github.com/containerd/plugin" + "github.com/containerd/plugin/registry" + "github.com/stretchr/testify/assert" +) + +const testPath = "/tmp/path/for/testing" + +func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T) { + path := testPath + err := CreateTopLevelDirectories(&srvconfig.Config{ + Root: path, + State: path, + }) + assert.EqualError(t, err, "root and state must be different paths") +} + +func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) { + statePath := "" + rootPath := testPath + err := CreateTopLevelDirectories(&srvconfig.Config{ + Root: rootPath, + State: statePath, + }) + assert.EqualError(t, err, "state must be specified") +} + +func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) { + statePath := testPath + rootPath := "" + err := CreateTopLevelDirectories(&srvconfig.Config{ + Root: rootPath, + State: statePath, + }) + assert.EqualError(t, err, "root must be specified") +} + +func TestMigration(t *testing.T) { + registry.Reset() + defer registry.Reset() + + configVersion := version.ConfigVersion - 1 + + type testConfig struct { + Migrated string `toml:"migrated"` + NotMigrated string `toml:"notmigrated"` + } + + registry.Register(&plugin.Registration{ + Type: "io.containerd.test", + ID: "t1", + Config: &testConfig{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + c, ok := ic.Config.(*testConfig) + if !ok { + t.Error("expected first plugin to have configuration") + } else { + if c.Migrated != "" { + t.Error("expected first plugin to have empty value for migrated config") + } + if c.NotMigrated != "don't migrate me" { + t.Errorf("expected first plugin does not have correct value for not migrated config: %q", c.NotMigrated) + } + } + return nil, nil + }, + }) + registry.Register(&plugin.Registration{ + Type: "io.containerd.new", + Requires: []plugin.Type{ + "io.containerd.test", // Ensure this test runs second + }, + ID: "t2", + Config: &testConfig{}, + InitFn: func(ic *plugin.InitContext) (interface{}, error) { + c, ok := ic.Config.(*testConfig) + if !ok { + t.Error("expected second plugin to have configuration") + } else { + if c.Migrated != "migrate me" { + t.Errorf("expected second plugin does not have correct value for migrated config: %q", c.Migrated) + } + if c.NotMigrated != "" { + t.Error("expected second plugin to have empty value for not migrated config") + } + } + return nil, nil + }, + ConfigMigration: func(ctx context.Context, v int, plugins map[string]interface{}) error { + if v != configVersion { + t.Errorf("unxpected version: %d", v) + } + t1, ok := plugins["io.containerd.test.t1"] + if !ok { + t.Error("plugin not set as expected") + return nil + } + conf, ok := t1.(map[string]interface{}) + if !ok { + t.Errorf("unexpected config value: %v", t1) + return nil + } + newconf := map[string]interface{}{ + "migrated": conf["migrated"], + } + delete(conf, "migrated") + plugins["io.containerd.new.t2"] = newconf + + return nil + }, + }) + + config := &srvconfig.Config{} + config.Version = configVersion + config.Plugins = map[string]interface{}{ + "io.containerd.test.t1": map[string]interface{}{ + "migrated": "migrate me", + "notmigrated": "don't migrate me", + }, + } + + ctx := context.Background() + _, err := New(ctx, config) + if err != nil { + t.Fatal(err) + } +} diff --git a/services/server/server_unsupported.go b/cmd/containerd/server/server_unsupported.go similarity index 91% rename from services/server/server_unsupported.go rename to cmd/containerd/server/server_unsupported.go index def4b548a487..edb433868451 100644 --- a/services/server/server_unsupported.go +++ b/cmd/containerd/server/server_unsupported.go @@ -21,7 +21,7 @@ package server import ( "context" - srvconfig "github.com/containerd/containerd/services/server/config" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" "github.com/containerd/ttrpc" ) diff --git a/services/server/server_windows.go b/cmd/containerd/server/server_windows.go similarity index 78% rename from services/server/server_windows.go rename to cmd/containerd/server/server_windows.go index 4d7c06024f12..a0acc635139b 100644 --- a/services/server/server_windows.go +++ b/cmd/containerd/server/server_windows.go @@ -19,7 +19,8 @@ package server import ( "context" - srvconfig "github.com/containerd/containerd/services/server/config" + srvconfig "github.com/containerd/containerd/v2/cmd/containerd/server/config" + "github.com/containerd/otelttrpc" "github.com/containerd/ttrpc" ) @@ -28,5 +29,7 @@ func apply(_ context.Context, _ *srvconfig.Config) error { } func newTTRPCServer() (*ttrpc.Server, error) { - return ttrpc.NewServer() + return ttrpc.NewServer( + ttrpc.WithUnaryServerInterceptor(otelttrpc.UnaryServerInterceptor()), + ) } diff --git a/cmd/ctr/app/main.go b/cmd/ctr/app/main.go index e97a9f2966c5..13ec27635df5 100644 --- a/cmd/ctr/app/main.go +++ b/cmd/ctr/app/main.go @@ -20,38 +20,50 @@ import ( "fmt" "io" - "github.com/containerd/containerd/cmd/ctr/commands/containers" - "github.com/containerd/containerd/cmd/ctr/commands/content" - "github.com/containerd/containerd/cmd/ctr/commands/events" - "github.com/containerd/containerd/cmd/ctr/commands/images" - "github.com/containerd/containerd/cmd/ctr/commands/info" - "github.com/containerd/containerd/cmd/ctr/commands/install" - "github.com/containerd/containerd/cmd/ctr/commands/leases" - namespacesCmd "github.com/containerd/containerd/cmd/ctr/commands/namespaces" - ociCmd "github.com/containerd/containerd/cmd/ctr/commands/oci" - "github.com/containerd/containerd/cmd/ctr/commands/plugins" - "github.com/containerd/containerd/cmd/ctr/commands/pprof" - "github.com/containerd/containerd/cmd/ctr/commands/run" - "github.com/containerd/containerd/cmd/ctr/commands/sandboxes" - "github.com/containerd/containerd/cmd/ctr/commands/snapshots" - "github.com/containerd/containerd/cmd/ctr/commands/tasks" - versionCmd "github.com/containerd/containerd/cmd/ctr/commands/version" - "github.com/containerd/containerd/defaults" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/version" - "github.com/urfave/cli" + "github.com/containerd/log" + "github.com/urfave/cli/v2" "google.golang.org/grpc/grpclog" + + "github.com/containerd/containerd/v2/cmd/ctr/commands/containers" + "github.com/containerd/containerd/v2/cmd/ctr/commands/content" + "github.com/containerd/containerd/v2/cmd/ctr/commands/deprecations" + "github.com/containerd/containerd/v2/cmd/ctr/commands/events" + "github.com/containerd/containerd/v2/cmd/ctr/commands/images" + "github.com/containerd/containerd/v2/cmd/ctr/commands/info" + "github.com/containerd/containerd/v2/cmd/ctr/commands/install" + "github.com/containerd/containerd/v2/cmd/ctr/commands/leases" + namespacesCmd "github.com/containerd/containerd/v2/cmd/ctr/commands/namespaces" + ociCmd "github.com/containerd/containerd/v2/cmd/ctr/commands/oci" + "github.com/containerd/containerd/v2/cmd/ctr/commands/plugins" + "github.com/containerd/containerd/v2/cmd/ctr/commands/pprof" + "github.com/containerd/containerd/v2/cmd/ctr/commands/run" + "github.com/containerd/containerd/v2/cmd/ctr/commands/sandboxes" + "github.com/containerd/containerd/v2/cmd/ctr/commands/snapshots" + "github.com/containerd/containerd/v2/cmd/ctr/commands/tasks" + versionCmd "github.com/containerd/containerd/v2/cmd/ctr/commands/version" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/containerd/v2/version" ) -var extraCmds = []cli.Command{} +var extraCmds = []*cli.Command{} func init() { // Discard grpc logs so that they don't mess with our stdio grpclog.SetLoggerV2(grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard)) - cli.VersionPrinter = func(c *cli.Context) { - fmt.Println(c.App.Name, version.Package, c.App.Version) + cli.VersionPrinter = func(cliContext *cli.Context) { + fmt.Println(cliContext.App.Name, version.Package, cliContext.App.Version) + } + cli.VersionFlag = &cli.BoolFlag{ + Name: "version", + Aliases: []string{"v"}, + Usage: "Print the version", + } + cli.HelpFlag = &cli.BoolFlag{ + Name: "help", + Aliases: []string{"h"}, + Usage: "Show help", } } @@ -74,34 +86,37 @@ stable from release to release of the containerd project.` containerd CLI ` + app.DisableSliceFlagSeparator = true app.EnableBashCompletion = true app.Flags = []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "debug", Usage: "Enable debug output in logs", }, - cli.StringFlag{ - Name: "address, a", - Usage: "Address for containerd's GRPC server", - Value: defaults.DefaultAddress, - EnvVar: "CONTAINERD_ADDRESS", + &cli.StringFlag{ + Name: "address", + Aliases: []string{"a"}, + Usage: "Address for containerd's GRPC server", + Value: defaults.DefaultAddress, + EnvVars: []string{"CONTAINERD_ADDRESS"}, }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "timeout", Usage: "Total timeout for ctr commands", }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "connect-timeout", Usage: "Timeout for connecting to containerd", }, - cli.StringFlag{ - Name: "namespace, n", - Usage: "Namespace to use with commands", - Value: namespaces.Default, - EnvVar: namespaces.NamespaceEnvVar, + &cli.StringFlag{ + Name: "namespace", + Aliases: []string{"n"}, + Usage: "Namespace to use with commands", + Value: namespaces.Default, + EnvVars: []string{namespaces.NamespaceEnvVar}, }, } - app.Commands = append([]cli.Command{ + app.Commands = append([]*cli.Command{ plugins.Command, versionCmd.Command, containers.Command, @@ -118,9 +133,10 @@ containerd CLI ociCmd.Command, sandboxes.Command, info.Command, + deprecations.Command, }, extraCmds...) - app.Before = func(context *cli.Context) error { - if context.GlobalBool("debug") { + app.Before = func(cliContext *cli.Context) error { + if cliContext.Bool("debug") { return log.SetLevel("debug") } return nil diff --git a/cmd/ctr/app/main_unix.go b/cmd/ctr/app/main_unix.go index d80726325561..ab004e9e3b7e 100644 --- a/cmd/ctr/app/main_unix.go +++ b/cmd/ctr/app/main_unix.go @@ -18,7 +18,7 @@ package app -import "github.com/containerd/containerd/cmd/ctr/commands/shim" +import "github.com/containerd/containerd/v2/cmd/ctr/commands/shim" func init() { extraCmds = append(extraCmds, shim.Command) diff --git a/cmd/ctr/commands/client.go b/cmd/ctr/commands/client.go index 24639483af9f..7e7263ce86e9 100644 --- a/cmd/ctr/commands/client.go +++ b/cmd/ctr/commands/client.go @@ -17,13 +17,15 @@ package commands import ( - gocontext "context" + "context" + "os" + "strconv" - "github.com/containerd/containerd" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/pkg/epoch" - "github.com/urfave/cli" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/pkg/epoch" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/log" + "github.com/urfave/cli/v2" ) // AppContext returns the context for a command. Should only be called once per @@ -31,18 +33,18 @@ import ( // // This will ensure the namespace is picked up and set the timeout, if one is // defined. -func AppContext(context *cli.Context) (gocontext.Context, gocontext.CancelFunc) { +func AppContext(cliContext *cli.Context) (context.Context, context.CancelFunc) { var ( - ctx = gocontext.Background() - timeout = context.GlobalDuration("timeout") - namespace = context.GlobalString("namespace") - cancel gocontext.CancelFunc + ctx = cliContext.Context + timeout = cliContext.Duration("timeout") + namespace = cliContext.String("namespace") + cancel context.CancelFunc ) ctx = namespaces.WithNamespace(ctx, namespace) if timeout > 0 { - ctx, cancel = gocontext.WithTimeout(ctx, timeout) + ctx, cancel = context.WithTimeout(ctx, timeout) } else { - ctx, cancel = gocontext.WithCancel(ctx) + ctx, cancel = context.WithCancel(ctx) } if tm, err := epoch.SourceDateEpoch(); err != nil { log.L.WithError(err).Warn("Failed to read SOURCE_DATE_EPOCH") @@ -54,13 +56,30 @@ func AppContext(context *cli.Context) (gocontext.Context, gocontext.CancelFunc) } // NewClient returns a new containerd client -func NewClient(context *cli.Context, opts ...containerd.ClientOpt) (*containerd.Client, gocontext.Context, gocontext.CancelFunc, error) { - timeoutOpt := containerd.WithTimeout(context.GlobalDuration("connect-timeout")) +func NewClient(cliContext *cli.Context, opts ...containerd.Opt) (*containerd.Client, context.Context, context.CancelFunc, error) { + timeoutOpt := containerd.WithTimeout(cliContext.Duration("connect-timeout")) opts = append(opts, timeoutOpt) - client, err := containerd.New(context.GlobalString("address"), opts...) + client, err := containerd.New(cliContext.String("address"), opts...) if err != nil { return nil, nil, nil, err } - ctx, cancel := AppContext(context) + ctx, cancel := AppContext(cliContext) + var suppressDeprecationWarnings bool + if s := os.Getenv("CONTAINERD_SUPPRESS_DEPRECATION_WARNINGS"); s != "" { + suppressDeprecationWarnings, err = strconv.ParseBool(s) + if err != nil { + log.L.WithError(err).Warn("Failed to parse CONTAINERD_SUPPRESS_DEPRECATION_WARNINGS=" + s) + } + } + if !suppressDeprecationWarnings { + resp, err := client.IntrospectionService().Server(ctx) + if err != nil { + log.L.WithError(err).Warn("Failed to check deprecations") + } else { + for _, d := range resp.Deprecations { + log.L.Warn("DEPRECATION: " + d.Message) + } + } + } return client, ctx, cancel, nil } diff --git a/cmd/ctr/commands/cni.go b/cmd/ctr/commands/cni.go index c1620cea3b5a..43d2cb5abebb 100644 --- a/cmd/ctr/commands/cni.go +++ b/cmd/ctr/commands/cni.go @@ -20,14 +20,14 @@ import ( "context" "fmt" - "github.com/containerd/containerd" - "github.com/containerd/containerd/namespaces" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/typeurl/v2" ) func init() { typeurl.Register(&NetworkMetaData{}, - "github.com/containerd/containerd/cmd/ctr/commands", "NetworkMetaData") + "github.com/containerd/containerd/v2/cmd/ctr/commands", "NetworkMetaData") } const ( diff --git a/cmd/ctr/commands/commands.go b/cmd/ctr/commands/commands.go index 521e037395e2..946da78ed3f2 100644 --- a/cmd/ctr/commands/commands.go +++ b/cmd/ctr/commands/commands.go @@ -23,210 +23,219 @@ import ( "path/filepath" "strings" - "github.com/containerd/containerd/defaults" - "github.com/containerd/containerd/pkg/atomicfile" + "github.com/containerd/containerd/v2/defaults" + "github.com/containerd/containerd/v2/pkg/atomicfile" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) var ( // SnapshotterFlags are cli flags specifying snapshotter names SnapshotterFlags = []cli.Flag{ - cli.StringFlag{ - Name: "snapshotter", - Usage: "Snapshotter name. Empty value stands for the default value.", - EnvVar: "CONTAINERD_SNAPSHOTTER", + &cli.StringFlag{ + Name: "snapshotter", + Usage: "Snapshotter name. Empty value stands for the default value.", + EnvVars: []string{"CONTAINERD_SNAPSHOTTER"}, }, } // SnapshotterLabels are cli flags specifying labels which will be added to the new snapshot for container. - SnapshotterLabels = cli.StringSliceFlag{ + SnapshotterLabels = &cli.StringSliceFlag{ Name: "snapshotter-label", Usage: "Labels added to the new snapshot for this container.", } // LabelFlag is a cli flag specifying labels - LabelFlag = cli.StringSliceFlag{ + LabelFlag = &cli.StringSliceFlag{ Name: "label", Usage: "Labels to attach to the image", } // RegistryFlags are cli flags specifying registry options RegistryFlags = []cli.Flag{ - cli.BoolFlag{ - Name: "skip-verify,k", - Usage: "Skip SSL certificate validation", + &cli.BoolFlag{ + Name: "skip-verify", + Aliases: []string{"k"}, + Usage: "Skip SSL certificate validation", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "plain-http", Usage: "Allow connections using plain HTTP", }, - cli.StringFlag{ - Name: "user,u", - Usage: "User[:password] Registry user and password", + &cli.StringFlag{ + Name: "user", + Aliases: []string{"u"}, + Usage: "User[:password] Registry user and password", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "refresh", Usage: "Refresh token for authorization server", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "hosts-dir", // compatible with "/etc/docker/certs.d" Usage: "Custom hosts configuration directory", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "tlscacert", Usage: "Path to TLS root CA", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "tlscert", Usage: "Path to TLS client certificate", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "tlskey", Usage: "Path to TLS client key", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "http-dump", Usage: "Dump all HTTP request/responses when interacting with container registry", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "http-trace", Usage: "Enable HTTP tracing for registry interactions", }, } + // RuntimeFlags are cli flags specifying runtime + RuntimeFlags = []cli.Flag{ + &cli.StringFlag{ + Name: "runtime", + Usage: "Runtime name or absolute path to runtime binary", + Value: defaults.DefaultRuntime, + }, + &cli.StringFlag{ + Name: "runtime-config-path", + Usage: "Optional runtime config path", + }, + } + // ContainerFlags are cli flags specifying container options ContainerFlags = []cli.Flag{ - cli.StringFlag{ - Name: "config,c", - Usage: "Path to the runtime-specific spec config file", + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "Path to the runtime-specific spec config file", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "cwd", Usage: "Specify the working directory of the process", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "env", Usage: "Specify additional container environment variables (e.g. FOO=bar)", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "env-file", Usage: "Specify additional container environment variables in a file(e.g. FOO=bar, one per line)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "label", Usage: "Specify additional labels (e.g. foo=bar)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "annotation", Usage: "Specify additional OCI annotations (e.g. foo=bar)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "mount", Usage: "Specify additional container mount (e.g. type=bind,src=/tmp,dst=/host,options=rbind:ro)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "net-host", Usage: "Enable host networking for the container", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "privileged", Usage: "Run privileged container", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "read-only", Usage: "Set the containers filesystem as readonly", }, - cli.StringFlag{ - Name: "runtime", - Usage: "Runtime name or absolute path to runtime binary", - Value: defaults.DefaultRuntime, - }, - cli.StringFlag{ + &cli.StringFlag{ Name: "sandbox", Usage: "Create the container in the given sandbox", }, - cli.StringFlag{ - Name: "runtime-config-path", - Usage: "Optional runtime config path", - }, - cli.BoolFlag{ - Name: "tty,t", - Usage: "Allocate a TTY for the container", + &cli.BoolFlag{ + Name: "tty", + Aliases: []string{"t"}, + Usage: "Allocate a TTY for the container", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "with-ns", Usage: "Specify existing Linux namespaces to join at container runtime (format ':')", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "pid-file", Usage: "File path to write the task's pid", }, - cli.IntSliceFlag{ + &cli.IntSliceFlag{ Name: "gpus", Usage: "Add gpus to the container", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "allow-new-privs", Usage: "Turn off OCI spec's NoNewPrivileges feature flag", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "memory-limit", Usage: "Memory limit (in bytes) for the container", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "cap-add", Usage: "Add Linux capabilities (Set capabilities with 'CAP_' prefix)", }, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "cap-drop", Usage: "Drop Linux capabilities (Set capabilities with 'CAP_' prefix)", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "seccomp", Usage: "Enable the default seccomp profile", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "seccomp-profile", Usage: "File path to custom seccomp profile. seccomp must be set to true, before using seccomp-profile", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "apparmor-default-profile", Usage: "Enable AppArmor with the default profile with the specified name, e.g. \"cri-containerd.apparmor.d\"", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "apparmor-profile", Usage: "Enable AppArmor with an existing custom profile", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "blockio-config-file", Usage: "File path to blockio class definitions. By default class definitions are not loaded.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "blockio-class", Usage: "Name of the blockio class to associate the container with", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "rdt-class", Usage: "Name of the RDT class to associate the container with. Specifies a Class of Service (CLOS) for cache and memory bandwidth management.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "hostname", Usage: "Set the container's host name", }, - cli.StringFlag{ - Name: "user,u", - Usage: "Username or user id, group optional (format: [:])", + &cli.StringFlag{ + Name: "user", + Aliases: []string{"u"}, + Usage: "Username or user id, group optional (format: [:])", }, } ) // ObjectWithLabelArgs returns the first arg and a LabelArgs object -func ObjectWithLabelArgs(clicontext *cli.Context) (string, map[string]string) { +func ObjectWithLabelArgs(cliContext *cli.Context) (string, map[string]string) { var ( - first = clicontext.Args().First() - labelStrings = clicontext.Args().Tail() + first = cliContext.Args().First() + labelStrings = cliContext.Args().Tail() ) return first, LabelArgs(labelStrings) diff --git a/cmd/ctr/commands/commands_unix.go b/cmd/ctr/commands/commands_unix.go index 569113e96101..b17e789f4468 100644 --- a/cmd/ctr/commands/commands_unix.go +++ b/cmd/ctr/commands/commands_unix.go @@ -19,28 +19,81 @@ package commands import ( - "github.com/urfave/cli" + "errors" + + "github.com/containerd/containerd/api/types/runc/options" + runtimeoptions "github.com/containerd/containerd/api/types/runtimeoptions/v1" + "github.com/urfave/cli/v2" ) func init() { - ContainerFlags = append(ContainerFlags, cli.BoolFlag{ + RuntimeFlags = append(RuntimeFlags, &cli.StringFlag{ + Name: "runc-binary", + Usage: "Specify runc-compatible binary", + }, &cli.StringFlag{ + Name: "runc-root", + Usage: "Specify runc-compatible root", + }, &cli.BoolFlag{ + Name: "runc-systemd-cgroup", + Usage: "Start runc with systemd cgroup manager", + }) + ContainerFlags = append(ContainerFlags, &cli.BoolFlag{ Name: "rootfs", Usage: "Use custom rootfs that is not managed by containerd snapshotter", - }, cli.BoolFlag{ + }, &cli.BoolFlag{ Name: "no-pivot", Usage: "Disable use of pivot-root (linux only)", - }, cli.Int64Flag{ + }, &cli.Int64Flag{ Name: "cpu-quota", Usage: "Limit CPU CFS quota", Value: -1, - }, cli.Uint64Flag{ + }, &cli.Uint64Flag{ Name: "cpu-period", Usage: "Limit CPU CFS period", - }, cli.StringFlag{ + }, &cli.StringFlag{ Name: "rootfs-propagation", Usage: "Set the propagation of the container rootfs", - }, cli.StringSliceFlag{ + }, &cli.StringSliceFlag{ Name: "device", Usage: "File path to a device to add to the container; or a path to a directory tree of devices to add to the container", }) } + +func getRuncOptions(cliContext *cli.Context) (*options.Options, error) { + runtimeOpts := &options.Options{} + if runcBinary := cliContext.String("runc-binary"); runcBinary != "" { + runtimeOpts.BinaryName = runcBinary + } + if cliContext.Bool("runc-systemd-cgroup") { + if cliContext.String("cgroup") == "" { + // runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope" + return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"") + } + runtimeOpts.SystemdCgroup = true + } + if root := cliContext.String("runc-root"); root != "" { + runtimeOpts.Root = root + } + + return runtimeOpts, nil +} + +func RuntimeOptions(cliContext *cli.Context) (interface{}, error) { + // validate first + if (cliContext.String("runc-binary") != "" || cliContext.Bool("runc-systemd-cgroup")) && + cliContext.String("runtime") != "io.containerd.runc.v2" { + return nil, errors.New("specifying runc-binary and runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime") + } + + if cliContext.String("runtime") == "io.containerd.runc.v2" { + return getRuncOptions(cliContext) + } + + if configPath := cliContext.String("runtime-config-path"); configPath != "" { + return &runtimeoptions.Options{ + ConfigPath: configPath, + }, nil + } + + return nil, nil +} diff --git a/cmd/ctr/commands/commands_windows.go b/cmd/ctr/commands/commands_windows.go index d7b6be2860cc..15bc3951cebb 100644 --- a/cmd/ctr/commands/commands_windows.go +++ b/cmd/ctr/commands/commands_windows.go @@ -17,24 +17,26 @@ package commands import ( - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) func init() { ContainerFlags = append(ContainerFlags, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "cpu-count", Usage: "Number of CPUs available to the container", - }, - cli.Uint64Flag{ + }, &cli.Uint64Flag{ Name: "cpu-shares", Usage: "The relative number of CPU shares given to the container relative to other workloads. Between 0 and 10,000.", - }, - cli.Uint64Flag{ + }, &cli.Uint64Flag{ Name: "cpu-max", Usage: "The number of processor cycles threads in a container can use per 10,000 cycles. Set to a percentage times 100. Between 1 and 10,000", - }, cli.StringSliceFlag{ + }, &cli.StringSliceFlag{ Name: "device", Usage: "Identifier of a device to add to the container (e.g. class://5B45201D-F2F2-4F3B-85BB-30FF1F953599)", }) } + +func RuntimeOptions(cliContext *cli.Context) (interface{}, error) { + return nil, nil +} diff --git a/cmd/ctr/commands/containers/checkpoint.go b/cmd/ctr/commands/containers/checkpoint.go index 3d616c13773e..da048f1ca1be 100644 --- a/cmd/ctr/commands/containers/checkpoint.go +++ b/cmd/ctr/commands/containers/checkpoint.go @@ -20,40 +20,40 @@ import ( "errors" "fmt" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cmd/ctr/commands" - "github.com/containerd/containerd/errdefs" - "github.com/urfave/cli" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/cmd/ctr/commands" + "github.com/containerd/errdefs" + "github.com/urfave/cli/v2" ) -var checkpointCommand = cli.Command{ +var checkpointCommand = &cli.Command{ Name: "checkpoint", Usage: "Checkpoint a container", ArgsUsage: "CONTAINER REF", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "rw", Usage: "Include the rw layer in the checkpoint", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "image", Usage: "Include the image in the checkpoint", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "task", Usage: "Checkpoint container task", }, }, - Action: func(context *cli.Context) error { - id := context.Args().First() + Action: func(cliContext *cli.Context) error { + id := cliContext.Args().First() if id == "" { return errors.New("container id must be provided") } - ref := context.Args().Get(1) + ref := cliContext.Args().Get(1) if ref == "" { return errors.New("ref must be provided") } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -62,13 +62,13 @@ var checkpointCommand = cli.Command{ containerd.WithCheckpointRuntime, } - if context.Bool("image") { + if cliContext.Bool("image") { opts = append(opts, containerd.WithCheckpointImage) } - if context.Bool("rw") { + if cliContext.Bool("rw") { opts = append(opts, containerd.WithCheckpointRW) } - if context.Bool("task") { + if cliContext.Bool("task") { opts = append(opts, containerd.WithCheckpointTask) } container, err := client.LoadContainer(ctx, id) diff --git a/cmd/ctr/commands/containers/containers.go b/cmd/ctr/commands/containers/containers.go index 046c72a602e9..4f7e5394252d 100644 --- a/cmd/ctr/commands/containers/containers.go +++ b/cmd/ctr/commands/containers/containers.go @@ -23,23 +23,23 @@ import ( "strings" "text/tabwriter" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/cmd/ctr/commands" - "github.com/containerd/containerd/cmd/ctr/commands/run" - "github.com/containerd/containerd/containers" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/log" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/cmd/ctr/commands" + "github.com/containerd/containerd/v2/cmd/ctr/commands/run" + "github.com/containerd/containerd/v2/core/containers" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/errdefs" + "github.com/containerd/log" "github.com/containerd/typeurl/v2" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) // Command is the cli command for managing containers -var Command = cli.Command{ +var Command = &cli.Command{ Name: "containers", Usage: "Manage containers", Aliases: []string{"c", "container"}, - Subcommands: []cli.Command{ + Subcommands: []*cli.Command{ createCommand, deleteCommand, infoCommand, @@ -50,27 +50,26 @@ var Command = cli.Command{ }, } -var createCommand = cli.Command{ - Name: "create", - Usage: "Create container", - ArgsUsage: "[flags] Image|RootFS CONTAINER [COMMAND] [ARG...]", - SkipArgReorder: true, - Flags: append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...), commands.ContainerFlags...), - Action: func(context *cli.Context) error { +var createCommand = &cli.Command{ + Name: "create", + Usage: "Create container", + ArgsUsage: "[flags] Image|RootFS CONTAINER [COMMAND] [ARG...]", + Flags: append(commands.RuntimeFlags, append(append(commands.SnapshotterFlags, []cli.Flag{commands.SnapshotterLabels}...), commands.ContainerFlags...)...), + Action: func(cliContext *cli.Context) error { var ( id string ref string - config = context.IsSet("config") + config = cliContext.IsSet("config") ) if config { - id = context.Args().First() - if context.NArg() > 1 { + id = cliContext.Args().First() + if cliContext.NArg() > 1 { return fmt.Errorf("with spec config file, only container id should be provided: %w", errdefs.ErrInvalidArgument) } } else { - id = context.Args().Get(1) - ref = context.Args().First() + id = cliContext.Args().Get(1) + ref = cliContext.Args().First() if ref == "" { return fmt.Errorf("image ref must be provided: %w", errdefs.ErrInvalidArgument) } @@ -78,12 +77,12 @@ var createCommand = cli.Command{ if id == "" { return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument) } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } defer cancel() - _, err = run.NewContainer(ctx, client, context) + _, err = run.NewContainer(ctx, client, cliContext) if err != nil { return err } @@ -91,23 +90,24 @@ var createCommand = cli.Command{ }, } -var listCommand = cli.Command{ +var listCommand = &cli.Command{ Name: "list", Aliases: []string{"ls"}, Usage: "List containers", ArgsUsage: "[flags] [, ...]", Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "quiet, q", - Usage: "Print only the container id", + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Print only the container id", }, }, - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { var ( - filters = context.Args() - quiet = context.Bool("quiet") + filters = cliContext.Args().Slice() + quiet = cliContext.Bool("quiet") ) - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -145,33 +145,33 @@ var listCommand = cli.Command{ }, } -var deleteCommand = cli.Command{ +var deleteCommand = &cli.Command{ Name: "delete", Usage: "Delete one or more existing containers", ArgsUsage: "[flags] CONTAINER [CONTAINER, ...]", Aliases: []string{"del", "remove", "rm"}, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "keep-snapshot", Usage: "Do not clean up snapshot with container", }, }, - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { var exitErr error - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } defer cancel() deleteOpts := []containerd.DeleteOpts{} - if !context.Bool("keep-snapshot") { + if !cliContext.Bool("keep-snapshot") { deleteOpts = append(deleteOpts, containerd.WithSnapshotCleanup) } - if context.NArg() == 0 { + if cliContext.NArg() == 0 { return fmt.Errorf("must specify at least one container to delete: %w", errdefs.ErrInvalidArgument) } - for _, arg := range context.Args() { + for _, arg := range cliContext.Args().Slice() { if err := deleteContainer(ctx, client, arg, deleteOpts...); err != nil { if exitErr == nil { exitErr = err @@ -206,18 +206,18 @@ func deleteContainer(ctx context.Context, client *containerd.Client, id string, } -var setLabelsCommand = cli.Command{ +var setLabelsCommand = &cli.Command{ Name: "label", Usage: "Set and clear labels for a container", ArgsUsage: "[flags] CONTAINER [=, ...]", Description: "set and clear labels for a container", Flags: []cli.Flag{}, - Action: func(context *cli.Context) error { - containerID, labels := commands.ObjectWithLabelArgs(context) + Action: func(cliContext *cli.Context) error { + containerID, labels := commands.ObjectWithLabelArgs(cliContext) if containerID == "" { return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument) } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -244,22 +244,22 @@ var setLabelsCommand = cli.Command{ }, } -var infoCommand = cli.Command{ +var infoCommand = &cli.Command{ Name: "info", Usage: "Get info about a container", ArgsUsage: "CONTAINER", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "spec", Usage: "Only display the spec", }, }, - Action: func(context *cli.Context) error { - id := context.Args().First() + Action: func(cliContext *cli.Context) error { + id := cliContext.Args().First() if id == "" { return fmt.Errorf("container id must be provided: %w", errdefs.ErrInvalidArgument) } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -272,7 +272,7 @@ var infoCommand = cli.Command{ if err != nil { return err } - if context.Bool("spec") { + if cliContext.Bool("spec") { v, err := typeurl.UnmarshalAny(info.Spec) if err != nil { return err diff --git a/cmd/ctr/commands/containers/restore.go b/cmd/ctr/commands/containers/restore.go index e3c011dd77fc..e63b25b993a5 100644 --- a/cmd/ctr/commands/containers/restore.go +++ b/cmd/ctr/commands/containers/restore.go @@ -20,39 +20,39 @@ import ( "errors" "github.com/containerd/console" - "github.com/containerd/containerd" - "github.com/containerd/containerd/cio" - "github.com/containerd/containerd/cmd/ctr/commands" - "github.com/containerd/containerd/cmd/ctr/commands/tasks" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/log" - "github.com/urfave/cli" + containerd "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/cmd/ctr/commands" + "github.com/containerd/containerd/v2/cmd/ctr/commands/tasks" + "github.com/containerd/containerd/v2/pkg/cio" + "github.com/containerd/errdefs" + "github.com/containerd/log" + "github.com/urfave/cli/v2" ) -var restoreCommand = cli.Command{ +var restoreCommand = &cli.Command{ Name: "restore", Usage: "Restore a container from checkpoint", ArgsUsage: "CONTAINER REF", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "rw", Usage: "Restore the rw layer from the checkpoint", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "live", Usage: "Restore the runtime and memory data from the checkpoint", }, }, - Action: func(context *cli.Context) error { - id := context.Args().First() + Action: func(cliContext *cli.Context) error { + id := cliContext.Args().First() if id == "" { return errors.New("container id must be provided") } - ref := context.Args().Get(1) + ref := cliContext.Args().Get(1) if ref == "" { return errors.New("ref must be provided") } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -76,7 +76,7 @@ var restoreCommand = cli.Command{ containerd.WithRestoreSpec, containerd.WithRestoreRuntime, } - if context.Bool("rw") { + if cliContext.Bool("rw") { opts = append(opts, containerd.WithRestoreRW) } @@ -85,7 +85,7 @@ var restoreCommand = cli.Command{ return err } topts := []containerd.NewTaskOpts{} - if context.Bool("live") { + if cliContext.Bool("live") { topts = append(topts, containerd.WithTaskCheckpoint(checkpoint)) } spec, err := ctr.Spec(ctx) @@ -136,7 +136,7 @@ var restoreCommand = cli.Command{ return err } if code != 0 { - return cli.NewExitError("", int(code)) + return cli.Exit("", int(code)) } return nil }, diff --git a/cmd/ctr/commands/content/content.go b/cmd/ctr/commands/content/content.go index 277eda3422a3..236b6e335fa6 100644 --- a/cmd/ctr/commands/content/content.go +++ b/cmd/ctr/commands/content/content.go @@ -21,26 +21,26 @@ import ( "fmt" "io" "os" + "os/exec" "sort" "strings" "text/tabwriter" "time" - "github.com/containerd/containerd/cmd/ctr/commands" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/log" - "github.com/containerd/containerd/remotes" + "github.com/containerd/containerd/v2/cmd/ctr/commands" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/remotes" + "github.com/containerd/errdefs" + "github.com/containerd/log" units "github.com/docker/go-units" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/urfave/cli" - exec "golang.org/x/sys/execabs" + "github.com/urfave/cli/v2" ) var ( // Command is the cli command for managing content - Command = cli.Command{ + Command = &cli.Command{ Name: "content", Usage: "Manage content", Subcommands: cli.Commands{ @@ -59,17 +59,17 @@ var ( }, } - getCommand = cli.Command{ + getCommand = &cli.Command{ Name: "get", Usage: "Get the data for an object", ArgsUsage: "[, ...]", Description: "display the image object", - Action: func(context *cli.Context) error { - dgst, err := digest.Parse(context.Args().First()) + Action: func(cliContext *cli.Context) error { + dgst, err := digest.Parse(cliContext.Args().First()) if err != nil { return err } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -88,26 +88,26 @@ var ( }, } - ingestCommand = cli.Command{ + ingestCommand = &cli.Command{ Name: "ingest", Usage: "Accept content into the store", ArgsUsage: "[flags] ", Description: "ingest objects into the local content store", Flags: []cli.Flag{ - cli.Int64Flag{ + &cli.Int64Flag{ Name: "expected-size", Usage: "Validate against provided size", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "expected-digest", Usage: "Verify content against expected digest", }, }, - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { var ( - ref = context.Args().First() - expectedSize = context.Int64("expected-size") - expectedDigest = digest.Digest(context.String("expected-digest")) + ref = cliContext.Args().First() + expectedSize = cliContext.Int64("expected-size") + expectedDigest = digest.Digest(cliContext.String("expected-digest")) ) if err := expectedDigest.Validate(); expectedDigest != "" && err != nil { return err @@ -115,7 +115,7 @@ var ( if ref == "" { return errors.New("must specify a transaction reference") } - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -130,26 +130,27 @@ var ( }, } - activeIngestCommand = cli.Command{ + activeIngestCommand = &cli.Command{ Name: "active", Usage: "Display active transfers", ArgsUsage: "[flags] []", Description: "display the ongoing transfers", Flags: []cli.Flag{ - cli.DurationFlag{ - Name: "timeout, t", - Usage: "Total timeout for fetch", - EnvVar: "CONTAINERD_FETCH_TIMEOUT", + &cli.DurationFlag{ + Name: "timeout", + Aliases: []string{"t"}, + Usage: "Total timeout for fetch", + EnvVars: []string{"CONTAINERD_FETCH_TIMEOUT"}, }, - cli.StringFlag{ + &cli.StringFlag{ Name: "root", Usage: "Path to content store root", Value: "/tmp/content", // TODO(stevvooe): for now, just use the PWD/.content }, }, - Action: func(context *cli.Context) error { - match := context.Args().First() - client, ctx, cancel, err := commands.NewClient(context) + Action: func(cliContext *cli.Context) error { + match := cliContext.Args().First() + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -172,24 +173,25 @@ var ( }, } - listCommand = cli.Command{ + listCommand = &cli.Command{ Name: "list", Aliases: []string{"ls"}, Usage: "List all blobs in the store", ArgsUsage: "[flags]", Description: "list blobs in the content store", Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "quiet, q", - Usage: "Print only the blob digest", + &cli.BoolFlag{ + Name: "quiet", + Aliases: []string{"q"}, + Usage: "Print only the blob digest", }, }, - Action: func(context *cli.Context) error { + Action: func(cliContext *cli.Context) error { var ( - quiet = context.Bool("quiet") - args = []string(context.Args()) + quiet = cliContext.Bool("quiet") + args = cliContext.Args().Slice() ) - client, ctx, cancel, err := commands.NewClient(context) + client, ctx, cancel, err := commands.NewClient(cliContext) if err != nil { return err } @@ -232,14 +234,14 @@ var ( }, } - setLabelsCommand = cli.Command{ + setLabelsCommand = &cli.Command{ Name: "label", Usage: "Add labels to content", ArgsUsage: " [