Repository: containerd/nerdctl
Pull request #4159: [CI]: cleanup, breakout 1: `./hack`
Author: login: apostasie
Labels: name: area/ci
description: e.g., CI failure
Created: 2025-04-25T00:04:22Z | Merged: 2025-04-26T01:39:09Z

Breaking-out #4154 into small chunks, starting with (hopefully) non controversial bits.

TL;DR is github workflows and helper scripts have grown baroque.

This series of PR purports to:
- increase readibility and have a more modular, sensical organization of scripts and workflows
- preparing for testing more "on the host" and less "in container"

This first PR is (mostly) trivial cleanup inside `./hack`.

I will comment inline on changes where necessary to explain them.


Diff:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index b79138a70d9..3bda482409d 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -45,8 +45,8 @@ jobs:
         run: |
           # If canary is specified, get the latest available golang pre-release instead of the major version
           if [ "${{ matrix.canary }}" != "" ]; then
-            . ./hack/build-integration-canary.sh
-            canary::golang::latest
+            . ./hack/provisioning/version/fetch.sh
+            printf "GO_VERSION=%s\n" "$(go::canary::for::go-setup)" >> "$GITHUB_ENV"
           fi
       - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b  # v5.4.0
         with:
diff --git a/.github/workflows/test-canary.yml b/.github/workflows/test-canary.yml
index ffd14400c26..39b32d21783 100644
--- a/.github/workflows/test-canary.yml
+++ b/.github/workflows/test-canary.yml
@@ -68,8 +68,8 @@ jobs:
           ctd_v="$("${args[@]}" https://api.github.com/repos/containerd/containerd/tags | jq -rc .[0].name)"
           echo "CONTAINERD_VERSION=${ctd_v:1}" >> "$GITHUB_ENV"
 
-          . ./hack/build-integration-canary.sh
-          canary::golang::latest
+          . ./hack/provisioning/version/fetch.sh
+          printf "GO_VERSION=%s\n" "$(go::canary::for::go-setup)" >> "$GITHUB_ENV"
       - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b  # v5.4.0
         with:
           go-version: ${{ env.GO_VERSION }}
@@ -82,7 +82,7 @@ jobs:
       - name: "Set up containerd"
         env:
           ctrdVersion: ${{ env.CONTAINERD_VERSION }}
-        run: powershell hack/configure-windows-ci.ps1
+        run: powershell hack/provisioning/windows/containerd.ps1
       - name: "Run integration tests"
         run: ./hack/test-integration.sh -test.only-flaky=false
       - name: "Run integration tests (flaky)"
diff --git a/.github/workflows/test-kube.yml b/.github/workflows/test-kube.yml
index 57871c3abee..7fd8d880f89 100644
--- a/.github/workflows/test-kube.yml
+++ b/.github/workflows/test-kube.yml
@@ -23,5 +23,5 @@ jobs:
       - name: "Run Kubernetes integration tests"
         # See https://github.com/containerd/nerdctl/blob/main/docs/testing/README.md#about-parallelization
         run: |
-          ./hack/build-integration-kubernetes.sh
+          ./hack/provisioning/kube/kind.sh
           sudo ./_output/nerdctl exec nerdctl-test-control-plane bash -c -- 'export TMPDIR="$HOME"/tmp; mkdir -p "$TMPDIR"; cd /nerdctl-source; /usr/local/go/bin/go test -p 1 ./cmd/nerdctl/... -test.only-kubernetes'
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1e87734d697..53bc9a45bf8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -369,7 +369,7 @@ jobs:
       - name: "Set up containerd"
         env:
           ctrdVersion: 1.7.27
-        run: powershell hack/configure-windows-ci.ps1
+        run: powershell hack/provisioning/windows/containerd.ps1
       - name: "Run integration tests"
         run: ./hack/test-integration.sh -test.only-flaky=false
       - name: "Run integration tests (flaky)"
diff --git a/.github/workflows/tigron.yml b/.github/workflows/tigron.yml
index dd0cc615167..5915adae0ad 100644
--- a/.github/workflows/tigron.yml
+++ b/.github/workflows/tigron.yml
@@ -37,10 +37,9 @@ jobs:
           fetch-depth: 100
       - name: "Set GO env"
         run: |
-          # If canary is specified, get the latest available golang pre-release instead of the major version
           if [ "${{ matrix.canary }}" != "" ]; then
-            . ./hack/build-integration-canary.sh
-            canary::golang::latest
+            . ./hack/provisioning/version/fetch.sh
+            printf "GO_VERSION=%s\n" "$(go::canary::for::go-setup)" >> "$GITHUB_ENV"
           fi
       - name: "Install go"
         uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b  # v5.4.0
diff --git a/hack/build-integration-canary.sh b/hack/build-integration-canary.sh
index ff53db891a0..ae205c90bed 100755
--- a/hack/build-integration-canary.sh
+++ b/hack/build-integration-canary.sh
@@ -323,27 +323,3 @@ canary::golang::hublatest(){
 
   printf "%s" "$available_version"
 }
