Skip to content

Commit 89336b2

Browse files
authored
Merge branch 'main' into feat/api-format-types
2 parents 031b477 + 04f5de5 commit 89336b2

32 files changed

Lines changed: 612 additions & 54 deletions

.github/workflows/release-dynamo-provider.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,6 @@ jobs:
5555
ghcr.io/kaito-project/airunway/dynamo-provider:latest
5656
build-args: |
5757
DYNAMO_VERSION=${{ env.DYNAMO_VERSION }}
58+
SHIM_VERSION=${{ inputs.version }}
5859
cache-from: type=gha
5960
cache-to: type=gha,mode=max

.github/workflows/release-kaito-provider.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@ jobs:
4545
tags: |
4646
ghcr.io/kaito-project/airunway/kaito-provider:${{ inputs.version }}
4747
ghcr.io/kaito-project/airunway/kaito-provider:latest
48+
build-args: |
49+
SHIM_VERSION=${{ inputs.version }}
4850
cache-from: type=gha
4951
cache-to: type=gha,mode=max

.github/workflows/release-kuberay-provider.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@ jobs:
4545
tags: |
4646
ghcr.io/kaito-project/airunway/kuberay-provider:${{ inputs.version }}
4747
ghcr.io/kaito-project/airunway/kuberay-provider:latest
48+
build-args: |
49+
SHIM_VERSION=${{ inputs.version }}
4850
cache-from: type=gha
4951
cache-to: type=gha,mode=max

.github/workflows/release-llmd-provider.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ jobs:
3535
username: ${{ github.actor }}
3636
password: ${{ secrets.GITHUB_TOKEN }}
3737

38+
- name: Load pinned versions
39+
run: |
40+
set -a
41+
# shellcheck disable=SC1091
42+
. ./versions.env
43+
set +a
44+
echo "LLMD_VERSION=$LLMD_VERSION" >> "$GITHUB_ENV"
45+
3846
- name: Build and push Docker image
3947
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
4048
with:
@@ -45,5 +53,8 @@ jobs:
4553
tags: |
4654
ghcr.io/kaito-project/airunway/llmd-provider:${{ inputs.version }}
4755
ghcr.io/kaito-project/airunway/llmd-provider:latest
56+
build-args: |
57+
LLMD_VERSION=${{ env.LLMD_VERSION }}
58+
SHIM_VERSION=${{ inputs.version }}
4859
cache-from: type=gha
4960
cache-to: type=gha,mode=max
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Temporary — providers will be moved out-of-tree.
2+
# Remove this workflow once vLLM provider has its own repository and CI.
3+
name: Release vLLM Provider
4+
5+
on:
6+
workflow_dispatch:
7+
inputs:
8+
version:
9+
description: 'Version tag (e.g., v1.0.0)'
10+
required: true
11+
type: string
12+
13+
permissions:
14+
contents: read
15+
packages: write
16+
17+
env:
18+
REGISTRY: ghcr.io
19+
20+
jobs:
21+
build-and-push:
22+
name: Build and Push vLLM Provider Image
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
27+
28+
- name: Set up Docker Buildx
29+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
30+
31+
- name: Log in to Container Registry
32+
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
33+
with:
34+
registry: ${{ env.REGISTRY }}
35+
username: ${{ github.actor }}
36+
password: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: Load pinned versions
39+
run: |
40+
set -a
41+
# shellcheck disable=SC1091
42+
. ./versions.env
43+
set +a
44+
echo "VLLM_VERSION=$VLLM_VERSION" >> "$GITHUB_ENV"
45+
46+
- name: Build and push Docker image
47+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
48+
with:
49+
context: .
50+
file: providers/vllm/Dockerfile
51+
platforms: linux/amd64,linux/arm64
52+
push: true
53+
tags: |
54+
ghcr.io/kaito-project/airunway/vllm-provider:${{ inputs.version }}
55+
ghcr.io/kaito-project/airunway/vllm-provider:latest
56+
build-args: |
57+
VLLM_VERSION=${{ env.VLLM_VERSION }}
58+
SHIM_VERSION=${{ inputs.version }}
59+
cache-from: type=gha
60+
cache-to: type=gha,mode=max

.github/workflows/test.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,36 @@ jobs:
146146
- name: make build
147147
run: make -C providers/${{ matrix.provider }} build
148148

