diff options
Diffstat (limited to 'recipes-containers/vcontainer/files/vrunner.sh')
| -rwxr-xr-x | recipes-containers/vcontainer/files/vrunner.sh | 80 |
1 files changed, 65 insertions, 15 deletions
diff --git a/recipes-containers/vcontainer/files/vrunner.sh b/recipes-containers/vcontainer/files/vrunner.sh index 04f0e39e..aaaaeb61 100755 --- a/recipes-containers/vcontainer/files/vrunner.sh +++ b/recipes-containers/vcontainer/files/vrunner.sh | |||
| @@ -323,6 +323,7 @@ BATCH_IMPORT="false" | |||
| 323 | DAEMON_MODE="" # start, send, stop, status | 323 | DAEMON_MODE="" # start, send, stop, status |
| 324 | DAEMON_SOCKET_DIR="" # Directory for daemon socket/PID files | 324 | DAEMON_SOCKET_DIR="" # Directory for daemon socket/PID files |
| 325 | IDLE_TIMEOUT="1800" # Default: 30 minutes | 325 | IDLE_TIMEOUT="1800" # Default: 30 minutes |
| 326 | EXIT_GRACE_PERIOD="" # Entrypoint exit grace period (vxn) | ||
| 326 | 327 | ||
| 327 | while [ $# -gt 0 ]; do | 328 | while [ $# -gt 0 ]; do |
| 328 | case $1 in | 329 | case $1 in |
| @@ -443,6 +444,10 @@ while [ $# -gt 0 ]; do | |||
| 443 | DAEMON_MODE="interactive" | 444 | DAEMON_MODE="interactive" |
| 444 | shift | 445 | shift |
| 445 | ;; | 446 | ;; |
| 447 | --daemon-run) | ||
| 448 | DAEMON_MODE="run" | ||
| 449 | shift | ||
| 450 | ;; | ||
| 446 | --daemon-stop) | 451 | --daemon-stop) |
| 447 | DAEMON_MODE="stop" | 452 | DAEMON_MODE="stop" |
| 448 | shift | 453 | shift |
| @@ -459,11 +464,20 @@ while [ $# -gt 0 ]; do | |||
| 459 | IDLE_TIMEOUT="$2" | 464 | IDLE_TIMEOUT="$2" |
| 460 | shift 2 | 465 | shift 2 |
| 461 | ;; | 466 | ;; |
| 467 | --container-name) | ||
| 468 | CONTAINER_NAME="$2" | ||
| 469 | export CONTAINER_NAME | ||
| 470 | shift 2 | ||
| 471 | ;; | ||
| 462 | --no-daemon) | 472 | --no-daemon) |
| 463 | # Placeholder for CLI wrapper - vrunner.sh itself doesn't use this | 473 | # Placeholder for CLI wrapper - vrunner.sh itself doesn't use this |
| 464 | # but we accept it so callers can pass it through | 474 | # but we accept it so callers can pass it through |
| 465 | shift | 475 | shift |
| 466 | ;; | 476 | ;; |
| 477 | --exit-grace-period) | ||
| 478 | EXIT_GRACE_PERIOD="$2" | ||
| 479 | shift 2 | ||
| 480 | ;; | ||
| 467 | --verbose|-v) | 481 | --verbose|-v) |
| 468 | VERBOSE="true" | 482 | VERBOSE="true" |
| 469 | shift | 483 | shift |
| @@ -597,6 +611,12 @@ daemon_send() { | |||
| 597 | exit 1 | 611 | exit 1 |
| 598 | fi | 612 | fi |
| 599 | 613 | ||
| 614 | # Use backend-specific send if available (e.g. Xen PTY-based IPC) | ||
| 615 | if type hv_daemon_send >/dev/null 2>&1; then | ||
| 616 | hv_daemon_send "$cmd" | ||
| 617 | return $? | ||
| 618 | fi | ||
| 619 | |||
| 600 | if [ ! -S "$DAEMON_SOCKET" ]; then | 620 | if [ ! -S "$DAEMON_SOCKET" ]; then |
| 601 | log "ERROR" "Daemon socket not found: $DAEMON_SOCKET" | 621 | log "ERROR" "Daemon socket not found: $DAEMON_SOCKET" |
| 602 | exit 1 | 622 | exit 1 |
| @@ -704,6 +724,14 @@ daemon_interactive() { | |||
| 704 | return 1 | 724 | return 1 |
| 705 | fi | 725 | fi |
| 706 | 726 | ||
| 727 | # PTY-based backends don't support interactive daemon mode | ||
| 728 | # (file-descriptor polling isn't practical for interactive I/O) | ||
| 729 | if type hv_daemon_send >/dev/null 2>&1; then | ||
| 730 | log "ERROR" "Interactive daemon mode not supported with ${VCONTAINER_HYPERVISOR} backend" | ||
| 731 | log "ERROR" "Use: ${TOOL_NAME} -it --no-daemon run ... for interactive mode" | ||
| 732 | return 1 | ||
| 733 | fi | ||
| 734 | |||
| 707 | if [ ! -S "$DAEMON_SOCKET" ]; then | 735 | if [ ! -S "$DAEMON_SOCKET" ]; then |
| 708 | log "ERROR" "Daemon socket not found: $DAEMON_SOCKET" | 736 | log "ERROR" "Daemon socket not found: $DAEMON_SOCKET" |
| 709 | return 1 | 737 | return 1 |
| @@ -1032,6 +1060,25 @@ if [ -n "$INPUT_PATH" ] && [ "$INPUT_TYPE" != "none" ]; then | |||
| 1032 | log "DEBUG" "Input disk: $(ls -lh "$INPUT_IMG" | awk '{print $5}')" | 1060 | log "DEBUG" "Input disk: $(ls -lh "$INPUT_IMG" | awk '{print $5}')" |
| 1033 | fi | 1061 | fi |
| 1034 | 1062 | ||
| 1063 | # Daemon run mode: try to use memres DomU, fall back to ephemeral | ||
| 1064 | # This runs after input disk creation so we have the container disk ready | ||
| 1065 | if [ "$DAEMON_MODE" = "run" ]; then | ||
| 1066 | if type hv_daemon_ping >/dev/null 2>&1 && hv_daemon_ping; then | ||
| 1067 | # Memres DomU is responsive — use it | ||
| 1068 | log "INFO" "Memres DomU is idle, dispatching container..." | ||
| 1069 | INPUT_IMG_PATH="" | ||
| 1070 | if [ -n "$DISK_OPTS" ]; then | ||
| 1071 | INPUT_IMG_PATH=$(echo "$DISK_OPTS" | sed -n 's/.*file=\([^,]*\).*/\1/p') | ||
| 1072 | fi | ||
| 1073 | hv_daemon_run_container "$DOCKER_CMD" "$INPUT_IMG_PATH" | ||
| 1074 | exit $? | ||
| 1075 | else | ||
| 1076 | # Memres DomU is occupied or not responding — fall through to ephemeral | ||
| 1077 | log "INFO" "Memres occupied or not responding, using ephemeral mode" | ||
| 1078 | DAEMON_MODE="" | ||
| 1079 | fi | ||
| 1080 | fi | ||
| 1081 | |||
| 1035 | # Create state disk for persistent storage (--state-dir) | 1082 | # Create state disk for persistent storage (--state-dir) |
| 1036 | # Xen backend skips this: DomU Docker storage lives in the guest's overlay | 1083 | # Xen backend skips this: DomU Docker storage lives in the guest's overlay |
| 1037 | # filesystem and persists as long as the domain is running (daemon mode). | 1084 | # filesystem and persists as long as the domain is running (daemon mode). |
| @@ -1175,6 +1222,11 @@ if [ "$INTERACTIVE" = "true" ]; then | |||
| 1175 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_interactive=1" | 1222 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_interactive=1" |
| 1176 | fi | 1223 | fi |
| 1177 | 1224 | ||
| 1225 | # Exit grace period for entrypoint death detection (vxn) | ||
| 1226 | if [ -n "${EXIT_GRACE_PERIOD:-}" ]; then | ||
| 1227 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_exit_grace=$EXIT_GRACE_PERIOD" | ||
| 1228 | fi | ||
| 1229 | |||
| 1178 | # Build VM configuration via hypervisor backend | 1230 | # Build VM configuration via hypervisor backend |
| 1179 | # Drive ordering is important: | 1231 | # Drive ordering is important: |
| 1180 | # rootfs.img (read-only), input disk (if any), state disk (if any) | 1232 | # rootfs.img (read-only), input disk (if any), state disk (if any) |
| @@ -1187,15 +1239,15 @@ if [ "$BATCH_IMPORT" = "true" ]; then | |||
| 1187 | BATCH_SHARE_DIR="$TEMP_DIR/share" | 1239 | BATCH_SHARE_DIR="$TEMP_DIR/share" |
| 1188 | mkdir -p "$BATCH_SHARE_DIR" | 1240 | mkdir -p "$BATCH_SHARE_DIR" |
| 1189 | SHARE_TAG="${TOOL_NAME}_share" | 1241 | SHARE_TAG="${TOOL_NAME}_share" |
| 1190 | HV_OPTS="$HV_OPTS $(hv_build_9p_opts "$BATCH_SHARE_DIR" "$SHARE_TAG")" | 1242 | hv_build_9p_opts "$BATCH_SHARE_DIR" "$SHARE_TAG" |
| 1191 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_9p=1" | 1243 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_9p=1" |
| 1192 | log "INFO" "Using 9p for fast storage output" | 1244 | log "INFO" "Using 9p for fast storage output" |
| 1193 | fi | 1245 | fi |
| 1194 | 1246 | ||
| 1195 | # Daemon mode: add serial channel for command I/O | 1247 | # Daemon mode: add serial channel for command I/O |
| 1196 | if [ "$DAEMON_MODE" = "start" ]; then | 1248 | if [ "$DAEMON_MODE" = "start" ]; then |
| 1197 | # Check for required tools | 1249 | # Check for required tools (socat needed unless backend provides PTY-based IPC) |
| 1198 | if ! command -v socat >/dev/null 2>&1; then | 1250 | if ! type hv_daemon_send >/dev/null 2>&1 && ! command -v socat >/dev/null 2>&1; then |
| 1199 | log "ERROR" "Daemon mode requires 'socat' but it is not installed." | 1251 | log "ERROR" "Daemon mode requires 'socat' but it is not installed." |
| 1200 | log "ERROR" "Install with: sudo apt install socat" | 1252 | log "ERROR" "Install with: sudo apt install socat" |
| 1201 | exit 1 | 1253 | exit 1 |
| @@ -1210,15 +1262,6 @@ if [ "$DAEMON_MODE" = "start" ]; then | |||
| 1210 | # Create socket directory | 1262 | # Create socket directory |
| 1211 | mkdir -p "$DAEMON_SOCKET_DIR" | 1263 | mkdir -p "$DAEMON_SOCKET_DIR" |
| 1212 | 1264 | ||
| 1213 | # Create shared directory for file I/O (9p) | ||
| 1214 | DAEMON_SHARE_DIR="$DAEMON_SOCKET_DIR/share" | ||
| 1215 | mkdir -p "$DAEMON_SHARE_DIR" | ||
| 1216 | |||
| 1217 | # Add 9p for shared directory access | ||
| 1218 | SHARE_TAG="${TOOL_NAME}_share" | ||
| 1219 | HV_OPTS="$HV_OPTS $(hv_build_9p_opts "$DAEMON_SHARE_DIR" "$SHARE_TAG")" | ||
| 1220 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_9p=1" | ||
| 1221 | |||
| 1222 | # Add daemon command channel (backend-specific: virtio-serial or PV console) | 1265 | # Add daemon command channel (backend-specific: virtio-serial or PV console) |
| 1223 | hv_build_daemon_opts | 1266 | hv_build_daemon_opts |
| 1224 | HV_OPTS="$HV_OPTS $HV_DAEMON_OPTS" | 1267 | HV_OPTS="$HV_OPTS $HV_DAEMON_OPTS" |
| @@ -1266,11 +1309,18 @@ if [ "$DAEMON_MODE" = "start" ]; then | |||
| 1266 | 1309 | ||
| 1267 | log "INFO" "VM started (PID: $HV_VM_PID)" | 1310 | log "INFO" "VM started (PID: $HV_VM_PID)" |
| 1268 | 1311 | ||
| 1269 | # Wait for socket to appear (container runtime starting) | 1312 | # Wait for daemon to be ready (backend-specific or socket-based) |
| 1270 | log "INFO" "Waiting for daemon to be ready..." | 1313 | log "INFO" "Waiting for daemon to be ready..." |
| 1271 | READY=false | 1314 | READY=false |
| 1272 | for i in $(seq 1 120); do | 1315 | for i in $(seq 1 120); do |
| 1273 | if [ -S "$DAEMON_SOCKET" ]; then | 1316 | # Backend-specific readiness check (e.g. Xen PTY-based) |
| 1317 | if type hv_daemon_ping >/dev/null 2>&1; then | ||
| 1318 | if hv_daemon_ping; then | ||
| 1319 | log "DEBUG" "Got PONG response (backend)" | ||
| 1320 | READY=true | ||
| 1321 | break | ||
| 1322 | fi | ||
| 1323 | elif [ -S "$DAEMON_SOCKET" ]; then | ||
| 1274 | RESPONSE=$( { echo "===PING==="; sleep 3; } | timeout 10 socat - "UNIX-CONNECT:$DAEMON_SOCKET" 2>/dev/null || true) | 1324 | RESPONSE=$( { echo "===PING==="; sleep 3; } | timeout 10 socat - "UNIX-CONNECT:$DAEMON_SOCKET" 2>/dev/null || true) |
| 1275 | if echo "$RESPONSE" | grep -q "===PONG==="; then | 1325 | if echo "$RESPONSE" | grep -q "===PONG==="; then |
| 1276 | log "DEBUG" "Got PONG response" | 1326 | log "DEBUG" "Got PONG response" |
| @@ -1356,7 +1406,7 @@ if [ -n "$CA_CERT" ] && [ -f "$CA_CERT" ]; then | |||
| 1356 | cp "$CA_CERT" "$CA_SHARE_DIR/ca.crt" | 1406 | cp "$CA_CERT" "$CA_SHARE_DIR/ca.crt" |
| 1357 | 1407 | ||
| 1358 | SHARE_TAG="${TOOL_NAME}_share" | 1408 | SHARE_TAG="${TOOL_NAME}_share" |
| 1359 | HV_OPTS="$HV_OPTS $(hv_build_9p_opts "$CA_SHARE_DIR" "$SHARE_TAG" "readonly=on")" | 1409 | hv_build_9p_opts "$CA_SHARE_DIR" "$SHARE_TAG" "readonly=on" |
| 1360 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_9p=1" | 1410 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_9p=1" |
| 1361 | log "DEBUG" "CA certificate available via 9p" | 1411 | log "DEBUG" "CA certificate available via 9p" |
| 1362 | fi | 1412 | fi |
