forked from NVIDIA/OpenShell
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgateway-vm.sh
More file actions
executable file
·361 lines (324 loc) · 11.2 KB
/
Copy pathgateway-vm.sh
File metadata and controls
executable file
·361 lines (324 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
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
352
353
354
355
356
357
358
359
360
361
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# Start a standalone openshell-gateway backed by the VM compute driver
# (openshell-driver-vm) for local manual testing.
#
# Invocation:
# mise run gateway:vm
#
# Defaults:
# - Plaintext HTTP on 127.0.0.1:18081
# - Dedicated CLI gateway "vm-dev"
# - Persistent gateway state (SQLite DB) under .cache/gateway-vm
# - Per-sandbox VM driver state (rootfs + compute-driver.sock) under
# /tmp/openshell-vm-driver-<user>-<gateway-name> so the AF_UNIX socket
# path stays under macOS SUN_LEN
#
# Common overrides:
# OPENSHELL_SERVER_PORT=18091 mise run gateway:vm
# OPENSHELL_VM_GATEWAY_NAME=my-vm-gateway mise run gateway:vm
# OPENSHELL_SANDBOX_NAMESPACE=my-ns mise run gateway:vm
# OPENSHELL_SANDBOX_IMAGE=ghcr.io/... mise run gateway:vm
# mise run gateway:vm -- --gpu
#
# This script also writes ~/.config/openshell/active_gateway so the
# `openshell` CLI automatically targets this gateway in subsequent shells.
# No need to run `openshell gateway select`. Inside this repo you can
# override per-developer with OPENSHELL_GATEWAY in `.env` (mise loads it).
# An explicit `--gateway` / `--gateway-endpoint` flag still wins.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
PORT="${OPENSHELL_SERVER_PORT:-18081}"
GATEWAY_NAME="${OPENSHELL_VM_GATEWAY_NAME:-vm-dev}"
STATE_DIR="${OPENSHELL_VM_GATEWAY_STATE_DIR:-${ROOT}/.cache/gateway-vm}"
SANDBOX_NAMESPACE="${OPENSHELL_SANDBOX_NAMESPACE:-vm-dev}"
SANDBOX_IMAGE="${OPENSHELL_SANDBOX_IMAGE:-${COMMUNITY_SANDBOX_IMAGE:-ghcr.io/nvidia/openshell-community/sandboxes/base:latest}}"
VM_BOOTSTRAP_IMAGE="${OPENSHELL_VM_BOOTSTRAP_IMAGE:-}"
SANDBOX_IMAGE_PULL_POLICY="${OPENSHELL_SANDBOX_IMAGE_PULL_POLICY:-IfNotPresent}"
LOG_LEVEL="${OPENSHELL_LOG_LEVEL:-info}"
GATEWAY_BIN="${ROOT}/target/debug/openshell-gateway"
DRIVER_DIR_DEFAULT="${ROOT}/target/debug"
DRIVER_DIR="${OPENSHELL_DRIVER_DIR:-${DRIVER_DIR_DEFAULT}}"
COMPRESSED_DIR_DEFAULT="${ROOT}/target/vm-runtime-compressed"
COMPRESSED_DIR="${OPENSHELL_VM_RUNTIME_COMPRESSED_DIR:-${COMPRESSED_DIR_DEFAULT}}"
VM_HOST_GATEWAY_DEFAULT="${OPENSHELL_VM_HOST_GATEWAY:-host.containers.internal}"
GRPC_ENDPOINT="${OPENSHELL_GRPC_ENDPOINT:-http://${VM_HOST_GATEWAY_DEFAULT}:${PORT}}"
normalize_arch() {
case "$1" in
x86_64|amd64) echo "amd64" ;;
aarch64|arm64) echo "arm64" ;;
*) echo "$1" ;;
esac
}
normalize_bool() {
local val
val="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')"
case "${val}" in
1|true|yes|on) echo "true" ;;
0|false|no|off) echo "false" ;;
*)
echo "ERROR: invalid boolean value '$1' (expected true/false, 1/0, yes/no, on/off)" >&2
exit 2
;;
esac
}
port_is_in_use() {
local port=$1
if command -v lsof >/dev/null 2>&1; then
lsof -nP -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1
return $?
fi
if command -v nc >/dev/null 2>&1; then
nc -z 127.0.0.1 "${port}" >/dev/null 2>&1
return $?
fi
(echo >/dev/tcp/127.0.0.1/"${port}") >/dev/null 2>&1
}
invoking_user() {
if [ -n "${SUDO_USER:-}" ] && [ "${SUDO_USER}" != "root" ]; then
printf '%s\n' "${SUDO_USER}"
else
id -un
fi
}
invoking_user_home() {
local user=$1
local home
if [ "${user}" = "$(id -un)" ]; then
printf '%s\n' "${HOME}"
return
fi
if command -v getent >/dev/null 2>&1; then
home="$(getent passwd "${user}" | cut -d: -f6)"
if [ -n "${home}" ]; then
printf '%s\n' "${home}"
return
fi
fi
if command -v dscl >/dev/null 2>&1; then
home="$(dscl . -read "/Users/${user}" NFSHomeDirectory 2>/dev/null | awk '{print $2}')"
if [ -n "${home}" ]; then
printf '%s\n' "${home}"
return
fi
fi
if [ "$(uname -s)" = "Darwin" ]; then
printf '/Users/%s\n' "${user}"
else
printf '/home/%s\n' "${user}"
fi
}
gateway_config_home() {
local user home
user="$(invoking_user)"
if [ -n "${SUDO_USER:-}" ] && [ "${user}" != "$(id -un)" ]; then
home="$(invoking_user_home "${user}")"
printf '%s\n' "${home}/.config"
else
printf '%s\n' "${XDG_CONFIG_HOME:-${HOME}/.config}"
fi
}
chown_invoking_user() {
if [ -n "${SUDO_UID:-}" ] && [ -n "${SUDO_GID:-}" ]; then
chown -R "${SUDO_UID}:${SUDO_GID}" "$@" 2>/dev/null || true
fi
}
register_gateway_metadata() {
local name=$1
local endpoint=$2
local port=$3
local vm_driver_state_dir=$4
local config_home gateway_dir
config_home="$(gateway_config_home)"
gateway_dir="${config_home}/openshell/gateways/${name}"
mkdir -p "${gateway_dir}"
chmod 700 "${gateway_dir}" 2>/dev/null || true
cat >"${gateway_dir}/metadata.json" <<EOF
{
"name": "${name}",
"gateway_endpoint": "${endpoint}",
"is_remote": false,
"gateway_port": ${port},
"auth_mode": "plaintext",
"vm_driver_state_dir": "${vm_driver_state_dir}"
}
EOF
chmod 600 "${gateway_dir}/metadata.json" 2>/dev/null || true
chown_invoking_user "${config_home}/openshell"
}
# Mirror what `openshell gateway select <name>` does: write the gateway name
# to $XDG_CONFIG_HOME/openshell/active_gateway. The CLI picks it up as the
# default target when neither --gateway nor OPENSHELL_GATEWAY is set.
save_active_gateway() {
local name=$1
local config_home active_gateway_path
config_home="$(gateway_config_home)"
active_gateway_path="${config_home}/openshell/active_gateway"
mkdir -p "$(dirname "${active_gateway_path}")"
printf '%s' "${name}" >"${active_gateway_path}"
chown_invoking_user "${config_home}/openshell"
}
check_supervisor_cross_toolchain() {
# The sandbox supervisor inside the guest is always Linux. On non-Linux
# hosts (macOS) and on Linux hosts with a different arch than the guest,
# `mise run vm:supervisor` cross-compiles via cargo-zigbuild and needs
# the matching rustup target installed.
local host_os host_arch guest_arch rust_target
host_os="$(uname -s)"
host_arch="$(uname -m)"
guest_arch="${GUEST_ARCH:-${host_arch}}"
case "${guest_arch}" in
arm64|aarch64) rust_target="aarch64-unknown-linux-gnu" ;;
x86_64|amd64) rust_target="x86_64-unknown-linux-gnu" ;;
*) return 0 ;;
esac
if [ "${host_os}" = "Linux" ] && [ "${host_arch}" = "${guest_arch}" ]; then
return 0
fi
local missing=0
if ! command -v cargo-zigbuild >/dev/null 2>&1; then
echo "ERROR: cargo-zigbuild not found (required to cross-compile the guest supervisor)." >&2
echo " Install: cargo install --locked cargo-zigbuild && brew install zig" >&2
missing=1
fi
if ! rustup target list --installed 2>/dev/null | grep -qx "${rust_target}"; then
echo "ERROR: Rust target '${rust_target}' not installed." >&2
echo " Install: rustup target add ${rust_target}" >&2
missing=1
fi
if [ "${missing}" -ne 0 ]; then
exit 1
fi
}
VM_GPU="$(normalize_bool "${OPENSHELL_VM_GPU:-false}")"
while [ "$#" -gt 0 ]; do
case "$1" in
--gpu)
VM_GPU="true"
shift
;;
--gpu-mem-mib)
if [ "$#" -lt 2 ]; then
echo "ERROR: --gpu-mem-mib requires a value" >&2
exit 2
fi
export OPENSHELL_VM_GPU_MEM_MIB="$2"
shift 2
;;
--gpu-vcpus)
if [ "$#" -lt 2 ]; then
echo "ERROR: --gpu-vcpus requires a value" >&2
exit 2
fi
export OPENSHELL_VM_GPU_VCPUS="$2"
shift 2
;;
-h|--help)
echo "Usage: mise run gateway:vm -- [--gpu] [--gpu-mem-mib MIB] [--gpu-vcpus N]"
exit 0
;;
*)
echo "ERROR: unknown gateway-vm option '$1'" >&2
exit 2
;;
esac
done
if [ "${VM_GPU}" = "true" ]; then
export OPENSHELL_VM_GPU="true"
else
unset OPENSHELL_VM_GPU
fi
if [[ ! "${GATEWAY_NAME}" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "ERROR: OPENSHELL_VM_GATEWAY_NAME must contain only letters, numbers, dots, underscores, or dashes" >&2
exit 2
fi
if port_is_in_use "${PORT}"; then
echo "ERROR: port ${PORT} is already in use; free it or set OPENSHELL_SERVER_PORT" >&2
exit 2
fi
# AF_UNIX SUN_LEN on macOS is 104 bytes; the VM driver places
# `compute-driver.sock` directly under VM_DRIVER_STATE_DIR, so anchor it
# under /tmp instead of `${ROOT}/.cache` (which is typically too long on
# macOS dev boxes with worktree paths).
STATE_LABEL="$(printf '%s' "${GATEWAY_NAME}" | tr -cs '[:alnum:]._-' '-')"
if [ -z "${STATE_LABEL}" ]; then
STATE_LABEL="vm-dev"
fi
VM_DRIVER_STATE_DIR_DEFAULT="${OPENSHELL_VM_DRIVER_STATE_ROOT:-/tmp}/openshell-vm-driver-${USER:-user}-${STATE_LABEL}"
VM_DRIVER_STATE_DIR="${OPENSHELL_VM_DRIVER_STATE_DIR:-${VM_DRIVER_STATE_DIR_DEFAULT}}"
DISABLE_TLS="$(normalize_bool "${OPENSHELL_DISABLE_TLS:-true}")"
# Build prerequisites: VM runtime artifacts + bundled supervisor.
if [ ! -d "${COMPRESSED_DIR}" ] \
|| ! find "${COMPRESSED_DIR}" -maxdepth 1 -name 'libkrun*.zst' | grep -q . \
|| [ ! -f "${COMPRESSED_DIR}/gvproxy.zst" ] \
|| [ ! -f "${COMPRESSED_DIR}/umoci.zst" ]; then
echo "==> Preparing embedded VM runtime (mise run vm:setup)"
mise run vm:setup
fi
if [ ! -f "${COMPRESSED_DIR}/openshell-sandbox.zst" ]; then
check_supervisor_cross_toolchain
echo "==> Building bundled VM supervisor (mise run vm:supervisor)"
mise run vm:supervisor
fi
export OPENSHELL_VM_RUNTIME_COMPRESSED_DIR="${COMPRESSED_DIR}"
CARGO_BUILD_JOBS_ARG=()
if [[ -n "${CARGO_BUILD_JOBS:-}" ]]; then
CARGO_BUILD_JOBS_ARG=(-j "${CARGO_BUILD_JOBS}")
fi
echo "==> Building openshell-gateway and openshell-driver-vm"
cargo build ${CARGO_BUILD_JOBS_ARG[@]+"${CARGO_BUILD_JOBS_ARG[@]}"} \
-p openshell-server -p openshell-driver-vm
if [ "$(uname -s)" = "Darwin" ]; then
echo "==> Codesigning openshell-driver-vm (Hypervisor entitlement)"
codesign \
--entitlements "${ROOT}/crates/openshell-driver-vm/entitlements.plist" \
--force \
-s - \
"${DRIVER_DIR}/openshell-driver-vm"
fi
mkdir -p "${STATE_DIR}"
mkdir -p "${VM_DRIVER_STATE_DIR}"
chmod 700 "${VM_DRIVER_STATE_DIR}"
CONFIG_PATH="${STATE_DIR}/gateway.toml"
cat >"${CONFIG_PATH}" <<EOF
[openshell]
version = 1
[openshell.gateway]
compute_drivers = ["vm"]
disable_tls = ${DISABLE_TLS}
[openshell.drivers.vm]
default_image = "${SANDBOX_IMAGE}"
bootstrap_image = "${VM_BOOTSTRAP_IMAGE}"
grpc_endpoint = "${GRPC_ENDPOINT}"
driver_dir = "${DRIVER_DIR}"
state_dir = "${VM_DRIVER_STATE_DIR}"
EOF
GATEWAY_ENDPOINT="http://127.0.0.1:${PORT}"
register_gateway_metadata "${GATEWAY_NAME}" "${GATEWAY_ENDPOINT}" "${PORT}" "${VM_DRIVER_STATE_DIR}"
save_active_gateway "${GATEWAY_NAME}"
echo "Starting standalone VM gateway..."
echo " gateway: ${GATEWAY_NAME}"
echo " endpoint: ${GATEWAY_ENDPOINT}"
echo " namespace: ${SANDBOX_NAMESPACE}"
echo " state dir: ${STATE_DIR}"
echo " driver: ${DRIVER_DIR}/openshell-driver-vm"
echo " driver dir: ${VM_DRIVER_STATE_DIR}"
echo " gpu: ${VM_GPU}"
echo " image: ${SANDBOX_IMAGE}"
echo
echo "Active gateway set to '${GATEWAY_NAME}'. The CLI now targets this gateway"
echo "by default — just run \`openshell <command>\`. Override with --gateway"
echo "or by setting OPENSHELL_GATEWAY (e.g. in .env)."
echo
GATEWAY_ARGS=(
--config "${CONFIG_PATH}"
--port "${PORT}"
--log-level "${LOG_LEVEL}"
--drivers vm
--db-url "sqlite:${STATE_DIR}/gateway.db?mode=rwc"
)
if [ "${DISABLE_TLS}" = "true" ]; then
GATEWAY_ARGS+=(--disable-tls)
fi
exec "${GATEWAY_BIN}" "${GATEWAY_ARGS[@]}"