Skip to content

Commit 7b04604

Browse files
committed
review fixes + retire kustomize
Signed-off-by: Andrey Kolkov <androndo@gmail.com>
1 parent 717af08 commit 7b04604

52 files changed

Lines changed: 572 additions & 6070 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ jobs:
1818
cache: true
1919

2020
- name: codegen drift
21-
# If a contributor edits an API type without re-running codegen,
22-
# this gate catches it before CRDs and deepcopy ship out of sync
23-
# with the Go types. Runs before `make test` so the as-committed
24-
# state of generated files is what we check.
21+
# If a contributor edits an API type or +kubebuilder:rbac markers
22+
# without re-running codegen, this gate catches it before the chart's
23+
# CRDs (charts/etcd-operator/crd-bases), manager RBAC rules
24+
# (charts/etcd-operator/files/manager-role-rules.yaml), or deepcopy ship
25+
# out of sync. Runs before `make test` so the as-committed state of
26+
# generated files is what we check.
2527
run: |
2628
make generate manifests
2729
if ! git diff --quiet --exit-code; then

.github/workflows/helm-publish.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ jobs:
2424
- name: Checkout repository
2525
uses: actions/checkout@v4
2626

27-
# make helm-sync regenerates the CRDs (controller-gen) and copies them
28-
# into the chart, so the published package always carries CRDs matching
29-
# the tagged API types — never a stale committed copy.
27+
# make manifests regenerates the CRDs and manager RBAC rules (controller-gen)
28+
# straight into the chart, so the published package always matches the
29+
# tagged API types and +kubebuilder:rbac markers — never a stale committed
30+
# copy. (ci.yml's drift gate already enforces this on PRs; this is belt-and-
31+
# suspenders at publish time.)
3032
- uses: actions/setup-go@v5
3133
with:
3234
go-version-file: go.mod
@@ -37,8 +39,8 @@ jobs:
3739
with:
3840
version: 'v3.16.4'
3941

40-
- name: Sync CRDs into the chart
41-
run: make helm-sync
42+
- name: Regenerate CRDs and RBAC into the chart
43+
run: make manifests
4244

4345
- name: Resolve chart versions from tag
4446
run: |

.github/workflows/release-assets.yml

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ name: Upload release assets
22

33
# When a GitHub release is created for a tag, render the install manifests for
44
# that tag's image and attach them to the release. `make build-dist-manifests`
5-
# sets the `controller` image (and, via the kustomize replacement in
6-
# config/default, the manager's OPERATOR_IMAGE env) to the released ref, so the
7-
# attached YAML deploys the matching operator and its snapshot/restore agent.
5+
# is `helm template` of the chart with image.repository/tag set to the released
6+
# ref; the chart renders image == OPERATOR_IMAGE, so the attached YAML deploys
7+
# the matching operator and its snapshot/restore agent. For consumers who
8+
# kubectl-apply rather than helm-install.
89

910
on:
1011
release:
@@ -28,6 +29,12 @@ jobs:
2829
go-version-file: go.mod
2930
cache: true
3031

32+
# build-dist-manifests renders the chart via `helm template`.
33+
- name: Install Helm
34+
uses: azure/setup-helm@v4
35+
with:
36+
version: 'v3.16.4'
37+
3138
- name: Resolve release tag
3239
run: echo "RELEASE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
3340

