-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskfile.yaml
More file actions
351 lines (303 loc) · 11.8 KB
/
Copy pathTaskfile.yaml
File metadata and controls
351 lines (303 loc) · 11.8 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
version: '3'
vars:
TOOL_DIR: "{{.USER_WORKING_DIR}}/bin"
IPAM_IMAGE_NAME: "ipam-apiserver"
IPAM_IMAGE_TAG: "dev"
TEST_INFRA_CLUSTER_NAME: "test-infra"
TEST_INFRA_REPO_REF: 'v0.6.0'
includes:
test-infra:
taskfile: https://raw.githubusercontent.com/datum-cloud/test-infra/{{.TEST_INFRA_REPO_REF}}/Taskfile.yml
vars:
REPO_REF: "{{.TEST_INFRA_REPO_REF}}"
load:
taskfile: ./test/load/Taskfile.yaml
dir: ./test/load
# observability: dashboard generation + promtool/kubeconform CI gates.
# Tasks defined under config/components/observability/Taskfile.yaml are
# exposed here as `observability:<task>`.
observability:
taskfile: ./config/components/observability/Taskfile.yaml
dir: ./config/components/observability
tasks:
default:
desc: List all available tasks
cmds:
- task --list
silent: true
build:
desc: Build the ipam binary
cmds:
- |
set -e
mkdir -p {{.TOOL_DIR}}
GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
VERSION="v0.0.0-dev+${GIT_COMMIT:0:7}"
GIT_TREE_STATE="clean"
if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
GIT_TREE_STATE="dirty"
fi
BUILD_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || echo "unknown")
echo "Version: ${VERSION}, Commit: ${GIT_COMMIT:0:7}, Tree: ${GIT_TREE_STATE}"
go build \
-ldflags="-X 'go.miloapis.com/ipam/internal/version.Version=${VERSION}' \
-X 'go.miloapis.com/ipam/internal/version.GitCommit=${GIT_COMMIT}' \
-X 'go.miloapis.com/ipam/internal/version.GitTreeState=${GIT_TREE_STATE}' \
-X 'go.miloapis.com/ipam/internal/version.BuildDate=${BUILD_DATE}'" \
-o {{.TOOL_DIR}}/ipam ./cmd/ipam
echo "Binary built: {{.TOOL_DIR}}/ipam"
silent: true
plugin:build:
desc: Build the milo-ipam CLI plugin
cmds:
- |
set -e
mkdir -p {{.TOOL_DIR}}
go build -o {{.TOOL_DIR}}/milo-ipam ./cmd/milo-ipam
echo "Plugin built: {{.TOOL_DIR}}/milo-ipam"
silent: true
test:
desc: Run Go unit tests
cmd: go test -timeout 5m ./pkg/... ./internal/... -count=1
vet:
desc: Run go vet
cmd: go vet ./...
lint:
desc: Run golangci-lint
deps: [lint:install]
cmd: golangci-lint run ./...
lint:install:
desc: Install the golangci-lint version CI uses, built with this repo's Go
# A binary built with an older Go refuses this module outright: it reports
# "the Go language version used to build golangci-lint is lower than the
# targeted Go version" and lints nothing. `go install` builds it with the
# local toolchain, so it tracks whatever go.mod targets.
status:
- test "$(golangci-lint version --short 2>/dev/null)" = "{{.GOLANGCI_VERSION}}"
cmd: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v{{.GOLANGCI_VERSION}}
vars:
GOLANGCI_VERSION: 2.12.2
generate:
desc: Run code generation
silent: true
cmds:
- |
if [ -f "./hack/update-codegen.sh" ]; then
./hack/update-codegen.sh
else
echo "hack/update-codegen.sh not present yet"
fi
migrate:
desc: Run database migrations against $POSTGRES_DSN
deps: [build]
cmd: "{{.TOOL_DIR}}/ipam migrate up"
# ----- Container & cluster dev workflow -----
dev:build:
desc: Build the IPAM container image
silent: true
cmds:
- |
set -e
GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
VERSION="v0.0.0-dev+${GIT_COMMIT:0:7}"
GIT_TREE_STATE="clean"
if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
GIT_TREE_STATE="dirty"
fi
BUILD_DATE=$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || echo "unknown")
docker build \
--build-arg VERSION="${VERSION}" \
--build-arg GIT_COMMIT="${GIT_COMMIT}" \
--build-arg GIT_TREE_STATE="${GIT_TREE_STATE}" \
--build-arg BUILD_DATE="${BUILD_DATE}" \
-t "{{.IPAM_IMAGE_NAME}}:{{.IPAM_IMAGE_TAG}}" .
echo "Built {{.IPAM_IMAGE_NAME}}:{{.IPAM_IMAGE_TAG}}"
dev:load:
desc: Load the IPAM image into the kind cluster
cmd: kind load docker-image "{{.IPAM_IMAGE_NAME}}:{{.IPAM_IMAGE_TAG}}" --name "{{.TEST_INFRA_CLUSTER_NAME}}"
dev:install-dependencies:
desc: Install infra dependencies for dev (postgres via component)
silent: true
cmds:
- task test-infra:kubectl -- apply -k config/components/postgres
dev:deploy:
desc: Deploy IPAM via the dev overlay
silent: true
cmds:
- |
set -e
task test-infra:kubectl -- apply -k config/overlays/dev
task test-infra:kubectl -- wait --for=condition=ready pod -l app=ipam-apiserver -n ipam-system --timeout=180s || echo "apiserver pods not ready yet"
task test-infra:kubectl -- wait --for=condition=Available apiservice/v1alpha1.ipam.miloapis.com --timeout=180s || echo "APIService not Available yet"
dev:setup:
desc: Full dev setup (cluster + build + load + deploy)
silent: true
cmds:
- task: test-infra:cluster-up
- task: dev:install-dependencies
- task: dev:build
- task: dev:load
- task: dev:deploy
dev:redeploy:
desc: Quick rebuild and rollout
deps: [dev:build, dev:load]
silent: true
cmds:
- task test-infra:kubectl -- rollout restart -n ipam-system deployment/ipam-apiserver
- task test-infra:kubectl -- rollout status -n ipam-system deployment/ipam-apiserver --timeout=180s
install-observability:
desc: Install the test-infra observability stack
cmds:
- task: test-infra:install-observability
# ----- E2E -----
# Every suite drives the apiserver as a project tenant: a claim resolves its
# class, and resolving a class needs a project. Each context carries act-as +
# act-as-user-extra (iam.miloapis.com/parent-*), so the suites stay native
# chainsaw ops rather than curl/proxy bash.
#
# Chainsaw resolves every `clusters:` kubeconfig path when it loads a suite,
# before the first step runs, so a suite cannot generate its own.
# E2E_KUBE_CONTEXT overrides the source context (default: current context).
e2e:verify-ranges:
desc: Refuse overlapping root-pool ranges between fixture suites
cmd: go test ./test/fixtures/ -run TestFixtureRootRangesAreDisjoint -count=1 -v
e2e:tenant-setup:
desc: Generate the shared impersonation kubeconfig and apply its RBAC
cmds:
# The suites share one project and chainsaw runs them concurrently, so
# two suites holding overlapping roots fail intermittently, on whichever
# one creates its root second. Cheap to check, and the failure it
# prevents reads like an unrelated allocator bug.
- go test ./test/fixtures/ -run TestFixtureRootRangesAreDisjoint -count=1
# A suite that starts while the apiservice is still settling fails on
# ServiceUnavailable, which reads like a test bug and is not one.
- kubectl wait --for=condition=Available
apiservice/v1alpha1.ipam.miloapis.com --timeout=180s
- sh test/e2e/lib/gen-impersonation-kubeconfig.sh test/e2e/.tenant-impersonation.kubeconfig
- kubectl apply -f test/e2e/lib/tenant-rbac.yaml
# IPPools and IPClasses are cluster-scoped, so chainsaw's namespace
# teardown does not reach them and a run that fails mid-suite leaves them
# behind — which makes the NEXT run fail on "already exists", for a reason
# that has nothing to do with what changed. project-alpha and
# project-beta hold nothing but e2e fixtures.
- sh test/e2e/lib/clear-tenant-fixtures.sh
e2e:
desc: Run all chainsaw e2e suites
deps: [e2e:tenant-setup]
cmd: chainsaw test test/e2e/
e2e:suite:
desc: 'Run a single suite. Var: SUITE=ippool|ip-claim|pool-nesting|pool-validation|class-exhaustion|…'
deps: [e2e:tenant-setup]
cmd: chainsaw test test/e2e/{{.SUITE}}
# ----- k6 load tests (delegated to test/load/Taskfile.yaml) -----
test/load:setup:
desc: Provision pools and namespaces for perf tests
cmds:
- task: load:setup
test/load:throughput:
desc: Run prefix-claim throughput load test
cmds:
- task: load:throughput
test/load:asn-throughput:
desc: Run ASN-claim throughput load test
cmds:
- task: load:asn-throughput
test/load:address-concurrent:
desc: Run IPAddressClaim concurrency + uniqueness load test
cmds:
- task: load:address-concurrent
test/load:validate:
desc: Lint all k6 scripts with k6 inspect
cmds:
- task: load:validate
test/load:exhaustion:
desc: Run pool-exhaustion deny-path load test
cmds:
- task: load:exhaustion
test/load:reads:
desc: Run read-latency load test
cmds:
- task: load:reads
test/load:mixed:
desc: Run mixed read+write production-traffic load test
cmds:
- task: load:mixed
test/load:scale:
desc: Run pool-scale load test
cmds:
- task: load:scale
test/load:scale-setup:
desc: Provision 1000-project scale test pools (20 parallel VUs)
cmds:
- task: load:scale-setup
test/load:scale-throughput:
desc: 'Throughput test at 1000-project scale. Vars: VUS, DURATION'
cmds:
- task: load:scale-throughput
test/load:cleanup:
desc: Delete all perf namespaces and pool resources
cmds:
- task: load:cleanup
test/load:generate:
desc: Bundle k6 scripts for the in-cluster k6-performance-tests component
cmds:
- task: load:generate
# ----- k6 in-cluster operator workflow -----
test/load:k6:install-operator:
desc: Install the k6 operator into the cluster (one-time setup)
cmds:
- task: load:k6:install-operator
test/load:k6:apply:
desc: Push k6 ConfigMap + RBAC + TestRun manifests to the cluster
cmds:
- task: load:k6:apply
test/load:k6:run:
desc: 'Trigger a single in-cluster TestRun. Var: TEST=setup|throughput|asn-throughput|exhaustion|reads|scale|address-concurrent|mixed-load'
cmds:
- task: load:k6:run
vars:
TEST: '{{.TEST}}'
test/load:k6:logs:
desc: 'Tail logs from an in-cluster TestRun. Var: TEST=setup|throughput|asn-throughput|exhaustion|reads|scale|address-concurrent|mixed-load'
cmds:
- task: load:k6:logs
vars:
TEST: '{{.TEST}}'
# ----- Verification gates -----
verify:
desc: Run all build/test/lint gates
cmds:
- task: build
- task: test
- task: vet
- task: lint
- task: verify:imports
- task: verify:kustomize
# Generated code must match the generators. This gate could not exist
# until the `tool` directive stopped `go mod tidy` from dropping
# k8s.io/code-generator — in the meantime pkg/client and the zz_generated
# files were hand-edited, which drifts silently.
- task: verify:codegen
# Observability: dashboard drift, PromQL syntax, manifest schema.
- task: observability:verify
verify:imports:
desc: Ensure no datum-cloud/milo or datum-cloud/quota imports
silent: true
cmd: |
if grep -rE "datum-cloud/(milo|quota)" --include='*.go' .; then
echo "FAIL: unwanted imports"
exit 1
else
echo "OK: no forbidden imports"
fi
verify:codegen:
desc: Fail if committed generated code differs from what the generators produce
silent: true
cmd: "{{.TASKFILE_DIR}}/hack/verify-codegen.sh"
verify:kustomize:
desc: Verify all kustomize overlays render cleanly
silent: true
cmds:
- kustomize build config/overlays/dev/ > /dev/null && echo " ok config/overlays/dev"
- kustomize build config/overlays/test-infra/ > /dev/null && echo " ok config/overlays/test-infra"
- kustomize build config/components/k6-performance-tests/ > /dev/null && echo " ok config/components/k6-performance-tests"