-
-canary::golang::latest(){
-  # Enable extended globbing features to use advanced pattern matching
-  shopt -s extglob
-
-  # Get latest golang version and split it in components
-  norm=()
-  while read -r line; do
-    line_trimmed="${line//+([[:space:]])/}"
-    norm+=("$line_trimmed")
-  done < \
-    <(sed -E 's/^go([0-9]+)[.]([0-9]+)([.]([0-9]+))?(([a-z]+)([0-9]+))?/\1.\2\n\4\n\6\n\7/i' \
-      <(curl -fsSL "https://go.dev/dl/?mode=json&include=all" | jq -rc .[0].version) \
-    )
-
-  # Serialize version, making sure we have a patch version, and separate possible rcX into .rc-X
-  [ "${norm[1]}" != "" ] || norm[1]="0"
-  norm[1]=".${norm[1]}"
-  [ "${norm[2]}" == "" ] || norm[2]="-${norm[2]}"
-  [ "${norm[3]}" == "" ] || norm[3]=".${norm[3]}"
-  # Save it
-  IFS=
-  echo "GO_VERSION=${norm[*]}" >> "$GITHUB_ENV"
-}
diff --git a/hack/provisioning/README.md b/hack/provisioning/README.md
new file mode 100644
index 00000000000..314ffc9fed4
--- /dev/null
+++ b/hack/provisioning/README.md
@@ -0,0 +1,15 @@
+# Dependencies provisioning for integration testing
+
+This folder provides a set of scripts useful (for the CI) to configure hosts for
+the purpose of testing.
+
+While this is agnostic and would (probably) work outside the context of GitHub Actions,
+this is not the right way for people to install a functioning stack.
+Use provided installation scripts instead (see user documentation).
+
+## Contents
+
+- `/version` allows retrieving latest (or experimental) versions of certain products (golang, containerd, etc)
+- `/linux` allows updating in-place containerd, cni (future: buildkit)
+- `/windows` allows install WinCNI, containerd
+- `/kube` allows spinning-up a Kind cluster
\ No newline at end of file
diff --git a/hack/build-integration-kubernetes.sh b/hack/provisioning/kube/kind.sh
similarity index 81%
rename from hack/build-integration-kubernetes.sh
rename to hack/provisioning/kube/kind.sh
index d2aa564a551..1260758dfa0 100755
--- a/hack/build-integration-kubernetes.sh
+++ b/hack/provisioning/kube/kind.sh
@@ -14,16 +14,19 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-# shellcheck disable=SC2034,SC2015
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
 readonly root
 # shellcheck source=/dev/null
-. "$root/scripts/lib.sh"
+. "$root/../../scripts/lib.sh"
 
 GO_VERSION=1.24
 KIND_VERSION=v0.27.0
-CNI_PLUGINS_VERSION=v1.6.2
+CNI_PLUGINS_VERSION=v1.7.1
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_AMD64=1a28a0506bfe5bcdc981caf1a49eeab7e72da8321f1119b7be85f22621013098
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_ARM64=119fcb508d1ac2149e49a550752f9cd64d023a1d70e189b59c476e4d2bf7c497
 
 [ "$(uname -m)" == "aarch64" ] && GOARCH=arm64 || GOARCH=amd64
 
@@ -55,19 +58,6 @@ install::kubectl(){
   host::install "$temp"/kubectl
 }
 