149+
# Assert the shimVersion injection survives future refactors. Checks (a)
150+
# and (b) read the -ldflags string recorded in the binary (proves the flag
151+
# was *passed*); check (c) asserts the *runtime* value of ProviderVersion
152+
# after injection (proves the linker actually *patched* the symbol). (c) is
153+
# the one that catches a silent -X no-op — e.g. shimVersion becoming a
154+
# const, being renamed, or ProviderVersion being retargeted — which (a)/(b)
155+
# cannot, since the flag is still present in those cases.
156+
- name: Assert shimVersion injection + git-stamp default
157+
run: |
158+
set -euo pipefail
159+
p=${{ matrix.provider }}
160+
mod=$(cd "providers/$p" && go list -m)
161+
# (a) the un-overridden build above used the Makefile git-stamp default
162+
# (hex sha, or "unknown" outside a git tree — e.g. source tarball)
163+
go version -m "providers/$p/bin/provider" \
164+
| grep -Eq -- "-X ${mod}.shimVersion=dev-([0-9a-f]+|unknown)(-dirty)?" \
165+
|| { echo "❌ git-stamp default missing in $p"; exit 1; }
166+
# (b) explicit override proves the injection flag is wired
167+
make -C "providers/$p" build SHIM_VERSION=v9.9.9-citest
168+
go version -m "providers/$p/bin/provider" \
169+
| grep -F -- "-X ${mod}.shimVersion=v9.9.9-citest" \
170+
|| { echo "❌ shimVersion override injection missing in $p"; exit 1; }
171+
# (c) prove the injection actually takes EFFECT at runtime, not just
172+
# that the flag was passed. Fails on a silent -X no-op.
173+
EXPECT_PROVIDER_VERSION="${p}-provider:v9.9.9-citest" \
174+
go test -C "providers/$p" \
175+
-ldflags "-X ${mod}.shimVersion=v9.9.9-citest" \
176+
-run TestShimVersionInjection -v ./... \
177+
|| { echo "❌ shimVersion injection had no runtime effect in $p (silent no-op)"; exit 1; }
178+
149179
- name: make test
150180
run: make -C providers/${{ matrix.provider }} test
151181

providers/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,66 @@
11
# Providers
22

33
> **Note:** These provider implementations are included in-tree temporarily for testing and development purposes. The intention is for all providers to live out-of-tree as independent operators.
4+
5+
## Reported version contract (`shimVersion` / `SHIM_VERSION`)
6+
7+
Every shim reports its own version through `InferenceProviderConfig.status.version`,
8+
which `kubectl`, the Web UI, and the Headlamp plugin display. That value is
9+
**injected at build time** — it is deliberately *not* a hand-maintained constant
10+
(a constant is never bumped at release and silently goes stale, which is the bug
11+
this pattern exists to prevent).
12+
13+
If you add a new shim, replicate the contract exactly:
14+
15+
1. **`config.go`** — declare the injection target as an **unexported `var` with a
16+
plain string literal**, then compose the public version from it:
17+
18+
```go
19+
// shimVersion is injected at build time via -ldflags -X; "dev" is the
20+
// fallback for bare `go build`/`go run`/`go test` that bypass the Makefile.
21+
var shimVersion = "dev"
22+
23+
// ProviderVersion is written to InferenceProviderConfig.status.version.
24+
var ProviderVersion = ProviderConfigName + "-provider:" + shimVersion
25+
```
26+
27+
- Inject **`shimVersion`**, never `ProviderVersion`: `-X` can only patch a var
28+
whose initializer is a single string constant. `ProviderVersion` has a
29+
composite initializer, so `-X` on it silently no-ops. Keep `shimVersion`
30+
unexported — `-X` resolves a linker symbol regardless of Go visibility.
31+
- Both must be `var`, not `const` (`-X` cannot touch a `const`, and a `const`
32+
cannot reference a `var`).
33+
34+
2. **`Makefile`** — resolve the module path with `go list -m` (never hand-type it)
35+
and feed both a release tag and a git-stamp default through one `-X`:
36+
37+
```makefile
38+
MODULE := $(shell go list -m)
39+
GIT_SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
40+
GIT_DIRTY := $(shell test -n "$$(git status --porcelain 2>/dev/null)" && echo '-dirty')
41+
SHIM_VERSION ?= dev-$(GIT_SHA)$(GIT_DIRTY)
42+
LDFLAGS += -X $(MODULE).shimVersion=$(SHIM_VERSION)
43+
```
44+
45+
Pass `--build-arg SHIM_VERSION=$(SHIM_VERSION)` to `docker-build`.
46+
47+
3. **`Dockerfile`** — declare `ARG SHIM_VERSION` **with no default** and fail loud
48+
if it is missing, so a bare `docker build` cannot ship `:dev` under a real
49+
release tag. Resolve the module path the same way:
50+
51+
```dockerfile
52+
ARG SHIM_VERSION
53+
RUN test -n "${SHIM_VERSION}" || (echo "ERROR: SHIM_VERSION build arg is required; pass --build-arg SHIM_VERSION=..." >&2; exit 1)
54+
RUN cd providers/<name> && MODULE=$(go list -m) && \
55+
go build -ldflags="-X ${MODULE}.shimVersion=${SHIM_VERSION}" -o provider cmd/main.go
56+
```
57+
58+
4. **Release workflow** — pass `SHIM_VERSION=${{ inputs.version }}` (the same value
59+
that tags the image) in the `build-args:` block, so `status.version` equals the
60+
image tag by construction.
61+
62+
5. **Tests** — assert the *shape* (`strings.HasPrefix(ProviderVersion, "<name>-provider:")`),
63+
not an exact literal, and include a `TestShimVersionInjection` that asserts the
64+
**runtime** value under injection (gated on `EXPECT_PROVIDER_VERSION` so plain
65+
`go test` skips). The CI matrix in `.github/workflows/test.yml` runs it built
66+
with `-ldflags` so a silent `-X` no-op fails the build.

