Skip to content

Commit 13bae67

Browse files
committed
cleanup
1 parent 9e65793 commit 13bae67

3 files changed

Lines changed: 109 additions & 91 deletions

File tree

.github/workflows/driver-vm-linux.yml

Lines changed: 20 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -75,80 +75,22 @@ jobs:
7575
path: runtime-artifacts/vm-runtime-*.tar.zst
7676
retention-days: 1
7777

78-
build-rootfs:
79-
name: Build Rootfs (${{ matrix.arch }})
80-
strategy:
81-
matrix:
82-
include:
83-
- arch: arm64
84-
runner: build-arm64
85-
guest_arch: aarch64
86-
- arch: amd64
87-
runner: build-amd64
88-
guest_arch: x86_64
89-
runs-on: ${{ matrix.runner }}
90-
timeout-minutes: 30
91-
container:
92-
image: ghcr.io/nvidia/openshell/ci:latest
93-
credentials:
94-
username: ${{ github.actor }}
95-
password: ${{ secrets.GITHUB_TOKEN }}
96-
options: --privileged
97-
volumes:
98-
- /var/run/docker.sock:/var/run/docker.sock
99-
env:
100-
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101-
OPENSHELL_IMAGE_TAG: ${{ inputs['image-tag'] }}
102-
steps:
103-
- uses: actions/checkout@v4
104-
with:
105-
ref: ${{ inputs['checkout-ref'] }}
106-
107-
- name: Mark workspace safe for git
108-
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
109-
110-
- name: Log in to GHCR
111-
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
112-
113-
- name: Install tools
114-
run: mise install --locked
115-
116-
- name: Install zstd
117-
run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/*
118-
119-
- name: Build base rootfs tarball
120-
run: |
121-
set -euo pipefail
122-
crates/openshell-vm/scripts/build-rootfs.sh \
123-
--base \
124-
--arch ${{ matrix.guest_arch }} \
125-
target/rootfs-build
126-
127-
mkdir -p target/vm-runtime-compressed
128-
tar -C target/rootfs-build -cf - . \
129-
| zstd -19 -T0 -o target/vm-runtime-compressed/rootfs.tar.zst
130-
131-
- name: Upload rootfs artifact
132-
uses: actions/upload-artifact@v4
133-
with:
134-
name: driver-vm-rootfs-${{ matrix.arch }}
135-
path: target/vm-runtime-compressed/rootfs.tar.zst
136-
retention-days: 1
137-
13878
build-driver-vm-linux:
13979
name: Build Driver VM (Linux ${{ matrix.arch }})
140-
needs: [download-kernel-runtime, build-rootfs]
80+
needs: [download-kernel-runtime]
14181
strategy:
14282
matrix:
14383
include:
14484
- arch: arm64
14585
runner: build-arm64
14686
target: aarch64-unknown-linux-gnu
14787
platform: linux-aarch64
88+
guest_arch: aarch64
14889
- arch: amd64
14990
runner: build-amd64
15091
target: x86_64-unknown-linux-gnu
15192
platform: linux-x86_64
93+
guest_arch: x86_64
15294
runs-on: ${{ matrix.runner }}
15395
timeout-minutes: 30
15496
container:
@@ -192,12 +134,6 @@ jobs:
192134
name: driver-vm-kernel-runtime-tarballs
193135
path: runtime-download/
194136

195-
- name: Download rootfs tarball
196-
uses: actions/download-artifact@v4
197-
with:
198-
name: driver-vm-rootfs-${{ matrix.arch }}
199-
path: rootfs-download/
200-
201137
- name: Stage compressed runtime for embedding
202138
run: |
203139
set -euo pipefail
@@ -208,16 +144,32 @@ jobs:
208144
zstd -d "runtime-download/vm-runtime-${{ matrix.platform }}.tar.zst" --stdout \
209145
| tar -xf - -C "$EXTRACT_DIR"
210146
147+
echo "Extracted runtime files:"
148+
ls -lah "$EXTRACT_DIR"
149+
211150
for file in "$EXTRACT_DIR"/*; do
212151
[ -f "$file" ] || continue
213152
name=$(basename "$file")
214153
[ "$name" = "provenance.json" ] && continue
215154
zstd -19 -f -q -T0 -o "${COMPRESSED_DIR}/${name}.zst" "$file"
216155
done
217156
218-
cp rootfs-download/rootfs.tar.zst "${COMPRESSED_DIR}/rootfs.tar.zst"
157+
echo "Staged compressed runtime artifacts:"
219158
ls -lah "$COMPRESSED_DIR"
220159
160+
- name: Build bundled supervisor
161+
run: |
162+
set -euo pipefail
163+
OPENSHELL_VM_RUNTIME_COMPRESSED_DIR="${PWD}/target/vm-runtime-compressed" \
164+
tasks/scripts/vm/build-supervisor-bundle.sh --arch "${{ matrix.guest_arch }}"
165+
166+
- name: Verify embedded driver inputs
167+
run: |
168+
set -euo pipefail
169+
for file in libkrun.so.zst libkrunfw.so.5.zst gvproxy.zst openshell-sandbox.zst; do
170+
test -s "target/vm-runtime-compressed/${file}"
171+
done
172+
221173
- name: Scope workspace to driver-vm crates
222174
run: |
223175
set -euo pipefail

crates/openshell-driver-vm/scripts/openshell-vm-sandbox-init.sh

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99

1010
set -euo pipefail
1111

12-
# Source QEMU-injected environment variables if present
12+
# Source QEMU-injected environment variables if present.
1313
if [ -f /srv/openshell-env.sh ]; then
14+
# shellcheck source=/dev/null
1415
source /srv/openshell-env.sh
1516
fi
1617

@@ -31,21 +32,11 @@ GVPROXY_GATEWAY_IP="192.168.127.1"
3132
GVPROXY_HOST_LOOPBACK_IP="192.168.127.254"
3233
GATEWAY_IP="$GVPROXY_GATEWAY_IP"
3334

34-
# Parse kernel cmdline for GPU and TAP networking parameters
3535
GPU_ENABLED="${GPU_ENABLED:-false}"
3636
VM_NET_IP="${VM_NET_IP:-}"
3737
VM_NET_GW="${VM_NET_GW:-}"
3838
VM_NET_DNS="${VM_NET_DNS:-}"
3939

40-
for param in $(cat /proc/cmdline 2>/dev/null || true); do
41-
case "$param" in
42-
GPU_ENABLED=*) GPU_ENABLED="${param#GPU_ENABLED=}" ;;
43-
VM_NET_IP=*) VM_NET_IP="${param#VM_NET_IP=}" ;;
44-
VM_NET_GW=*) VM_NET_GW="${param#VM_NET_GW=}" ;;
45-
VM_NET_DNS=*) VM_NET_DNS="${param#VM_NET_DNS=}" ;;
46-
esac
47-
done
48-
4940
ts() {
5041
local now
5142
now=$(date +%s%3N 2>/dev/null || date +%s)
@@ -102,9 +93,9 @@ tcp_probe() {
10293
local port="$2"
10394

10495
if command -v timeout >/dev/null 2>&1; then
105-
timeout 2 bash -c "exec 3<>/dev/tcp/${host}/${port}" >/dev/null 2>&1
96+
timeout 2 bash -c "exec 3<>/dev/tcp/\$1/\$2" _ "$host" "$port" >/dev/null 2>&1
10697
else
107-
bash -c "exec 3<>/dev/tcp/${host}/${port}" >/dev/null 2>&1
98+
bash -c "exec 3<>/dev/tcp/\$1/\$2" _ "$host" "$port" >/dev/null 2>&1
10899
fi
109100
}
110101

@@ -312,12 +303,22 @@ if [ -n "${VM_NET_IP}" ] && [ -n "${VM_NET_GW}" ]; then
312303
TAP_NIC=""
313304
NIC_WAIT=0
314305
while [ -z "$TAP_NIC" ] && [ "$NIC_WAIT" -lt 10 ]; do
315-
for candidate in eth0 ens3 enp0s2 $(ls /sys/class/net/ 2>/dev/null | grep -v '^lo$'); do
306+
for candidate in eth0 ens3 enp0s2; do
316307
if ip link show "$candidate" >/dev/null 2>&1 && [ "$candidate" != "lo" ]; then
317308
TAP_NIC="$candidate"
318309
break
319310
fi
320311
done
312+
if [ -z "$TAP_NIC" ]; then
313+
for sys_nic in /sys/class/net/*; do
314+
[ -e "$sys_nic" ] || continue
315+
candidate="${sys_nic##*/}"
316+
if ip link show "$candidate" >/dev/null 2>&1 && [ "$candidate" != "lo" ]; then
317+
TAP_NIC="$candidate"
318+
break
319+
fi
320+
done
321+
fi
321322
if [ -z "$TAP_NIC" ]; then
322323
sleep 1
323324
NIC_WAIT=$((NIC_WAIT + 1))
@@ -348,7 +349,7 @@ elif ip link show eth0 >/dev/null 2>&1; then
348349
if command -v udhcpc >/dev/null 2>&1; then
349350
UDHCPC_SCRIPT="/usr/share/udhcpc/default.script"
350351
if [ ! -f "$UDHCPC_SCRIPT" ]; then
351-
mkdir -p /usr/share/udhcpc
352+
UDHCPC_SCRIPT="/run/openshell-udhcpc.script"
352353
cat > "$UDHCPC_SCRIPT" <<'DHCP_SCRIPT'
353354
#!/bin/sh
354355
case "$1" in

