Skip to content

Commit daabd8d

Browse files
kvapsclaude
andcommitted
feat(controller): kubebuilder scaffold + LINSTOR-compatible /v1/controller/version
Phase 1 first slice. The controller binary is built on the kubebuilder manager runtime; we register an additional Runnable that serves the LINSTOR REST contract on :3370. A single endpoint is wired so far — /v1/controller/version — but it returns the exact JSON shape (snake_case keys, full field set, application/json) that golinstor unmarshals. Tests cover the contract from every angle that today's stub can fail at: - TestVersionViaGolinstor: real golinstor client end-to-end (compatibility bar) - TestVersionRawJSON: pins on-wire shape — keys, count, content-type - TestVersionMethodNotAllowed: GET-only endpoint refuses POST/PUT/DELETE/PATCH - TestUnknownEndpointNotFound: unimplemented paths return 404 - TestHealthzReturnsNoContent: probe returns 204 with empty body - TestServerShutdownOnContextCancel: manager.Runnable cancellation contract - TestServerListenError: bind failure surfaces through Start - TestNeedLeaderElection: pins leader-election declaration Misc: - cockroachdb/errors instead of stdlib errors (stack traces, Wrap) - .golangci.yml borrowed from cloudflare-tunnel-gateway-controller, with exclusions for LINSTOR's snake_case JSON in pkg/api/ and the kubebuilder scaffold in cmd/main.go - stand/setup-host.sh installs go + golangci-lint - root Makefile includes stand/Makefile so dev-stand targets stay reachable Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
1 parent 29241bb commit daabd8d

42 files changed

Lines changed: 3128 additions & 32 deletions

Some content is hidden

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

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
2+
# Ignore everything by default and re-include only needed files
3+
**
4+
5+
# Re-include Go source files (but not *_test.go)
6+
!**/*.go
7+
**/*_test.go
8+
9+
# Re-include Go module files
10+
!go.mod
11+
!go.sum

.github/workflows/lint.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Lint
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions: {}
8+
9+
jobs:
10+
lint:
11+
permissions:
12+
contents: read
13+
name: Run on Ubuntu
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Clone the code
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
persist-credentials: false
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
23+
with:
24+
go-version-file: go.mod
25+
26+
- name: Check linter configuration
27+
run: make lint-config
28+
- name: Run linter
29+
run: make lint

.github/workflows/test-e2e.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: E2E Tests
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions: {}
8+
9+
jobs:
10+
test-e2e:
11+
permissions:
12+
contents: read
13+
name: Run on Ubuntu
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Clone the code
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
persist-credentials: false
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
23+
with:
24+
go-version-file: go.mod
25+
26+
- name: Install the latest version of kind
27+
run: |
28+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-$(go env GOARCH)
29+
chmod +x ./kind
30+
sudo mv ./kind /usr/local/bin/kind
31+
32+
- name: Verify kind installation
33+
run: kind version
34+
35+
- name: Running Test e2e
36+
run: |
37+
go mod tidy
38+
make test-e2e

.github/workflows/test.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions: {}
8+
9+
jobs:
10+
test:
11+
permissions:
12+
contents: read
13+
name: Run on Ubuntu
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Clone the code
17+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
18+
with:
19+
persist-credentials: false
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
23+
with:
24+
go-version-file: go.mod
25+
26+
- name: Running Tests
27+
run: |
28+
go mod tidy
29+
make test

