-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathMakefile
More file actions
executable file
·378 lines (326 loc) · 14.1 KB
/
Makefile
File metadata and controls
executable file
·378 lines (326 loc) · 14.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
.DEFAULT_GOAL := help
# Include bingo-managed tool variables
include .bingo/Variables.mk
# CGO_ENABLED=0 is not FIPS compliant. large commercial vendors and FedRAMP require FIPS compliant crypto
# Use ?= to allow Dockerfile to override (CGO_ENABLED=0 for Alpine-based dev images)
CGO_ENABLED ?= 1
GO ?= go
# Auto-detect container tool (podman preferred when available)
CONTAINER_TOOL ?= $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)
.PHONY: check-container-tool
check-container-tool:
ifndef CONTAINER_TOOL
@echo "Error: No container tool found (podman or docker)"
@echo ""
@echo "Please install one of:"
@echo " brew install podman # macOS"
@echo " brew install docker # macOS"
@echo " dnf install podman # Fedora/RHEL"
@exit 1
endif
# Version information
GIT_SHA ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
GIT_DIRTY ?= $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] || echo "-modified")
APP_VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "0.0.0-dev")
BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
# Go build flags
GOFLAGS ?= -trimpath
LDFLAGS := -s -w \
-X github.com/openshift-hyperfleet/hyperfleet-api/pkg/api.Version=$(APP_VERSION) \
-X github.com/openshift-hyperfleet/hyperfleet-api/pkg/api.Commit=$(GIT_SHA) \
-X 'github.com/openshift-hyperfleet/hyperfleet-api/pkg/api.BuildTime=$(BUILD_DATE)'
# =============================================================================
# Image Configuration
# =============================================================================
IMAGE_REGISTRY ?= quay.io/openshift-hyperfleet
IMAGE_NAME ?= hyperfleet-api
IMAGE_TAG ?= $(APP_VERSION)
PLATFORM ?= linux/amd64
# Dev image configuration - set QUAY_USER to push to personal registry
# Usage: QUAY_USER=myuser make image-dev
QUAY_USER ?=
DEV_TAG ?= dev-$(GIT_SHA)
DEV_BASE_IMAGE ?= registry.access.redhat.com/ubi9/ubi-minimal:latest
# Encourage consistent tool versions
OPENAPI_GENERATOR_VERSION := 5.4.0
GO_VERSION := go1.25.
# Database connection details
db_name := hyperfleet
db_port := 5432
db_user := hyperfleet
db_password := foobar-bizz-buzz
db_password_file := ${PWD}/secrets/db.password
db_sslmode := disable
db_image ?= docker.io/library/postgres:14.2
# Location of the JSON web key set used to verify tokens
jwks_url := https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/certs
# Test output files
unit_test_json_output ?= ${PWD}/unit-test-results.json
integration_test_json_output ?= ${PWD}/integration-test-results.json
### Environment-sourced variables with defaults
ifndef OCM_ENV
OCM_ENV := development
endif
ifndef TEST_SUMMARY_FORMAT
TEST_SUMMARY_FORMAT = short-verbose
endif
ifndef OCM_BASE_URL
OCM_BASE_URL := "https://api.integration.openshift.com"
endif
.PHONY: help
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_\/-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Code Quality
.PHONY: verify
verify: ## Verify source passes standard checks
${GO} vet \
./cmd/... \
./pkg/...
! gofmt -l cmd pkg test |\
sed 's/^/Unformatted file: /' |\
grep .
@ ${GO} version | grep -q "$(GO_VERSION)" || \
( \
printf '\033[41m\033[97m\n'; \
echo "* Your go version is not the expected $(GO_VERSION) *" | sed 's/./*/g'; \
echo "* Your go version is not the expected $(GO_VERSION) *"; \
echo "* Your go version is not the expected $(GO_VERSION) *" | sed 's/./*/g'; \
printf '\033[0m'; \
)
.PHONY: lint
lint: $(GOLANGCI_LINT) ## Run golangci-lint
$(GOLANGCI_LINT) run ./cmd/... ./pkg/... ./test/...
##@ Code Generation
.PHONY: generate
generate: $(OAPI_CODEGEN) ## Generate OpenAPI types using oapi-codegen
rm -rf pkg/api/openapi
mkdir -p pkg/api/openapi
$(OAPI_CODEGEN) --config openapi/oapi-codegen.yaml openapi/openapi.yaml
.PHONY: generate-mocks
generate-mocks: $(MOCKGEN) ## Generate mock implementations for services
${GO} generate ./pkg/services/...
.PHONY: generate-all
generate-all: generate generate-mocks ## Generate all code (openapi + mocks)
.PHONY: generate-vendor
generate-vendor: generate
##@ Development
.PHONY: build
build: generate-all ## Build the hyperfleet-api binary
@mkdir -p bin
@echo "Building version: ${APP_VERSION}"
CGO_ENABLED=$(CGO_ENABLED) GOEXPERIMENT=boringcrypto ${GO} build $(GOFLAGS) -ldflags="$(LDFLAGS)" -o bin/hyperfleet-api ./cmd/hyperfleet-api
.PHONY: install
install: generate-all ## Build and install binary to GOPATH/bin
CGO_ENABLED=$(CGO_ENABLED) GOEXPERIMENT=boringcrypto ${GO} install $(GOFLAGS) -ldflags="$(LDFLAGS)" ./cmd/hyperfleet-api
.PHONY: run
run: build ## Run the application
./bin/hyperfleet-api migrate
./bin/hyperfleet-api serve
.PHONY: run-no-auth
run-no-auth: build ## Run the application without auth
./bin/hyperfleet-api migrate
./bin/hyperfleet-api serve --enable-authz=false --enable-jwt=false
.PHONY: run/docs
run/docs: check-container-tool ## Run swagger and host the api spec
@echo "Please open http://localhost:8081/"
# Port 8081 instead of 80: ports <1024 are privileged and fail with rootless Podman.
# Port 8080 is avoided since it's used by the health endpoint server.
$(CONTAINER_TOOL) run -d -p 8081:8080 -e SWAGGER_JSON=/hyperfleet.yaml -v $(PWD)/openapi/hyperfleet.yaml:/hyperfleet.yaml swaggerapi/swagger-ui
.PHONY: cmds
cmds: ## Build all binaries under cmd/
@mkdir -p bin
for cmd in $$(ls cmd); do \
CGO_ENABLED=$(CGO_ENABLED) GOEXPERIMENT=boringcrypto ${GO} build \
$(GOFLAGS) \
-ldflags="$(LDFLAGS)" \
-o "bin/$${cmd}" \
"./cmd/$${cmd}" \
|| exit 1; \
done
.PHONY: clean
clean: ## Delete temporary generated files
rm -rf \
bin \
pkg/api/openapi \
data/generated/openapi/*.json \
secrets \
.PHONY: secrets
secrets: ## Initialize secrets directory with default values
@mkdir -p secrets
@printf "localhost" > secrets/db.host
@printf "$(db_name)" > secrets/db.name
@printf "$(db_password)" > secrets/db.password
@printf "$(db_port)" > secrets/db.port
@printf "$(db_user)" > secrets/db.user
@printf "ocm-hyperfleet-testing" > secrets/ocm-service.clientId
@printf "your-client-secret-here" > secrets/ocm-service.clientSecret
@printf "your-token-here" > secrets/ocm-service.token
@echo "Secrets directory initialized with default values"
##@ Testing
.PHONY: test
test: install secrets $(GOTESTSUM) ## Run unit tests
OCM_ENV=unit_testing $(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
./pkg/... \
./cmd/...
.PHONY: ci-test-unit
ci-test-unit: install secrets $(GOTESTSUM) ## Run unit tests with JSON output
OCM_ENV=unit_testing $(GOTESTSUM) --jsonfile-timing-events=$(unit_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -v $(TESTFLAGS) \
./pkg/... \
./cmd/...
.PHONY: test-integration
test-integration: install secrets $(GOTESTSUM) ## Run integration tests
TESTCONTAINERS_RYUK_DISABLED=true OCM_ENV=integration_testing $(GOTESTSUM) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
./test/integration
.PHONY: ci-test-integration
ci-test-integration: install secrets $(GOTESTSUM) ## Run integration tests with JSON output
TESTCONTAINERS_RYUK_DISABLED=true OCM_ENV=integration_testing $(GOTESTSUM) --jsonfile-timing-events=$(integration_test_json_output) --format $(TEST_SUMMARY_FORMAT) -- -p 1 -ldflags -s -v -timeout 1h $(TESTFLAGS) \
./test/integration
.PHONY: test-all
test-all: lint test test-integration test-helm ## Run all checks (lint, unit, integration, helm)
##@ Agent Verification
.PHONY: verify-all
verify-all: verify lint test ## Run all static checks + unit tests (no database required)
@echo "All static checks and unit tests passed."
@echo "Run 'make test-integration' separately for integration tests (requires database)."
##@ Database
.PHONY: db/setup
db/setup: check-container-tool secrets ## Start local PostgreSQL container
@echo $(db_password) > $(db_password_file)
$(CONTAINER_TOOL) run --name psql-hyperfleet -e POSTGRES_DB=$(db_name) -e POSTGRES_USER=$(db_user) -e POSTGRES_PASSWORD=$(db_password) -p $(db_port):5432 -d $(db_image)
.PHONY: db/login
db/login: check-container-tool ## Login to local PostgreSQL
$(CONTAINER_TOOL) exec -it psql-hyperfleet bash -c "psql -h localhost -U $(db_user) $(db_name)"
.PHONY: db/teardown
db/teardown: check-container-tool ## Stop and remove local PostgreSQL container
$(CONTAINER_TOOL) stop psql-hyperfleet
$(CONTAINER_TOOL) rm psql-hyperfleet
##@ Container Images
.PHONY: test-helm
test-helm: ## Test Helm charts (lint, template, validate)
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo "Testing Helm charts..."
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@if ! command -v helm > /dev/null; then \
echo "Error: helm not found. Please install Helm:"; \
echo " brew install helm # macOS"; \
echo " curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # Linux"; \
exit 1; \
fi
@echo "Linting Helm chart..."
helm lint charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]'
@echo ""
@echo "Testing template rendering with default values..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' > /dev/null
@echo "Default values template OK"
@echo ""
@echo "Testing template with external database..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set database.postgresql.enabled=false \
--set database.external.enabled=true \
--set database.external.secretName=my-db-secret > /dev/null
@echo "External database config template OK"
@echo ""
@echo "Testing template with autoscaling..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set autoscaling.enabled=true \
--set autoscaling.minReplicas=2 \
--set autoscaling.maxReplicas=5 > /dev/null
@echo "Autoscaling config template OK"
@echo ""
@echo "Testing template with PDB enabled..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set podDisruptionBudget.enabled=true \
--set podDisruptionBudget.minAvailable=1 > /dev/null
@echo "PDB config template OK"
@echo ""
@echo "Testing template with ServiceMonitor enabled..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set serviceMonitor.enabled=true \
--set serviceMonitor.interval=15s > /dev/null
@echo "ServiceMonitor config template OK"
@echo ""
@echo "Testing template with auth disabled..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set auth.enableJwt=false \
--set auth.enableAuthz=false > /dev/null
@echo "Auth disabled config template OK"
@echo ""
@echo "Testing template with custom image..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set image.registry=quay.io/myorg \
--set image.repository=hyperfleet-api \
--set image.tag=v1.0.0 > /dev/null
@echo "Custom image config template OK"
@echo ""
@echo "Testing template with pgbouncer enabled..."
helm template test-release charts/ \
--set 'adapters.cluster=["validation"]' \
--set 'adapters.nodepool=["validation"]' \
--set database.pgbouncer.enabled=true > /dev/null
@echo "PgBouncer sidecar config template OK"
@echo ""
@echo "Testing template with full adapter config..."
helm template test-release charts/ \
--set-json 'adapters.cluster=["validation","dns","pullsecret","hypershift"]' \
--set-json 'adapters.nodepool=["validation","hypershift"]' > /dev/null
@echo "Full adapter config template OK"
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo "All Helm chart tests passed!"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Build container image (multi-stage build, no local binary needed)
.PHONY: image
image: check-container-tool ## Build container image with configurable registry/tag
@echo "Building container image $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)..."
$(CONTAINER_TOOL) build \
--platform $(PLATFORM) \
--build-arg GIT_SHA=$(GIT_SHA) \
--build-arg GIT_DIRTY=$(GIT_DIRTY) \
--build-arg BUILD_DATE=$(BUILD_DATE) \
--build-arg APP_VERSION=$(APP_VERSION) \
-t $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) .
@echo "Image built: $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)"
.PHONY: image-push
image-push: image ## Build and push container image
@echo "Pushing image $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)..."
$(CONTAINER_TOOL) push $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
@echo "Image pushed: $(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)"
.PHONY: image-dev
image-dev: check-container-tool ## Build and push to personal Quay registry (requires QUAY_USER)
ifeq ($(strip $(QUAY_USER)),)
@echo "Error: QUAY_USER is not set"
@echo ""
@echo "Usage: QUAY_USER=myuser make image-dev"
@echo ""
@echo "This will build and push to: quay.io/$$QUAY_USER/$(IMAGE_NAME):$(DEV_TAG)"
@exit 1
endif
@echo "Building dev image quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)..."
$(CONTAINER_TOOL) build \
--platform $(PLATFORM) \
--build-arg BASE_IMAGE=$(DEV_BASE_IMAGE) \
--build-arg GIT_SHA=$(GIT_SHA) \
--build-arg GIT_DIRTY=$(GIT_DIRTY) \
--build-arg BUILD_DATE=$(BUILD_DATE) \
--build-arg APP_VERSION=0.0.0-dev \
-t quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG) .
@echo "Pushing dev image..."
$(CONTAINER_TOOL) push quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)
@echo ""
@echo "Dev image pushed: quay.io/$(QUAY_USER)/$(IMAGE_NAME):$(DEV_TAG)"