providers/dynamo/Dockerfile

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ ARG TARGETARCH
88
# `docker build` cannot silently fall back to the Go source literal in config.go
99
# and produce an image untracked by versions.env.
1010
ARG DYNAMO_VERSION
11+
# SHIM_VERSION is the reported shim version tag. Required so a hand-run
12+
# `docker build` cannot silently ship status.version=dynamo-provider:dev under
13+
# a real release tag. The Makefile and release workflow always pass it via
14+
# --build-arg.
15+
ARG SHIM_VERSION
1116

1217
WORKDIR /workspace
1318

@@ -31,12 +36,17 @@ COPY providers/dynamo/ providers/dynamo/
3136
RUN cd providers/dynamo && go mod tidy
3237

3338
# Build
34-
# Require DYNAMO_VERSION so hand-run `docker build` cannot silently drift from
35-
# versions.env. Builds should pass it via --build-arg (the Makefile does this).
39+
# Require DYNAMO_VERSION and SHIM_VERSION so hand-run `docker build` cannot
40+
# silently drift from versions.env or ship status.version=dynamo-provider:dev.
41+
# Builds should pass both via --build-arg (the Makefile and release workflow do).
3642
RUN test -n "${DYNAMO_VERSION}" || (echo "ERROR: DYNAMO_VERSION build arg is required (see versions.env); pass --build-arg DYNAMO_VERSION=..." >&2; exit 1)
37-
RUN cd providers/dynamo && CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
43+
RUN test -n "${SHIM_VERSION}" || (echo "ERROR: SHIM_VERSION build arg is required; pass --build-arg SHIM_VERSION=..." >&2; exit 1)
44+
# MODULE is resolved from go.mod (not hand-typed) so every -X target can never
45+
# drift from the package path.
46+
RUN cd providers/dynamo && MODULE=$(go list -m) && \
47+
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
3848
go build -a \
39-
-ldflags="-X github.com/kaito-project/airunway/providers/dynamo.DynamoVersion=${DYNAMO_VERSION}" \
49+
-ldflags="-X ${MODULE}.DynamoVersion=${DYNAMO_VERSION} -X ${MODULE}.shimVersion=${SHIM_VERSION}" \
4050
-o provider cmd/main.go
4151

4252
# Use distroless as minimal base image to package the provider binary

providers/dynamo/Makefile

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,29 @@ IMAGE_OUTPUT_FLAG := $(if $(PUSH_ENABLED),--push,--load)
99
include ../../versions.env
1010
export
1111

