From 2a8ef4eaebf07013e3e9f8cf70176231b60661c9 Mon Sep 17 00:00:00 2001 From: Ayoub Mrini Date: Thu, 4 Jun 2026 14:14:18 +0200 Subject: [PATCH 1/3] chore: Add kubectl plugin support with krew distribution --- .github/workflows/ci.yml | 9 +++++ .github/workflows/release.yml | 68 +++++++++++++++++++++++++++++++++-- .krew.yaml | 48 +++++++++++++++++++++++++ Makefile | 8 +++-- README.md | 8 +++++ e2e/krew-test-manifest.yaml | 18 ++++++++++ e2e/tests/krew.sh | 52 +++++++++++++++++++++++++++ 7 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 .krew.yaml create mode 100644 e2e/krew-test-manifest.yaml create mode 100644 e2e/tests/krew.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9736f00..d60c9f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,11 +39,20 @@ jobs: cache: true - name: Install FUSE run: sudo apt-get update && sudo apt-get install -y fuse3 + - name: Install krew + run: | + cd "$(mktemp -d)" + curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_amd64.tar.gz" + tar zxf krew-linux_amd64.tar.gz + ./krew-linux_amd64 install krew + echo "${HOME}/.krew/bin" >> "$GITHUB_PATH" - uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0, kind v0.31.0, kubectl v1.35.0 with: cluster_name: vifal-test node_image: kindest/node:v1.35.0@sha256:452d707d4862f52530247495d180205e029056831160e22870e37e3f6c1ac31f - run: make e2e-test-shell + env: + VIFAL_E2E_KREW: "1" # With race detector and no attr caching. - run: FUSE_TIMEOUT=5 make e2e-test-shell-nocache env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d17a582..057db85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,8 +7,58 @@ on: permissions: {} jobs: - release: + create-release: runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Create draft release + env: + GH_TOKEN: ${{ github.token }} + run: gh release create "${GITHUB_REF_NAME}" --draft --generate-notes + + build: + runs-on: ubuntu-24.04 + needs: create-release + permissions: + contents: write + strategy: + matrix: + include: + - goos: linux + goarch: amd64 + - goos: linux + goarch: arm64 + - goos: darwin + goarch: amd64 + - goos: darwin + goarch: arm64 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: go.mod + + - name: Build and package + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: "0" + run: make release-archive VERSION="${GITHUB_REF_NAME}" GOOS="${GOOS}" GOARCH="${GOARCH}" + + - name: Upload asset + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload "${GITHUB_REF_NAME}" "kubectl-vifal_${GITHUB_REF_NAME}_${{ matrix.goos }}_${{ matrix.goarch }}.tar.gz" + + publish: + runs-on: ubuntu-24.04 + needs: build permissions: contents: write steps: @@ -24,7 +74,19 @@ jobs: GOPROXY: proxy.golang.org run: go list -m "github.com/machine424/vifal@${GITHUB_REF_NAME}" - - name: Create GitHub release + - name: Publish release env: GH_TOKEN: ${{ github.token }} - run: gh release create "${GITHUB_REF_NAME}" + run: gh release edit "${GITHUB_REF_NAME}" --draft=false + + update-krew-index: + runs-on: ubuntu-24.04 + needs: publish + permissions: + contents: read + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Update krew-index + uses: rajatjindal/krew-release-bot@c970b8a8f6dbc2f2285a26e3ae160903b87002c3 # v0.0.51 diff --git a/.krew.yaml b/.krew.yaml new file mode 100644 index 0000000..bfa7696 --- /dev/null +++ b/.krew.yaml @@ -0,0 +1,48 @@ +apiVersion: krew.googlecontainertools.github.com/v1alpha2 +kind: Plugin +metadata: + name: vifal +spec: + version: {{ .TagName }} + homepage: https://github.com/machine424/vifal + platforms: + - selector: + matchLabels: + os: linux + arch: amd64 + {{addURIAndSha "https://github.com/machine424/vifal/releases/download/{{ .TagName }}/kubectl-vifal_{{ .TagName }}_linux_amd64.tar.gz" .TagName }} + bin: kubectl-vifal + - selector: + matchLabels: + os: linux + arch: arm64 + {{addURIAndSha "https://github.com/machine424/vifal/releases/download/{{ .TagName }}/kubectl-vifal_{{ .TagName }}_linux_arm64.tar.gz" .TagName }} + bin: kubectl-vifal + - selector: + matchLabels: + os: darwin + arch: amd64 + {{addURIAndSha "https://github.com/machine424/vifal/releases/download/{{ .TagName }}/kubectl-vifal_{{ .TagName }}_darwin_amd64.tar.gz" .TagName }} + bin: kubectl-vifal + - selector: + matchLabels: + os: darwin + arch: arm64 + {{addURIAndSha "https://github.com/machine424/vifal/releases/download/{{ .TagName }}/kubectl-vifal_{{ .TagName }}_darwin_arm64.tar.gz" .TagName }} + bin: kubectl-vifal + shortDescription: exposing and unifying Kubernetes container filesystems locally + description: | + FUSE mount that exposes and unifies Kubernetes container filesystems locally. + Browse namespaces, pods, and containers as directories, read files, and diff + configs across pods using standard shell tools. + caveats: | + Requires FUSE: + - Linux: install fuse3 + - macOS: install macFUSE (https://github.com/macfuse/macfuse) + + Containers must have sh, stat, find, and dd available. + + Usage: + kubectl vifal /mnt/my-cluster + ls /mnt/my-cluster//// + kubectl vifal unmount /mnt/my-cluster diff --git a/Makefile b/Makefile index 34bb53f..b588ce2 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -BINARY = vifal +BINARY ?= vifal GOLANGCI_LINT_VERSION = v2.12.1 GO_LICENSES_VERSION = v2.0.1 GO_BUILD_FLAGS ?= GO_LDFLAGS ?= -s -w TIMEOUT_CMD = timeout --foreground -.PHONY: build build-debug build-race clean test unit-test e2e-test e2e-test-go e2e-test-shell e2e-test-shell-debug e2e-test-shell-nocache lint shellcheck licenses-check +.PHONY: build build-debug build-race release-archive clean test unit-test e2e-test e2e-test-go e2e-test-shell e2e-test-shell-debug e2e-test-shell-nocache lint shellcheck licenses-check build: go build $(GO_BUILD_FLAGS) -ldflags="$(GO_LDFLAGS)" -o $(BINARY) . @@ -15,6 +15,10 @@ build-debug: build-race: $(MAKE) --no-print-directory build GO_BUILD_FLAGS=-race GO_LDFLAGS= +release-archive: + $(MAKE) --no-print-directory build BINARY=kubectl-vifal + tar czf "kubectl-vifal_$(VERSION)_$(GOOS)_$(GOARCH).tar.gz" kubectl-vifal LICENSE LICENSES/ + test: unit-test e2e-test unit-test: diff --git a/README.md b/README.md index 7f94901..bff1289 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,14 @@ Works on Linux and macOS. - Linux: install `fuse3`. - macOS: install [macFUSE](https://github.com/macfuse/macfuse/wiki/Getting-Started). The mount appears as a network volume, so your terminal may need [access to network volumes](https://github.com/macfuse/macfuse/issues/690#issuecomment-1527424231). +Via [Krew](https://krew.sigs.k8s.io/) (kubectl plugin manager): + +```bash +$ kubectl krew install vifal +``` + +Via `go install`: + ```bash $ go install github.com/machine424/vifal@latest ``` diff --git a/e2e/krew-test-manifest.yaml b/e2e/krew-test-manifest.yaml new file mode 100644 index 0000000..8dd178f --- /dev/null +++ b/e2e/krew-test-manifest.yaml @@ -0,0 +1,18 @@ +# Static manifest for testing krew install locally (with --archive). +# krew ignores uri/sha256 when --archive is provided. +apiVersion: krew.googlecontainertools.github.com/v1alpha2 +kind: Plugin +metadata: + name: vifal +spec: + version: v0.0.0-ci + platforms: + - selector: + matchLabels: + os: linux + arch: amd64 + uri: https://example.com/placeholder.tar.gz + sha256: "0000000000000000000000000000000000000000000000000000000000000000" + bin: kubectl-vifal + shortDescription: test + description: test diff --git a/e2e/tests/krew.sh b/e2e/tests/krew.sh new file mode 100644 index 0000000..93a3a07 --- /dev/null +++ b/e2e/tests/krew.sh @@ -0,0 +1,52 @@ +# Test vifal as a kubectl plugin installed via krew: install, mount, read, unmount, uninstall. +# Skipped unless VIFAL_E2E_KREW=1 (set in CI after installing krew). + +if [ "${VIFAL_E2E_KREW:-}" != "1" ]; then + log_step "SKIP: VIFAL_E2E_KREW not set" + return 0 +fi + +NAMESPACE="vifal-krew" +TEST_DIR=$(mktemp -d /tmp/vifal-krew-XXXXXX) +MOUNT="$TEST_DIR/mount" +LOGS="$TEST_DIR" + +setup() { + kubectl delete namespace "$NAMESPACE" --ignore-not-found + mkdir -p "$MOUNT" + kubectl create namespace "$NAMESPACE" + kubectl run nginx --image="$IMAGE" -n "$NAMESPACE" --overrides="$FAST_TERM" --command -- sleep infinity + kubectl wait --for=condition=Ready pod/nginx -n "$NAMESPACE" --timeout="${KUBECTL_TIMEOUT}s" +} + +teardown() { + dump_vifal_logs "$?" + kubectl vifal unmount "$MOUNT" 2>/dev/null || true + kubectl krew uninstall vifal 2>/dev/null || true + rm -rf "$TEST_DIR" + kubectl delete namespace "$NAMESPACE" --ignore-not-found --wait=false +} + +trap teardown EXIT +setup + +log_step "build and install via krew" +make -s release-archive VERSION=v0.0.0-ci GOOS=linux GOARCH=amd64 +kubectl krew install --manifest="$DIR/krew-test-manifest.yaml" --archive=kubectl-vifal_v0.0.0-ci_linux_amd64.tar.gz +rm -f kubectl-vifal_v0.0.0-ci_linux_amd64.tar.gz kubectl-vifal + +log_step "mount" +kubectl vifal --fsname "$VIFAL_SHELL_TEST" --attr-ttl "$CACHE_TTL" "$MOUNT" 2>"$LOGS/vifal.log" & +VIFAL_PID=$! +wait_for_fuse_sync "$MOUNT/$NAMESPACE/nginx/nginx" + +log_step "read file" +diff <(fuse cat "$MOUNT/$NAMESPACE/nginx/nginx/etc/hostname") <(kubectl exec nginx -n "$NAMESPACE" -c nginx -- cat /etc/hostname) + +log_step "unmount" +kubectl vifal unmount "$MOUNT" +wait_process_dead "$VIFAL_PID" +check_clean_unmount "$MOUNT" + +log_step "krew uninstall" +kubectl krew uninstall vifal From 7ae4fe23d59f714352377e129cd7a023c8a64848 Mon Sep 17 00:00:00 2001 From: Ayoub Mrini Date: Thu, 4 Jun 2026 15:40:10 +0200 Subject: [PATCH 2/3] fix --- e2e/tests/krew.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/e2e/tests/krew.sh b/e2e/tests/krew.sh index 93a3a07..31b327e 100644 --- a/e2e/tests/krew.sh +++ b/e2e/tests/krew.sh @@ -31,9 +31,13 @@ trap teardown EXIT setup log_step "build and install via krew" +MANIFEST="$TEST_DIR/manifest.yaml" +ARCHIVE="kubectl-vifal_v0.0.0-ci_linux_amd64.tar.gz" make -s release-archive VERSION=v0.0.0-ci GOOS=linux GOARCH=amd64 -kubectl krew install --manifest="$DIR/krew-test-manifest.yaml" --archive=kubectl-vifal_v0.0.0-ci_linux_amd64.tar.gz -rm -f kubectl-vifal_v0.0.0-ci_linux_amd64.tar.gz kubectl-vifal +# krew validates sha256 even with --archive, patch the placeholder in the manifest. +sed "s/SHA256SUM/$(sha256sum "$ARCHIVE" | awk '{print $1}')/" "$DIR/krew-test-manifest.yaml" > "$MANIFEST" +kubectl krew install --manifest="$MANIFEST" --archive="$ARCHIVE" +rm -f "$ARCHIVE" kubectl-vifal log_step "mount" kubectl vifal --fsname "$VIFAL_SHELL_TEST" --attr-ttl "$CACHE_TTL" "$MOUNT" 2>"$LOGS/vifal.log" & From df51f0ee3713200f5b5691f9c3bb0edac23710bc Mon Sep 17 00:00:00 2001 From: Ayoub Mrini Date: Thu, 4 Jun 2026 18:07:19 +0200 Subject: [PATCH 3/3] test --- .gitignore | 2 ++ e2e/krew-test-manifest.yaml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d898006..4fb3bab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ # Build output vifal +kubectl-vifal +kubectl-vifal_*.tar.gz # macOS .DS_Store diff --git a/e2e/krew-test-manifest.yaml b/e2e/krew-test-manifest.yaml index 8dd178f..9c93600 100644 --- a/e2e/krew-test-manifest.yaml +++ b/e2e/krew-test-manifest.yaml @@ -1,5 +1,5 @@ # Static manifest for testing krew install locally (with --archive). -# krew ignores uri/sha256 when --archive is provided. +# The test script replaces SHA256SUM with the real checksum at runtime. apiVersion: krew.googlecontainertools.github.com/v1alpha2 kind: Plugin metadata: @@ -12,7 +12,7 @@ spec: os: linux arch: amd64 uri: https://example.com/placeholder.tar.gz - sha256: "0000000000000000000000000000000000000000000000000000000000000000" + sha256: SHA256SUM bin: kubectl-vifal shortDescription: test description: test