From a512e221ad1c2a8676a837a9934e8541bbf07ffd Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Sun, 26 Apr 2026 23:55:41 +0100 Subject: [PATCH] add socat to allow mac to access socket files --- docker-compose.yml | 16 ++++++++++ scripts/helper/cardano-cli-wrapper.sh | 6 ++-- scripts/helper/get-container.sh | 4 +-- scripts/helper/load-config.sh | 2 +- start-node.sh | 46 +++++++++++++++++++++++++++ stop-nodes.sh | 36 ++++++++++++++++++++- 6 files changed, 103 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1f0c58d..f683d5a 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,6 +27,22 @@ services: max-size: "200k" max-file: "10" + cardano-node-socat-${NETWORK}-${NODE_VERSION}: + container_name: node-${NETWORK}-${NODE_VERSION}-socat + image: alpine/socat + ports: + - "127.0.0.1:${SOCAT_PORT}:${SOCAT_PORT}" + depends_on: + - cardano-node-${NETWORK}-${NODE_VERSION} + labels: + - "managed-by=testnet-docker-node" + volumes: + - ./node-${NETWORK}-${NODE_VERSION}/ipc:/ipc + entrypoint: ["/bin/sh", "-c"] + command: + - "while [ ! -S /ipc/node.socket ]; do sleep 1; done; exec socat TCP-LISTEN:${SOCAT_PORT},fork,reuseaddr UNIX-CONNECT:/ipc/node.socket" + restart: always + volumes: node-db: node-ipc: diff --git a/scripts/helper/cardano-cli-wrapper.sh b/scripts/helper/cardano-cli-wrapper.sh index 8d36f01..b912c35 100755 --- a/scripts/helper/cardano-cli-wrapper.sh +++ b/scripts/helper/cardano-cli-wrapper.sh @@ -85,9 +85,9 @@ check_cardano_cli_version() { container_name="$CARDANO_CONTAINER_NAME_OVERRIDE" else # Only try to get container name if there's exactly one running container (non-interactive) - local running_count=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | wc -l | tr -d ' ') + local running_count=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | grep -v -- '-socat$' | wc -l | tr -d ' ') if [ "$running_count" -eq 1 ]; then - container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | head -n 1) + container_name=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | grep -v -- '-socat$' | head -n 1) fi fi @@ -195,7 +195,7 @@ cardano_cli() { # Display version info for the selected container # Only show if multiple containers are running (selection happened) to avoid duplicate when single container - local running_count=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | wc -l | tr -d ' ') + local running_count=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | grep -v -- '-socat$' | wc -l | tr -d ' ') if [ "$running_count" -gt 1 ]; then display_version_info "$container_name" fi diff --git a/scripts/helper/get-container.sh b/scripts/helper/get-container.sh index b672e03..3d9d379 100755 --- a/scripts/helper/get-container.sh +++ b/scripts/helper/get-container.sh @@ -16,8 +16,8 @@ if [ -n "$CARDANO_CONTAINER_NAME_OVERRIDE" ]; then fi fi -# Get the list of running containers -running_containers=$(docker ps --format '{{.Names}}') +# Get the list of running containers (exclude socat sidecars) +running_containers=$(docker ps --format '{{.Names}}' | grep -v -- '-socat$' || true) # Convert the running containers to an array IFS=$'\n' read -r -d '' -a running_containers <<< "$running_containers" diff --git a/scripts/helper/load-config.sh b/scripts/helper/load-config.sh index 61e5d77..486ba83 100755 --- a/scripts/helper/load-config.sh +++ b/scripts/helper/load-config.sh @@ -38,7 +38,7 @@ docker_compose_file="$base_dir/docker-compose.yml" # Get running containers running_containers="" if command -v docker &> /dev/null; then - running_containers=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' || true) + running_containers=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -E '^node-' | grep -v -- '-socat$' || true) fi # Safety check: If docker-compose.yml exists but no containers are running and no socket is set, diff --git a/start-node.sh b/start-node.sh index bc90933..f233a68 100755 --- a/start-node.sh +++ b/start-node.sh @@ -485,10 +485,14 @@ done # Return to the base directory cd "$base_dir" || exit +# Calculate socat bridge port (node socket -> TCP for host access on macOS) +SOCAT_PORT=$((NODE_PORT + 10000)) + # Export environment variables for use in docker-compose.yml export NETWORK=$network_normalized export NODE_VERSION=$node_version export NODE_PORT=$NODE_PORT +export SOCAT_PORT=$SOCAT_PORT # Get the network magic from the shelley-genesis.json file and pass it into the container export NETWORK_ID=$(jq -r '.networkMagic' "$config_dir/shelley-genesis.json") @@ -538,6 +542,48 @@ if [ "$container_status" != "running" ]; then exit 1 fi +# Start host-side socat bridge (macOS only - unix sockets don't work across Docker VM boundary) +host_socket_path="$node_dir/node.socket" +if [ "$(uname -s)" = "Darwin" ]; then + if command -v socat >/dev/null 2>&1; then + # Kill any existing socat for this socket + if [ -f "$node_dir/socat.pid" ]; then + old_pid=$(cat "$node_dir/socat.pid" 2>/dev/null || true) + if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then + kill "$old_pid" 2>/dev/null || true + fi + rm -f "$node_dir/socat.pid" + fi + rm -f "$host_socket_path" + + echo -e "${CYAN}Starting host-side socket bridge (socat)...${NC}" + echo -e "${BLUE}Bridging TCP port $SOCAT_PORT -> $host_socket_path${NC}" + socat UNIX-LISTEN:"$host_socket_path",fork,reuseaddr TCP:127.0.0.1:"$SOCAT_PORT" & + echo $! > "$node_dir/socat.pid" + + echo -e "${GREEN}Host socket bridge started.${NC}" + echo -e "${BLUE}Use the node socket from any script:${NC}" + echo -e "${YELLOW} export CARDANO_NODE_SOCKET_PATH=\"$host_socket_path\"${NC}" + echo -e "${YELLOW} export CARDANO_NODE_NETWORK_ID=\"$NETWORK_ID\"${NC}" + echo + else + echo -e "${YELLOW}Note: 'socat' is not installed. On macOS, the container socket cannot be used directly.${NC}" + echo -e "${YELLOW}Install socat to enable transparent host-side socket access:${NC}" + echo -e "${BLUE} brew install socat${NC}" + echo -e "${YELLOW}The socat sidecar is running inside Docker on TCP port $SOCAT_PORT.${NC}" + echo -e "${YELLOW}You can manually bridge it:${NC}" + echo -e "${BLUE} socat UNIX-LISTEN:\"$host_socket_path\",fork,reuseaddr TCP:127.0.0.1:$SOCAT_PORT &${NC}" + echo + fi +else + # Linux: bind-mounted unix sockets work directly + echo -e "${GREEN}Socket available at: $node_dir/ipc/node.socket${NC}" + echo -e "${BLUE}Use the node socket from any script:${NC}" + echo -e "${YELLOW} export CARDANO_NODE_SOCKET_PATH=\"$node_dir/ipc/node.socket\"${NC}" + echo -e "${YELLOW} export CARDANO_NODE_NETWORK_ID=\"$NETWORK_ID\"${NC}" + echo +fi + # Forward the logs to the terminal echo -e "${GREEN}Docker container started successfully!${NC}" echo -e "${BLUE}Container name: $container_name${NC}" diff --git a/stop-nodes.sh b/stop-nodes.sh index aa79360..2c9dcc9 100755 --- a/stop-nodes.sh +++ b/stop-nodes.sh @@ -54,12 +54,46 @@ else fi fi -# Stop and remove selected containers +# Get the project root directory +script_dir=$(cd "$(dirname "$0")" && pwd) + +# Stop and remove selected containers, and clean up host-side socat bridges for container in "${stop_list[@]}"; do echo -e "${YELLOW}Stopping: $container${NC}" docker stop "$container" 2>/dev/null || true docker rm "$container" 2>/dev/null || true echo -e "${GREEN}Stopped: $container${NC}" + + # If this is a node container (not a socat sidecar), clean up the host-side socat bridge + if [[ "$container" == node-*-container ]]; then + # Derive node directory from container name: node-{network}-{version}-container -> node-{network}-{version} + node_dir_name=$(echo "$container" | sed 's/-container$//') + node_dir="$script_dir/$node_dir_name" + + # Kill host-side socat process if running + if [ -f "$node_dir/socat.pid" ]; then + socat_pid=$(cat "$node_dir/socat.pid" 2>/dev/null || true) + if [ -n "$socat_pid" ] && kill -0 "$socat_pid" 2>/dev/null; then + echo -e "${YELLOW}Stopping host-side socat bridge (PID $socat_pid)${NC}" + kill "$socat_pid" 2>/dev/null || true + fi + rm -f "$node_dir/socat.pid" + fi + + # Clean up the host socket file + rm -f "$node_dir/node.socket" + + # Also stop the socat sidecar container if it wasn't already in the stop list + socat_container="${node_dir_name}-socat" + if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${socat_container}$"; then + if ! printf '%s\n' "${stop_list[@]}" | grep -q "^${socat_container}$"; then + echo -e "${YELLOW}Stopping socat sidecar: $socat_container${NC}" + docker stop "$socat_container" 2>/dev/null || true + docker rm "$socat_container" 2>/dev/null || true + echo -e "${GREEN}Stopped: $socat_container${NC}" + fi + fi + fi done echo