diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-01-08 04:54:11 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-09 03:32:52 +0000 |
| commit | 0ebf4ef7838d5c831a7e56a91981a53480ea5d5f (patch) | |
| tree | ba776810b61bcd3898614b531724ff8db79d6e0d /recipes-containers/vcontainer | |
| parent | 9e17cd687de956fd421454f1918131f824b95dbf (diff) | |
| download | meta-virtualization-0ebf4ef7838d5c831a7e56a91981a53480ea5d5f.tar.gz | |
vcontainer: add dynamic port forwarding via QEMU QMP
Add dynamic port forwarding for containers using QEMU's QMP (QEMU
Machine Protocol). This enables running multiple detached containers
with different port mappings without needing to declare ports upfront.
Key changes:
- vrunner.sh: Add QMP socket (-qmp unix:...) to daemon startup
- vcontainer-common.sh:
* QMP helper functions (qmp_send, qmp_add_hostfwd, qmp_remove_hostfwd)
* Port forward registry (port-forwards.txt) for tracking mappings
* Parse -p, -d, --name flags in run command
* Add port forwards via QMP for detached containers
* Enhanced ps command to show host port forwards
* Cleanup port forwards on stop/rm/vmemres stop
Usage:
vdkr run -d -p 8080:80 nginx # Adds 8080->80 forward
vdkr run -d -p 3000:3000 myapp # Adds 3000->3000 forward
vdkr ps # Shows containers + port forwards
vdkr stop nginx # Removes 8080->80 forward
This solves the problem where auto-started vmemres couldn't handle
multiple containers with different port mappings. QMP allows adding
and removing port forwards at runtime without restarting the daemon.
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/vcontainer')
| -rwxr-xr-x | recipes-containers/vcontainer/files/vcontainer-common.sh | 304 | ||||
| -rwxr-xr-x | recipes-containers/vcontainer/files/vrunner.sh | 4 |
2 files changed, 291 insertions, 17 deletions
diff --git a/recipes-containers/vcontainer/files/vcontainer-common.sh b/recipes-containers/vcontainer/files/vcontainer-common.sh index 7fd62514..7d7c0ee6 100755 --- a/recipes-containers/vcontainer/files/vcontainer-common.sh +++ b/recipes-containers/vcontainer/files/vcontainer-common.sh | |||
| @@ -355,17 +355,31 @@ ${BOLD}EXTENDED COMMANDS (${VCONTAINER_RUNTIME_NAME}-specific):${NC} | |||
| 355 | ${CYAN}clean${NC} ${YELLOW}[DEPRECATED]${NC} Use 'vstorage clean' instead | 355 | ${CYAN}clean${NC} ${YELLOW}[DEPRECATED]${NC} Use 'vstorage clean' instead |
| 356 | 356 | ||
| 357 | ${BOLD}MEMORY RESIDENT MODE (vmemres):${NC} | 357 | ${BOLD}MEMORY RESIDENT MODE (vmemres):${NC} |
| 358 | ${CYAN}vmemres start${NC} [-p port:port] Start memory resident VM in background | 358 | By default, vmemres auto-starts on the first command and stops after idle timeout. |
| 359 | This provides fast command execution without manual daemon management. | ||
| 360 | |||
| 361 | ${CYAN}vmemres start${NC} Start memory resident VM in background | ||
| 359 | ${CYAN}vmemres stop${NC} Stop memory resident VM | 362 | ${CYAN}vmemres stop${NC} Stop memory resident VM |
| 360 | ${CYAN}vmemres restart${NC} [--clean] Restart VM (optionally clean state first) | 363 | ${CYAN}vmemres restart${NC} [--clean] Restart VM (optionally clean state first) |
| 361 | ${CYAN}vmemres status${NC} Show memory resident VM status | 364 | ${CYAN}vmemres status${NC} Show memory resident VM status |
| 362 | ${CYAN}vmemres list${NC} List all running memres instances | 365 | ${CYAN}vmemres list${NC} List all running memres instances |
| 363 | (Note: 'memres' also works as an alias for 'vmemres') | 366 | (Note: 'memres' also works as an alias for 'vmemres') |
| 364 | 367 | ||
| 365 | Port forwarding with vmemres: | 368 | Auto-start and idle timeout: |
| 366 | -p <host_port>:<container_port>[/protocol] | 369 | - Daemon auto-starts when you run any command (configurable via vconfig auto-daemon) |
| 367 | Forward host port to container port (protocol: tcp or udp, default: tcp) | 370 | - Daemon auto-stops after 30 minutes of inactivity (configurable via vconfig idle-timeout) |
| 368 | Multiple -p options can be specified | 371 | - Use --no-daemon to run commands in ephemeral mode (no daemon) |
| 372 | |||
| 373 | ${BOLD}Dynamic Port Forwarding:${NC} | ||
| 374 | When running detached containers with -p, port forwards are added dynamically: | ||
| 375 | ${PROG_NAME} run -d -p 8080:80 nginx # Adds 8080->80 forward | ||
| 376 | ${PROG_NAME} run -d -p 3000:3000 myapp # Adds 3000->3000 forward | ||
| 377 | ${PROG_NAME} ps # Shows containers AND port forwards | ||
| 378 | ${PROG_NAME} stop nginx # Removes 8080->80 forward | ||
| 379 | |||
| 380 | Port format: -p <host_port>:<container_port>[/protocol] | ||
| 381 | - protocol: tcp (default) or udp | ||
| 382 | - Multiple -p options can be specified | ||
| 369 | 383 | ||
| 370 | ${YELLOW}NOTE:${NC} --network=host is used by default for all containers. | 384 | ${YELLOW}NOTE:${NC} --network=host is used by default for all containers. |
| 371 | Docker bridge networking is not available inside the VM. Host networking | 385 | Docker bridge networking is not available inside the VM. Host networking |
| @@ -688,6 +702,139 @@ daemon_is_running() { | |||
| 688 | return 1 | 702 | return 1 |
| 689 | } | 703 | } |
| 690 | 704 | ||
| 705 | # ============================================================================ | ||
| 706 | # QMP (QEMU Machine Protocol) Helpers for Dynamic Port Forwarding | ||
| 707 | # ============================================================================ | ||
| 708 | # These functions communicate with QEMU's QMP socket to add/remove port | ||
| 709 | # forwards at runtime without restarting the daemon. | ||
| 710 | |||
| 711 | # Get the QMP socket path | ||
| 712 | get_qmp_socket() { | ||
| 713 | local state_dir="${STATE_DIR:-$DEFAULT_STATE_DIR/$TARGET_ARCH}" | ||
| 714 | echo "$state_dir/qmp.sock" | ||
| 715 | } | ||
| 716 | |||
| 717 | # Send a QMP command and get the response | ||
| 718 | # Usage: qmp_send "command-line" | ||
| 719 | qmp_send() { | ||
| 720 | local cmd="$1" | ||
| 721 | local qmp_socket=$(get_qmp_socket) | ||
| 722 | |||
| 723 | if [ ! -S "$qmp_socket" ]; then | ||
| 724 | echo "QMP socket not found: $qmp_socket" >&2 | ||
| 725 | return 1 | ||
| 726 | fi | ||
| 727 | |||
| 728 | # QMP requires a capabilities negotiation first, then human-monitor-command | ||
| 729 | # We use socat to send the command | ||
| 730 | { | ||
| 731 | echo '{"execute":"qmp_capabilities"}' | ||
| 732 | sleep 0.1 | ||
| 733 | echo "{\"execute\":\"human-monitor-command\",\"arguments\":{\"command-line\":\"$cmd\"}}" | ||
| 734 | } | socat - "unix-connect:$qmp_socket" 2>/dev/null | ||
| 735 | } | ||
| 736 | |||
| 737 | # Add a port forward to the running daemon | ||
| 738 | # Usage: qmp_add_hostfwd <host_port> <guest_port> [protocol] | ||
| 739 | qmp_add_hostfwd() { | ||
| 740 | local host_port="$1" | ||
| 741 | local guest_port="$2" | ||
| 742 | local protocol="${3:-tcp}" | ||
| 743 | |||
| 744 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Adding port forward: ${host_port} -> ${guest_port}/${protocol}" >&2 | ||
| 745 | |||
| 746 | local result=$(qmp_send "hostfwd_add user.0 ${protocol}::${host_port}-:${guest_port}") | ||
| 747 | if echo "$result" | grep -q '"error"'; then | ||
| 748 | echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Failed to add port forward: $result" >&2 | ||
| 749 | return 1 | ||
| 750 | fi | ||
| 751 | return 0 | ||
| 752 | } | ||
| 753 | |||
| 754 | # Remove a port forward from the running daemon | ||
| 755 | # Usage: qmp_remove_hostfwd <host_port> [protocol] | ||
| 756 | qmp_remove_hostfwd() { | ||
| 757 | local host_port="$1" | ||
| 758 | local protocol="${2:-tcp}" | ||
| 759 | |||
| 760 | [ "$VERBOSE" = "true" ] && echo -e "${CYAN}[$VCONTAINER_RUNTIME_NAME]${NC} Removing port forward: ${host_port}/${protocol}" >&2 | ||
| 761 | |||
| 762 | local result=$(qmp_send "hostfwd_remove user.0 ${protocol}::${host_port}") | ||
| 763 | if echo "$result" | grep -q '"error"'; then | ||
| 764 | echo -e "${RED}[$VCONTAINER_RUNTIME_NAME]${NC} Failed to remove port forward: $result" >&2 | ||
| 765 | return 1 | ||
| 766 | fi | ||
| 767 | return 0 | ||
| 768 | } | ||
| 769 | |||
| 770 | # ============================================================================ | ||
| 771 | # Port Forward Registry | ||
| 772 | # ============================================================================ | ||
| 773 | # Track which ports are forwarded for which containers so we can clean up | ||
| 774 | # when containers are stopped. | ||
| 775 | |||
| 776 | PORT_FORWARD_FILE="" | ||
| 777 | |||
| 778 | get_port_forward_file() { | ||
| 779 | if [ -z "$PORT_FORWARD_FILE" ]; then | ||
| 780 | local state_dir="${STATE_DIR:-$DEFAULT_STATE_DIR/$TARGET_ARCH}" | ||
| 781 | PORT_FORWARD_FILE="$state_dir/port-forwards.txt" | ||
| 782 | fi | ||
| 783 | echo "$PORT_FORWARD_FILE" | ||
| 784 | } | ||
| 785 | |||
| 786 | # Register a port forward for a container | ||
| 787 | # Usage: register_port_forward <container_name> <host_port> <guest_port> [protocol] | ||
| 788 | register_port_forward() { | ||
| 789 | local container_name="$1" | ||
| 790 | local host_port="$2" | ||
| 791 | local guest_port="$3" | ||
| 792 | local protocol="${4:-tcp}" | ||
| 793 | |||
| 794 | local pf_file=$(get_port_forward_file) | ||
| 795 | mkdir -p "$(dirname "$pf_file")" | ||
| 796 | echo "${container_name}:${host_port}:${guest_port}:${protocol}" >> "$pf_file" | ||
| 797 | } | ||
| 798 | |||
| 799 | # Unregister and remove port forwards for a container | ||
| 800 | # Usage: unregister_port_forwards <container_name> | ||
| 801 | unregister_port_forwards() { | ||
| 802 | local container_name="$1" | ||
| 803 | local pf_file=$(get_port_forward_file) | ||
| 804 | |||
| 805 | if [ ! -f "$pf_file" ]; then | ||
| 806 | return 0 | ||
| 807 | fi | ||
| 808 | |||
| 809 | # Find and remove all port forwards for this container | ||
| 810 | local temp_file="${pf_file}.tmp" | ||
| 811 | while IFS=: read -r name host_port guest_port protocol; do | ||
| 812 | if [ "$name" = "$container_name" ]; then | ||
| 813 | qmp_remove_hostfwd "$host_port" "$protocol" | ||
| 814 | else | ||
| 815 | echo "${name}:${host_port}:${guest_port}:${protocol}" | ||
| 816 | fi | ||
| 817 | done < "$pf_file" > "$temp_file" | ||
| 818 | mv "$temp_file" "$pf_file" | ||
| 819 | } | ||
| 820 | |||
| 821 | # List all registered port forwards | ||
| 822 | # Usage: list_port_forwards [container_name] | ||
| 823 | list_port_forwards() { | ||
| 824 | local filter_name="$1" | ||
| 825 | local pf_file=$(get_port_forward_file) | ||
| 826 | |||
| 827 | if [ ! -f "$pf_file" ]; then | ||
| 828 | return 0 | ||
| 829 | fi | ||
| 830 | |||
| 831 | while IFS=: read -r name host_port guest_port protocol; do | ||
| 832 | if [ -z "$filter_name" ] || [ "$name" = "$filter_name" ]; then | ||
| 833 | echo "0.0.0.0:${host_port}->${guest_port}/${protocol}" | ||
| 834 | fi | ||
| 835 | done < "$pf_file" | ||
| 836 | } | ||
| 837 | |||
| 691 | # Helper function to run command via daemon or regular mode | 838 | # Helper function to run command via daemon or regular mode |
| 692 | run_runtime_command() { | 839 | run_runtime_command() { |
| 693 | local runtime_cmd="$1" | 840 | local runtime_cmd="$1" |
| @@ -1166,12 +1313,37 @@ case "$COMMAND" in | |||
| 1166 | 1313 | ||
| 1167 | # Container lifecycle commands | 1314 | # Container lifecycle commands |
| 1168 | ps) | 1315 | ps) |
| 1169 | # List containers | 1316 | # List containers and show port forwards if daemon is running |
| 1170 | run_runtime_command "$VCONTAINER_RUNTIME_CMD ps ${COMMAND_ARGS[*]}" | 1317 | run_runtime_command "$VCONTAINER_RUNTIME_CMD ps ${COMMAND_ARGS[*]}" |
| 1318 | PS_EXIT=$? | ||
| 1319 | |||
| 1320 | # Show host port forwards if daemon is running and we have any | ||
| 1321 | if daemon_is_running; then | ||
| 1322 | local pf_file=$(get_port_forward_file) | ||
| 1323 | if [ -f "$pf_file" ] && [ -s "$pf_file" ]; then | ||
| 1324 | echo "" | ||
| 1325 | echo -e "${CYAN}Host Port Forwards (QEMU):${NC}" | ||
| 1326 | printf " %-20s %-15s %-15s %-8s\n" "CONTAINER" "HOST PORT" "GUEST PORT" "PROTO" | ||
| 1327 | while IFS=: read -r name host_port guest_port protocol; do | ||
| 1328 | printf " %-20s %-15s %-15s %-8s\n" "$name" "0.0.0.0:$host_port" "$guest_port" "${protocol:-tcp}" | ||
| 1329 | done < "$pf_file" | ||
| 1330 | fi | ||
| 1331 | fi | ||
| 1332 | exit $PS_EXIT | ||
| 1171 | ;; | 1333 | ;; |
| 1172 | 1334 | ||
| 1173 | rm) | 1335 | rm) |
| 1174 | # Remove containers | 1336 | # Remove containers and cleanup any registered port forwards |
| 1337 | for arg in "${COMMAND_ARGS[@]}"; do | ||
| 1338 | # Skip flags like -f, --force, etc. | ||
| 1339 | case "$arg" in | ||
| 1340 | -*) continue ;; | ||
| 1341 | esac | ||
| 1342 | # This is a container name/id - clean up its port forwards | ||
| 1343 | if daemon_is_running; then | ||
| 1344 | unregister_port_forwards "$arg" | ||
| 1345 | fi | ||
| 1346 | done | ||
| 1175 | run_runtime_command "$VCONTAINER_RUNTIME_CMD rm ${COMMAND_ARGS[*]}" | 1347 | run_runtime_command "$VCONTAINER_RUNTIME_CMD rm ${COMMAND_ARGS[*]}" |
| 1176 | ;; | 1348 | ;; |
| 1177 | 1349 | ||
| @@ -1185,11 +1357,23 @@ case "$COMMAND" in | |||
| 1185 | run_runtime_command "$VCONTAINER_RUNTIME_CMD inspect ${COMMAND_ARGS[*]}" | 1357 | run_runtime_command "$VCONTAINER_RUNTIME_CMD inspect ${COMMAND_ARGS[*]}" |
| 1186 | ;; | 1358 | ;; |
| 1187 | 1359 | ||
| 1188 | start|stop|restart|kill|pause|unpause) | 1360 | start|restart|kill|pause|unpause) |
| 1189 | # Container state commands | 1361 | # Container state commands (no special handling needed) |
| 1190 | run_runtime_command "$VCONTAINER_RUNTIME_CMD $COMMAND ${COMMAND_ARGS[*]}" | 1362 | run_runtime_command "$VCONTAINER_RUNTIME_CMD $COMMAND ${COMMAND_ARGS[*]}" |
| 1191 | ;; | 1363 | ;; |
| 1192 | 1364 | ||
| 1365 | stop) | ||
| 1366 | # Stop container and cleanup any registered port forwards | ||
| 1367 | if [ ${#COMMAND_ARGS[@]} -ge 1 ]; then | ||
| 1368 | STOP_CONTAINER_NAME="${COMMAND_ARGS[0]}" | ||
| 1369 | # Remove port forwards for this container (if any) | ||
| 1370 | if daemon_is_running; then | ||
| 1371 | unregister_port_forwards "$STOP_CONTAINER_NAME" | ||
| 1372 | fi | ||
| 1373 | fi | ||
| 1374 | run_runtime_command "$VCONTAINER_RUNTIME_CMD stop ${COMMAND_ARGS[*]}" | ||
| 1375 | ;; | ||
| 1376 | |||
| 1193 | # Image commands | 1377 | # Image commands |
| 1194 | commit) | 1378 | commit) |
| 1195 | # Commit container to image | 1379 | # Commit container to image |
| @@ -1335,7 +1519,7 @@ case "$COMMAND" in | |||
| 1335 | 1519 | ||
| 1336 | vconfig) | 1520 | vconfig) |
| 1337 | # Configuration management (runs on host, not in VM) | 1521 | # Configuration management (runs on host, not in VM) |
| 1338 | VALID_KEYS="arch timeout state-dir verbose" | 1522 | VALID_KEYS="arch timeout state-dir verbose idle-timeout auto-daemon" |
| 1339 | 1523 | ||
| 1340 | if [ ${#COMMAND_ARGS[@]} -lt 1 ]; then | 1524 | if [ ${#COMMAND_ARGS[@]} -lt 1 ]; then |
| 1341 | # Show all config | 1525 | # Show all config |
| @@ -1800,17 +1984,46 @@ case "$COMMAND" in | |||
| 1800 | exit 1 | 1984 | exit 1 |
| 1801 | fi | 1985 | fi |
| 1802 | 1986 | ||
| 1803 | # Check if any volume mounts are present and if user specified --network | 1987 | # Check if any volume mounts, network, port forwards, or detach are present |
| 1804 | RUN_HAS_VOLUMES=false | 1988 | RUN_HAS_VOLUMES=false |
| 1805 | RUN_HAS_NETWORK=false | 1989 | RUN_HAS_NETWORK=false |
| 1990 | RUN_HAS_PORT_FORWARDS=false | ||
| 1991 | RUN_IS_DETACHED=false | ||
| 1992 | RUN_CONTAINER_NAME="" | ||
| 1993 | RUN_PORT_FORWARDS=() | ||
| 1994 | |||
| 1995 | # Parse COMMAND_ARGS to extract relevant flags | ||
| 1996 | local i=0 | ||
| 1997 | local prev_arg="" | ||
| 1806 | for arg in "${COMMAND_ARGS[@]}"; do | 1998 | for arg in "${COMMAND_ARGS[@]}"; do |
| 1807 | if [ "$arg" = "-v" ] || [ "$arg" = "--volume" ]; then | ||
| 1808 | RUN_HAS_VOLUMES=true | ||
| 1809 | fi | ||
| 1810 | # Check for explicit --network option (user override) | ||
| 1811 | case "$arg" in | 1999 | case "$arg" in |
| 1812 | --network=*|--net=*) RUN_HAS_NETWORK=true ;; | 2000 | -v|--volume) |
| 2001 | RUN_HAS_VOLUMES=true | ||
| 2002 | ;; | ||
| 2003 | --network=*|--net=*) | ||
| 2004 | RUN_HAS_NETWORK=true | ||
| 2005 | ;; | ||
| 2006 | -p|--publish) | ||
| 2007 | RUN_HAS_PORT_FORWARDS=true | ||
| 2008 | ;; | ||
| 2009 | -d|--detach) | ||
| 2010 | RUN_IS_DETACHED=true | ||
| 2011 | ;; | ||
| 2012 | --name=*) | ||
| 2013 | RUN_CONTAINER_NAME="${arg#--name=}" | ||
| 2014 | ;; | ||
| 1813 | esac | 2015 | esac |
| 2016 | # Check if previous arg was -p or --publish | ||
| 2017 | if [ "$prev_arg" = "-p" ] || [ "$prev_arg" = "--publish" ]; then | ||
| 2018 | # arg is the port specification (e.g., 8080:80) | ||
| 2019 | RUN_PORT_FORWARDS+=("$arg") | ||
| 2020 | fi | ||
| 2021 | # Check if previous arg was --name | ||
| 2022 | if [ "$prev_arg" = "--name" ]; then | ||
| 2023 | RUN_CONTAINER_NAME="$arg" | ||
| 2024 | fi | ||
| 2025 | prev_arg="$arg" | ||
| 2026 | i=$((i + 1)) | ||
| 1814 | done | 2027 | done |
| 1815 | 2028 | ||
| 1816 | # Volume mounts require daemon mode | 2029 | # Volume mounts require daemon mode |
| @@ -1885,6 +2098,54 @@ case "$COMMAND" in | |||
| 1885 | fi | 2098 | fi |
| 1886 | else | 2099 | else |
| 1887 | # Non-interactive - use daemon mode when available | 2100 | # Non-interactive - use daemon mode when available |
| 2101 | |||
| 2102 | # For detached containers with port forwards, add them dynamically via QMP | ||
| 2103 | if [ "$RUN_IS_DETACHED" = "true" ] && [ "$RUN_HAS_PORT_FORWARDS" = "true" ] && daemon_is_running; then | ||
| 2104 | # Generate container name if not provided (needed for port tracking) | ||
| 2105 | if [ -z "$RUN_CONTAINER_NAME" ]; then | ||
| 2106 | # Generate a random name like docker does | ||
| 2107 | RUN_CONTAINER_NAME="$(cat /proc/sys/kernel/random/uuid | cut -c1-12)" | ||
| 2108 | # Update COMMAND_ARGS to include the generated name | ||
| 2109 | RUNTIME_CMD="$VCONTAINER_RUNTIME_CMD run --name=$RUN_CONTAINER_NAME $RUN_NETWORK_OPTS ${COMMAND_ARGS[*]}" | ||
| 2110 | fi | ||
| 2111 | |||
| 2112 | # Add port forwards via QMP and register them | ||
| 2113 | for port_spec in "${RUN_PORT_FORWARDS[@]}"; do | ||
| 2114 | # Parse port specification: [host_ip:]host_port:container_port[/protocol] | ||
| 2115 | # Examples: 8080:80, 127.0.0.1:8080:80, 8080:80/tcp, 8080:80/udp | ||
| 2116 | local spec="$port_spec" | ||
| 2117 | local protocol="tcp" | ||
| 2118 | local host_port="" | ||
| 2119 | local guest_port="" | ||
| 2120 | |||
| 2121 | # Extract protocol if present | ||
| 2122 | if echo "$spec" | grep -q '/'; then | ||
| 2123 | protocol="${spec##*/}" | ||
| 2124 | spec="${spec%/*}" | ||
| 2125 | fi | ||
| 2126 | |||
| 2127 | # Count colons to determine format | ||
| 2128 | local colon_count=$(echo "$spec" | tr -cd ':' | wc -c) | ||
| 2129 | if [ "$colon_count" -eq 2 ]; then | ||
| 2130 | # Format: host_ip:host_port:container_port (ignore host_ip for now) | ||
| 2131 | host_port=$(echo "$spec" | cut -d: -f2) | ||
| 2132 | guest_port=$(echo "$spec" | cut -d: -f3) | ||
| 2133 | else | ||
| 2134 | # Format: host_port:container_port | ||
| 2135 | host_port=$(echo "$spec" | cut -d: -f1) | ||
| 2136 | guest_port=$(echo "$spec" | cut -d: -f2) | ||
| 2137 | fi | ||
| 2138 | |||
| 2139 | if [ -n "$host_port" ] && [ -n "$guest_port" ]; then | ||
| 2140 | if qmp_add_hostfwd "$host_port" "$guest_port" "$protocol"; then | ||
| 2141 | register_port_forward "$RUN_CONTAINER_NAME" "$host_port" "$guest_port" "$protocol" | ||
| 2142 | else | ||
| 2143 | echo -e "${YELLOW}[$VCONTAINER_RUNTIME_NAME]${NC} Warning: Could not add port forward ${host_port}:${guest_port}" >&2 | ||
| 2144 | fi | ||
| 2145 | fi | ||
| 2146 | done | ||
| 2147 | fi | ||
| 2148 | |||
| 1888 | run_runtime_command "$RUNTIME_CMD" | 2149 | run_runtime_command "$RUNTIME_CMD" |
| 1889 | RUN_EXIT=$? | 2150 | RUN_EXIT=$? |
| 1890 | 2151 | ||
| @@ -1970,10 +2231,19 @@ case "$COMMAND" in | |||
| 1970 | fi | 2231 | fi |
| 1971 | ;; | 2232 | ;; |
| 1972 | stop) | 2233 | stop) |
| 2234 | # Clear port forward registry when stopping daemon | ||
| 2235 | local pf_file=$(get_port_forward_file) | ||
| 2236 | if [ -f "$pf_file" ]; then | ||
| 2237 | rm -f "$pf_file" | ||
| 2238 | fi | ||
| 1973 | "$RUNNER" $RUNNER_ARGS --daemon-stop | 2239 | "$RUNNER" $RUNNER_ARGS --daemon-stop |
| 1974 | ;; | 2240 | ;; |
| 1975 | restart) | 2241 | restart) |
| 1976 | # Stop if running | 2242 | # Stop if running and clear port forward registry |
| 2243 | local pf_file=$(get_port_forward_file) | ||
| 2244 | if [ -f "$pf_file" ]; then | ||
| 2245 | rm -f "$pf_file" | ||
| 2246 | fi | ||
| 1977 | "$RUNNER" $RUNNER_ARGS --daemon-stop 2>/dev/null || true | 2247 | "$RUNNER" $RUNNER_ARGS --daemon-stop 2>/dev/null || true |
| 1978 | 2248 | ||
| 1979 | # Clean if --clean was passed | 2249 | # Clean if --clean was passed |
diff --git a/recipes-containers/vcontainer/files/vrunner.sh b/recipes-containers/vcontainer/files/vrunner.sh index cd504f7b..c9950618 100755 --- a/recipes-containers/vcontainer/files/vrunner.sh +++ b/recipes-containers/vcontainer/files/vrunner.sh | |||
| @@ -1073,6 +1073,10 @@ if [ "$DAEMON_MODE" = "start" ]; then | |||
| 1073 | QEMU_OPTS="$QEMU_OPTS -device virtio-serial-pci" | 1073 | QEMU_OPTS="$QEMU_OPTS -device virtio-serial-pci" |
| 1074 | QEMU_OPTS="$QEMU_OPTS -device virtserialport,chardev=vdkr,name=vdkr" | 1074 | QEMU_OPTS="$QEMU_OPTS -device virtserialport,chardev=vdkr,name=vdkr" |
| 1075 | 1075 | ||
| 1076 | # Add QMP socket for dynamic control (port forwarding, etc.) | ||
| 1077 | QMP_SOCKET="$DAEMON_SOCKET_DIR/qmp.sock" | ||
| 1078 | QEMU_OPTS="$QEMU_OPTS -qmp unix:$QMP_SOCKET,server,nowait" | ||
| 1079 | |||
| 1076 | # Tell init script to run in daemon mode with idle timeout | 1080 | # Tell init script to run in daemon mode with idle timeout |
| 1077 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_daemon=1" | 1081 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_daemon=1" |
| 1078 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_idle_timeout=$IDLE_TIMEOUT" | 1082 | KERNEL_APPEND="$KERNEL_APPEND ${CMDLINE_PREFIX}_idle_timeout=$IDLE_TIMEOUT" |