-install::cni(){
-  local version="$1"
-  local temp
-  temp="$(fs::mktemp "install")"
-
-  http::get "$temp"/cni.tgz "https://github.com/containernetworking/plugins/releases/download/$version/cni-plugins-${GOOS:-linux}-${GOARCH:-amd64}-$version.tgz"
-  sudo mkdir -p /opt/cni/bin
-  sudo tar xzf "$temp"/cni.tgz -C /opt/cni/bin
-  mkdir -p ~/opt/cni/bin
-  tar xzf "$temp"/cni.tgz -C ~/opt/cni/bin
-  rm "$temp"/cni.tgz
-}
-
 exec::kind(){
   local args=()
   [ ! "$_rootful" ] || args=(sudo env PATH="$PATH" KIND_EXPERIMENTAL_PROVIDER="$KIND_EXPERIMENTAL_PROVIDER")
@@ -92,16 +82,20 @@ main(){
   configure::rootful "${ROOTFUL:-}"
 
   log::info "Installing host dependencies if necessary"
+  host::require make go
   host::require kind 2>/dev/null || install::kind "$KIND_VERSION"
   host::require kubectl 2>/dev/null || install::kubectl
 
   # Build nerdctl to use for kind
-  make binaries
+  make -f "$root/../../../Makefile" binaries
   PATH=$(pwd)/_output:"$PATH"
   export PATH
 
   # Add CNI plugins
-  install::cni "$CNI_PLUGINS_VERSION"
+  local sha
+  sha="CNI_PLUGINS_SHA_$(tr "[:lower:]" "[:upper:]" <<<"$GOARCH")"
+  # shellcheck source=/dev/null
+  "$root"/../linux/cni.sh "$CNI_PLUGINS_VERSION" "$GOARCH" "${!sha}"
 
   # Hack to get go into kind control plane
   exec::nerdctl rm -f go-kind 2>/dev/null || true
@@ -113,7 +107,7 @@ main(){
   log::info "Creating new cluster"
   export KIND_EXPERIMENTAL_PROVIDER=nerdctl
   exec::kind delete cluster --name nerdctl-test 2>/dev/null || true
-  exec::kind create cluster --name nerdctl-test --config=./hack/kind.yaml
+  exec::kind create cluster --name nerdctl-test --config="$root"/kind.yaml
 }
 
 main "$@"
diff --git a/hack/kind.yaml b/hack/provisioning/kube/kind.yaml
similarity index 100%
rename from hack/kind.yaml
rename to hack/provisioning/kube/kind.yaml
diff --git a/hack/provisioning/linux/cni.sh b/hack/provisioning/linux/cni.sh
new file mode 100755
index 00000000000..aaee9ad7fe0
--- /dev/null
+++ b/hack/provisioning/linux/cni.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
+readonly root
+# shellcheck source=/dev/null
+. "$root/../../scripts/lib.sh"
+
+provision::cni::uninstall(){
+  [ "$(id -u)" == 0 ] || {
+    log::error "You need to be root"
+    return 1
+  }
+
+  rm -Rf /opt/cni/bin
+}
+
+# provision::containerd::cni will retrieve a specific version of cni plugins and extract it in place on the host
+provision::cni(){
+  local version="$1"
+  local arch="$2"
+  local bin_sha="$3"
+
+  cd "$(fs::mktemp "cni-install")"
+
+  http::get::secure \
+    cni.tgz \
+    https://github.com/containernetworking/plugins/releases/download/"$version"/cni-plugins-linux-"$arch"-"$version".tgz \
+    "$bin_sha"
+
+  sudo mkdir -p /opt/cni/bin
+  sudo tar -C /opt/cni/bin -xzf cni.tgz
+
+  cd - >/dev/null
+}
+
+provision::cni "$1" "$2" "$3"
\ No newline at end of file
diff --git a/hack/provisioning/linux/containerd.sh b/hack/provisioning/linux/containerd.sh
new file mode 100755
index 00000000000..f49ef9c9cc0
--- /dev/null
+++ b/hack/provisioning/linux/containerd.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
+readonly root
+# shellcheck source=/dev/null
+. "$root/../../scripts/lib.sh"
+
+# provision::containerd::uninstall will ensure deb containerd are purged
+provision::containerd::uninstall(){
+  [ "$(id -u)" == 0 ] || {
+    log::error "You need to be root"
+    return 1
+  }
+
+  # Purge deb package
+  apt-get -q purge containerd* 2>/dev/null || true
+  # Remove conf
+  rm -f /etc/containerd/containerd.toml
+  # Remove manually installed containerd if leftover
+  systemctl stop containerd 2>/dev/null
+  rm -f /lib/systemd/system/containerd.service
+  systemctl daemon-reload 2>/dev/null || true
+  ! command -v containerd || rm -f "$(which containerd)"
+}
+
+# provision::containerd::rootful will retrieve a specific version of containerd and install it on the host.
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+  local bin_sha="$3"
+  local service_sha="$4"
+
+  # Be tolerant with passed versions - with or without leading "v"
+  [ "${version:0:1}" != "v" ] || version="${version:1}"
+
+  cd "$(fs::mktemp "containerd-install")"
+
+  # Get the binary and install it
+  http::get::secure \
+    containerd.tar.gz \
+    https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz \
+    "$bin_sha"
+
+  sudo tar::expand /usr/local containerd.tar.gz
+
+  # Get the systemd unit
+  http::get::secure \
+    containerd.service \
+    https://raw.githubusercontent.com/containerd/containerd/refs/tags/v"$version"/containerd.service \
+    "$service_sha"
+
+  sudo cp containerd.service /lib/systemd/system/containerd.service
+
+  # Start it
+  sudo systemctl daemon-reload
+  sudo systemctl start containerd
+
+  cd - >/dev/null || true
+}
+
+provision::containerd::rootful "$1" "$2" "$3" "$4"
\ No newline at end of file
diff --git a/hack/provisioning/version/fetch.sh b/hack/provisioning/version/fetch.sh
new file mode 100755
index 00000000000..3145d2670be
--- /dev/null
+++ b/hack/provisioning/version/fetch.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# go::canary::for::go-setup retrieves the latest unstable golang version and format it for use by
+# https://github.com/actions/setup-go
+# Note that if the latest unstable is an old RC for the current stable, we print the empty string.
+go::canary::for::go-setup(){
+  local all_versions
+  local stable_major_minor
+  local canary_major_minor
+  local canary_full_version
+
+  # Get all golang versions
+  all_versions="$(curl -fsSL --proto '=https' --tlsv1.2 "https://go.dev/dl/?mode=json&include=all")"
+
+  # Get the latest stable release major.minor for comparison
+  read -r stable_major_minor < \
+    <(sed -E 's/^go([0-9]+[.][0-9]+).*/\1/i' \
+      <(jq -rc 'map(select(.stable==true)).[0].version' <<<"$all_versions") \
+    )
+
+  # Get the latest unstable release major.minor, and full version (formatted for use by go-setup)
+  read -r canary_major_minor canary_full_version < \
+    <(sed -E 's/^go([0-9]+)[.]([0-9]+)(([a-z]+)([0-9]+))?/\1.\2 \1.\2.0-\4.\5/i' \
+      <(jq -rc 'map(select(.stable==false)).[0].version' <<<"$all_versions") \
+    )
+
+  # If the latest RC is for the same major.minor as the latest stable one, then there is no canary, return empty string
+  [ "$canary_major_minor" != "$stable_major_minor" ] || return 0
+
+  # Otherwise, print the full version
+  printf "%s" "$canary_full_version"
+}
+
+# github::project::latest retrieves the latest tag from a github project
+github::project::latest(){
+  local project="$1"
+  local args
+
+  # Get latest
+  args=(curl -fsSL --proto '=https' --tlsv1.2 -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28")
+  [ "${GITHUB_TOKEN:-}" == "" ] && {
+    >&2 printf "GITHUB_TOKEN is not set - you might face rate limitations with the Github API\n"
+  } || args+=(-H "Authorization: Bearer $GITHUB_TOKEN")
+
+  "${args[@]}" https://api.github.com/repos/"$project"/tags | jq -rc .[0].name
+}
\ No newline at end of file
diff --git a/hack/provisioning/windows/cni.sh b/hack/provisioning/windows/cni.sh
index 8f6aae4323f..2c1b90ce40b 100755
--- a/hack/provisioning/windows/cni.sh
+++ b/hack/provisioning/windows/cni.sh
@@ -16,11 +16,9 @@
 
 # adapted from: https://raw.githubusercontent.com/containerd/containerd/refs/tags/v2.0.3/script/setup/install-cni-windows
 
-#shellcheck disable=SC2154
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 
-# FIXME: make this configurable
-WINCNI_VERSION=v0.3.1
+WINCNI_VERSION="${WINCNI_VERSION:-v0.3.1}"
 
 git config --global advice.detachedHead false
 
@@ -28,7 +26,7 @@ DESTDIR="${DESTDIR:-"C:\\Program Files\\containerd\\cni"}"
 WINCNI_BIN_DIR="${DESTDIR}/bin"
 WINCNI_PKG=github.com/Microsoft/windows-container-networking
 
-git clone --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
+git clone --quiet --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
 cd "${GOPATH}/src/${WINCNI_PKG}"
 make all
 install -D -m 755 "out/nat.exe" "${WINCNI_BIN_DIR}/nat.exe"
@@ -62,6 +60,7 @@ calculate_subnet() {
       mask=0
     fi
     (( len -= 8 ))
+    #shellcheck disable=SC2154
     result_array[i]=$(( gateway_array[i] & mask ))
   done
   result="$(printf ".%s" "${result_array[@]}")"
diff --git a/hack/configure-windows-ci.ps1 b/hack/provisioning/windows/containerd.ps1
similarity index 89%
rename from hack/configure-windows-ci.ps1
rename to hack/provisioning/windows/containerd.ps1
index c3505c269b4..56f4219008c 100644
--- a/hack/configure-windows-ci.ps1
+++ b/hack/provisioning/windows/containerd.ps1
@@ -1,5 +1,3 @@
-# To install CNI, see https://github.com/containerd/containerd/blob/release/1.7/script/setup/install-cni-windows
-
 $ErrorActionPreference = "Stop"
 
 #install containerd
diff --git a/hack/scripts/lib.sh b/hack/scripts/lib.sh
index c29b056ea70..8eb93ca527a 100755
--- a/hack/scripts/lib.sh
+++ b/hack/scripts/lib.sh
@@ -83,11 +83,18 @@ log::error(){
 
 # Helpers
 host::require(){
-  local binary="$1"
+  local binary
+
+  miss=
+  for binary in "$@"; do
+    log::debug "Checking presence of $binary"
+    command -v "$binary" >/dev/null || {
+      miss+="$binary"
+    }
+  done
 
-  log::debug "Checking presence of $binary"
-  command -v "$binary" >/dev/null || {
-    log::error "You need $binary for this script to work, and it cannot be found in your path"
+  [ "$miss" == "" ] || {
+    log::error "For this script to work, you need: $miss (could not find them in your path)"
     return 1
   }
 }
@@ -160,6 +167,23 @@ http::get(){
   _http::get "$url" "$output" "2" "1" "" "" "$@"
 }
 
+http::get::secure(){
+  local output="$1"
+  local url="$2"
+  local sha="$3"
+  shift
+  shift
+  shift
+
+  _http::get "$url" "$output" "2" "1" "" "" "$@"
+  shasum -a 256 -c <<<"$sha  $output" || {
+    ret=$?
+    log::error "Expected sha: $sha"
+    log::error "Actual sha: $(shasum -a 256 "$output")"
+    return $ret
+  }
+}
+
 http::healthcheck(){
   local url="$1"
   local retry="${2:-5}"
@@ -182,8 +206,6 @@ http::checksum(){
   local temp
   temp="$(fs::mktemp "http-checksum")"
 
-  host::require shasum
-
   for url in "${urls[@]}"; do
     http::get "$temp/${url##*/}" "$url"
   done
@@ -232,6 +254,4 @@ github::releases::latest(){
 }
 
 log::init
-host::require jq
-host::require tar
-host::require curl
+host::require jq tar curl shasum


Reviews:
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:04:55Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:05:39Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:06:08Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:06:16Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:06:36Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:07:05Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:07:11Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:08:46Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:09:04Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:09:10Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:09:17Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:59:04Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T00:59:12Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:07:14Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:07:52Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:08:59Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:09:29Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:09:51Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:10:19Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:10:48Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T15:47:46Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T15:48:52Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T15:52:51Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T15:53:39Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T15:54:41Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T16:03:31Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T16:03:35Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T16:38:18Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T17:09:20Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T18:06:40Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T18:06:58Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T18:19:48Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T23:52:42Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T23:54:41Z
user: login: AkihiroSuda
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-25T23:55:56Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T23:59:48Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T00:05:12Z
user: login: apostasie
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T00:05:39Z
user: login: AkihiroSuda
body: Thanks
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-26T01:38:54Z

Review comments:
diff_hunk: @@ -45,8 +45,8 @@ jobs:
         run: |
           # If canary is specified, get the latest available golang pre-release instead of the major version
           if [ "${{ matrix.canary }}" != "" ]; then
-            . ./hack/build-integration-canary.sh
-            canary::golang::latest
+            . ./hack/provisioning/version/fetcher.sh
+            printf "GO_VERSION=%s\n" "$(go::canary::for::go-setup)" >> "$GITHUB_ENV"
path: .github/workflows/lint.yml
user: login: apostasie
body: Taking out the github-actions "specifics" out of the helper script.
created_at: 2025-04-25T00:04:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -323,27 +323,3 @@ canary::golang::hublatest(){
 
   printf "%s" "$available_version"
 }
-
path: hack/build-integration-canary.sh
user: login: apostasie
body: No need for this in this big script.
Broken out into `./hack/provisioning/version`
created_at: 2025-04-25T00:05:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+# Provisioning
path: hack/provisioning/docs.md
user: login: apostasie
body: Not "documentation" per-se. Just a few words, in-context, to explain what this is.
created_at: 2025-04-25T00:06:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,12 +14,11 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-# shellcheck disable=SC2034,SC2015
path: hack/provisioning/kube/kind.sh
user: login: apostasie
body: Unnecessary.
created_at: 2025-04-25T00:06:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,19 +54,6 @@ install::kubectl(){
   host::install "$temp"/kubectl
 }
 
-install::cni(){
path: hack/provisioning/kube/kind.sh
user: login: apostasie
body: Useful on its own. Broken out in `./hack/provisioning/linux`
created_at: 2025-04-25T00:06:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::cni will retrieve a specific version of cni plugins and extract it in place on the host
path: hack/provisioning/linux/cni.sh
user: login: apostasie
body: Will be useful to manipulate version on the CI.
created_at: 2025-04-25T00:07:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: Will be useful to manipulate version on the CI.
created_at: 2025-04-25T00:07:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# go::canary::for::go-setup retrieves the latest unstable golang version and format it for use by
+# https://github.com/actions/setup-go
+# Note that if the latest unstable is an old RC for the current stable, we print the empty string.
+go::canary::for::go-setup(){
+  local all_versions
+  local stable_major_minor
+  local canary_major_minor
+  local canary_full_version
+
+  # Get all golang versions
+  all_versions="$(curl -fsSL --proto '=https' --tlsv1.2 "https://go.dev/dl/?mode=json&include=all")"
+
+  # Get the latest stable release major.minor for comparison
+  read -r stable_major_minor < \
+    <(sed -E 's/^go([0-9]+[.][0-9]+).*/\1/i' \
+      <(jq -rc 'map(select(.stable==true)).[0].version' <<<"$all_versions") \
+    )
+
+  # Get the latest unstable release major.minor, and full version (formatted for use by go-setup)
+  read -r canary_major_minor canary_full_version < \
+    <(sed -E 's/^go([0-9]+)[.]([0-9]+)(([a-z]+)([0-9]+))?/\1.\2 \1.\2.0-\4.\5/i' \
+      <(jq -rc 'map(select(.stable==false)).[0].version' <<<"$all_versions") \
+    )
+
+  # If the latest RC is for the same major.minor as the latest stable one, then there is no canary, return empty string
+  [ "$canary_major_minor" != "$stable_major_minor" ] || return 0
path: hack/provisioning/version/fetch.sh
user: login: apostasie
body: Script has been updated compared to prior version:
- it will now retrieve the _latest unstable golang release_, instead of _the latest golang release_
- if the latest unstable release is an old RC (eg: same major.minor as current stable), the script will return the empty string, allowing consumers to _not_ run useless canary targets
created_at: 2025-04-25T00:08:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -16,19 +16,17 @@
 
 # adapted from: https://raw.githubusercontent.com/containerd/containerd/refs/tags/v2.0.3/script/setup/install-cni-windows
 
-#shellcheck disable=SC2154
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 
-# FIXME: make this configurable
-WINCNI_VERSION=v0.3.1
+WINCNI_VERSION="${WINCNI_VERSION:-v0.3.1}"
path: hack/provisioning/windows/cni.sh
user: login: apostasie
body: Make it configurable from the consumer side.
created_at: 2025-04-25T00:09:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -16,19 +16,17 @@
 
 # adapted from: https://raw.githubusercontent.com/containerd/containerd/refs/tags/v2.0.3/script/setup/install-cni-windows
 
-#shellcheck disable=SC2154
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 
-# FIXME: make this configurable
-WINCNI_VERSION=v0.3.1
+WINCNI_VERSION="${WINCNI_VERSION:-v0.3.1}"
 
 git config --global advice.detachedHead false
 
 DESTDIR="${DESTDIR:-"C:\\Program Files\\containerd\\cni"}"
 WINCNI_BIN_DIR="${DESTDIR}/bin"
 WINCNI_PKG=github.com/Microsoft/windows-container-networking
 
-git clone --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
+git clone --quiet --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
path: hack/provisioning/windows/cni.sh
user: login: apostasie
body: Silence.
created_at: 2025-04-25T00:09:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,5 +1,3 @@
-# To install CNI, see https://github.com/containerd/containerd/blob/release/1.7/script/setup/install-cni-windows
path: hack/provisioning/windows/containerd.ps1
user: login: apostasie
body: No longer relevant.
created_at: 2025-04-25T00:09:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -82,7 +82,7 @@ jobs:
       - name: "Set up containerd"
         env:
           ctrdVersion: ${{ env.CONTAINERD_VERSION }}
-        run: powershell hack/configure-windows-ci.ps1
+        run: powershell hack/provisioning/windows/containerd.ps1
path: .github/workflows/test-canary.yml
user: login: apostasie
body: More logical name.
created_at: 2025-04-25T00:59:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,5 +23,5 @@ jobs:
       - name: "Run Kubernetes integration tests"
         # See https://github.com/containerd/nerdctl/blob/main/docs/testing/README.md#about-parallelization
         run: |
-          ./hack/build-integration-kubernetes.sh
+          ./hack/provisioning/kube/kind.sh
path: .github/workflows/test-kube.yml
user: login: apostasie
body: More logical name.
created_at: 2025-04-25T00:59:12Z
author_association: CONTRIBUTOR
path: hack/provisioning/docs.md
user: login: AkihiroSuda
body: Should be README.md
created_at: 2025-04-25T15:07:14Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,15 @@
+# Provisioning
path: hack/provisioning/docs.md
user: login: AkihiroSuda
body: ```suggestion
# Provisioning of the integration test dependencies
```
created_at: 2025-04-25T15:07:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::cni will retrieve a specific version of cni plugins and extract it in place on the host
+provision::cni(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o cni.tgz -fsSL --proto '=https' --tlsv1.2 https://github.com/containernetworking/plugins/releases/download/"$version"/cni-plugins-linux-"$arch"-"$version".tgz
path: hack/provisioning/linux/cni.sh
user: login: AkihiroSuda
body: Binary sha256sums or git hash has to be verified.

Same for other deps too 
created_at: 2025-04-25T15:08:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: Ditto.
Hash has to be verified
created_at: 2025-04-25T15:09:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: /usr/local for non-dpkg deps
created_at: 2025-04-25T15:09:50Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
+  sudo systemctl restart containerd
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: Where is the systemd unit installed?
created_at: 2025-04-25T15:10:18Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: Probably sudo should be specified in the caller of this script, not here
created_at: 2025-04-25T15:10:45Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: This is meant to override github preinstalled containerd, which is in /usr/bin
created_at: 2025-04-25T15:47:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
+  sudo systemctl restart containerd
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: See note above.
This is meant to override the github action pre installed containerd which already has a unit in place.
created_at: 2025-04-25T15:48:52Z
author_association: CONTRIBUTOR
path: hack/provisioning/docs.md
user: login: apostasie
body: Done with next push.
created_at: 2025-04-25T15:52:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: Preinstalled one should be removed with apt-get remove
created_at: 2025-04-25T15:53:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::cni will retrieve a specific version of cni plugins and extract it in place on the host
+provision::cni(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o cni.tgz -fsSL --proto '=https' --tlsv1.2 https://github.com/containernetworking/plugins/releases/download/"$version"/cni-plugins-linux-"$arch"-"$version".tgz
path: hack/provisioning/linux/cni.sh
user: login: apostasie
body: Agreed. This applies generally in the (many) places we install things.
Suggesting to do a pass on them all in a subsequent PR. 
created_at: 2025-04-25T15:54:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::cni will retrieve a specific version of cni plugins and extract it in place on the host
+provision::cni(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o cni.tgz -fsSL --proto '=https' --tlsv1.2 https://github.com/containernetworking/plugins/releases/download/"$version"/cni-plugins-linux-"$arch"-"$version".tgz
path: hack/provisioning/linux/cni.sh
user: login: apostasie
body: Tracking in #4163
created_at: 2025-04-25T16:03:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: Tracking in #4163
created_at: 2025-04-25T16:03:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: Fair enough.
This requires more work to setup from scratch - hang on for a minute.
created_at: 2025-04-25T16:38:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: re: `sudo`

I would prefer to not use `sudo` when not necessary (eg: calling `curl`, or `shasum`), and only where it matters.
Fine with you?
created_at: 2025-04-25T17:09:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -92,16 +82,20 @@ main(){
   configure::rootful "${ROOTFUL:-}"
 
   log::info "Installing host dependencies if necessary"
+  host::require make go
   host::require kind 2>/dev/null || install::kind "$KIND_VERSION"
   host::require kubectl 2>/dev/null || install::kubectl
 
   # Build nerdctl to use for kind
-  make binaries
+  make -f "$root/../../../Makefile" binaries
path: hack/provisioning/kube/kind.sh
user: login: apostasie
body: Allow to work out of tree.
created_at: 2025-04-25T18:06:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -113,7 +107,7 @@ main(){
   log::info "Creating new cluster"
   export KIND_EXPERIMENTAL_PROVIDER=nerdctl
   exec::kind delete cluster --name nerdctl-test 2>/dev/null || true
-  exec::kind create cluster --name nerdctl-test --config=./hack/kind.yaml
+  exec::kind create cluster --name nerdctl-test --config="$root"/kind.yaml
path: hack/provisioning/kube/kind.sh
user: login: apostasie
body: Allow to work out of tree.
created_at: 2025-04-25T18:06:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,11 +83,18 @@ log::error(){
 
 # Helpers
 host::require(){
-  local binary="$1"
+  local binary
+
+  miss=
+  for binary in "$@"; do
path: hack/scripts/lib.sh
user: login: apostasie
body: Small quality of life change to allow reporting _all_ missing binaries at once instead of stopping at the first missing one. 
created_at: 2025-04-25T18:11:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+
+# provision::containerd::rootful will retrieve a specific version of containerd and extract it in place on the host
+# then restart with systemctl (assumes that there was a previously installed version).
+provision::containerd::rootful(){
+  local version="$1"
+  local arch="$2"
+
+  cd /tmp
+  curl -o containerd.tar.gz -fsSL --proto '=https' --tlsv1.2 https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz
+  sudo tar -C /usr/bin -xzf containerd.tar.gz
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: Ok. Updated.
created_at: 2025-04-25T18:14:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
+readonly root
+# shellcheck source=/dev/null
+. "$root/../../scripts/lib.sh"
+
+# provision::containerd::uninstall will ensure deb containerd are purged
+provision::containerd::uninstall(){
+  [ "$(id -u)" == 0 ] || {
+    log::error "You need to be root"
+    return 1
+  }
+
+  # Purge deb package
+  apt-get -q purge containerd 2>/dev/null || true
path: hack/provisioning/linux/containerd.sh
user: login: AkihiroSuda
body: ```suggestion
  apt-get -q purge containerd* 2>/dev/null || true
```
Pkg can be containerd.io
created_at: 2025-04-25T23:52:42Z
author_association: MEMBER
diff_hunk: @@ -16,19 +16,17 @@
 
 # adapted from: https://raw.githubusercontent.com/containerd/containerd/refs/tags/v2.0.3/script/setup/install-cni-windows
 
-#shellcheck disable=SC2154
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 
-# FIXME: make this configurable
-WINCNI_VERSION=v0.3.1
+WINCNI_VERSION="${WINCNI_VERSION:-v0.3.1}"
 
 git config --global advice.detachedHead false
 
 DESTDIR="${DESTDIR:-"C:\\Program Files\\containerd\\cni"}"
 WINCNI_BIN_DIR="${DESTDIR}/bin"
 WINCNI_PKG=github.com/Microsoft/windows-container-networking
 
-git clone --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
+git clone --quiet --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
path: hack/provisioning/windows/cni.sh
user: login: AkihiroSuda
body: Hash is not verified
created_at: 2025-04-25T23:54:41Z
author_association: MEMBER
diff_hunk: @@ -14,16 +14,19 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-# shellcheck disable=SC2034,SC2015
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
 readonly root
 # shellcheck source=/dev/null
-. "$root/scripts/lib.sh"
+. "$root/../../scripts/lib.sh"
 
 GO_VERSION=1.24
 KIND_VERSION=v0.27.0
-CNI_PLUGINS_VERSION=v1.6.2
+CNI_PLUGINS_VERSION=v1.7.1
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_AMD64=1a28a0506bfe5bcdc981caf1a49eeab7e72da8321f1119b7be85f22621013098
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_ARM64=119fcb508d1ac2149e49a550752f9cd64d023a1d70e189b59c476e4d2bf7c497
path: hack/provisioning/kube/kind.sh
user: login: AkihiroSuda
body: The existing SHA256SUMS.d can be used
created_at: 2025-04-25T23:55:56Z
author_association: MEMBER
diff_hunk: @@ -16,19 +16,17 @@
 
 # adapted from: https://raw.githubusercontent.com/containerd/containerd/refs/tags/v2.0.3/script/setup/install-cni-windows
 
-#shellcheck disable=SC2154
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 
-# FIXME: make this configurable
-WINCNI_VERSION=v0.3.1
+WINCNI_VERSION="${WINCNI_VERSION:-v0.3.1}"
 
 git config --global advice.detachedHead false
 
 DESTDIR="${DESTDIR:-"C:\\Program Files\\containerd\\cni"}"
 WINCNI_BIN_DIR="${DESTDIR}/bin"
 WINCNI_PKG=github.com/Microsoft/windows-container-networking
 
-git clone --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
+git clone --quiet --depth 1 --branch "${WINCNI_VERSION}" "https://${WINCNI_PKG}.git" "${GOPATH}/src/${WINCNI_PKG}"
path: hack/provisioning/windows/cni.sh
user: login: apostasie
body: Existing code.
Tracked in #4163 alongside all the rest.


created_at: 2025-04-25T23:59:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,16 +14,19 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-# shellcheck disable=SC2034,SC2015
 set -o errexit -o errtrace -o functrace -o nounset -o pipefail
 root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
 readonly root
 # shellcheck source=/dev/null
-. "$root/scripts/lib.sh"
+. "$root/../../scripts/lib.sh"
 
 GO_VERSION=1.24
 KIND_VERSION=v0.27.0
-CNI_PLUGINS_VERSION=v1.6.2
+CNI_PLUGINS_VERSION=v1.7.1
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_AMD64=1a28a0506bfe5bcdc981caf1a49eeab7e72da8321f1119b7be85f22621013098
+# shellcheck disable=SC2034
+CNI_PLUGINS_SHA_ARM64=119fcb508d1ac2149e49a550752f9cd64d023a1d70e189b59c476e4d2bf7c497
path: hack/provisioning/kube/kind.sh
user: login: apostasie
body: Right, but then the versions themselves are scattered (in Dockerfile, here) and the usage is wildly different.
I would rather keep some level of duplication for now, rather than create dependencies between unrelated systems (Dockerfile vs. Kubernetes provisioner) - tying this together will undoubtedly bite the next person who is going to try update CNI in the dockerfile.

To be cleaned-up later, with an actually centralized location listing all resources and that can be used by testing, provisioning, CI, and Dockerfile (probably a lot of work and a fair amount of discussions).
created_at: 2025-04-26T00:05:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+
+#   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.
+
+set -o errexit -o errtrace -o functrace -o nounset -o pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
+readonly root
+# shellcheck source=/dev/null
+. "$root/../../scripts/lib.sh"
+
+# provision::containerd::uninstall will ensure deb containerd are purged
+provision::containerd::uninstall(){
+  [ "$(id -u)" == 0 ] || {
+    log::error "You need to be root"
+    return 1
+  }
+
+  # Purge deb package
+  apt-get -q purge containerd 2>/dev/null || true
path: hack/provisioning/linux/containerd.sh
user: login: apostasie
body: Ok.
created_at: 2025-04-26T00:05:39Z
author_association: CONTRIBUTOR

PR comments:
user: login: apostasie
created_at: 2025-04-25T00:25:56Z
body: Failure is #3556 
author_association: CONTRIBUTOR
user: login: apostasie
created_at: 2025-04-25T00:42:44Z
body: Failure 2 is #4143 
author_association: CONTRIBUTOR
user: login: apostasie
created_at: 2025-04-25T18:16:14Z
body: @AkihiroSuda amended with your requested changes.
Only thing I did not address is the `sudo` question (see comment). LMK your thoughts on it though.
author_association: CONTRIBUTOR