@@ -57,3 +64,52 @@ jobs:
5764
asset_name: etcd-operator.non-crds.yaml
5865
tag: ${{ github.ref }}
5966
overwrite: true
67+
68+
# Standalone client CLIs (kubectl-etcd plugin + etcd-migrate). They are not in
69+
# the operator image (client-side / admin tools), so they ship as
70+
# cross-compiled release binaries. Separate job: no Helm needed, and a failure
71+
# here doesn't block the manifest assets above.
72+
cli-binaries:
73+
runs-on: ubuntu-22.04
74+
permissions:
75+
contents: write
76+
steps:
77+
- uses: actions/checkout@v4
78+
79+
- uses: actions/setup-go@v5
80+
with:
81+
go-version-file: go.mod
82+
cache: true
83+
84+
- name: Resolve release tag
85+
run: echo "RELEASE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
86+
87+
- name: Cross-compile CLIs
88+
run: make dist-cli VERSION=${RELEASE_TAG}
89+
90+
- name: Upload etcd-migrate binaries
91+
uses: svenstaro/upload-release-action@2.9.0
92+
with:
93+
repo_token: ${{ secrets.GITHUB_TOKEN }}
94+
file: dist/etcd-migrate-*
95+
file_glob: true
96+
tag: ${{ github.ref }}
97+
overwrite: true
98+
99+
- name: Upload kubectl-etcd binaries
100+
uses: svenstaro/upload-release-action@2.9.0
101+
with:
102+
repo_token: ${{ secrets.GITHUB_TOKEN }}
103+
file: dist/kubectl-etcd-*
104+
file_glob: true
105+
tag: ${{ github.ref }}
106+
overwrite: true
107+
108+
- name: Upload CLI checksums
109+
uses: svenstaro/upload-release-action@2.9.0
110+
with:
111+
repo_token: ${{ secrets.GITHUB_TOKEN }}
112+
file: dist/cli-SHA256SUMS.txt
113+
asset_name: cli-SHA256SUMS.txt
114+
tag: ${{ github.ref }}
115+
overwrite: true

.github/workflows/release-smoke.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ on:
2020
- 'charts/**'
2121
- 'Makefile'
2222
- 'Dockerfile'
23-
- 'config/**'
2423
- 'api/**'
2524
workflow_dispatch:
2625

Makefile

Lines changed: 77 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11

22
# Image URL to use all building/pushing image targets
33
IMG ?= controller:latest
4+
5+
# Version stamped into the standalone CLIs (etcd-migrate, kubectl-etcd) via
6+
# -ldflags. Defaults to `git describe`; the release workflow passes the tag.
7+
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
8+
CLI_LDFLAGS ?= -X main.version=$(VERSION)
49
# ENVTEST_K8S_VERSION is derived from the k8s.io/api version in go.mod so a
510
# dependency bump automatically pulls the matching envtest assets — no need
611
# to remember to update this in two places. (Pattern stolen from
@@ -42,8 +47,20 @@ help: ## Display this help.
4247
##@ Development
4348

4449
.PHONY: manifests
45-
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
46-
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
50+
manifests: controller-gen yq ## Generate CRDs and the manager RBAC rules straight into the Helm chart.
51+
# CRDs land in charts/etcd-operator/crd-bases/ (templates/crds.yaml renders
52+
# them, with the helm.sh/resource-policy:keep annotation); the manager
53+
# ClusterRole rules land in charts/etcd-operator/files/ for templates/rbac.yaml
54+
# to pull in via .Files.Get. ci.yml's codegen-drift gate (make manifests +
55+
# git diff) then guards BOTH against drift from the API types and the
56+
# +kubebuilder:rbac markers — no second source of truth, no grep guard.
57+
$(CONTROLLER_GEN) rbac:roleName=manager-role crd paths="./..." \
58+
output:crd:artifacts:config=charts/etcd-operator/crd-bases \
59+
output:rbac:artifacts:config=charts/etcd-operator/files
60+
# controller-gen emits a whole ClusterRole; the chart only needs its rules
61+
# (it wraps them in a release-named, labelled ClusterRole of its own).
62+
$(YQ) eval '.rules' charts/etcd-operator/files/role.yaml > charts/etcd-operator/files/manager-role-rules.yaml
63+
rm -f charts/etcd-operator/files/role.yaml
4764

4865
.PHONY: generate
4966
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
@@ -74,7 +91,7 @@ release-smoke: ## Smoke-test the tag-release manifest install path on kind: buil
7491
hack/release-smoke.sh
7592

7693
.PHONY: helm-smoke
77-
helm-smoke: helm-sync ## Smoke-test the Helm chart install path on kind: build image -> helm install chart -> assert operator Available and a 1-node cluster READY. KEEP_CLUSTER=1 keeps the cluster.
94+
helm-smoke: ## Smoke-test the Helm chart install path on kind: build image -> helm install chart -> assert operator Available and a 1-node cluster READY. KEEP_CLUSTER=1 keeps the cluster.
7895
INSTALL_MODE=helm hack/release-smoke.sh
7996

