diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..537b455 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,91 @@ +# Copyright 2026 The Fluid 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. + +name: "Fluid CLI — bug report" +description: Report incorrect behavior, crashes, or confusing output from `fluid`. +title: "[bug] " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + **fluid-cli** talks to Kubernetes clusters that run [Fluid](https://github.com/fluid-cloudnative/fluid). The fastest fixes include a tight repro, exact versions, and (redacted) command output. + + - type: textarea + id: summary + attributes: + label: What went wrong? + description: In one short paragraph, what did you expect vs what happened? + validations: + required: true + + - type: textarea + id: repro + attributes: + label: Reproduction steps + description: Commands you ran, in order. Use placeholder names if needed. + placeholder: | + fluid version + kubectl config current-context + fluid inspect dataset my-dataset -n fluid-system + validations: + required: true + + - type: textarea + id: output + attributes: + label: Output / logs + description: Paste stderr/stdout. Remove secrets, tokens, and internal hostnames if needed. + render: shell + validations: + required: false + + - type: textarea + id: cluster + attributes: + label: Cluster + Fluid context + description: Kubernetes version, cloud/on-prem, CNI if relevant, Fluid version, and whether this is a dev/test cluster. + placeholder: | + Kubernetes: v1.30.x + Fluid: v1.0.x + Install method: Helm / manifest / other + validations: + required: true + + - type: dropdown + id: entrypoint + attributes: + label: How are you invoking the tool? + options: + - fluid + - Not sure + validations: + required: true + + - type: input + id: cli-version + attributes: + label: fluid-cli version + description: Output of `fluid version` (or your best guess if the command won't run). + placeholder: e.g. v0.2.0 / dev@ + validations: + required: true + + - type: checkboxes + id: checks + attributes: + label: Confirmations + options: + - label: I searched existing issues for duplicates. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..c4737d5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,15 @@ +# Copyright 2026 The Fluid 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. + +blank_issues_enabled: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..9d0b6a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,72 @@ +# Copyright 2026 The Fluid 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. + +name: "Fluid CLI — feature / UX idea" +description: Suggest a new command, flag, output format, or workflow improvement for operating Fluid from the terminal. +title: "[idea] " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Good CLI features are **discoverable**, **predictable**, and safe on real clusters. A concrete example command or snippet helps a lot. + + - type: textarea + id: problem + attributes: + label: Problem or gap + description: What are you trying to accomplish with Fluid on a cluster, and what's missing from the CLI today? + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposed behavior + description: Example invocations, flags, default output, and how errors should read. + placeholder: | + fluid datasets list -A --sort=age + # prints: namespace, name, phase, dataset ref, last transition + validations: + required: true + + - type: dropdown + id: scope + attributes: + label: Primary surface + options: + - New subcommand + - Extend an existing subcommand + - TUI / interactive flow + - Output / formatting only + - Docs / help text + - Other + validations: + required: true + + - type: textarea + id: compatibility + attributes: + label: Compatibility notes + description: Should this be backward compatible? Any kubectl version constraints or breaking changes you're OK with? + validations: + required: false + + - type: checkboxes + id: checks + attributes: + label: Confirmations + options: + - label: I’m proposing this for fluid-cli (not Fluid controller behavior unless the CLI must surface it). + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..2a9ed4d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +# Copyright 2026 The Fluid 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. + +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..f66fc03 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,38 @@ +## Summary + + +## Motivation / context + +Why is this needed? Link an issue if one exists: Fixes # + +## Type of change + +- [ ] Bug fix (user-visible misbehavior or broken command) +- [ ] Feature / UX improvement +- [ ] Refactor (no intended user-visible change) +- [ ] Tests only +- [ ] Docs / comments / metadata + +## Risk & rollout + +- **User impact:** (none / low / medium) — brief note +- **Backward compatibility:** (yes / no — explain if no) + +## Verification + +What did you run locally? + +- [ ] `go test ./...` +- [ ] `go vet ./...` +- [ ] `gofmt` clean +- [ ] Exercised the command path manually (describe below) + +**Manual check (optional):** + +```text +(paste commands + short output) +``` + +## Screenshots / TUI + +If this affects Bubble Tea / tables / spinners, attach a short recording or screenshot when possible. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..08b6b28 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,77 @@ +# Copyright 2026 The Fluid 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. + +# CI uses only the Go toolchain and GitHub-hosted runners (no Dagger or other build DAG). + +name: CI + +on: + push: + branches: [main] + pull_request: + paths-ignore: + - "*.md" + - "assets/**" + - "docs/**" + workflow_dispatch: + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify module checksums + run: go mod verify + + - name: Verify gofmt + run: | + set -euo pipefail + out="$(find . -name '*.go' -not -path './vendor/*' -print0 | xargs -0 -r gofmt -l)" + if [ -n "${out}" ]; then + echo "${out}" + exit 1 + fi + + - name: Vet + run: go vet ./... + + - name: Test (race) + run: go test ./... -count=1 -race -timeout=5m + + - name: Build + env: + CGO_ENABLED: "0" + run: | + go build -trimpath -ldflags '-s -w' -o /dev/null ./cmd/fluid + + - name: Verify generated docs + run: | + make docs + git diff --exit-code docs/reference/ diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..1e511b9 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,136 @@ +# Copyright 2026 The Fluid 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. + +# Publishes tarball artifacts to a GitHub Release when a semver tag is pushed, +# or when this workflow is run manually against an existing tag. +# Builds use plain `go build` — no container DAG / Dagger. + +name: Release + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + tag: + description: "Existing git tag to build and publish (e.g. v1.0.0)" + required: true + type: string + +concurrency: + group: release-${{ github.workflow }}-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} + cancel-in-progress: false + +permissions: + contents: write + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Vet + run: go vet ./... + + - name: Test (race) + run: go test ./... -count=1 -race -timeout=5m + + release: + needs: test + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Resolve release tag + id: meta + shell: bash + run: | + set -euo pipefail + if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then + TAG="${{ inputs.tag }}" + else + TAG="${GITHUB_REF_NAME}" + fi + TAG="${TAG#refs/tags/}" + if [[ ! "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error ::Tag must look like vMAJOR.MINOR.PATCH (got: ${TAG})" + exit 1 + fi + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "Releasing ${TAG}" + + - name: Build release archives + env: + TAG: ${{ steps.meta.outputs.tag }} + shell: bash + run: | + set -euo pipefail + COMMIT="$(git rev-parse --short HEAD)" + DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + # Match Makefile versioning; use reproducible-ish builds on the runner. + LDFLAGS="-s -w \ + -X github.com/fluid-cloudnative/fluid-cli/cmd/fluid/internal/version.Version=${TAG} \ + -X github.com/fluid-cloudnative/fluid-cli/cmd/fluid/internal/version.GitCommit=${COMMIT} \ + -X github.com/fluid-cloudnative/fluid-cli/cmd/fluid/internal/version.BuildDate=${DATE}" + + mkdir -p artifacts tmp + for os in linux darwin; do + for arch in amd64 arm64; do + dir="tmp/fluid_${TAG}_${os}_${arch}" + mkdir -p "$dir" + CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \ + go build -trimpath -buildid= -ldflags="${LDFLAGS}" -o "$dir/fluid" ./cmd/fluid + tar -czf "artifacts/fluid_${TAG}_${os}_${arch}.tar.gz" -C "$dir" fluid + done + done + rm -rf tmp + ( cd artifacts && sha256sum fluid_*.tar.gz > checksums.txt ) + + - name: Publish GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.meta.outputs.tag }} + name: Fluid CLI ${{ steps.meta.outputs.tag }} + files: | + artifacts/*.tar.gz + artifacts/checksums.txt + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9ea0aa3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,73 @@ +# Contributing to fluid-cli + +Thank you for contributing. This project is a Go CLI built with [Cobra](https://github.com/spf13/cobra). + +## Prerequisites + +- Go version from [go.mod](go.mod) +- Access to a Kubernetes cluster with Fluid installed (for manual testing) +- `kubectl` configured for that cluster + +## Build and test + +```bash +make build # produces bin/fluid +make test # unit tests (race detector in CI) +make fmt vet # format and static analysis +make install-plugin # install fluid onto PATH +``` + +Run a single package: + +```bash +go test ./pkg/inspect/... -v -count=1 +``` + +## Documentation + +### In-terminal help (source of truth) + +Command text lives in `cmd/fluid/root/`: + +- `Short`, `Long`, and `Example` on each `cobra.Command` +- Flag descriptions on `cmd.Flags()` + +Users rely on `fluid --help`; keep examples copy-pasteable. + +### Repository docs + +| Path | Purpose | +|------|---------| +| [README.md](README.md) | Quickstart and links | +| [docs/](docs/) | Guides (hand-written) | +| [docs/reference/](docs/reference/) | Auto-generated; do not edit by hand | + +After changing commands or flags: + +```bash +make docs +git add docs/reference/ +``` + +CI runs `make docs` and fails if `docs/reference/` is out of date. + +### End-to-end testing + +See [test/e2e/test.md](test/e2e/test.md) for manual e2e scenarios (when documented). + +## Pull requests + +- Use the PR template checklist +- Run `make test` and `make docs` before pushing +- One logical change per PR when possible +- Link related Fluid or fluid-cli issues + +## Code style + +- Match existing copyright headers and package layout +- `go fmt` on all touched Go files +- Prefer extending existing packages over new abstractions + +## License + +By contributing, you agree that your contributions are licensed under the Apache License 2.0. diff --git a/Makefile b/Makefile index f84810b..5e3439e 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ GO ?= go GOOS ?= $(shell $(GO) env GOOS) GOARCH ?= $(shell $(GO) env GOARCH) -.PHONY: all build fmt vet test install-plugin uninstall-plugin clean help +.PHONY: all build fmt vet test docs install-plugin uninstall-plugin clean help all: build @@ -78,7 +78,11 @@ vet: test: $(GO) test ./... -v -count=1 -## install-plugin: Install the binary into the same directory as kubectl (as kubectl-fluid). +## docs: Regenerate docs/reference/ from the Cobra command tree. +docs: + $(GO) run ./hack/gen-docs + +## install-plugin: Install the fluid binary onto PATH. install-plugin: build @KUBECTL_DIR=$$(dirname $$(which kubectl 2>/dev/null) 2>/dev/null); \ if [ -z "$$KUBECTL_DIR" ]; then \ @@ -89,7 +93,7 @@ install-plugin: build echo "Installed $$KUBECTL_DIR/$(BINARY)"; \ echo "Run: fluid --help" -## uninstall-plugin: Remove the installed plugin binary. +## uninstall-plugin: Remove the installed fluid binary. uninstall-plugin: @KUBECTL_DIR=$$(dirname $$(which kubectl 2>/dev/null) 2>/dev/null); \ if [ -z "$$KUBECTL_DIR" ]; then KUBECTL_DIR=/usr/local/bin; fi; \ diff --git a/README.md b/README.md index e20ed41..cff85e6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,54 @@ # fluid-cli -Official Fluid CLI + +Official CLI for [Fluid](https://github.com/fluid-cloudnative/fluid) — inspect and diagnose Fluid-managed Datasets and their Kubernetes resources. + +Install the `fluid` binary on your `PATH`. + +## Quick start + +```bash +git clone https://github.com/fluid-cloudnative/fluid-cli.git +cd fluid-cli +make install-plugin + +fluid --help +fluid inspect my-dataset -n default +fluid diagnose my-dataset -n default --archive +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `fluid inspect` | List Pods, Runtimes, PVCs, and related resources for a Dataset | +| `fluid diagnose` | Collect a support bundle (YAML, logs, events) for a Dataset | +| `fluid version` | Print CLI version | + +For flags and examples, use `--help` on any command: + +```bash +fluid inspect --help +fluid diagnose --help +``` + +## Documentation + +- [Install](docs/install.md) +- [Inspect guide](docs/guides/inspect.md) +- [Diagnose guide](docs/guides/diagnose.md) +- [Troubleshooting](docs/troubleshooting.md) +- [Command reference](docs/reference/) (auto-generated from Cobra; run `make docs` to refresh) + +## Development + +See [CONTRIBUTING.md](CONTRIBUTING.md). + +```bash +make build # build bin/fluid +make test # unit tests +make docs # regenerate docs/reference/ +``` + +## License + +Apache License 2.0 — see [LICENSE](LICENSE). diff --git a/doc/README.md b/doc/README.md deleted file mode 100644 index f80468f..0000000 --- a/doc/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# fluid CLI - -`fluid` is a kubectl plugin for the [Fluid](https://github.com/fluid-cloudnative/fluid) project. -It provides commands to inspect and diagnose Fluid-managed Datasets and their associated Kubernetes resources. - ---- - -## Installation - -### From source - -```bash -# Clone the repository -git clone https://github.com/fluid-cloudnative/fluid-cli.git -cd fluid-cli - -# Build and install into the same directory as kubectl -make install-plugin - -# Verify -fluid --help -``` - -### Manual install - -```bash -make build -cp bin/fluid /usr/local/bin/fluid -``` - -kubectl discovers any binary named `kubectl-` in `PATH` and exposes it as `kubectl `. - ---- - -## Usage - -```text -fluid [command] - -Inspect: - inspect List all Kubernetes resources associated with a Fluid Dataset - -Diagnose: - diagnose Collect diagnostic data for a Fluid Dataset and its Runtime(s) - -Utility: - version Print the version of fluid - -Global Flags: - --kubeconfig Path to kubeconfig file - --context Kubeconfig context to use - -n, --namespace Namespace scope -``` - -### inspect - -> **Phase 1 — available.** - -```bash -fluid inspect [-n namespace] [-o table|json|yaml] [--wide] -``` - -List all Kubernetes resources (Pods, StatefulSets, DaemonSets, PVCs, PVs, Services) -owned by a given Fluid Dataset and its Runtime(s). - -### diagnose - -> **Phase 2 — available.** - -```bash -fluid diagnose [-n namespace] [flags] - -Flags: - --archive Package artifacts into a tar.gz archive - --output-dir string Directory to write artifacts - --no-logs Skip collecting pod logs - --include-controller-logs Also collect Fluid controller logs - --since duration Only collect logs/events newer than this (e.g. 1h) -``` - -Collect diagnostic data (Dataset/Runtime YAML, pod logs, events, PVCs/PVs) -and optionally package them into a tar.gz archive for support. - -### version - -```bash -fluid version -``` - ---- - -## Roadmap - -| Phase | Focus | Status | -|-------|-------|--------| -| 0 | Plugin skeleton, build, install | Done | -| 1 | `inspect` subcommand | Done | -| 2 | `diagnose` subcommand | Done | -| 3 | AI/LLM-ready diagnostic format | Planned | -| 4 | Polish, docs, release | Planned | - ---- - -## Development - -```bash -# Build -make build - -# Run tests -make test - -# Cross-compile for all platforms -make build-all - -# Format and vet -make fmt vet -``` - -The module depends on published Fluid releases in `go.mod`. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..13a6526 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,28 @@ +# fluid CLI documentation + +`fluid` is the CLI for the [Fluid](https://github.com/fluid-cloudnative/fluid) project. It helps you inspect and collect diagnostics for Fluid-managed Datasets. + +## Guides + +- [Installation](install.md) +- [Inspect](guides/inspect.md) — list resources and status for a Dataset +- [Diagnose](guides/diagnose.md) — collect support bundles +- [Troubleshooting](troubleshooting.md) + +## Reference + +Command and flag reference is generated from the Cobra command tree: + +- [Reference index](reference/fluid.md) +- Regenerate after changing commands: `make docs` + +For the latest flags at your installed version, prefer `fluid --help`. + +## Roadmap + +| Phase | Focus | Status | +|-------|-------|--------| +| 0 | CLI skeleton, build, install | Done | +| 1 | `inspect` subcommand | Done | +| 2 | `diagnose` subcommand | Done | +| 3 | AI/LLM-ready diagnostic format | Planned | diff --git a/docs/guides/diagnose.md b/docs/guides/diagnose.md new file mode 100644 index 0000000..0c284ab --- /dev/null +++ b/docs/guides/diagnose.md @@ -0,0 +1,58 @@ +# Diagnose + +`fluid diagnose` collects diagnostic artifacts for a Fluid Dataset: CR YAML, pod descriptions, logs, namespace events, PVC/PV data, and an optional tar.gz archive for support. + +## When to use diagnose + +- Opening a GitHub issue or vendor support ticket +- Capturing cluster state after an incident +- Sharing a timestamped bundle with your team + +Use [`fluid inspect`](inspect.md) for a lightweight resource listing without log collection. + +## Basic usage + +```bash +# Collect into a timestamped directory (default TUI to browse results) +fluid diagnose my-dataset -n default + +# Write artifacts only (no TUI) +fluid diagnose my-dataset -n default -o dir + +# Create a tar.gz archive for attachment +fluid diagnose my-dataset -n default --archive -o dir +``` + +## Output layout + +Artifacts are written under a directory such as `fluid-diagnose--/`: + +| Path | Contents | +|------|----------| +| `dataset.yaml` | Dataset CR | +| `dataset.describe.txt` | Human-readable Dataset summary | +| `runtime/` | Runtime CRs and descriptions | +| `pods/` | Per-pod YAML, describe, and logs | +| `events/` | Namespace events | +| `storage/` | PVC and PV YAML | +| `controllers/` | Fluid controller logs (if `--include-controller-logs`) | +| `summary.txt` | High-level summary and warnings | +| `manifest.json` | Index of every artifact and collection status | + +`manifest.json` records each file with `status` (`collected`, `failed`, `skipped`) and an optional `reason`. Partial failures are normal when pods are missing or logs are unavailable; check `summary.txt` and the manifest. + +With `--archive`, a `.tar.gz` is produced alongside the directory (see command output for the path). + +## Support workflow + +1. Run diagnose with `--archive` and `-o dir` in non-interactive environments. +2. Redact secrets from the bundle if needed before sharing. +3. Attach the archive to your issue along with `fluid version` output. + +## Flags and help + +```bash +fluid diagnose --help +``` + +Notable options include `--output-dir`, `--no-logs`, `--include-controller-logs`, and `--since` (limit log/event age). Defaults and full descriptions are in `--help`. diff --git a/docs/guides/inspect.md b/docs/guides/inspect.md new file mode 100644 index 0000000..d878be1 --- /dev/null +++ b/docs/guides/inspect.md @@ -0,0 +1,56 @@ +# Inspect + +`fluid inspect` lists Kubernetes resources associated with a Fluid Dataset and its Runtime(s): Pods, StatefulSets, DaemonSets, PVCs, PVs, Services, and related status. + +## When to use inspect + +- Quick health check of a Dataset without collecting logs +- Scripted or CI output (`-o json` / `-o yaml`) +- Interactive exploration in the terminal TUI + +For support bundles (logs, events, archives), use [`fluid diagnose`](diagnose.md) instead. + +## Basic usage + +```bash +# Inspect a named Dataset (uses current kubeconfig namespace or default) +fluid inspect my-dataset + +# Explicit namespace +fluid inspect my-dataset -n production + +# Table output (non-interactive) +fluid inspect my-dataset -n default -o table + +# JSON for automation +fluid inspect my-dataset -n default -o json +``` + +## Interactive dataset picker + +Omit the dataset name to open a TUI that lists Datasets in the namespace: + +```bash +fluid inspect -n default +``` + +This requires an interactive terminal. In scripts or CI, always pass the dataset name and use `-o table`, `json`, or `yaml`. + +## Output modes + +| `-o` value | Description | +|------------|-------------| +| `tui` (default) | Full-screen terminal UI with tabs | +| `table` | Columnar text table | +| `json` | JSON document | +| `yaml` | YAML document | + +Use `--wide` with `table`, `json`, or `yaml` for extra columns (e.g. node, restart count). + +## Flags and help + +```bash +fluid inspect --help +``` + +Global Kubernetes flags (`--kubeconfig`, `--context`, `-n`) apply via the root command. diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..b61a196 --- /dev/null +++ b/docs/install.md @@ -0,0 +1,32 @@ +# Installation + +## From source (recommended) + +```bash +git clone https://github.com/fluid-cloudnative/fluid-cli.git +cd fluid-cli +make install-plugin +fluid --help +``` + +`make install-plugin` builds `bin/fluid` and copies it to a directory on your `PATH` (typically next to other CLI tools, or `/usr/local/bin`). + +## Manual install + +```bash +make build +cp bin/fluid /usr/local/bin/fluid # or any directory on your PATH +``` + +## Prerequisites + +- A Kubernetes cluster with [Fluid](https://github.com/fluid-cloudnative/fluid) installed (CRDs and controllers) +- Valid kubeconfig (`kubectl` should work against the cluster) +- For interactive TUI modes: a terminal with stdin/stdout (not a pipe-only CI job) + +## Verify + +```bash +fluid version +fluid inspect --help +``` diff --git a/docs/reference/fluid.md b/docs/reference/fluid.md new file mode 100644 index 0000000..ee48478 --- /dev/null +++ b/docs/reference/fluid.md @@ -0,0 +1,57 @@ +## fluid + +Inspect and diagnose Fluid-managed datasets + +### Synopsis + +fluid is a CLI for the Fluid project. + +It provides commands to inspect and diagnose Fluid-managed Datasets and their +associated Kubernetes resources (Runtimes, Pods, PVCs, PVs, Services, etc.). + +Install: copy the binary to a directory in your PATH as 'fluid'. +Usage: fluid + +### Examples + +``` + # List resources owned by a Dataset + fluid inspect my-dataset -n default + + # Collect diagnostic data and archive it + fluid diagnose my-dataset -n default --archive + + # Print version + fluid version +``` + +### Options + +``` + --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation. + --cache-dir string Default cache directory (default "~/.kube/cache") + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server + -h, --help help for fluid + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to the kubeconfig file to use for CLI requests. + -n, --namespace string If present, the namespace scope for this CLI request + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + -s, --server string The address and port of the Kubernetes API server + --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use +``` + +### SEE ALSO + +* [fluid diagnose](fluid_diagnose.md) - Collect diagnostic data for a Fluid Dataset and its Runtime(s) +* [fluid inspect](fluid_inspect.md) - List all Kubernetes resources associated with a Fluid Dataset +* [fluid version](fluid_version.md) - Print the version of fluid + diff --git a/docs/reference/fluid_diagnose.md b/docs/reference/fluid_diagnose.md new file mode 100644 index 0000000..1cc4cd8 --- /dev/null +++ b/docs/reference/fluid_diagnose.md @@ -0,0 +1,75 @@ +## fluid diagnose + +Collect diagnostic data for a Fluid Dataset and its Runtime(s) + +### Synopsis + +Diagnose collects diagnostic data for a given Fluid Dataset, including: + - Dataset and Runtime CR YAML + - Pod describe output and logs + - Namespace events + - PVC and PV descriptions + - Optional Fluid controller logs + +All artifacts are written to a timestamped directory and optionally packaged +into a tar.gz archive. + +``` +fluid diagnose [flags] +``` + +### Examples + +``` + # Diagnose a Dataset in the current namespace + fluid diagnose my-dataset + + # Diagnose and produce a tar.gz archive + fluid diagnose my-dataset -n default --archive + + # Write artifacts to a custom directory without collecting logs + fluid diagnose my-dataset -n default --output-dir /tmp/diag --no-logs + + # Only collect events from the last hour + fluid diagnose my-dataset -n default --since 1h +``` + +### Options + +``` + --archive Package artifacts into a tar.gz archive + -h, --help help for diagnose + --include-controller-logs Also collect Fluid controller logs from fluid-system namespace + --no-logs Skip collecting pod logs (useful in large clusters) + -o, --output string Output mode: tui|dir|stdout (default "tui") + --output-dir string Directory to write artifacts (default: fluid-diagnose--) + --since string Only collect logs/events newer than this duration (e.g. 1h, 30m) +``` + +### Options inherited from parent commands + +``` + --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation. + --cache-dir string Default cache directory (default "~/.kube/cache") + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to the kubeconfig file to use for CLI requests. + -n, --namespace string If present, the namespace scope for this CLI request + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + -s, --server string The address and port of the Kubernetes API server + --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use +``` + +### SEE ALSO + +* [fluid](fluid.md) - Inspect and diagnose Fluid-managed datasets + diff --git a/docs/reference/fluid_inspect.md b/docs/reference/fluid_inspect.md new file mode 100644 index 0000000..ea84ac1 --- /dev/null +++ b/docs/reference/fluid_inspect.md @@ -0,0 +1,68 @@ +## fluid inspect + +List all Kubernetes resources associated with a Fluid Dataset + +### Synopsis + +Inspect lists all Kubernetes resources (Pods, StatefulSets, DaemonSets, +PVCs, PVs, Services, etc.) owned by a given Fluid Dataset and its Runtime(s), +along with their current status. + +``` +fluid inspect [dataset-name] [flags] +``` + +### Examples + +``` + # Inspect a Dataset in the default namespace + fluid inspect my-dataset + + # Launch a TUI selector to choose a Dataset + fluid inspect + + # Inspect a Dataset in a specific namespace + fluid inspect my-dataset -n default + + # Output as JSON + fluid inspect my-dataset -n default -o json + + # Show extra columns (node, restarts) + fluid inspect my-dataset -n default --wide +``` + +### Options + +``` + -h, --help help for inspect + -o, --output string Output format: tui|table|json|yaml (default "tui") + --wide Show additional columns (node, restarts) +``` + +### Options inherited from parent commands + +``` + --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation. + --cache-dir string Default cache directory (default "~/.kube/cache") + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to the kubeconfig file to use for CLI requests. + -n, --namespace string If present, the namespace scope for this CLI request + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + -s, --server string The address and port of the Kubernetes API server + --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use +``` + +### SEE ALSO + +* [fluid](fluid.md) - Inspect and diagnose Fluid-managed datasets + diff --git a/docs/reference/fluid_version.md b/docs/reference/fluid_version.md new file mode 100644 index 0000000..46fd4e5 --- /dev/null +++ b/docs/reference/fluid_version.md @@ -0,0 +1,52 @@ +## fluid version + +Print the version of fluid + +### Synopsis + +Print version, git commit, and build date of fluid. + +``` +fluid version [flags] +``` + +### Examples + +``` + # Print version + fluid version +``` + +### Options + +``` + -h, --help help for version +``` + +### Options inherited from parent commands + +``` + --as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace. + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation. + --cache-dir string Default cache directory (default "~/.kube/cache") + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to the kubeconfig file to use for CLI requests. + -n, --namespace string If present, the namespace scope for this CLI request + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + -s, --server string The address and port of the Kubernetes API server + --tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use +``` + +### SEE ALSO + +* [fluid](fluid.md) - Inspect and diagnose Fluid-managed datasets + diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..a9dfd48 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,63 @@ +# Troubleshooting + +## Fluid CRDs not installed + +**Symptom:** Errors mentioning `no matches for kind`, `no kind is registered`, or `data.fluid.io/v1alpha1 not found`. + +**Fix:** Install Fluid on the cluster before using `fluid`. See the [Fluid install guide](https://github.com/fluid-cloudnative/fluid/blob/master/docs/en/userguide/install.md). + +```bash +kubectl get crd datasets.data.fluid.io +``` + +## Cannot reach the API server + +**Symptom:** Timeouts, connection refused, or TLS errors when running `fluid inspect` or `fluid diagnose`. + +**Fix:** Verify kubeconfig and cluster health: + +```bash +kubectl cluster-info +kubectl get ns +``` + +Ensure `--context` and `--kubeconfig` point at the intended cluster. + +## Interactive mode in a non-TTY environment + +**Symptom:** Errors about non-interactive mode when using default `-o tui` or omitting the dataset name on `inspect`. + +**Fix:** Pass explicit arguments and a non-TUI output mode: + +```bash +fluid inspect my-dataset -n default -o table +fluid diagnose my-dataset -n default -o dir +``` + +## RBAC permission denied + +**Symptom:** `Forbidden` or `cannot get resource` when listing or collecting resources. + +**Fix:** Your kubeconfig user or ServiceAccount needs read access to Fluid CRDs, Pods, Events, PVCs, PVs, and related objects in the target namespace (and `fluid-system` if using `--include-controller-logs`). + +## Diagnose partial collection + +**Symptom:** Message like `completed with N partial collection issues`. + +**Fix:** Open `summary.txt` and `manifest.json` in the output directory. Failed entries include a `reason` (e.g. pod not found, log stream error). The bundle is still useful; re-run with `--since` or `--no-logs` on very large clusters if collection is slow. + +## Stale documentation in the repo + +Generated command reference lives in `docs/reference/`. After changing commands or flags in `cmd/`, run: + +```bash +make docs +``` + +and commit the updated files. CI verifies they match the Cobra tree. + +## Getting help + +- Command help: `fluid --help` +- [Inspect guide](guides/inspect.md) / [Diagnose guide](guides/diagnose.md) +- [GitHub issues](https://github.com/fluid-cloudnative/fluid-cli/issues) — include `fluid version`, exact command, and redacted output diff --git a/go.mod b/go.mod index 356eec0..de61b6c 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/clipperhouse/displaywidth v0.9.0 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.5.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect @@ -74,6 +75,7 @@ require ( github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index 3d86fc5..9937805 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,7 @@ github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfa github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U= github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= @@ -185,6 +186,7 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= diff --git a/hack/gen-docs/main.go b/hack/gen-docs/main.go new file mode 100644 index 0000000..c7e2519 --- /dev/null +++ b/hack/gen-docs/main.go @@ -0,0 +1,99 @@ +// Copyright 2026 The Fluid 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. + +// gen-docs generates Markdown command reference under docs/reference/. +package main + +import ( + "log" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/fluid-cloudnative/fluid-cli/cmd/fluid/root" + "github.com/spf13/cobra/doc" +) + +// docHome is used when building the command tree so generated flag defaults +// do not embed a developer machine's home directory. +const docHome = "/home/user" + +var kubeCacheDefaultRE = regexp.MustCompile(`\(default "[^"]+/.kube/cache"\)`) + +func main() { + outDir := "docs/reference" + if len(os.Args) > 1 { + outDir = os.Args[1] + } + + _ = os.Setenv("HOME", docHome) + _ = os.Setenv("USERPROFILE", docHome) // Windows-style clients if consulted + + rootCmd := root.NewRootCmd() + rootCmd.DisableAutoGenTag = true + + if err := os.MkdirAll(outDir, 0o755); err != nil { + log.Fatalf("creating output directory: %v", err) + } + + // Remove stale generated pages so renamed commands do not linger. + entries, err := os.ReadDir(outDir) + if err != nil { + log.Fatalf("reading output directory: %v", err) + } + for _, e := range entries { + if e.IsDir() { + continue + } + if filepath.Ext(e.Name()) != ".md" { + continue + } + if err := os.Remove(filepath.Join(outDir, e.Name())); err != nil { + log.Fatalf("removing stale doc %s: %v", e.Name(), err) + } + } + + if err := doc.GenMarkdownTree(rootCmd, outDir); err != nil { + log.Fatalf("generating docs: %v", err) + } + if err := sanitizeGeneratedDocs(outDir); err != nil { + log.Fatalf("sanitizing docs: %v", err) + } + log.Printf("wrote command reference to %s", outDir) +} + +func sanitizeGeneratedDocs(outDir string) error { + entries, err := os.ReadDir(outDir) + if err != nil { + return err + } + for _, e := range entries { + if e.IsDir() || filepath.Ext(e.Name()) != ".md" { + continue + } + path := filepath.Join(outDir, e.Name()) + data, err := os.ReadFile(path) + if err != nil { + return err + } + s := string(data) + s = kubeCacheDefaultRE.ReplaceAllString(s, `(default "~/.kube/cache")`) + s = strings.ReplaceAll(s, docHome, "~") + if err := os.WriteFile(path, []byte(s), 0o644); err != nil { + return err + } + } + return nil +}