forked from skyhook-io/radar
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
450 lines (375 loc) · 17.1 KB
/
Copy pathMakefile
File metadata and controls
450 lines (375 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
.PHONY: build install clean dev frontend backend test test-e2e test-chart lint help restart restart-fe kill watch-backend watch-frontend loadtest
.PHONY: calico-demo calico-demo-down calico-demo-status
.PHONY: release release-binaries-dry docker docker-test docker-multiarch docker-push
.PHONY: desktop desktop-binary desktop-dev desktop-package-darwin desktop-package-windows desktop-package-linux
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS := -X main.version=$(VERSION)
DOCKER_REPO ?= ghcr.io/skyhook-io/radar
RADAR_FLAGS ?=
PORT ?= 9280
## Quick in-cluster test deploy (full build: frontend + embed + Go binary)
# Usage: make deploy-test (or make deploy-test TEST_IMAGE=... CLUSTER_NS=... CLUSTER_DEPLOY=...)
TEST_IMAGE ?= gcr.io/koalabackend/radar:auth-rbac
CLUSTER_NS ?= radar
CLUSTER_DEPLOY ?= radar
deploy-test: frontend embed
@echo "=== Fast test deploy: Go build → push → rollout ==="
@echo "Building Go binary for linux/amd64..."
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o /tmp/radar-linux ./cmd/explorer
@echo "Building minimal Docker image..."
@echo 'FROM gcr.io/distroless/static-debian12:nonroot' > /tmp/Dockerfile.test
@echo 'COPY radar-linux /app/radar' >> /tmp/Dockerfile.test
@echo 'ENTRYPOINT ["/app/radar"]' >> /tmp/Dockerfile.test
docker build -t $(TEST_IMAGE) -f /tmp/Dockerfile.test /tmp
docker push $(TEST_IMAGE)
kubectl rollout restart deploy/$(CLUSTER_DEPLOY) -n $(CLUSTER_NS)
kubectl rollout status deploy/$(CLUSTER_DEPLOY) -n $(CLUSTER_NS) --timeout=60s
@echo "=== Done. Tail logs: kubectl logs -n $(CLUSTER_NS) -l app.kubernetes.io/name=$(CLUSTER_DEPLOY) -f ==="
# Build a probe image from the CURRENT code and load it into a kind cluster, for
# developing the in-cluster reachability probe. A -dirty local build's version is
# not a published tag, so the default image won't exist - load a local one and run
# radar with --reachability-image $(PROBE_IMAGE). Binary path /radar + ENTRYPOINT
# match the official image so the probe Job's `["/radar","probe",...]` command works.
KIND_CLUSTER ?= test
PROBE_IMAGE ?= radar-probe:dev
kind-load-probe:
@echo "Building probe binary for linux/$$(go env GOARCH)..."
GOOS=linux GOARCH=$$(go env GOARCH) CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o /tmp/radar-probe-bin ./cmd/explorer
@echo 'FROM gcr.io/distroless/static-debian12:nonroot' > /tmp/Dockerfile.probe
@echo 'COPY radar-probe-bin /radar' >> /tmp/Dockerfile.probe
@echo 'ENTRYPOINT ["/radar"]' >> /tmp/Dockerfile.probe
docker build -t $(PROBE_IMAGE) -f /tmp/Dockerfile.probe /tmp
kind load docker-image $(PROBE_IMAGE) --name $(KIND_CLUSTER)
@echo "Loaded $(PROBE_IMAGE) into kind/$(KIND_CLUSTER). Run radar with: --reachability-image $(PROBE_IMAGE)"
## Build targets
# Build the complete application (frontend + embedded binary)
build: frontend embed backend
@echo "Build complete: ./radar"
# Build and install to /usr/local/bin
install: build
@echo "Installing to /usr/local/bin/kubectl-radar..."
@cp radar /usr/local/bin/kubectl-radar || sudo cp radar /usr/local/bin/kubectl-radar
@echo "Installed! Run 'kubectl radar' or 'kubectl-radar'"
# Build Go backend with embedded frontend
backend:
@echo "Building Go backend..."
go build -ldflags "$(LDFLAGS)" -o radar ./cmd/explorer
# Build frontend (auto-installs deps if needed)
frontend:
@echo "Building frontend..."
@test -f node_modules/typescript-7/bin/tsc || (echo "Installing npm dependencies..." && npm install)
cd web && npm run build
# Copy built frontend to embed directory
embed:
@echo "Copying frontend to static..."
rm -rf internal/static/dist
@mkdir -p internal/static/dist
cp -r web/dist/* internal/static/dist/
## Development targets
# Quick rebuild and restart
restart: frontend embed backend kill
@sleep 1
./radar --kubeconfig ~/.kube/config --no-browser --port $(PORT) $(RADAR_FLAGS) &
@sleep 4
@echo "Server running at http://localhost:$(PORT)"
# Frontend-only rebuild and restart (faster - no Go recompile, serves from web/dist via --dev)
restart-fe: frontend kill
@sleep 1
./radar --dev --kubeconfig ~/.kube/config --no-browser --port $(PORT) $(RADAR_FLAGS) &
@sleep 4
@echo "Server running at http://localhost:$(PORT)"
# Hot reload development (run both in separate terminals)
# Terminal 1: make watch-frontend
# Terminal 2: make watch-backend
dev:
@echo "=== Development Mode ==="
@echo ""
@echo "Run these in separate terminals:"
@echo " Terminal 1: make watch-frontend (Vite dev server on :9273)"
@echo " Terminal 2: make watch-backend (Go with air on :9280)"
@echo ""
@echo "Frontend proxies API calls to backend automatically."
# Frontend with Vite hot reload
watch-frontend:
cd web && npm run dev
# Backend with air hot reload
# Pass extra flags: make watch-backend RADAR_FLAGS="--fake-in-cluster"
watch-backend:
@command -v air >/dev/null 2>&1 || { echo "Installing air..."; go install github.com/air-verse/air@latest; }
air -- $(RADAR_FLAGS)
# Run built binary
run:
./radar --kubeconfig ~/.kube/config
# Run in dev mode (serve frontend from web/dist instead of embedded)
run-dev:
./radar --kubeconfig ~/.kube/config --dev
## Utility targets
# Kill any running radar process (on configured port and by process name)
kill:
@lsof -ti:$(PORT) | xargs kill -9 2>/dev/null || true
@pkill -9 -f './radar' 2>/dev/null || true
# Install all dependencies
deps:
go mod download
go mod tidy
npm install
# Install dev tools
install-tools:
go install github.com/air-verse/air@latest
npm install
# Clean build artifacts
clean:
rm -f radar radar-desktop
rm -rf web/dist
rm -f internal/static/dist/index.html
rm -rf internal/static/dist/assets
# Run tests
test:
go test -v ./...
# Run e2e tests against the current kubeconfig cluster (on-demand, not in CI)
test-e2e:
go test -tags e2e -v -timeout 5m ./internal/k8s/
# Smoke-test the Helm chart's template rendering (requires `helm` on PATH)
test-chart:
./scripts/test-chart.sh
# Bootstrap a kind cluster pre-loaded with curated GitOps scenarios
# (Argo CD + Flux + healthy/suspended/app-of-apps/ApplicationSet/etc).
# Useful for visual-testing GitOps UI changes against realistic state.
# See scripts/gitops-demo/README.md for the full coverage matrix.
gitops-demo:
./scripts/gitops-demo.sh up
gitops-demo-down:
./scripts/gitops-demo.sh down
gitops-demo-status:
./scripts/gitops-demo.sh status
gitops-demo-drift:
./scripts/gitops-demo.sh drift
# Bootstrap a kind cluster pre-loaded with Kyverno 1.18.2 and curated policy
# fixtures (both API families, the four enforcement-posture cases, dual-API
# PolicyExceptions, and ~40 real PolicyReports across several sources).
# Useful for visual-testing policy UI changes against realistic state.
# See scripts/kyverno-demo/README.md for the coverage matrix — and read the
# 1.20-simulation warning before running `kyverno-demo.sh modern-only`.
kyverno-demo:
./scripts/kyverno-demo.sh up
kyverno-demo-down:
./scripts/kyverno-demo.sh down
kyverno-demo-status:
./scripts/kyverno-demo.sh status
# Bootstrap a kind cluster pre-loaded with Argo Rollouts scenarios
# (paused canary, inconclusive analysis, blue-green, aborted, workloadRef).
# Useful for visual-testing the Rollout control surface against real state.
# See scripts/rollouts-demo/README.md for the full coverage matrix.
rollouts-demo:
./scripts/rollouts-demo.sh up
rollouts-demo-down:
./scripts/rollouts-demo.sh down
rollouts-demo-status:
./scripts/rollouts-demo.sh status
rollouts-demo-roll:
./scripts/rollouts-demo.sh roll
# Bootstrap a kind cluster pre-loaded with curated Crossplane fixtures
# (core + provider-kubernetes + function-patch-and-transform + XRD/Composition/XRs).
# Useful for visual-testing Crossplane UI changes against realistic state.
# See scripts/crossplane-demo/README.md for the full coverage matrix.
crossplane-demo:
./scripts/crossplane-demo.sh up
crossplane-demo-down:
./scripts/crossplane-demo.sh down
crossplane-demo-status:
./scripts/crossplane-demo.sh status
# Load-test the UI at high object counts against a synthetic, resource-free fake
# cluster (no real workloads, no kubelet, no etcd). Radar treats the fakes as a
# real cluster. Seeds a topology-realistic Deployment->ReplicaSet->Pod population
# with matching Services/ConfigMaps/Secrets, spread across nodes and namespaces.
# The pod count is live-controllable via the admin listener (default <port>+1):
# curl -XPOST localhost:9282/loadtest/scale -d '{"pods":10000}'
# curl localhost:9282/loadtest/status
# Override the count with PODS and the port with LOADTEST_PORT.
LOADTEST_PORT ?= 9281
PODS ?= 50000
loadtest: frontend embed
go run ./cmd/testserver -port $(LOADTEST_PORT) -pods $(PODS)
# Bootstrap a kind cluster pre-loaded with curated Velero fixtures (all 13
# Backup phases, the supersession series, a paused+invalid Schedule, an
# unavailable BSL, a restic repository, and the rancher plural collision).
# The Velero controller is deliberately scaled to 0, so the fixtures' own
# status survives and all thirteen phases are on screen at once. Run
# ./scripts/velero-demo.sh live for the other half: MinIO plus a running
# controller, which earns the states instead of asserting them.
# See scripts/velero-demo/README.md for the coverage matrix.
velero-demo:
./scripts/velero-demo.sh up
velero-demo-live:
./scripts/velero-demo.sh live
velero-demo-down:
./scripts/velero-demo.sh down
velero-demo-status:
./scripts/velero-demo.sh status
# Bootstrap a kind cluster pre-loaded with curated CloudNativePG fixtures
# (four clusters all 2/2 Ready with four different badges, a real WAL-archiving
# failure, Pooler/ScheduledBackup/Backups, plus Velero + KubeBlocks CRs for the
# shared `backups`/`clusters` plurals).
# See scripts/cnpg-demo/README.md for the coverage matrix and, more importantly,
# why the WAL failure is induced rather than patched.
cnpg-demo:
./scripts/cnpg-demo.sh up
cnpg-demo-down:
./scripts/cnpg-demo.sh down
cnpg-demo-status:
./scripts/cnpg-demo.sh status
# Live CNPG operator for real failovers and backup runs. Frozen-only terminal
# phases and Backup rows are omitted because the controller owns them.
cnpg-demo-live:
./scripts/cnpg-demo.sh live
# Grafana Beyla on kind: eBPF loaded, a minimal Prometheus scraping it, and two
# conversations to observe. Which labels Beyla exports depends on configuration —
# dst_port and transport are off by default, direction is on and doubles every
# edge — so read scripts/beyla-demo/README.md before changing the Beyla source.
# `attrs` and `no-network` switch between the three configurations that matter.
beyla-demo:
./scripts/beyla-demo.sh up
beyla-demo-down:
./scripts/beyla-demo.sh down
beyla-demo-status:
./scripts/beyla-demo.sh status
# Bootstrap a kind cluster running real Calico with its aggregated API server,
# plus the policy shapes the Calico surfaces render (both API groups serving the
# same objects, all three staged kinds including a staged deletion, a non-default
# tier, IP pools and a HostEndpoint).
# See scripts/calico-demo/README.md for the coverage matrix and the two Calico
# behaviours that are easy to get wrong without a cluster to check against.
calico-demo:
./scripts/calico-demo.sh up
calico-demo-down:
./scripts/calico-demo.sh down
calico-demo-status:
./scripts/calico-demo.sh status
# Run linter
lint:
go vet ./...
# Type check frontend
tsc:
cd web && npm run tsc
# Format code
fmt:
go fmt ./...
# ============================================================================
# Docker & Helm
# ============================================================================
# Docker build (single arch, for local testing)
# Uses --target full to build from source (the default 'release' target requires pre-built binaries)
docker:
docker build --target full -t $(DOCKER_REPO):$(VERSION) -t $(DOCKER_REPO):latest .
# Test Docker image with read-only filesystem (simulates in-cluster with readOnlyRootFilesystem)
# Requires ~/.kube/config for cluster access; runs on port 9280
docker-test: docker
@echo "Starting Radar with read-only filesystem (simulating in-cluster)..."
@echo "Press Ctrl+C to stop"
docker run --rm \
--read-only \
--tmpfs /tmp \
-e HELM_CACHE_HOME=/tmp/helm/cache \
-e HELM_CONFIG_HOME=/tmp/helm/config \
-e HELM_DATA_HOME=/tmp/helm/data \
-v $(HOME)/.kube/config:/home/nonroot/.kube/config:ro \
-p 9280:9280 \
$(DOCKER_REPO):$(VERSION) --no-browser
# Docker build multi-arch (amd64 + arm64, for production)
docker-multiarch:
@docker buildx inspect radar-builder &>/dev/null || docker buildx create --name radar-builder --use
docker buildx use radar-builder
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg VERSION=$(VERSION) \
-t $(DOCKER_REPO):$(VERSION) \
-t $(DOCKER_REPO):latest \
--push \
.
docker-push:
docker push $(DOCKER_REPO):$(VERSION)
docker push $(DOCKER_REPO):latest
# ============================================================================
# Desktop (Wails) Targets
# ============================================================================
# Build desktop app: frontend + Go desktop binary
desktop: frontend embed desktop-binary
@echo "Desktop build complete: ./radar-desktop"
# Build desktop binary only (assumes frontend is already in internal/static/dist)
desktop-binary:
@echo "Building desktop binary..."
CGO_ENABLED=1 CGO_LDFLAGS="-framework UniformTypeIdentifiers" go build -tags production -ldflags "$(LDFLAGS)" -o radar-desktop ./cmd/desktop
# Run desktop app in Wails dev mode with Go hot reload.
# wails.json lives in cmd/desktop/ (Wails requires it next to the main package).
# Requires wails CLI: go install github.com/wailsapp/wails/v2/cmd/wails@latest
desktop-dev:
@command -v wails >/dev/null 2>&1 || { echo "Error: wails CLI not found. Install with: go install github.com/wailsapp/wails/v2/cmd/wails@latest"; exit 1; }
cd cmd/desktop && wails dev -ldflags "$(LDFLAGS)"
# Package macOS .app bundle
desktop-package-darwin:
@command -v wails >/dev/null 2>&1 || { echo "Error: wails CLI not found"; exit 1; }
cd cmd/desktop && wails build -platform darwin/universal -ldflags "$(LDFLAGS)"
# Package Windows .exe
desktop-package-windows:
@command -v wails >/dev/null 2>&1 || { echo "Error: wails CLI not found"; exit 1; }
cd cmd/desktop && wails build -platform windows/amd64 -ldflags "$(LDFLAGS)"
# Package Linux binary
desktop-package-linux:
@command -v wails >/dev/null 2>&1 || { echo "Error: wails CLI not found"; exit 1; }
cd cmd/desktop && wails build -platform linux/amd64 -ldflags "$(LDFLAGS)"
# ============================================================================
# Release Targets
# ============================================================================
# Dry run goreleaser (no publish)
release-binaries-dry:
@command -v goreleaser >/dev/null 2>&1 || { echo "Error: goreleaser not found"; exit 1; }
goreleaser release --snapshot --clean
# Interactive release (remote via CI or local)
release:
./scripts/release.sh
# ============================================================================
# Help
# ============================================================================
help:
@echo "Radar - Kubernetes Cluster Visualization"
@echo ""
@echo "Development:"
@echo " make build - Build CLI binary (frontend + embedded)"
@echo " make watch-frontend - Vite dev server with HMR (port 9273)"
@echo " make watch-backend - Go with air hot reload (port 9280)"
@echo " make run - Run built binary"
@echo " make test - Run tests"
@echo ""
@echo "Demo clusters:"
@echo " make gitops-demo - GitOps fixtures (Argo CD + Flux)"
@echo " make crossplane-demo - Crossplane fixtures"
@echo " make kyverno-demo - Live Kyverno policy + report fixtures"
@echo " make rollouts-demo - Argo Rollouts progression fixtures"
@echo " make cnpg-demo - Frozen CNPG rendering fixtures"
@echo " make cnpg-demo-live - CNPG fixtures with the operator running"
@echo " make velero-demo - Velero fixtures, all 13 backup phases at once"
@echo " make velero-demo-live - Velero with real object storage; states produced by the controller"
@echo " make beyla-demo - Grafana Beyla eBPF traffic fixtures"
@echo " make calico-demo - Real Calico, both API groups, staged policies"
@echo ""
@echo "Desktop:"
@echo " make desktop - Build desktop app (frontend + Wails binary)"
@echo " make desktop-binary - Build desktop binary only"
@echo " make desktop-dev - Run desktop in Wails dev mode"
@echo " make desktop-package-darwin - Package macOS .app bundle"
@echo ""
@echo "Docker & In-Cluster:"
@echo " make docker - Build Docker image (local arch)"
@echo " make docker-test - Build and run with read-only filesystem (simulates in-cluster)"
@echo " make docker-multiarch - Build multi-arch image (amd64+arm64) and push"
@echo " make docker-push - Push to GHCR"
@echo ""
@echo "Release:"
@echo " make release - Interactive release (remote via CI or local)"
@echo " make release-binaries-dry - Dry run goreleaser (no publish)"
@echo ""
@echo "Utility:"
@echo " make deps - Install all dependencies"
@echo " make install - Install CLI to /usr/local/bin"
@echo " make clean - Clean build artifacts"
@echo " make kill - Kill running server"