Skip to content

Instantly share code, notes, and snippets.

@jonsherrard
Created February 24, 2026 15:32
Show Gist options
  • Select an option

  • Save jonsherrard/7bbea2b65363a796ed32a5bd7800a580 to your computer and use it in GitHub Desktop.

Select an option

Save jonsherrard/7bbea2b65363a796ed32a5bd7800a580 to your computer and use it in GitHub Desktop.
#!/bin/bash
# L2L VM tmux session setup
SESSION_NAME="l2lvm"
L2LDEVOPS_DIR="$HOME/projects/l2ldevops"
VM_NAME="l2lvm-dev1"
WINDOW_NAME="dispatch"
SWIPE_GUIDE_DIR="$HOME/projects/swipe-guide/repo"
VM_WORKDIR="/home/jons/dev/l2l/dispatchweb"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Ports used by the VM services
VM_PORTS=(8443 9443)
# Function to check for port collisions
# Sets PORT_COLLISION_MSG for display and HAS_PORT_COLLISION boolean
PORT_COLLISION_MSG=""
PORT_COLLISION_COLOR=""
HAS_PORT_COLLISION="false"
check_port_collisions() {
local has_collision=false
local collision_info=""
for port in "${VM_PORTS[@]}"; do
# Check local services using lsof (exclude lima which is the VM itself)
local lsof_result=$(lsof -i :${port} -sTCP:LISTEN 2>/dev/null | tail -n +2 | grep -v "lima")
if [ -n "$lsof_result" ]; then
has_collision=true
local process_name=$(echo "$lsof_result" | awk '{print $1}' | head -1)
local pid=$(echo "$lsof_result" | awk '{print $2}' | head -1)
collision_info+=" Port ${port}: ${process_name} (PID: ${pid})\n"
fi
# Check docker containers
local docker_result=$(docker ps --format '{{.Names}}: {{.Ports}}' 2>/dev/null | grep ":${port}->" || true)
if [ -n "$docker_result" ]; then
has_collision=true
collision_info+=" Port ${port}: Docker - ${docker_result}\n"
fi
done
if [ "$has_collision" = true ]; then
PORT_COLLISION_MSG="⚠️ Port collisions detected"
PORT_COLLISION_COLOR="${YELLOW}"
HAS_PORT_COLLISION="true"
echo -e "${YELLOW}⚠️ Port collisions detected with VM services:${NC}"
echo -e "$collision_info"
read -p "Continue anyway? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
else
PORT_COLLISION_MSG="✓ No port collisions"
PORT_COLLISION_COLOR="${GREEN}"
HAS_PORT_COLLISION="false"
fi
}
# Function to stop swipe-guide docker containers
stop_swipe_guide_docker() {
# Check if any swipe-guide containers are running
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "swipe-guide\|server-v2\|client-v2"; then
read -p "Stop swipe-guide docker containers? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Stopping swipe-guide docker containers..."
(cd "${SWIPE_GUIDE_DIR}" && docker compose down 2>/dev/null) || \
(cd "${SWIPE_GUIDE_DIR}/server-v2" && docker compose down 2>/dev/null) || \
docker stop $(docker ps -q --filter "name=swipe-guide") 2>/dev/null || \
docker stop $(docker ps -q --filter "name=server-v2") 2>/dev/null || \
docker stop $(docker ps -q --filter "name=client-v2") 2>/dev/null
echo "Done."
fi
fi
}
# Function to check if VM is running
vm_is_running() {
limactl list -q 2>/dev/null | grep -q "^${VM_NAME}$"
if [ $? -eq 0 ]; then
vm_status=$(limactl list --format '{{.Status}}' ${VM_NAME} 2>/dev/null)
[ "$vm_status" = "Running" ]
else
return 1
fi
}
# Function to start VM if not running
ensure_vm_running() {
if ! vm_is_running; then
echo "Starting ${VM_NAME}..."
limactl start ${VM_NAME}
# Wait a moment for SSH to be ready
sleep 2
fi
}
# Function to ensure services are running (runs before tmux setup)
ensure_services_running() {
local ssh_cmd="ssh -F $HOME/.lima/${VM_NAME}/ssh.config lima-${VM_NAME}"
# Check if nginx is listening on 8443
if ! ${ssh_cmd} "ss -tln | grep -q ':8443 '" 2>/dev/null; then
echo -e "${YELLOW}↑ Starting services (this may take a minute)...${NC}"
# Kill any stale supervisord
${ssh_cmd} "sudo pkill -9 -f 'supervisord.*sv-dispatch'" 2>/dev/null || true
sleep 1
# Start services
${ssh_cmd} "cd ${VM_WORKDIR} && ./l2ldevinit.sh start"
echo -e "${GREEN}✓ Services started${NC}"
else
echo -e "${GREEN}✓ Services already running${NC}"
fi
}
# Remote banner script (runs on VM after connecting)
# Using printf to avoid escape issues
REMOTE_BANNER='printf "\033[1;32m● Connected to l2lvm-dev1\033[0m\n"; printf "\033[0;36m ~/dev/l2l/dispatchweb\033[0m\n"; printf "\033[0;90m Login: jon.sherrard@leading2lean.com / dispatch\033[0m\n"; printf "\033[0;94m https://l2lvm-dev1.l2l.com:8443\033[0m\n"; echo'
# SSH to VM - first pane (services already started by ensure_services_running)
ssh_to_vm_primary() {
local ssh="ssh -Y -F ~/.lima/${VM_NAME}/ssh.config lima-${VM_NAME}"
local remote_cmd="cd ${VM_WORKDIR}; clear; ${REMOTE_BANNER}; exec bash -l"
echo "clear; ${ssh} -t '${remote_cmd}'"
}
# SSH to VM - secondary pane (with port collision status)
ssh_to_vm_secondary() {
local has_collision="$1"
local ssh="ssh -Y -F ~/.lima/${VM_NAME}/ssh.config lima-${VM_NAME}"
local status_line=""
if [ "$has_collision" = "true" ]; then
status_line='printf "\033[0;33m⚠ Port collisions detected\033[0m\n";'
else
status_line='printf "\033[0;32m✓ No port collisions\033[0m\n";'
fi
local remote_cmd="cd ${VM_WORKDIR}; clear; ${REMOTE_BANNER}; ${status_line} exec bash -l"
echo "clear; ${ssh} -t '${remote_cmd}'"
}
# Function to open Zed connected to VM
open_zed() {
read -p "Open Zed connected to VM? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Opening Zed..."
zed ssh://lima-${VM_NAME}${VM_WORKDIR} &
fi
}
# Setup two vertical panes, both SSH'd into VM at dispatchweb
setup_panes() {
local target=$1
# First pane - SSH into VM (handles service startup)
tmux send-keys -t "${target}" "$(ssh_to_vm_primary)" C-m
# Split vertically (creates right pane)
tmux split-window -h -t "${target}"
# Second pane - SSH with port collision status in banner
tmux send-keys -t "${target}" "$(ssh_to_vm_secondary "$HAS_PORT_COLLISION")" C-m
# Select the first pane
tmux select-pane -t "${target}.0"
}
# Prompt to stop swipe-guide docker containers
stop_swipe_guide_docker
# Check for port collisions before starting VM
check_port_collisions
# Check if we're already inside tmux
if [ -n "$TMUX" ]; then
# We're inside tmux, create a new window
echo "Creating new tmux window '${WINDOW_NAME}'..."
# Ensure VM is running before creating the window
ensure_vm_running
# Ensure services are running
ensure_services_running
# Prompt to open Zed
open_zed
tmux new-window -n "${WINDOW_NAME}"
# Setup two panes SSH'd into VM
setup_panes "${WINDOW_NAME}"
else
# We're outside tmux, create/attach to session
# Check if session already exists
tmux has-session -t $SESSION_NAME 2>/dev/null
if [ $? != 0 ]; then
echo "Creating new tmux session '${SESSION_NAME}'..."
# Ensure VM is running before creating session
ensure_vm_running
# Ensure services are running
ensure_services_running
# Prompt to open Zed
open_zed
# Create new session
tmux new-session -d -s $SESSION_NAME -n "${WINDOW_NAME}"
# Setup two panes SSH'd into VM
setup_panes "${SESSION_NAME}:${WINDOW_NAME}"
else
echo "Session '${SESSION_NAME}' already exists, attaching..."
fi
# Attach to the session
tmux attach-session -t $SESSION_NAME
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment