#!/bin/bash # # USB Docker Passthrough - One-Click Deployment Script # Suitable for SSH remote deployment, all files are self-contained in the script # # Usage: # Method 1: curl -fsSL /deploy-one-click.sh | sudo bash # Method 2: wget -qO- /deploy-one-click.sh | sudo bash # Method 3: Download and run: sudo bash deploy-one-click.sh # set -e # Color output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' print_success() { echo -e "${GREEN}[OK] $1${NC}"; } print_error() { echo -e "${RED}[ERROR] $1${NC}"; } print_warning() { echo -e "${YELLOW}[WARN] $1${NC}"; } print_info() { echo -e "${BLUE}[INFO] $1${NC}"; } print_header() { echo -e "${CYAN}$1${NC}"; } # Display welcome message clear cat << 'EOF' ================================================================ USB Device Docker Passthrough Auto USB Device Passthrough to Docker Container One-Click Deployment Script v1.0 ================================================================ EOF echo # Check root privileges if [ "$EUID" -ne 0 ]; then print_error "This script must be run as root" echo "Please run: sudo $0" exit 1 fi # Check system requirements print_header "==> Checking system requirements..." echo # Check Docker if ! command -v docker &> /dev/null; then print_warning "Docker is not installed" print_info "Installing Docker automatically..." curl -fsSL https://get.docker.com | sh systemctl enable docker systemctl start docker print_success "Docker installed" else print_success "Docker is installed" fi # Check Docker running status if ! docker info &> /dev/null; then print_warning "Docker is not running, starting..." systemctl start docker sleep 2 if docker info &> /dev/null; then print_success "Docker is running" else print_error "Failed to start Docker" exit 1 fi else print_success "Docker is running" fi # Check udev if ! command -v udevadm &> /dev/null; then print_error "udev is not installed" exit 1 else print_success "udev is available" fi echo # Use default configuration (optimized for EZ-mion) print_header "==> Configuration" echo print_info "Using default configuration for EZ-mion..." # Default configuration EZ_MION_MODE=true CONTAINER_FILTER="specific" SPECIFIC_CONTAINERS="system-monitor" DEVICE_FILTER="all" print_success "Container filter: $CONTAINER_FILTER" print_success "Target containers: $SPECIFIC_CONTAINERS" print_success "Device filter: $DEVICE_FILTER" print_info "EZ-mion mode enabled - will configure for system-monitor container" echo print_header "==> Installing USB Docker Passthrough..." echo # Create temporary directory TEMP_DIR=$(mktemp -d) cd "$TEMP_DIR" print_info "Creating installation files..." # ============================================ # Create main configuration file # ============================================ cat > usb-docker-passthrough.conf << 'CONF_EOF' # USB Docker Passthrough Configuration File ENABLE_PASSTHROUGH="true" CONTAINER_FILTER="PLACEHOLDER_CONTAINER_FILTER" SPECIFIC_CONTAINERS="PLACEHOLDER_SPECIFIC_CONTAINERS" DEVICE_FILTER="PLACEHOLDER_DEVICE_FILTER" AUTO_CREATE_DEVICE_NODES="true" VERBOSE_LOGGING="true" CONF_EOF # Replace configuration placeholders sed -i "s|PLACEHOLDER_CONTAINER_FILTER|$CONTAINER_FILTER|g" usb-docker-passthrough.conf sed -i "s|PLACEHOLDER_SPECIFIC_CONTAINERS|$SPECIFIC_CONTAINERS|g" usb-docker-passthrough.conf sed -i "s|PLACEHOLDER_DEVICE_FILTER|$DEVICE_FILTER|g" usb-docker-passthrough.conf # ============================================ # Create udev rules file # ============================================ cat > 99-usb-docker-passthrough.rules << 'RULES_EOF' # udev rules for automatic USB device passthrough to Docker containers ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", \ RUN+="/bin/sh -c '/usr/local/sbin/usb-docker-action.sh add %k %p'" ACTION=="remove", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", \ RUN+="/bin/sh -c '/usr/local/sbin/usb-docker-action.sh remove %k %p'" ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyUSB*", \ RUN+="/usr/local/sbin/usb-docker-action.sh add_serial %k /dev/%k" ACTION=="add", SUBSYSTEM=="tty", KERNEL=="ttyACM*", \ RUN+="/usr/local/sbin/usb-docker-action.sh add_serial %k /dev/%k" ACTION=="remove", SUBSYSTEM=="tty", KERNEL=="ttyUSB*", \ RUN+="/usr/local/sbin/usb-docker-action.sh remove_serial %k /dev/%k" ACTION=="remove", SUBSYSTEM=="tty", KERNEL=="ttyACM*", \ RUN+="/usr/local/sbin/usb-docker-action.sh remove_serial %k /dev/%k" RULES_EOF # ============================================ # Create core script (simplified version) # ============================================ cat > usb-docker-action.sh << 'SCRIPT_EOF' #!/bin/bash CONFIG_FILE="/etc/usb-docker-passthrough.conf" LOG_FILE="/var/log/usb-docker-passthrough.log" STATE_DIR="/var/run/usb-docker-passthrough" mkdir -p "$STATE_DIR" log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$1] ${*:2}" >> "$LOG_FILE" } load_config() { ENABLE_PASSTHROUGH="true" CONTAINER_FILTER="specific" SPECIFIC_CONTAINERS="system-monitor" DEVICE_FILTER="all" [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE" } get_target_containers() { local containers=() case "$CONTAINER_FILTER" in all|running) containers=($(docker ps --format '{{.Names}}' 2>/dev/null)) ;; specific) IFS=',' read -ra containers <<< "$SPECIFIC_CONTAINERS" ;; esac echo "${containers[@]}" } add_device_to_container() { local container_name=$1 local device_path=$2 [ ! -e "$device_path" ] && return 1 docker ps --format '{{.Names}}' | grep -q "^${container_name}$" || return 1 local major=$(stat -c '%t' "$device_path" 2>/dev/null) local minor=$(stat -c '%T' "$device_path" 2>/dev/null) [ -z "$major" ] || [ -z "$minor" ] && return 1 major=$((16#$major)) minor=$((16#$minor)) local dev_type="c" [ -b "$device_path" ] && dev_type="b" log_message "INFO" "Adding $device_path to $container_name" docker exec -u root "$container_name" mkdir -p "$(dirname $device_path)" 2>/dev/null docker exec -u root "$container_name" mknod "$device_path" "$dev_type" "$major" "$minor" 2>/dev/null docker exec -u root "$container_name" chmod 666 "$device_path" 2>/dev/null echo "${device_path}|${container_name}|$(date +%s)" >> "${STATE_DIR}/attached_devices.log" return 0 } remove_device_from_container() { local container_name=$1 local device_path=$2 docker ps --format '{{.Names}}' | grep -q "^${container_name}$" || return 1 docker exec -u root "$container_name" rm -f "$device_path" 2>/dev/null [ -f "${STATE_DIR}/attached_devices.log" ] && \ sed -i "\|^${device_path}|${container_name}|d" "${STATE_DIR}/attached_devices.log" return 0 } handle_serial_add() { local device_path=$2 log_message "INFO" "Serial device added: $device_path" sleep 0.5 local containers=($(get_target_containers)) for container in "${containers[@]}"; do add_device_to_container "$container" "$device_path" done } handle_serial_remove() { local device_path=$2 log_message "INFO" "Serial device removed: $device_path" local containers=($(get_target_containers)) for container in "${containers[@]}"; do remove_device_from_container "$container" "$device_path" done } main() { load_config [ "$ENABLE_PASSTHROUGH" != "true" ] && exit 0 case "$1" in add_serial) handle_serial_add "$@" ;; remove_serial) handle_serial_remove "$@" ;; *) log_message "WARN" "Unknown action: $1" ;; esac } main "$@" SCRIPT_EOF # ============================================ # Create management tool (simplified version) # ============================================ cat > usb-docker-ctl << 'CTL_EOF' #!/bin/bash LOG_FILE="/var/log/usb-docker-passthrough.log" STATE_DIR="/var/run/usb-docker-passthrough" show_status() { echo "=== USB Docker Passthrough Status ===" echo echo "Running Containers:" docker ps --format ' - {{.Names}}' 2>/dev/null || echo " (none)" echo echo "Connected USB Devices:" lsusb 2>/dev/null | sed 's/^/ /' echo [ -f "${STATE_DIR}/attached_devices.log" ] && { echo "Active Passthroughs:" tail -10 "${STATE_DIR}/attached_devices.log" | while IFS='|' read -r device container timestamp; do echo " $device -> $container" done } } show_logs() { [ -f "$LOG_FILE" ] && tail -n ${1:-50} "$LOG_FILE" || echo "No logs found" } case "$1" in status|"") show_status ;; logs) show_logs "$2" ;; *) echo "Usage: $0 {status|logs [lines]}" ;; esac CTL_EOF # Set execute permissions chmod +x usb-docker-action.sh usb-docker-ctl # ============================================ # Install files # ============================================ print_info "Installing files to system..." install -m 755 usb-docker-action.sh /usr/local/sbin/ print_success "Installed action script" install -m 755 usb-docker-ctl /usr/local/sbin/ print_success "Installed management tool" install -m 644 usb-docker-passthrough.conf /etc/ print_success "Installed configuration file" install -m 644 99-usb-docker-passthrough.rules /etc/udev/rules.d/ print_success "Installed udev rules" # Create necessary directories mkdir -p /var/run/usb-docker-passthrough mkdir -p /var/log touch /var/log/usb-docker-passthrough.log chmod 644 /var/log/usb-docker-passthrough.log print_success "Created runtime directories" # ============================================ # Activate configuration # ============================================ echo print_header "==> Activating configuration..." echo udevadm control --reload-rules udevadm trigger --subsystem-match=usb print_success "udev rules activated" # Clean up temporary files cd / rm -rf "$TEMP_DIR" # ============================================ # Complete # ============================================ echo print_header "==> Installation Complete!" echo cat << 'EOF' ================================================================ Installation Complete! ================================================================ Next Steps: 1. Check system status: usb-docker-ctl status 2. View passthrough logs: usb-docker-ctl logs 3. Test with a container: docker run -d --name test_container \ --cap-add=MKNOD --cap-add=SYS_ADMIN \ ubuntu:22.04 tail -f /dev/null EOF # Display current USB devices print_info "Current USB devices:" lsusb 2>/dev/null | head -5 | sed 's/^/ /' echo # EZ-mion specific configuration and testing if [ "$EZ_MION_MODE" = "true" ]; then echo print_header "==> EZ-mion Specific Configuration" echo # Check if EZ-mion container is running if docker ps --format '{{.Names}}' | grep -q "^system-monitor$"; then print_success "Detected system-monitor container is running" # Add existing USB devices to running container print_info "Adding existing USB devices to running container..." for device in /dev/ttyUSB* /dev/ttyACM* /dev/hidraw* /dev/video*; do if [ -e "$device" ]; then print_info "Adding device: $device" /usr/local/sbin/usb-docker-action.sh add_serial "$(basename "$device")" "$device" 2>/dev/null || true fi done print_success "Added existing USB devices to running container" else print_warning "system-monitor container is not running" print_info "USB devices will be automatically added when you start the EZ-mion container" fi echo print_info "EZ-mion startup recommendations:" echo "1. Start EZ-mion container:" echo " docker-compose up -d" echo echo "2. Or use startup script:" echo " ./start.sh (Linux)" echo " start.bat (Windows)" echo echo "3. Test USB devices:" echo " docker exec system-monitor ls -l /dev/ttyUSB*" echo echo "4. Check USB passthrough status:" echo " usb-docker-ctl status" echo print_success "EZ-mion USB passthrough configuration complete!" fi