Created
February 24, 2026 15:32
-
-
Save jonsherrard/7bbea2b65363a796ed32a5bd7800a580 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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