.golangci.yml

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
version: "2"
2+
3+
linters:
4+
default: all
5+
disable:
6+
- depguard
7+
- exhaustruct
8+
- gochecknoinits
9+
- wsl
10+
- lll
11+
- errchkjson
12+
- ireturn
13+
- gocheckcompilerdirectives
14+
settings:
15+
dupl:
16+
threshold: 100
17+
goconst:
18+
min-len: 2
19+
min-occurrences: 2
20+
gocritic:
21+
disabled-checks:
22+
- dupImport
23+
- unnamedResult
24+
enabled-tags:
25+
- diagnostic
26+
- experimental
27+
- opinionated
28+
- performance
29+
- style
30+
funlen:
31+
lines: 60
32+
statements: 60
33+
gocyclo:
34+
min-complexity: 15
35+
cyclop:
36+
max-complexity: 15
37+
mnd:
38+
ignored-numbers:
39+
- "10"
40+
- "100"
41+
- "1000"
42+
- "2"
43+
- "60"
44+
- "60.0"
45+
- "64"
46+
- "500"
47+
gomoddirectives:
48+
replace-allow-list:
49+
- github.com/cloudflare/cloudflared
50+
nolintlint:
51+
require-explanation: true
52+
require-specific: true
53+
allow-unused: false
54+
varnamelen:
55+
max-distance: 5
56+
min-name-length: 3
57+
check-receiver: false
58+
check-return: false
59+
ignore-type-assert-ok: false
60+
ignore-map-index-ok: false
61+
ignore-chan-recv-ok: false
62+
ignore-decls:
63+
- wg sync.WaitGroup
64+
- wg *sync.WaitGroup
65+
- mu sync.Mutex
66+
- ok bool
67+
ignore-names:
68+
- i
69+
- w
70+
- r
71+
- b
72+
- c
73+
- m
74+
- n
75+
- tt
76+
- rw
77+
exclusions:
78+
generated: lax
79+
presets:
80+
- comments
81+
- common-false-positives
82+
- legacy
83+
- std-error-handling
84+
paths:
85+
- third_party$
86+
- builtin$
87+
- examples/
88+
- generated\.go$
89+
rules:
90+
- linters:
91+
- funlen
92+
- dupl
93+
- gocognit
94+
- gocyclo
95+
- cyclop
96+
- errcheck
97+
- testableexamples
98+
- testpackage
99+
- forcetypeassert
100+
- gocritic
101+
- nlreturn
102+
- wsl_v5
103+
- varnamelen
104+
- unparam
105+
- modernize
106+
- gosec
107+
- testifylint
108+
- perfsprint
109+
- paralleltest
110+
- maintidx
111+
path: _test\.go
112+
- linters:
113+
- forbidigo
114+
- gocyclo
115+
- cyclop
116+
- goconst
117+
- funlen
118+
- gocognit
119+
- nestif
120+
- gocritic
121+
- maintidx
122+
path: examples/
123+
# Controller patterns - helper methods near reconcile logic
124+
- linters:
125+
- funcorder
126+
path: internal/controller/
127+
# Controller patterns - inline error handling in reconcile
128+
- linters:
129+
- noinlineerr
130+
path: internal/controller/
131+
# blockstor reproduces the LINSTOR REST API contract, which uses
132+
# snake_case JSON. Keep golinstor-compatible names verbatim.
133+
- linters:
134+
- tagliatelle
135+
path: pkg/api/
136+
# cmd/main.go is the kubebuilder manager scaffold — don't lint its
137+
# boilerplate (TODOs, function length, globals, inline err checks, wsl).
138+
- linters:
139+
- funlen
140+
- gochecknoglobals
141+
- godox
142+
- gocritic
143+
- noinlineerr
144+
- wsl_v5
145+
path: cmd/main.go
146+
formatters:
147+
enable:
148+
- gofmt
149+
- gofumpt
150+
- goimports
151+
exclusions:
152+
generated: lax
153+
paths:
154+
- third_party$
155+
- builtin$
156+
- examples/
157+
- generated\.go$

Dockerfile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Build the manager binary
2+
FROM golang:1.25 AS builder
3+
ARG TARGETOS
4+
ARG TARGETARCH
5+
6+
WORKDIR /workspace
7+
# Copy the Go Modules manifests
8+
COPY go.mod go.mod
9+
COPY go.sum go.sum
10+
# cache deps before building and copying source so that we don't need to re-download as much
11+
# and so that source changes don't invalidate our downloaded layer
12+
RUN go mod download
13+
14+
# Copy the Go source (relies on .dockerignore to filter)
15+
COPY . .
16+
17+
# Build
18+
# the GOARCH has no default value to allow the binary to be built according to the host where the command
19+
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
20+
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
21+
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
22+
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
23+
24+
# Use distroless as minimal base image to package the manager binary
25+
# Refer to https://github.com/GoogleContainerTools/distroless for more details
26+
FROM gcr.io/distroless/static:nonroot
27+
WORKDIR /
28+
COPY --from=builder /workspace/manager .
29+
USER 65532:65532
30+
31+
ENTRYPOINT ["/manager"]

0 commit comments

Comments
 (0)