8097
##@ Build
@@ -85,11 +102,27 @@ build: manifests generate fmt vet ## Build manager binary.
85102

86103
.PHONY: kubectl-etcd
87104
kubectl-etcd: fmt vet ## Build the kubectl-etcd plugin binary.
88-
go build -o bin/kubectl-etcd ./cmd/kubectl-etcd
105+
go build -ldflags "$(CLI_LDFLAGS)" -o bin/kubectl-etcd ./cmd/kubectl-etcd
89106

90107
.PHONY: etcd-migrate
91108
etcd-migrate: fmt vet ## Build the etcd-migrate (legacy v1alpha1 -> v1alpha2) CLI binary.
92-
go build -o bin/etcd-migrate ./cmd/etcd-migrate
109+
go build -ldflags "$(CLI_LDFLAGS)" -o bin/etcd-migrate ./cmd/etcd-migrate
110+
111+
.PHONY: dist-cli
112+
dist-cli: ## Cross-compile etcd-migrate and kubectl-etcd into dist/ for release (linux/darwin x amd64/arm64). VERSION stamps the binary version.
113+
# Produces the standalone CLIs the release-assets workflow attaches to a
114+
# release, named <cmd>-<os>-<arch>, plus a SHA256 checksum file. These are
115+
# client-side tools (kubectl-etcd is a kubectl plugin, etcd-migrate is an
116+
# admin-run migration CLI), so they ship as binaries, not in the operator image.
117+
mkdir -p dist
118+
for os in linux darwin; do for arch in amd64 arm64; do \
119+
for cmd in etcd-migrate kubectl-etcd; do \
120+
echo "building dist/$$cmd-$$os-$$arch"; \
121+
CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch \
122+
go build -ldflags "$(CLI_LDFLAGS)" -o dist/$$cmd-$$os-$$arch ./cmd/$$cmd; \
123+
done; \
124+
done; done
125+
cd dist && { command -v sha256sum >/dev/null 2>&1 && sha256sum etcd-migrate-* kubectl-etcd-* || shasum -a 256 etcd-migrate-* kubectl-etcd-*; } > cli-SHA256SUMS.txt
93126

94127
.PHONY: run
95128
run: manifests generate fmt vet ## Run a controller from your host.
@@ -124,51 +157,46 @@ docker-buildx: test ## Build and push docker image for the manager for cross-pla
124157
rm Dockerfile.cross
125158