crates/openshell-driver-vm/src/runtime.rs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ fn run_qemu_vm(config: &VmLaunchConfig) -> Result<(), String> {
110110
#[cfg(target_os = "linux")]
111111
check_kvm_access()?;
112112

113-
write_guest_env_file(&config.rootfs, &config.env)?;
113+
let guest_env = qemu_guest_env_vars(config, host_dns_server());
114+
write_guest_env_file(&config.rootfs, &guest_env)?;
114115

115116
let rootfs_str = config.rootfs.to_str().ok_or("rootfs path not UTF-8")?;
116117
let sandbox_dir = config.rootfs.parent().unwrap_or(&config.rootfs);
@@ -296,6 +297,27 @@ fn write_guest_env_file(rootfs: &Path, env_vars: &[String]) -> Result<(), String
296297
Ok(())
297298
}
298299

300+
fn qemu_guest_env_vars(config: &VmLaunchConfig, dns_server: Option<String>) -> Vec<String> {
301+
let mut env_vars = config.env.clone();
302+
303+
if let Some(ip) = &config.guest_ip
304+
&& let Some(host_ip) = &config.host_ip
305+
{
306+
env_vars.push(format!("VM_NET_IP={ip}"));
307+
env_vars.push(format!("VM_NET_GW={host_ip}"));
308+
}
309+
310+
if let Some(dns) = dns_server {
311+
env_vars.push(format!("VM_NET_DNS={dns}"));
312+
}
313+
314+
if config.gpu_bdf.is_some() {
315+
env_vars.push("GPU_ENABLED=true".to_string());
316+
}
317+
318+
env_vars
319+
}
320+
299321
/// Escape a string for use inside bash double quotes.
300322
fn shell_escape(s: &str) -> String {
301323
s.replace('\\', "\\\\")
@@ -320,16 +342,9 @@ fn build_kernel_cmdline(config: &VmLaunchConfig) -> String {
320342
&& let Some(host_ip) = &config.host_ip
321343
{
322344
parts.push(format!("ip={ip}::{host_ip}:255.255.255.252:sandbox::off"));
323-
parts.push(format!("VM_NET_IP={ip}"));
324-
parts.push(format!("VM_NET_GW={host_ip}"));
325-
}
326-
327-
if let Some(dns) = host_dns_server() {
328-
parts.push(format!("VM_NET_DNS={dns}"));
329345
}
330346

331347
if config.gpu_bdf.is_some() {
332-
parts.push("GPU_ENABLED=true".to_string());
333348
parts.push("firmware_class.path=/lib/firmware".to_string());
334349
}
335350

@@ -1310,6 +1325,56 @@ fn path_to_cstring(path: &Path) -> Result<CString, String> {
13101325
CString::new(path).map_err(|e| format!("invalid path string {path}: {e}"))
13111326
}
13121327

1328+
#[cfg(test)]
1329+
mod tests {
1330+
use super::*;
1331+
1332+
fn qemu_config() -> VmLaunchConfig {
1333+
VmLaunchConfig {
1334+
rootfs: PathBuf::from("/rootfs"),
1335+
vcpus: 2,
1336+
mem_mib: 2048,
1337+
exec_path: "/srv/openshell-vm-sandbox-init.sh".to_string(),
1338+
args: Vec::new(),
1339+
env: vec!["OPENSHELL_ENDPOINT=http://10.0.128.1:8080".to_string()],
1340+
workdir: "/".to_string(),
1341+
log_level: 0,
1342+
console_output: PathBuf::from("/console.log"),
1343+
backend: VmBackend::Qemu,
1344+
gpu_bdf: Some("0000:01:00.0".to_string()),
1345+
tap_device: Some("vmtap-test".to_string()),
1346+
guest_ip: Some("10.0.128.2".to_string()),
1347+
host_ip: Some("10.0.128.1".to_string()),
1348+
vsock_cid: Some(4),
1349+
guest_mac: Some("02:00:00:00:00:01".to_string()),
1350+
gateway_port: Some(8080),
1351+
}
1352+
}
1353+
1354+
#[test]
1355+
fn qemu_guest_env_vars_include_driver_runtime_metadata() {
1356+
let env = qemu_guest_env_vars(&qemu_config(), Some("1.1.1.1".to_string()));
1357+
1358+
assert!(env.contains(&"OPENSHELL_ENDPOINT=http://10.0.128.1:8080".to_string()));
1359+
assert!(env.contains(&"VM_NET_IP=10.0.128.2".to_string()));
1360+
assert!(env.contains(&"VM_NET_GW=10.0.128.1".to_string()));
1361+
assert!(env.contains(&"VM_NET_DNS=1.1.1.1".to_string()));
1362+
assert!(env.contains(&"GPU_ENABLED=true".to_string()));
1363+
}
1364+
1365+
#[test]
1366+
fn kernel_cmdline_keeps_guest_init_metadata_out_of_proc_cmdline() {
1367+
let cmdline = build_kernel_cmdline(&qemu_config());
1368+
1369+
assert!(cmdline.contains("ip=10.0.128.2::10.0.128.1:255.255.255.252:sandbox::off"));
1370+
assert!(cmdline.contains("firmware_class.path=/lib/firmware"));
1371+
assert!(!cmdline.contains("VM_NET_IP="));
1372+
assert!(!cmdline.contains("VM_NET_GW="));
1373+
assert!(!cmdline.contains("VM_NET_DNS="));
1374+
assert!(!cmdline.contains("GPU_ENABLED="));
1375+
}
1376+
}
1377+
13131378
#[cfg(target_os = "linux")]
13141379
fn check_kvm_access() -> Result<(), String> {
13151380
std::fs::OpenOptions::new()

0 commit comments

Comments
 (0)