-
Notifications
You must be signed in to change notification settings - Fork 5
270 lines (257 loc) · 11.2 KB
/
Copy pathci.yml
File metadata and controls
270 lines (257 loc) · 11.2 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
name: CI
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
workflow_dispatch: {}
env:
CARGO_TERM_COLOR: always
A3S_DEPS_STUB: "1"
jobs:
# ── Lint & Format ──────────────────────────────────────────────
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cd src && cargo fmt --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Create stub libkrun
run: |
echo "void krun_stub(void) {}" > /tmp/krun_stub.c
gcc -shared -o /tmp/libkrun.so /tmp/krun_stub.c
sudo cp /tmp/libkrun.so /usr/lib/
sudo ldconfig
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
- run: cd src && cargo clippy --workspace --all-targets -- -D warnings
# ── Tests (stub mode, no VM) ───────────────────────────────────
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Create stub libkrun
run: |
echo "void krun_stub(void) {}" > /tmp/krun_stub.c
gcc -shared -o /tmp/libkrun.so /tmp/krun_stub.c
sudo cp /tmp/libkrun.so /usr/lib/
sudo ldconfig
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
- run: cd src && cargo test --workspace --lib
# ── Build check (compile only, no artifacts) ────────────────────
build-check:
name: Build Check (${{ matrix.target }})
needs: [fmt, clippy, test]
strategy:
matrix:
include:
- target: linux-x86_64
os: ubuntu-latest
- target: linux-arm64
os: ubuntu-24.04-arm
- target: macos-arm64
os: macos-14
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential pkg-config libssl-dev \
musl-tools libclang-dev protobuf-compiler
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: brew install lld llvm protobuf
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
key: ${{ matrix.target }}
- name: Check compilation
run: |
cd src
cargo check --release -p a3s-box-cli -p a3s-box-shim
if [ "${{ runner.os }}" = "Linux" ]; then
cargo check --release -p a3s-box-cri
fi
# ── Windows native WHPX build check ────────────────────────────
build-windows:
name: Build Windows WHPX
needs: [fmt, clippy, test]
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
- uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc
- uses: Swatinem/rust-cache@v2
with:
workspaces: src
key: windows-whpx
- name: Build Windows native binaries
run: |
Remove-Item Env:A3S_DEPS_STUB -ErrorAction SilentlyContinue
cd src
cargo build --release -p a3s-box-cli -p a3s-box-shim --target x86_64-pc-windows-msvc
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: windows-whpx
path: |
src/target/x86_64-pc-windows-msvc/release/a3s-box.exe
src/target/x86_64-pc-windows-msvc/release/a3s-box-shim.exe
# ── Real microVM integration gate (self-hosted, /dev/kvm) ───────
# The fmt/clippy/test/build jobs above all run in STUB mode
# (A3S_DEPS_STUB) and never boot a real microVM, so a runtime
# regression (boot, exec, virtio-fs, CRI lifecycle, snapshot-fork)
# cannot be caught by hosted CI — GitHub-hosted runners have no
# /dev/kvm. This job links REAL libkrun and runs the `#[ignore]`
# integration + crictl-smoke suites against a real microVM.
#
# ARMING THE GATE (one-time, operator — see docs/ci-kvm-runner.md):
# 1. Register a self-hosted runner that has /dev/kvm, with labels:
# self-hosted, linux, kvm
# 2. Set repository variable KVM_CI = true
# (Settings -> Secrets and variables -> Actions -> Variables)
# Until both are done this job is SKIPPED (inert) and never blocks a PR.
integration-kvm:
name: Integration (real microVM, KVM)
needs: [fmt, clippy, test]
if: vars.KVM_CI == 'true'
runs-on: [self-hosted, linux, kvm]
timeout-minutes: 75
# The runner has no direct docker.io egress (CN network), so the smoke
# tests pull alpine/busybox through a mirror. The image keeps its canonical
# docker.io identity; only the fetch is redirected. Override per-runner with
# the KVM_CI_REGISTRY_MIRRORS repo variable.
env:
A3S_REGISTRY_MIRRORS: ${{ vars.KVM_CI_REGISTRY_MIRRORS || 'docker.io=docker.m.daocloud.io' }}
steps:
- uses: actions/checkout@v4
- name: Init submodules
run: git -c http.extraheader= submodule update --init --recursive
# The self-hosted runner already has a working rustup/cargo. Using
# dtolnay/rust-toolchain forces rustup to re-sync the whole `stable`
# channel (7 components) on every run — ~20 min on this box's network,
# which blew the job timeout. Use the runner's existing toolchain: add the
# musl target (a fast no-op if already installed) and put cargo on PATH
# for later steps (the runner service env does not source a login shell).
- name: Use the runner's existing Rust toolchain
run: |
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
"$HOME/.cargo/bin/rustup" target add x86_64-unknown-linux-musl
# NOTE: no Swatinem/rust-cache here — fetching that action from
# codeload.github.com times out on this runner's network, which fails
# "Set up job". The self-hosted runner keeps a warm cargo registry, and
# the 75-min budget covers a cold libkrun build.
- name: Verify /dev/kvm is present
run: |
if [ ! -e /dev/kvm ]; then
echo "::error::/dev/kvm missing — this runner cannot boot microVMs"; exit 1
fi
echo "/dev/kvm present"
# Build REAL binaries: unset the stub so libkrun-sys compiles the
# vendored libkrun (build.rs gates on env::var("A3S_DEPS_STUB").is_ok(),
# so the var must be UNSET, not just emptied).
- name: Build real binaries + musl guest-init (no stub)
run: |
unset A3S_DEPS_STUB
cd src
cargo build --release -p a3s-box-guest-init --target x86_64-unknown-linux-musl
cargo build --release -p a3s-box-cli -p a3s-box-cri -p a3s-box-shim
- name: Core smoke — real boot + exec over virtio-fs
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-cli --test core_smoke -- --ignored --nocapture --test-threads=1
- name: CRI crictl smoke — full pod/container lifecycle
env:
A3S_BOX_CRI_SMOKE: "1"
A3S_BOX_CRI_SMOKE_AGENT_IMAGE: ${{ vars.KVM_CI_AGENT_IMAGE || 'docker.m.daocloud.io/library/alpine:latest' }}
# A3S_REGISTRY_MIRRORS inherited from the job env (covers docker.io).
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-cri --test crictl_smoke -- --ignored --nocapture --test-threads=1
# Gate leak-freeness under churn against REAL VMs: create/run/remove cycles
# must return orphan shims / overlay mounts / box dirs to baseline. Exits
# non-zero on a leak, so a resource-leak regression fails the gate.
- name: Leak assertion — no orphan shims/mounts/box-dirs after churn
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
CHURN: "20"
run: |
unset A3S_DEPS_STUB
chmod +x bench/bench.sh
bench/bench.sh leak
# Gate the cross-process advisory lock on boxes.json against REAL VMs:
# concurrent `run -d` processes must NOT lose each other's state writes.
# The unit tests only race in-process threads, so a broken/missing flock
# across separate a3s-box processes is invisible to them — this boots a
# fleet at once and asserts no lost update + intact JSON. Exits non-zero
# on a lost update, failing the gate.
- name: Race assertion — no lost update on boxes.json under concurrent run -d
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
RACE: "8"
run: |
unset A3S_DEPS_STUB
chmod +x bench/bench.sh
bench/bench.sh race
# SDK programmable-CI pipeline against REAL microVMs: warm + CoW fork-per-step,
# parallel collect-all, `::metric` extraction, fork isolation, leak-freeness,
# and crash-orphan recovery (sweep_orphans). The unit suite only drives a fake
# CLI, so this is the only gate that the real fork/snapshot path actually works.
- name: SDK pipeline integration — real fork-per-step + sweep
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
A3S_SDK_TEST_IMAGE: ${{ vars.KVM_CI_AGENT_IMAGE || 'docker.m.daocloud.io/library/alpine:latest' }}
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-sdk --test integration_kvm -- --ignored --nocapture --test-threads=1
# Soak the fork-eval loop: sustained churn must stay leak-free (no orphan
# boxes/snapshots, snapshot count flat) and memory-stable. Light here (120
# fork-evals); crank A3S_SDK_SOAK_FORKS for a manual long soak.
- name: SDK pipeline soak — leak-free under churn
env:
A3S_BOX: ${{ github.workspace }}/src/target/release/a3s-box
A3S_SDK_TEST_IMAGE: ${{ vars.KVM_CI_AGENT_IMAGE || 'docker.m.daocloud.io/library/alpine:latest' }}
A3S_SDK_SOAK_FORKS: "120"
run: |
unset A3S_DEPS_STUB
cd src
cargo test --release -p a3s-box-sdk --test soak_kvm -- --ignored --nocapture --test-threads=1