|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to coding agents when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Kubernetes operator for managing ClickHouse database clusters and ClickHouse Keeper clusters. Built with `Kubebuilder` and `controller-runtime`. Manages two CRDs: `ClickHouseCluster` and `KeeperCluster` (both `v1alpha1` in the `clickhouse.com` API group). |
| 8 | + |
| 9 | +## Common Commands |
| 10 | + |
| 11 | +### Build & Run |
| 12 | +```bash |
| 13 | +make build # Build binary (bin/clickhouse-manager). Runs manifests, generate, fmt, vet first. |
| 14 | +make build-linux-manager # Build binary (bin/clickhouse-manager) for linux platform. Used to build Docker image. |
| 15 | +make docker-build # Build Docker image |
| 16 | +``` |
| 17 | + |
| 18 | +### Testing |
| 19 | +```bash |
| 20 | +make test # Unit tests (excludes e2e and deploy tests). Uses `envtest` with Ginkgo. |
| 21 | +make test-ci # CI tests with coverage (cover.out), race detection, JUnit report |
| 22 | +make fuzz # Fuzz tests for keeper and clickhouse spec validation |
| 23 | +make test-e2e # Full e2e tests (requires Kind cluster, 30m timeout) |
| 24 | +make test-keeper-e2e # Keeper-only e2e tests (--ginkgo.label-filter keeper) |
| 25 | +make test-clickhouse-e2e # ClickHouse-only e2e tests (--ginkgo.label-filter clickhouse) |
| 26 | +make test-compat-e2e # Compatibility smoke tests across ClickHouse versions |
| 27 | +``` |
| 28 | + |
| 29 | +Run a single test file or spec: |
| 30 | +```bash |
| 31 | +# Single package |
| 32 | +go test ./internal/controller/keeper/ -v --ginkgo.v |
| 33 | +# Single spec by name |
| 34 | +go test ./internal/controller/keeper/ -v --ginkgo.v --ginkgo.focus="spec name pattern" |
| 35 | +``` |
| 36 | + |
| 37 | +### Testing rules |
| 38 | +- Run `make lint-fix` before tests |
| 39 | +- Run `make test` or specific unit tests |
| 40 | +- Do NOT run `make test-e2e`, `test-keeper-e2e`, `test-clickhouse-e2e`, `test-compat-e2e` |
| 41 | +- If changes complex and require e2e testing run target with `--ginkgo.focus` to limit scope to a single test at a time |
| 42 | + |
| 43 | +### Test patterns |
| 44 | +- **Functional tests** (`controller_test.go`): Use `testutil.SetupEnvironment()` which starts `envtest` (real API server + `etcd`). Use for full reconciliation flow testing. |
| 45 | +- **Unit tests** (`sync_test.go`, `commands_test.go`): Use `fake.NewClientBuilder()` for faster, focused tests on individual methods. |
| 46 | +- **E2E tests** (`test/e2e/`): Real Kind cluster. Label tests with `Label("clickhouse")` or `Label("keeper")` for filtered runs. |
| 47 | + |
| 48 | +### Code Generation (run after modifying api/v1alpha1/ types) |
| 49 | +```bash |
| 50 | +make generate # DeepCopy methods (zz_generated.deepcopy.go) |
| 51 | +make manifests # CRDs, RBAC roles, webhooks → config/crd/bases/ |
| 52 | +make generate-helmchart-ci # Generate Helm chart templates and reset manually maintained files (dist/chart/templates/) |
| 53 | +make docs-generate-api-ref # Generate API reference docs (docs/api-reference.md) |
| 54 | +``` |
| 55 | + |
| 56 | +### Helm Chart |
| 57 | +The Helm chart in `dist/chart/` is partially **generated from `Kustomize` configs** — do not edit templates directly. Regenerate with `make generate-helmchart-ci`. Except you are directly asked. |
| 58 | + |
| 59 | +### Linting & Formatting |
| 60 | +```bash |
| 61 | +make lint # golangci-lint + codespell + actionlint |
| 62 | +make lint-fix # golangci-lint with --fix |
| 63 | +make golangci-fmt # gofmt + goimports formatting |
| 64 | +make docs-lint # markdownlint for docs |
| 65 | +``` |
| 66 | + |
| 67 | +### Running E2E Locally |
| 68 | +Kind cluster configuration at `ci/kind-cluster.config` creates 1 control-plane + 3 workers with zone topology labels: |
| 69 | +```bash |
| 70 | +kind create cluster --config ci/kind-cluster.config |
| 71 | +``` |
| 72 | + |
| 73 | +### CRD Compatibility |
| 74 | +```bash |
| 75 | +make check-crd-compat # Check CRD backward compatibility against origin/main |
| 76 | +``` |
| 77 | + |
| 78 | +## Coding Rules |
| 79 | +- Do not introduce new dependencies without justification |
| 80 | +- Follow existing error handling patterns |
| 81 | +- Try to minimize diff |
| 82 | +- Avoid API changes unless necessary |
| 83 | +- Always ensure `make lint` passes, use `make lint-fix` to automatically fix issues before writing code |
| 84 | + |
| 85 | +## CI Pipeline (what runs on PRs) |
| 86 | +1. Lint: `go mod tidy` check, `make manifests`/`make generate` freshness, CRD backward compatibility, golangci-lint, codespell, actionlint |
| 87 | +2. Build + unit tests (`make test-ci`) |
| 88 | +3. Fuzz tests |
| 89 | +4. Helm chart generation + lint |
| 90 | +5. OLM bundle + scorecard validation |
| 91 | +6. Compatibility e2e (multiple K8s + ClickHouse version matrices) |
| 92 | +7. Full e2e (Keeper + ClickHouse, on self-hosted runners) |
| 93 | + |
| 94 | +## Architecture |
| 95 | + |
| 96 | +### CRD API Types (`api/v1alpha1/`) |
| 97 | +- `clickhousecluster_types.go` — ClickHouseCluster spec: shards, replicas per shard, keeper reference, storage, settings |
| 98 | +- `keepercluster_types.go` — KeeperCluster spec: replicas (odd, 0-15), storage, settings |
| 99 | +- `common.go` — Shared types: ContainerImage, LoggerConfig, PodDisruptionBudgetSpec, ClickHouseSettings, KeeperSettings |
| 100 | +- `defaults.go` — Default value logic applied by webhooks |
| 101 | +- `conditions.go` — Status condition helpers |
| 102 | + |
| 103 | +After modifying types, always run `make generate manifests generate-helmchart-ci docs-generate-api-ref`. |
| 104 | + |
| 105 | +### Controllers (`internal/controller/`) |
| 106 | +Both controllers follow the same pattern, extending a shared base: |
| 107 | + |
| 108 | +- `reconcilerbase.go` — Base reconciliation logic shared by both controllers |
| 109 | +- `clickhouse/controller.go` — ClickHouseCluster reconciler (manages StatefulSets, ConfigMaps, Services) |
| 110 | +- `keeper/controller.go` — KeeperCluster reconciler |
| 111 | +- `clickhouse/sync.go`, `keeper/sync.go` — Sync desired state to Kubernetes |
| 112 | +- `clickhouse/templates.go`, `keeper/templates.go` — Generate Kubernetes resource specs |
| 113 | +- `clickhouse/config.go` — Generate ClickHouse YAML configuration |
| 114 | +- `clickhouse/commands.go`, `keeper/commands.go` — Interfaces to communicate to running containers |
| 115 | +- `overrides.go` — Pod/container spec overrides helpers via strategic merge patch |
| 116 | +- `versionprobe.go` — Creates Jobs to detect actual ClickHouse/Keeper versions |
| 117 | +- `upgradecheck.go` — Checks for newer version availability |
| 118 | +- `resources.go` — Shared Kubernetes resource creation helpers |
| 119 | +- `status.go` — Status update logic |
| 120 | + |
| 121 | +### Reconciliation Pattern |
| 122 | +Controllers execute reconcile as a sequence of step functions (`func(ctx, log) (*Result, error)`). Steps are defined in `sync()` and executed sequentially. |
| 123 | + |
| 124 | +### Resource Change Detection |
| 125 | +Resources are tracked via annotation hashes (`checksum/spec`, `checksum/configuration`). Before updating a K8s resource, compare `util.DeepHashResource()` output against the stored annotation. Skip updates when hashes match. Always call `util.AddSpecHashToObject()` on reconciled resources. |
| 126 | + |
| 127 | +### Webhooks (`internal/webhook/v1alpha1/`) |
| 128 | +Validation and defaulting webhooks for both CRDs. `ENABLE_WEBHOOKS` Env var controls whether they are registered. |
| 129 | + |
| 130 | +### Key Packages |
| 131 | +- `internal/upgrade/` — Version update checking (fetcher + compatibility checker) |
| 132 | +- `internal/version/` — Build version info injected via `ldflags` |
| 133 | +- `internal/environment/` — Environment variable processing (`ENABLE_WEBHOOKS`, `WATCH_NAMESPACE`) |
| 134 | +- `internal/controllerutil/` — Shared utilities (annotations, dialer, logger) |
| 135 | + |
| 136 | +### Config/Deploy (`config/`) |
| 137 | +Kustomize-based configuration: `config/default/` is the main overlay composing CRDs, RBAC, manager deployment, webhooks, and cert-manager integration. |
| 138 | + |
| 139 | +### Entry Point |
| 140 | +`cmd/main.go` — Sets up controller-runtime manager, registers both controllers and webhooks, configures metrics and health probes. |
| 141 | + |
| 142 | +## Code Style & Conventions |
| 143 | + |
| 144 | +- **Import ordering**: `stdlib`, third-party, then `github.com/ClickHouse/clickhouse-operator` (enforced by goimports with local-prefixes) |
| 145 | +- **`interface{}` → `any`**: gofmt rewrites `interface{}` to `any` automatically |
| 146 | +- **Testing**: Ginkgo v2 BDD style with Gomega matchers. Dot imports for `ginkgo/v2` and `gomega` are allowed. |
| 147 | +- **Linting**: 80+ linters enabled in `.golangci.yml`. Notable: `wsl_v5` (whitespace), `mnd` (magic numbers, `2` is exempted), `godot` (comment periods), `ireturn` (interface return restrictions with whitelisted types) |
| 148 | +- **Generated files**: Never edit `zz_generated.deepcopy.go` or files in `config/crd/bases/`, `config/rbac/` directly |
0 commit comments