diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-08 04:46:41 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | 9e17cd687de956fd421454f1918131f824b95dbf (patch) | |
| tree | 64841606793f703758ce7e7b05a5e89434e7d4f1 /recipes-containers/vcontainer | |
| parent | 70a9de6c79b916991fcbf6fcc714891592a41a8b (diff) | |
| download | meta-virtualization-9e17cd687de956fd421454f1918131f824b95dbf.tar.gz | |
vcontainer: add auto-start daemon with idle timeout
Add automatic daemon startup and idle timeout cleanup for vdkr/vpdmn:
- vmemres daemon auto-starts on first command (no manual start needed)
- Daemon auto-stops after idle timeout (default: 30 minutes)
- --no-daemon flag for ephemeral mode (single-shot QEMU)
- New config keys: idle-timeout, auto-daemon
Changes:
- vcontainer-init-common.sh: Parse idle_timeout from cmdline, add
read -t timeout to daemon loop for auto-shutdown
- vrunner.sh: Add --idle-timeout option, pass to kernel cmdline
- vcontainer-common.sh: Auto-start logic in run_runtime_command(),
--no-daemon flag, config defaults
- container-cross-install.bbclass: Add --no-daemon for explicit
ephemeral mode during Yocto builds
Configuration:
vdkr vconfig idle-timeout 3600 # 1 hour timeout
vdkr vconfig auto-daemon false # Disable auto-start
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/vcontainer')
3 files changed, 100 insertions, 15 deletions
diff --git a/recipes-containers/vcontainer/files/vcontainer-common.sh b/recipes-containers/vcontainer/files/vcontainer-common.sh index c63d2b3c..7fd62514 100755 --- a/recipes-containers/vcontainer/files/vcontainer-common.sh +++ b/recipes-containers/vcontainer/files/vcontainer-common.sh | |||
| @@ -36,7 +36,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |||
| 36 | # 3. Default: ~/.config/${VCONTAINER_RUNTIME_NAME} | 36 | # 3. Default: ~/.config/${VCONTAINER_RUNTIME_NAME} |
| 37 | # | 37 | # |
| 38 | # Config file format: key=value (one per line) | 38 | # Config file format: key=value (one per line) |
| 39 | # Supported keys: arch, timeout, state-dir, verbose | 39 | # Supported keys: arch, timeout, state-dir, verbose, idle-timeout, auto-daemon |
| 40 | # ============================================================================ | 40 | # ============================================================================ |
| 41 | 41 | ||
| 42 | # Pre-parse --config-dir from command line (needs to happen before detect_default_arch) | 42 | # Pre-parse --config-dir from command line (needs to happen before detect_default_arch) |
| @@ -128,11 +128,13 @@ config_list() { | |||
| 128 | config_default() { | 128 | config_default() { |
| 129 | local key="$1" | 129 | local key="$1" |
| 130 | case "$key" in | 130 | case "$key" in |
| 131 | arch) uname -m ;; | 131 | arch) uname -m ;; |
| 132 | timeout) echo "300" ;; | 132 | timeout) echo "300" ;; |
| 133 | state-dir) echo "$HOME/.$VCONTAINER_RUNTIME_NAME" ;; | 133 | state-dir) echo "$HOME/.$VCONTAINER_RUNTIME_NAME" ;; |
| 134 | verbose) echo "false" ;; | 134 | verbose) echo "false" ;; |
| 135 | *) echo "" ;; | 135 | idle-timeout) echo "1800" ;; # 30 minutes |
| 136 | auto-daemon) echo "true" ;; # Auto-start daemon by default | ||
| 137 | *) echo "" ;; | ||
| 136 | esac | 138 | esac |
| 137 | } | 139 | } |
| 138 | 140 | ||
| @@ -387,9 +389,12 @@ ${BOLD}CONFIGURATION (vconfig):${NC} | |||
| 387 | ${CYAN}vconfig${NC} <key> <value> Set configuration value | 389 | ${CYAN}vconfig${NC} <key> <value> Set configuration value |
| 388 | ${CYAN}vconfig${NC} <key> --reset Reset to default value | 390 | ${CYAN}vconfig${NC} <key> --reset Reset to default value |
| 389 | 391 | ||
| 390 | Supported keys: arch, timeout, state-dir, verbose | 392 | Supported keys: arch, timeout, state-dir, verbose, idle-timeout, auto-daemon |
| 391 | Config file: \$CONFIG_DIR/config (default: ~/.config/${VCONTAINER_RUNTIME_NAME}/config) | 393 | Config file: \$CONFIG_DIR/config (default: ~/.config/${VCONTAINER_RUNTIME_NAME}/config) |
| 392 | 394 | ||
| 395 | idle-timeout: Daemon idle timeout in seconds [default: 1800] | ||
| 396 | auto-daemon: Auto-start daemon on first command [default: true] | ||
| 397 | |||
| 393 | ${BOLD}GLOBAL OPTIONS:${NC} | 398 | ${BOLD}GLOBAL OPTIONS:${NC} |
| 394 | --arch, -a <arch> Target architecture: x86_64 or aarch64 [default: ${DEFAULT_ARCH}] | 399 | --arch, -a <arch> Target architecture: x86_64 or aarch64 [default: ${DEFAULT_ARCH}] |
| 395 | --config-dir <path> Configuration directory [default: ~/.config/${VCONTAINER_RUNTIME_NAME}] | 400 | --config-dir <path> Configuration directory [default: ~/.config/${VCONTAINER_RUNTIME_NAME}] |
| @@ -400,6 +405,7 @@ ${BOLD}GLOBAL OPTIONS:${NC} | |||
| 400 | --storage <file> Export ${VCONTAINER_RUNTIME_CMD} storage after command (tar file) | 405 | --storage <file> Export ${VCONTAINER_RUNTIME_CMD} storage after command (tar file) |
| 401 | --input-storage <tar> Load ${RUNTIME_UPPER} state from tar before command | 406 | --input-storage <tar> Load ${RUNTIME_UPPER} state from tar before command |
| 402 | --no-kvm Disable KVM acceleration (use TCG emulation) | 407 | --no-kvm Disable KVM acceleration (use TCG emulation) |
| 408 | --no-daemon Run in ephemeral mode (don't auto-start/use daemon) | ||
| 403 | --verbose, -v Enable verbose output | 409 | --verbose, -v Enable verbose output |
| 404 | --help, -h Show this help | 410 | --help, -h Show this help |
| 405 | 411 | ||
| @@ -529,6 +535,7 @@ NETWORK="true" | |||
| 529 | INTERACTIVE="false" | 535 | INTERACTIVE="false" |
| 530 | PORT_FORWARDS=() | 536 | PORT_FORWARDS=() |
| 531 | DISABLE_KVM="false" | 537 | DISABLE_KVM="false" |
| 538 | NO_DAEMON="false" | ||
| 532 | COMMAND="" | 539 | COMMAND="" |
| 533 | COMMAND_ARGS=() | 540 | COMMAND_ARGS=() |
| 534 | 541 | ||
| @@ -585,6 +592,10 @@ while [ $# -gt 0 ]; do | |||
| 585 | DISABLE_KVM="true" | 592 | DISABLE_KVM="true" |
| 586 | shift | 593 | shift |
| 587 | ;; | 594 | ;; |
| 595 | --no-daemon) | ||
| 596 | NO_DAEMON="true" | ||
| 597 | shift | ||
| 598 | ;; | ||
| 588 | -it|--interactive) | 599 | -it|--interactive) |
| 589 | INTERACTIVE="true" | 600 | INTERACTIVE="true" |
| 590 | shift | 601 | shift |
| @@ -682,13 +693,37 @@ run_runtime_command() { | |||
| 682 | local runtime_cmd="$1" | 693 | local runtime_cmd="$1" |
| 683 | local runner_args=$(build_runner_args) | 694 | local runner_args=$(build_runner_args) |
| 684 | 695 | ||
| 696 | # Check for --no-daemon flag - use ephemeral mode | ||
| 697 | if [ "$NO_DAEMON" = "true" ]; then | ||
| 698 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using ephemeral mode (--no-daemon)" >&2 | ||
| 699 | "$RUNNER" $runner_args -- "$runtime_cmd" | ||
| 700 | return $? | ||
| 701 | fi | ||
| 702 | |||
| 685 | if daemon_is_running; then | 703 | if daemon_is_running; then |
| 686 | # Use daemon mode - faster | 704 | # Use daemon mode - faster |
| 687 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode" >&2 | 705 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode" >&2 |
| 688 | "$RUNNER" $runner_args --daemon-send "$runtime_cmd" | 706 | "$RUNNER" $runner_args --daemon-send "$runtime_cmd" |
| 689 | else | 707 | else |
| 690 | # Regular mode - start QEMU for this command | 708 | # Check if auto-daemon is enabled |
| 691 | "$RUNNER" $runner_args -- "$runtime_cmd" | 709 | local auto_daemon=$(config_get "auto-daemon" "true") |
| 710 | if [ "$auto_daemon" = "true" ]; then | ||
| 711 | # Auto-start daemon | ||
| 712 | echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Starting daemon..." >&2 | ||
| 713 | local idle_timeout=$(config_get "idle-timeout" "1800") | ||
| 714 | "$RUNNER" $runner_args --idle-timeout "$idle_timeout" --daemon-start | ||
| 715 | |||
| 716 | if daemon_is_running; then | ||
| 717 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode" >&2 | ||
| 718 | "$RUNNER" $runner_args --daemon-send "$runtime_cmd" | ||
| 719 | else | ||
| 720 | echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Failed to start daemon, using ephemeral mode" >&2 | ||
| 721 | "$RUNNER" $runner_args -- "$runtime_cmd" | ||
| 722 | fi | ||
| 723 | else | ||
| 724 | # Auto-daemon disabled - use ephemeral mode | ||
| 725 | "$RUNNER" $runner_args -- "$runtime_cmd" | ||
| 726 | fi | ||
| 692 | fi | 727 | fi |
| 693 | } | 728 | } |
| 694 | 729 | ||
| @@ -700,13 +735,37 @@ run_runtime_command_with_input() { | |||
| 700 | local runtime_cmd="$3" | 735 | local runtime_cmd="$3" |
| 701 | local runner_args=$(build_runner_args) | 736 | local runner_args=$(build_runner_args) |
| 702 | 737 | ||
| 738 | # Check for --no-daemon flag - use ephemeral mode | ||
| 739 | if [ "$NO_DAEMON" = "true" ]; then | ||
| 740 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using ephemeral mode (--no-daemon)" >&2 | ||
| 741 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" -- "$runtime_cmd" | ||
| 742 | return $? | ||
| 743 | fi | ||
| 744 | |||
| 703 | if daemon_is_running; then | 745 | if daemon_is_running; then |
| 704 | # Use daemon mode with virtio-9p shared directory | 746 | # Use daemon mode with virtio-9p shared directory |
| 705 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode for file I/O" >&2 | 747 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode for file I/O" >&2 |
| 706 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" --daemon-send-input -- "$runtime_cmd" | 748 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" --daemon-send-input -- "$runtime_cmd" |
| 707 | else | 749 | else |
| 708 | # Regular mode - start QEMU for this command | 750 | # Check if auto-daemon is enabled |
| 709 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" -- "$runtime_cmd" | 751 | local auto_daemon=$(config_get "auto-daemon" "true") |
| 752 | if [ "$auto_daemon" = "true" ]; then | ||
| 753 | # Auto-start daemon | ||
| 754 | echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Starting daemon..." >&2 | ||
| 755 | local idle_timeout=$(config_get "idle-timeout" "1800") | ||
| 756 | "$RUNNER" $runner_args --idle-timeout "$idle_timeout" --daemon-start | ||
| 757 | |||
| 758 | if daemon_is_running; then | ||
| 759 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Using daemon mode for file I/O" >&2 | ||
| 760 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" --daemon-send-input -- "$runtime_cmd" | ||
| 761 | else | ||
| 762 | echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Failed to start daemon, using ephemeral mode" >&2 | ||
| 763 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" -- "$runtime_cmd" | ||
| 764 | fi | ||
| 765 | else | ||
| 766 | # Auto-daemon disabled - use ephemeral mode | ||
| 767 | "$RUNNER" $runner_args --input "$input_path" --input-type "$input_type" -- "$runtime_cmd" | ||
| 768 | fi | ||
| 710 | fi | 769 | fi |
| 711 | } | 770 | } |
| 712 | 771 | ||
diff --git a/recipes-containers/vcontainer/files/vcontainer-init-common.sh b/recipes-containers/vcontainer/files/vcontainer-init-common.sh index 872508db..5bfee9b7 100755 --- a/recipes-containers/vcontainer/files/vcontainer-init-common.sh +++ b/recipes-containers/vcontainer/files/vcontainer-init-common.sh | |||
| @@ -106,6 +106,7 @@ parse_cmdline() { | |||
| 106 | RUNTIME_NETWORK="0" | 106 | RUNTIME_NETWORK="0" |
| 107 | RUNTIME_INTERACTIVE="0" | 107 | RUNTIME_INTERACTIVE="0" |
| 108 | RUNTIME_DAEMON="0" | 108 | RUNTIME_DAEMON="0" |
| 109 | RUNTIME_IDLE_TIMEOUT="1800" # Default: 30 minutes | ||
| 109 | 110 | ||
| 110 | for param in $(cat /proc/cmdline); do | 111 | for param in $(cat /proc/cmdline); do |
| 111 | case "$param" in | 112 | case "$param" in |
| @@ -130,6 +131,9 @@ parse_cmdline() { | |||
| 130 | ${VCONTAINER_RUNTIME_PREFIX}_daemon=*) | 131 | ${VCONTAINER_RUNTIME_PREFIX}_daemon=*) |
| 131 | RUNTIME_DAEMON="${param#${VCONTAINER_RUNTIME_PREFIX}_daemon=}" | 132 | RUNTIME_DAEMON="${param#${VCONTAINER_RUNTIME_PREFIX}_daemon=}" |
| 132 | ;; | 133 | ;; |
| 134 | ${VCONTAINER_RUNTIME_PREFIX}_idle_timeout=*) | ||
| 135 | RUNTIME_IDLE_TIMEOUT="${param#${VCONTAINER_RUNTIME_PREFIX}_idle_timeout=}" | ||
| 136 | ;; | ||
| 133 | esac | 137 | esac |
| 134 | done | 138 | done |
| 135 | 139 | ||
| @@ -284,6 +288,7 @@ DNSEOF | |||
| 284 | 288 | ||
| 285 | run_daemon_mode() { | 289 | run_daemon_mode() { |
| 286 | log "=== Daemon Mode ===" | 290 | log "=== Daemon Mode ===" |
| 291 | log "Idle timeout: ${RUNTIME_IDLE_TIMEOUT}s" | ||
| 287 | 292 | ||
| 288 | # Find the virtio-serial port for command channel | 293 | # Find the virtio-serial port for command channel |
| 289 | DAEMON_PORT="" | 294 | DAEMON_PORT="" |
| @@ -321,10 +326,10 @@ run_daemon_mode() { | |||
| 321 | 326 | ||
| 322 | log "Daemon ready, waiting for commands..." | 327 | log "Daemon ready, waiting for commands..." |
| 323 | 328 | ||
| 324 | # Command loop | 329 | # Command loop with idle timeout |
| 325 | while true; do | 330 | while true; do |
| 326 | CMD_B64="" | 331 | CMD_B64="" |
| 327 | if read -r CMD_B64 <&3; then | 332 | if read -t "$RUNTIME_IDLE_TIMEOUT" -r CMD_B64 <&3; then |
| 328 | log "Received: '$CMD_B64'" | 333 | log "Received: '$CMD_B64'" |
| 329 | # Handle special commands | 334 | # Handle special commands |
| 330 | case "$CMD_B64" in | 335 | case "$CMD_B64" in |
| @@ -414,7 +419,15 @@ run_daemon_mode() { | |||
| 414 | 419 | ||
| 415 | log "Command completed (exit code: $EXEC_EXIT_CODE)" | 420 | log "Command completed (exit code: $EXEC_EXIT_CODE)" |
| 416 | else | 421 | else |
| 417 | sleep 1 | 422 | # Read returned non-zero: either timeout or error |
| 423 | if [ -z "$CMD_B64" ]; then | ||
| 424 | # Timeout expired with no data - shut down | ||
| 425 | log "Idle timeout (${RUNTIME_IDLE_TIMEOUT}s), shutting down..." | ||
| 426 | echo "===IDLE_SHUTDOWN===" | cat >&3 | ||
| 427 | break | ||
| 428 | fi | ||
| 429 | # Empty line or other issue - just continue | ||
| 430 | sleep 0.1 | ||
| 418 | fi | 431 | fi |
| 419 | done | 432 | done |
| 420 | 433 | ||
diff --git a/recipes-containers/vcontainer/files/vrunner.sh b/recipes-containers/vcontainer/files/vrunner.sh index 2be33765..cd504f7b 100755 --- a/recipes-containers/vcontainer/files/vrunner.sh +++ b/recipes-containers/vcontainer/files/vrunner.sh | |||
| @@ -122,7 +122,9 @@ OPTIONS: | |||
| 122 | --network, -n Enable networking (slirp user-mode, outbound only) | 122 | --network, -n Enable networking (slirp user-mode, outbound only) |
| 123 | --interactive, -it Run in interactive mode (connects terminal to container) | 123 | --interactive, -it Run in interactive mode (connects terminal to container) |
| 124 | --timeout <secs> QEMU timeout [default: 300] | 124 | --timeout <secs> QEMU timeout [default: 300] |
| 125 | --idle-timeout <s> Daemon idle timeout in seconds [default: 1800] | ||
| 125 | --no-kvm Disable KVM acceleration (use TCG emulation) | 126 | --no-kvm Disable KVM acceleration (use TCG emulation) |
| 127 | --no-daemon Placeholder for CLI wrapper (ignored by vrunner) | ||
| 126 | --batch-import Batch import mode: import multiple OCI containers in one session | 128 | --batch-import Batch import mode: import multiple OCI containers in one session |
| 127 | --keep-temp Keep temporary files for debugging | 129 | --keep-temp Keep temporary files for debugging |
| 128 | --verbose, -v Enable verbose output | 130 | --verbose, -v Enable verbose output |
| @@ -195,6 +197,7 @@ BATCH_IMPORT="false" | |||
| 195 | # Daemon mode options | 197 | # Daemon mode options |
| 196 | DAEMON_MODE="" # start, send, stop, status | 198 | DAEMON_MODE="" # start, send, stop, status |
| 197 | DAEMON_SOCKET_DIR="" # Directory for daemon socket/PID files | 199 | DAEMON_SOCKET_DIR="" # Directory for daemon socket/PID files |
| 200 | IDLE_TIMEOUT="1800" # Default: 30 minutes | ||
| 198 | 201 | ||
| 199 | while [ $# -gt 0 ]; do | 202 | while [ $# -gt 0 ]; do |
| 200 | case $1 in | 203 | case $1 in |
| @@ -293,6 +296,15 @@ while [ $# -gt 0 ]; do | |||
| 293 | DAEMON_SOCKET_DIR="$2" | 296 | DAEMON_SOCKET_DIR="$2" |
| 294 | shift 2 | 297 | shift 2 |
| 295 | ;; | 298 | ;; |
| 299 | --idle-timeout) | ||
| 300 | IDLE_TIMEOUT="$2" | ||
| 301 | shift 2 | ||
| 302 | ;; | ||
| 303 | --no-daemon) | ||
| 304 | # Placeholder for CLI wrapper - vrunner.sh itself doesn't use this | ||
| 305 | # but we accept it so callers can pass it through | ||
| 306 | shift | ||
| 307 | ;; | ||
| 296 | --verbose|-v) | 308 | --verbose|-v) |
| 297 | VERBOSE="true" | 309 | VERBOSE="true" |
| 298 | shift | 310 | shift |
| @@ -1061,8 +1073,9 @@ if [ "$DAEMON_MODE" = "start" ]; then | |||
| 1061 | QEMU_OPTS="$QEMU_OPTS -device virtio-serial-pci" | 1073 | QEMU_OPTS="$QEMU_OPTS -device virtio-serial-pci" |
| 1062 | QEMU_OPTS="$QEMU_OPTS -device virtserialport,chardev=vdkr,name=vdkr" | 1074 | QEMU_OPTS="$QEMU_OPTS -device virtserialport,chardev=vdkr,name=vdkr" |
| 1063 | 1075 | ||
| 1064 | # Tell init script to run in daemon mode | 1076 | # Tell init script to run in daemon mode with idle timeout |
| 1065 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_daemon=1" | 1077 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_daemon=1" |
| 1078 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_idle_timeout=$IDLE_TIMEOUT" | ||
| 1066 | 1079 | ||
| 1067 | # Always enable networking for daemon mode | 1080 | # Always enable networking for daemon mode |
| 1068 | if [ "$NETWORK" != "true" ]; then | 1081 | if [ "$NETWORK" != "true" ]; then |