12-
# Inject the build-time Dynamo runtime tag into the provider binary so it
13-
# tracks /versions.env automatically. The Go fallback in config.go only
14-
# applies when bypassing this Makefile (e.g. `go run`, `go test`).
15-
LDFLAGS := -X github.com/kaito-project/airunway/providers/dynamo.DynamoVersion=$(DYNAMO_VERSION)
12+
# Module path, resolved from go.mod so the -X target can never drift from a
13+
# hand-typed string. Drives every -X below.
14+
MODULE := $(shell go list -m)
15+
16+
# Reported shim version: a git stamp for local/CI builds, overridden by the
17+
# release workflow with the tag (SHIM_VERSION=v0.3.0). bin/provider is
18+
# gitignored, so building never dirties the tree. The dirty check uses a
19+
# repo-wide `git status --porcelain` (no pathspec) on purpose: it is the
20+
# conservative superset — it never reports a clean sha when the tree has *any*
21+
# uncommitted divergence. That includes the controller/ dependency this binary
22+
# compiles in via the go.mod replace directive, not just this package dir, so
23+
# the stamp cannot claim "clean" while the binary actually differs. The
24+
# tradeoff is that unrelated edits (e.g. docs/) also flip it to -dirty.
25+
GIT_SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
26+
GIT_DIRTY := $(shell test -n "$$(git status --porcelain 2>/dev/null)" && echo '-dirty')
27+
SHIM_VERSION ?= dev-$(GIT_SHA)$(GIT_DIRTY)
28+
29+
# Inject the build-time Dynamo runtime tag and the reported shim version into
30+
# the provider binary so they track /versions.env and the release tag
31+
# automatically. The Go fallbacks in config.go only apply when bypassing this
32+
# Makefile (e.g. `go run`, `go test`).
33+
LDFLAGS := -X $(MODULE).DynamoVersion=$(DYNAMO_VERSION)
34+
LDFLAGS += -X $(MODULE).shimVersion=$(SHIM_VERSION)
1635

1736
.PHONY: build vet test docker-build deploy generate-deploy-manifests setup-dynamo setup-dynamo-mocker cleanup-dynamo test-e2e test-e2e-mocker verify-versions
1837

@@ -39,7 +58,7 @@ build: verify-versions vet
3958

4059
## Build provider Docker image
4160
docker-build: verify-versions
42-
docker buildx build --platform $(PLATFORM) $(IMAGE_OUTPUT_FLAG) --build-arg DYNAMO_VERSION=$(DYNAMO_VERSION) -f Dockerfile -t $(IMG) ../..
61+
docker buildx build --platform $(PLATFORM) $(IMAGE_OUTPUT_FLAG) --build-arg DYNAMO_VERSION=$(DYNAMO_VERSION) --build-arg SHIM_VERSION=$(SHIM_VERSION) -f Dockerfile -t $(IMG) ../..
4362
@echo "✅ Dynamo provider image built: $(IMG) ($(PLATFORM), $(if $(PUSH_ENABLED),pushed,loaded locally))"
4463

4564
## Deploy provider to the K8s cluster

providers/dynamo/config.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ const (
3838
// ProviderConfigName is the name of the InferenceProviderConfig for Dynamo
3939
ProviderConfigName = "dynamo"
4040

41-
// ProviderVersion is the version of the AIRunway Dynamo provider controller.
42-
ProviderVersion = "dynamo-provider:v0.2.0"
43-
4441
// ProviderDocumentation is the documentation URL for the Dynamo provider
4542
ProviderDocumentation = "https://github.com/kaito-project/airunway/tree/main/docs/providers/dynamo.md"
4643

@@ -51,6 +48,19 @@ const (
5148
dynamoGraphDeploymentResource = "dynamographdeployments"
5249
)
5350

51+
// shimVersion is this shim's reported version tag, injected at build time via:
52+
//
53+
// -ldflags "-X $(go list -m).shimVersion=$(SHIM_VERSION)"
54+
//
55+
// The Makefile supplies a release tag (e.g. "v0.3.0") or a git stamp
56+
// ("dev-<sha>" / "dev-<sha>-dirty"). The "dev" literal below is the last-resort
57+
// fallback for bare `go build`/`go run`/`go test` that bypass the Makefile.
58+
var shimVersion = "dev"
59+
60+
// ProviderVersion is the reported version of this shim (e.g.
61+
// "dynamo-provider:v0.3.0"), written to InferenceProviderConfig.status.version.
62+
var ProviderVersion = ProviderConfigName + "-provider:" + shimVersion
63+
5464
// DynamoVersion is the upstream Dynamo platform chart and runtime image tag.
5565
//
5666
// Single source of truth: /versions.env at the repo root. The build-time value

0 commit comments

Comments
 (0)