126159
.PHONY: build-dist-manifests
127-
build-dist-manifests: manifests generate kustomize yq ## Render the release install manifests into dist/ for IMG.
128-
# Produces the YAMLs the release-assets workflow attaches to a tag:
129-
# dist/etcd-operator.yaml – everything (CRDs + deployment)
160+
build-dist-manifests: manifests generate require-helm yq ## Render the release install manifests into dist/ for IMG.
161+
# Produces the YAMLs the release-assets workflow attaches to a tag, for users
162+
# who kubectl-apply instead of helm-install:
163+
# dist/etcd-operator.yaml – everything (Namespace + CRDs + operator)
130164
# dist/etcd-operator.crds.yaml – CRDs only
131165
# dist/etcd-operator.non-crds.yaml – everything except CRDs
132-
# Setting the `controller` image also propagates into the manager's
133-
# OPERATOR_IMAGE env via the kustomize replacement in config/default, so
134-
# the snapshot/restore agent runs the same ref. Pass IMG=<registry>/etcd-operator:<tag>.
166+
# This is just `helm template` of the chart, so the rendered manifest IS the
167+
# chart: the image == OPERATOR_IMAGE wiring and the RBAC come from one source.
168+
# namespace.create emits the Namespace so a bare `kubectl apply -f
169+
# etcd-operator.yaml` is self-contained. Rendering is pure — no tracked file
170+
# is mutated. Pass IMG=<registry>/etcd-operator:<tag>.
135171
mkdir -p dist
136-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
137-
$(KUSTOMIZE) build config/default > dist/etcd-operator.yaml
138-
$(KUSTOMIZE) build config/default | $(YQ) eval 'select(.kind != "CustomResourceDefinition")' - > dist/etcd-operator.non-crds.yaml
139-
$(KUSTOMIZE) build config/default | $(YQ) eval 'select(.kind == "CustomResourceDefinition")' - > dist/etcd-operator.crds.yaml
140-
141-
.PHONY: helm-sync
142-
helm-sync: manifests ## Vendor the generated CRDs into the Helm chart's crds/ directory.
143-
# The chart's RBAC/Deployment templates are hand-authored from config/, but
144-
# the CRDs (large, schema-bearing, regenerated by controller-gen) are copied
145-
# verbatim so they never drift from the API types. helm-publish.yml re-runs
146-
# this before packaging so a published chart always carries current CRDs.
147-
mkdir -p charts/etcd-operator/crds
148-
cp config/crd/bases/*.yaml charts/etcd-operator/crds/
172+
img='$(IMG)'; $(HELM) template etcd-operator charts/etcd-operator \
173+
--namespace etcd-operator-system \
174+
--set image.repository="$${img%:*}" --set image.tag="$${img##*:}" \
175+
--set namespace.create=true \
176+
> dist/etcd-operator.yaml
177+
$(YQ) eval 'select(.kind != "CustomResourceDefinition")' dist/etcd-operator.yaml > dist/etcd-operator.non-crds.yaml
178+
$(YQ) eval 'select(.kind == "CustomResourceDefinition")' dist/etcd-operator.yaml > dist/etcd-operator.crds.yaml
149179

150180
##@ Deployment
151181

152-
ifndef ignore-not-found
153-
ignore-not-found = false
154-
endif
155-
156-
.PHONY: install
157-
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
158-
$(KUSTOMIZE) build config/crd | kubectl apply -f -
159-
160-
.PHONY: uninstall
161-
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
162-
$(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
182+
# The Helm-driven install targets below. The chart is the single source of
183+
# truth for CRDs, RBAC, and the manager Deployment.
184+
HELM_RELEASE ?= etcd-operator
185+
NAMESPACE ?= etcd-operator-system
163186

164187
.PHONY: deploy
165-
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
166-
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
167-
$(KUSTOMIZE) build config/default | kubectl apply -f -
188+
deploy: manifests require-helm ## Install/upgrade the operator (CRDs + RBAC + manager) via Helm. Pass IMG=<registry>/etcd-operator:<tag>.
189+
# The chart renders image == OPERATOR_IMAGE, so there is no separate image-
190+
# replacement step; CRDs are templated into the release so `helm upgrade`
191+
# keeps them current. The IMG split into repository:tag handles registry ports.
192+
img='$(IMG)'; $(HELM) upgrade --install $(HELM_RELEASE) charts/etcd-operator \
193+
--namespace $(NAMESPACE) --create-namespace \
194+
--set image.repository="$${img%:*}" --set image.tag="$${img##*:}" \
195+
--wait --timeout 5m
168196

169197
.PHONY: undeploy
170-
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
171-
$(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
198+
undeploy: require-helm ## Uninstall the operator release. CRDs carry resource-policy:keep, so EtcdClusters survive — delete them (and the CRDs) by hand to wipe data.
199+
$(HELM) uninstall $(HELM_RELEASE) --namespace $(NAMESPACE)
172200

173201
##@ Build Dependencies
174202

@@ -178,16 +206,17 @@ $(LOCALBIN):
178206
mkdir -p $(LOCALBIN)
179207

180208
## Tool Versions
181-
KUSTOMIZE_VERSION ?= v5.6.0
182209
CONTROLLER_TOOLS_VERSION ?= v0.18.0
183210
YQ_VERSION ?= v4.44.1
184211

185212
## Tool Binaries (version-suffixed so a version bump auto-triggers reinstall
186213
## and stale builds of an old version stay on disk alongside the new one).
187-
KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION)
188214
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION)
189215
ENVTEST ?= $(LOCALBIN)/setup-envtest
190216
YQ ?= $(LOCALBIN)/yq-$(YQ_VERSION)
217+
# Helm is the one tool we don't vendor (no clean `go install`); it must be on
218+
# PATH. release-smoke/e2e and the publish workflows install it via setup-helm.
219+
HELM ?= helm
191220

192221
# go-install-tool installs $2@$3 under $1. `go install` drops the binary at
193222
# $LOCALBIN/<basename>, so we rename it after install to the version-suffixed
@@ -202,10 +231,12 @@ mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
202231
}
203232
endef
204233

205-
.PHONY: kustomize
206-
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
207-
$(KUSTOMIZE): $(LOCALBIN)
208-
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
234+
.PHONY: require-helm
235+
require-helm: ## Assert Helm is on PATH (used by deploy/undeploy/build-dist-manifests).
236+
@command -v $(HELM) >/dev/null 2>&1 || { \
237+
echo "ERROR: helm not found on PATH. Install Helm v3.16+ (https://helm.sh/docs/intro/install/)."; \
238+
exit 1; \
239+
}
209240

210241
.PHONY: controller-gen
211242
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ No multi-user / per-tenant RBAC inside etcd — single-user `root` auth is avail
3737
## Quick start
3838

3939
```sh
40-
# 1. Install CRDs and the operator. Builds an image and pushes it to your
41-
# registry; substitute IMG= for a prebuilt tag if you have one. The cluster
42-
# must be able to pull from <your-registry> — for local clusters (kind /
43-
# minikube / k3d) sideload the image or use an ephemeral registry such as
44-
# ttl.sh, otherwise the operator Deployment will sit in ImagePullBackOff.
45-
make install
40+
# 1. Install the operator (CRDs + RBAC + manager) with Helm. Builds an image and
41+
# pushes it to your registry; substitute IMG= for a prebuilt tag if you have
42+
# one. The cluster must be able to pull from <your-registry> — for local
43+
# clusters (kind / minikube / k3d) sideload the image or use an ephemeral
44+
# registry such as ttl.sh, otherwise the Deployment sits in ImagePullBackOff.
45+
# `make deploy` runs `helm upgrade --install` (needs helm v3.16+ on PATH).
4646
make docker-build docker-push deploy IMG=<your-registry>/etcd-operator:<tag>
4747

4848
# 2. Create a cluster.

api/v1alpha2/validation_envtest_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,12 @@ func TestMain(m *testing.M) {
7777
os.Exit(code)
7878
}
7979

80-
// crdBasesDir resolves config/crd/bases relative to this test file —
81-
// go test's CWD is the package directory and the CRDs live two levels up.
80+
// crdBasesDir resolves the chart's raw generated CRDs relative to this test
81+
// file — go test's CWD is the package directory and the CRDs (written by
82+
// `make manifests`) live under charts/etcd-operator/crd-bases two levels up.
8283
func crdBasesDir() string {
8384
_, here, _, _ := runtime.Caller(0)
84-
return filepath.Join(filepath.Dir(here), "..", "..", "config", "crd", "bases")
85+
return filepath.Join(filepath.Dir(here), "..", "..", "charts", "etcd-operator", "crd-bases")
8586
}
8687

8788
func ptr32(v int32) *int32 { return &v }

charts/etcd-operator/crds/etcd-operator.cozystack.io_etcdclusters.yaml renamed to charts/etcd-operator/crd-bases/etcd-operator.cozystack.io_etcdclusters.yaml

File renamed without changes.

charts/etcd-operator/crds/etcd-operator.cozystack.io_etcdmembers.yaml renamed to charts/etcd-operator/crd-bases/etcd-operator.cozystack.io_etcdmembers.yaml

File renamed without changes.

charts/etcd-operator/crds/etcd-operator.cozystack.io_etcdsnapshots.yaml renamed to charts/etcd-operator/crd-bases/etcd-operator.cozystack.io_etcdsnapshots.yaml

File renamed without changes.

0 commit comments

Comments
 (0)