Skip to content

Commit 3f181ba

Browse files
authored
scaffolds maintainer-d API and workspaces for kcp (#23)
First-pass implementation #22 that sets up new CRDs, schema exports, binding manifests and some Makefile targets and docs for kcp. Also includes a partial synchronistation of those CRDs from data in the database.
2 parents ae9455b + 5d66695 commit 3f181ba

35 files changed

+5787
-44
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ demo.db
99
.dirlocals.el
1010
./db/db
1111
.gocache/
12+
.modcache/
1213
coverage.out

.golangci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ version: "2"
22
run:
33
modules-download-mode: readonly
44
tests: true
5+
skip-dirs:
6+
- .modcache
7+
- .gocache
58
linters:
69
enable:
710
- bodyclose

Makefile

Lines changed: 125 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,52 @@
11
TOPDIR=$(PWD)
2-
GH_ORG_LC="robertkielty"
2+
GH_ORG_LC=robertkielty
33
REGISTRY ?= ghcr.io
44
IMAGE ?= $(REGISTRY)/$(GH_ORG_LC)/maintainerd:latest
5+
SYNC_IMAGE ?= $(REGISTRY)/$(GH_ORG_LC)/maintainerd-sync:latest
56
WHOAMI=$(shell whoami)
67

78
# Helpful context string for logs
89
CTX_STR := $(if $(KUBECONTEXT),$(KUBECONTEXT),$(shell kubectl config current-context 2>/dev/null || echo current))
910

11+
# kcp release download settings
12+
KCP_VERSION ?= 0.28.3
13+
KCP_TAG ?= v$(KCP_VERSION)
14+
KCP_OS ?= $(shell uname | tr '[:upper:]' '[:lower:]')
15+
KCP_ARCH ?= $(shell uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')
16+
KCP_TAR ?= kcp_$(KCP_VERSION)_$(KCP_OS)_$(KCP_ARCH).tar.gz
17+
APIGEN_TAR ?= apigen_$(KCP_VERSION)_$(KCP_OS)_$(KCP_ARCH).tar.gz
18+
KCP_CHECKSUMS ?= kcp_$(KCP_VERSION)_checksums.txt
19+
KCP_RELEASE_URL ?= https://github.com/kcp-dev/kcp/releases/download/$(KCP_TAG)
20+
BIN_DIR ?= $(TOPDIR)/bin
21+
KCP_BIN := $(BIN_DIR)/kcp
22+
APIGEN_BIN := $(BIN_DIR)/apigen
23+
CONTROLLER_GEN ?= $(BIN_DIR)/controller-gen
24+
APIGEN ?= $(APIGEN_BIN)
25+
GOCACHE_DIR ?= $(TOPDIR)/.gocache
26+
KCP_CRD_DIR ?= $(TOPDIR)/config/crd/bases
27+
KCP_SCHEMA_DIR ?= $(TOPDIR)/config/kcp
28+
KCP_RESOURCES := $(shell ls $(KCP_CRD_DIR)/maintainer-d.cncf.io_*.yaml 2>/dev/null | sed -E 's@.*/maintainer-d\.cncf\.io_([^.]*)\.yaml@\1@')
29+
GOFMT_PATHS ?= $(shell go list -f '{{.Dir}}' ./...)
30+
1031
# GHCR auth (optional for push). If set, we will docker login before push.
1132
GHCR_USER ?= $(DOCKER_REGISTRY_USERNAME)
1233
GHCR_TOKEN ?= $(GITHUB_GHCR_TOKEN)
1334

1435

1536

1637
# ---- Image ----
17-
.PHONY: image
18-
image:
38+
.PHONY: image-build
39+
image-build:
1940
@echo "Building container image: $(IMAGE)"
2041
@docker buildx build -t $(IMAGE) -f Dockerfile .
42+
43+
.PHONY: sync-image-build
44+
sync-image-build:
45+
@echo "Building sync image: $(SYNC_IMAGE)"
46+
@docker buildx build -t $(SYNC_IMAGE) -f deploy/sync/Dockerfile .
47+
48+
.PHONY: image-push
49+
image-push: image-build
2150
@echo "Ensuring docker is logged in to $(REGISTRY) (uses GHCR_TOKEN if set)"
2251
@if [ -n "$(GHCR_TOKEN)" ]; then \
2352
echo "Logging into $(REGISTRY) as $(GHCR_USER) using token from GHCR_TOKEN"; \
@@ -27,6 +56,9 @@ image:
2756
fi
2857
@echo "Pushing image: $(IMAGE)"
2958
@docker push $(IMAGE)
59+
60+
.PHONY: image-deploy
61+
image-deploy: image-push
3062
@echo "Image pushed. Attempting rollout on context $(CTX_STR)."
3163
@CTX_FLAG="$(if $(KUBECONTEXT),--context $(KUBECONTEXT))" ; \
3264
if kubectl $$CTX_FLAG config current-context >/dev/null 2>&1; then \
@@ -40,8 +72,41 @@ image:
4072
echo "kubectl context $(CTX_STR) unavailable; skipping rollout"; \
4173
fi
4274

43-
.PHONY: image-push
44-
image-push: image
75+
.PHONY: sync-image-push
76+
sync-image-push: sync-image-build
77+
@echo "Ensuring docker is logged in to $(REGISTRY) (uses GHCR_TOKEN if set)"
78+
@if [ -n "$(GHCR_TOKEN)" ]; then \
79+
echo "Logging into $(REGISTRY) as $(GHCR_USER) using token from GHCR_TOKEN"; \
80+
echo "$(GHCR_TOKEN)" | docker login $(REGISTRY) -u "$(GHCR_USER)" --password-stdin; \
81+
else \
82+
echo "GHCR_TOKEN not set; attempting push with existing docker auth"; \
83+
fi
84+
@echo "Pushing image: $(SYNC_IMAGE)"
85+
@docker push $(SYNC_IMAGE)
86+
87+
.PHONY: sync-image-deploy
88+
sync-image-deploy: sync-image-push
89+
@echo "Image pushed. Updating CronJob/maintainer-sync in $(NAMESPACE) [ctx=$(CTX_STR)]"
90+
@CTX_FLAG="$(if $(KUBECONTEXT),--context $(KUBECONTEXT))" ; \
91+
if ! kubectl $$CTX_FLAG config current-context >/dev/null 2>&1; then \
92+
echo "kubectl context $(CTX_STR) unavailable; skipping rollout"; exit 0; \
93+
fi ; \
94+
if ! kubectl -n $(NAMESPACE) $$CTX_FLAG get cronjob/maintainer-sync >/dev/null 2>&1; then \
95+
echo "CronJob/maintainer-sync not found in namespace $(NAMESPACE)."; \
96+
echo "Hint: apply deploy/manifests/sync.yaml or run 'make sync-apply' (or 'make manifests-apply')."; \
97+
exit 1; \
98+
fi ; \
99+
kubectl -n $(NAMESPACE) $$CTX_FLAG set image cronjob/maintainer-sync '*=$(SYNC_IMAGE)'; \
100+
kubectl -n $(NAMESPACE) $$CTX_FLAG delete job -l job-name=maintainer-sync --ignore-not-found; \
101+
echo "Next scheduled run will pull $(SYNC_IMAGE)."
102+
103+
.PHONY: sync-apply
104+
sync-apply:
105+
@echo "Applying sync resources in namespace $(NAMESPACE) [ctx=$(CTX_STR)]"
106+
@kubectl -n $(NAMESPACE) $(if $(KUBECONTEXT),--context $(KUBECONTEXT)) apply -f deploy/manifests/sync.yaml
107+
108+
.PHONY: image
109+
image: image-build
45110
@true
46111

47112
.PHONY: image-run
@@ -52,7 +117,7 @@ image-run: image
52117
NAMESPACE ?= maintainerd
53118
ENVSRC ?= .envrc
54119
ENVOUT ?= bootstrap.env
55-
KUBECONTEXT ?=context-cdv2c4jfn5q
120+
KUBECONTEXT ?=
56121

57122

58123
# Secret names (keep these stable across clusters)
@@ -87,8 +152,9 @@ help:
87152
@echo "make apply-creds -> create/update $(CREDS_SECRET_NAME) from $(CREDS_FILE)"
88153
@echo "make clean-env -> remove $(ENVOUT)"
89154
@echo "make print -> show which keys would be loaded (without values)"
90-
@echo "make image -> build+push $(IMAGE), then restart Deployment in $(NAMESPACE)"
91-
@echo " (uses GHCR_TOKEN/GITHUB_GHCR_TOKEN + GHCR_USER/DOCKER_REGISTRY_USERNAME for ghcr login)"
155+
@echo "make image-build -> build container image $(IMAGE) locally"
156+
@echo "make image-push -> build and push $(IMAGE) (uses GHCR_TOKEN/GITHUB_GHCR_TOKEN + GHCR_USER/DOCKER_REGISTRY_USERNAME for ghcr login)"
157+
@echo "make image-deploy -> build, push, and restart Deployment in $(NAMESPACE)"
92158
@echo "make ensure-ns -> ensure namespace $(NAMESPACE) exists"
93159
@echo "make apply-ghcr-secret -> create/update docker-registry Secret 'ghcr-secret'"
94160
@echo "make manifests-apply -> kubectl apply -f deploy/manifests (prod-only)"
@@ -99,6 +165,7 @@ help:
99165
@echo "make maintainerd-drain -> scale Deployment/maintainerd to 0 and wait for pods to exit"
100166
@echo "make maintainerd-port-forward -> forward :2525 -> svc/maintainerd:2525"
101167
@echo "make cluster-down -> delete manifests applied via deploy/manifests"
168+
@echo "make kcp-install -> download kcp $(KCP_VERSION) binaries into $(BIN_DIR)"
102169

103170
# Convert .envrc (export FOO=bar) to KEY=VALUE lines
104171
# - drops comments/blank lines
@@ -208,6 +275,47 @@ maintainerd-port-forward:
208275
@echo "Port-forwarding localhost:2525 -> service/maintainerd:2525 [ctx=$(CTX_STR)]"
209276
@kubectl -n $(NAMESPACE) $(if $(KUBECONTEXT),--context $(KUBECONTEXT)) port-forward svc/maintainerd 2525:2525
210277

278+
.PHONY: kcp-install
279+
kcp-install:
280+
@mkdir -p $(BIN_DIR)
281+
@echo "Fetching kcp $(KCP_VERSION) for $(KCP_OS)/$(KCP_ARCH)"
282+
@TMP_DIR=$$(mktemp -d); \
283+
set -euo pipefail; \
284+
echo "+ curl -sSL $(KCP_RELEASE_URL)/$(KCP_CHECKSUMS)"; \
285+
curl -sSL -o $$TMP_DIR/$(KCP_CHECKSUMS) $(KCP_RELEASE_URL)/$(KCP_CHECKSUMS); \
286+
for tarball in $(KCP_TAR) $(APIGEN_TAR); do \
287+
echo "+ curl -sSL $(KCP_RELEASE_URL)/$$tarball -o $$TMP_DIR/$$tarball"; \
288+
curl -sSL -o $$TMP_DIR/$$tarball $(KCP_RELEASE_URL)/$$tarball; \
289+
grep " $$tarball$$" $$TMP_DIR/$(KCP_CHECKSUMS) > $$TMP_DIR/$$tarball.sha256; \
290+
SUM=$$(cut -d' ' -f1 $$TMP_DIR/$$tarball.sha256); \
291+
( cd $$TMP_DIR && sha256sum --check $$tarball.sha256 ); \
292+
echo "Verified $$tarball (sha256=$$SUM)"; \
293+
done; \
294+
tar -xzf $$TMP_DIR/$(KCP_TAR) -C $(BIN_DIR) --strip-components=1 bin/kcp; \
295+
tar -xzf $$TMP_DIR/$(APIGEN_TAR) -C $(BIN_DIR) --strip-components=1 bin/apigen; \
296+
chmod +x $(KCP_BIN) $(APIGEN_BIN); \
297+
rm -rf $$TMP_DIR; \
298+
echo "Installed kcp and apigen into $(BIN_DIR)"
299+
300+
.PHONY: kcp-generate
301+
kcp-generate:
302+
@[ -x "$(CONTROLLER_GEN)" ] || { echo "Missing controller-gen binary at $(CONTROLLER_GEN). Install it or set CONTROLLER_GEN to the binary path."; exit 1; }
303+
@[ -x "$(APIGEN)" ] || { echo "Missing apigen binary at $(APIGEN). Run 'make kcp-install' or download it manually."; exit 1; }
304+
@mkdir -p $(GOCACHE_DIR) $(KCP_CRD_DIR) $(KCP_SCHEMA_DIR)
305+
@echo "Generating CustomResourceDefinitions in $(KCP_CRD_DIR)"
306+
@GOCACHE=$(GOCACHE_DIR) $(CONTROLLER_GEN) crd paths=./apis/... output:crd:dir=$(KCP_CRD_DIR)
307+
@rm -f $(KCP_CRD_DIR)/_.yaml
308+
@TMP_DIR=$$(mktemp -d); \
309+
set -euo pipefail; \
310+
echo "Rendering APIResourceSchemas with apigen"; \
311+
$(APIGEN) --input-dir $(KCP_CRD_DIR) --output-dir $$TMP_DIR; \
312+
for resource in $(KCP_RESOURCES); do \
313+
cp $$TMP_DIR/apiresourceschema-$$resource.maintainer-d.cncf.io.yaml $(KCP_SCHEMA_DIR)/schema-$$resource.yaml; \
314+
done; \
315+
cp $$TMP_DIR/apiexport-maintainer-d.cncf.io.yaml $(KCP_SCHEMA_DIR)/api-export.yaml; \
316+
rm -rf $$TMP_DIR; \
317+
echo "Updated APIExport and APIResourceSchemas in $(KCP_SCHEMA_DIR)"
318+
211319
# ---- Testing and CI ----
212320
.PHONY: test
213321
test:
@@ -247,25 +355,20 @@ ci-local:
247355
@echo "→ Verifying dependencies..."
248356
@go mod verify
249357
@echo "→ Running go fmt..."
250-
@if [ "$$(gofmt -s -l . | wc -l)" -gt 0 ]; then \
251-
echo "❌ Code needs formatting. Run: go fmt ./..."; \
252-
gofmt -s -l .; \
358+
@GOFILES="$$(find . -path './.modcache' -prune -o -path './.gocache' -prune -o -path './.git' -prune -o -name '*.go' -print)"; \
359+
if [ "$$(gofmt -s -l $$GOFILES | wc -l)" -gt 0 ]; then \
360+
echo "❌ Code needs formatting. Run: gofmt -w $$(echo $$GOFILES)"; \
361+
gofmt -s -l $$GOFILES; \
253362
exit 1; \
254363
fi
255364
@echo "→ Running go vet..."
256-
@go vet ./...
365+
@go vet # ./...
257366
@echo "→ Running staticcheck..."
258-
@if command -v staticcheck >/dev/null 2>&1; then \
259-
staticcheck ./...; \
260-
else \
261-
echo "⚠️ staticcheck not installed. Run: go install honnef.co/go/tools/cmd/staticcheck@latest"; \
262-
fi
367+
@command -v staticcheck >/dev/null 2>&1 || { echo "staticcheck not installed. Run: go install honnef.co/go/tools/cmd/staticcheck@latest"; exit 1; }
368+
@staticcheck # ./...
263369
@echo "→ Running golangci-lint..."
264-
@if command -v golangci-lint >/dev/null 2>&1; then \
265-
golangci-lint run ./...; \
266-
else \
267-
echo "⚠️ golangci-lint not installed. Run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
268-
fi
370+
@command -v golangci-lint >/dev/null 2>&1 || { echo "golangci-lint not installed. Run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; exit 1; }
371+
@golangci-lint run ./...
269372
@echo "→ Running tests with race detector..."
270373
@go test -race -coverprofile=coverage.out -covermode=atomic ./...
271374
@echo "→ Coverage report:"

apis/maintainers/v1alpha1/groupversion_info.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ var SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
2424
// AddToScheme adds the types in this group-version to the given scheme.
2525
var AddToScheme = SchemeBuilder.AddToScheme
2626

27-
// addKnownTypes adds the set of types defined in this package to the supplied scheme.
28-
func addKnownTypes(scheme *runtime.Scheme) error {
29-
scheme.AddKnownTypes(SchemeGroupVersion)
30-
return nil
31-
}
32-
3327
// Resource takes an unqualified resource and returns a Group qualified GroupResource.
3428
func Resource(resource string) schema.GroupResource {
3529
return SchemeGroupVersion.WithResource(resource).GroupResource()

0 commit comments

Comments
 (0)