|
1 | 1 | #!/usr/bin/env bash |
2 | | -# deploy.sh — Docker-based bootstrapper for Coral TPU Detection Skill |
| 2 | +# deploy.sh — Native local bootstrapper for Coral TPU Detection Skill |
3 | 3 | # |
4 | | -# Builds the Docker image locally and verifies Edge TPU connectivity. |
| 4 | +# Builds a local Python virtual environment and verifies Edge TPU connectivity. |
5 | 5 | # Called by Aegis skill-runtime-manager during installation. |
6 | 6 | # |
7 | 7 | # Exit codes: |
8 | 8 | # 0 = success |
9 | | -# 1 = fatal error (Docker not found) |
| 9 | +# 1 = fatal error (Python/pip not found) |
10 | 10 | # 2 = partial success (no TPU detected, will use CPU fallback) |
11 | 11 |
|
12 | 12 | set -euo pipefail |
13 | 13 |
|
14 | 14 | SKILL_DIR="$(cd "$(dirname "$0")" && pwd)" |
15 | | -IMAGE_NAME="aegis-coral-tpu" |
16 | | -IMAGE_TAG="latest" |
17 | 15 | LOG_PREFIX="[coral-tpu-deploy]" |
18 | 16 |
|
19 | 17 | log() { echo "$LOG_PREFIX $*" >&2; } |
20 | 18 | emit() { echo "$1"; } # JSON to stdout for Aegis to parse |
21 | 19 |
|
22 | | -# ─── Step 1: Check Docker ──────────────────────────────────────────────────── |
23 | | - |
24 | | -find_docker() { |
25 | | - for cmd in docker podman; do |
26 | | - if command -v "$cmd" &>/dev/null; then |
27 | | - echo "$cmd" |
28 | | - return 0 |
29 | | - fi |
30 | | - done |
31 | | - return 1 |
32 | | -} |
33 | | - |
34 | | -DOCKER_CMD=$(find_docker) || { |
35 | | - log "ERROR: Docker (or Podman) not found. Install Docker Desktop 4.35+ and retry." |
36 | | - emit '{"event": "error", "stage": "docker", "message": "Docker not found. Install Docker Desktop 4.35+"}' |
37 | | - exit 1 |
38 | | -} |
| 20 | +# ─── Step 1: Detect Platform ──────────────────────────────────────────────── |
| 21 | + |
| 22 | +PLATFORM="$(uname -s)" |
| 23 | +ARCH="$(uname -m)" |
| 24 | +log "Platform: $PLATFORM ($ARCH)" |
| 25 | +emit "{\"event\": \"progress\", \"stage\": \"platform\", \"message\": \"Platform: $PLATFORM/$ARCH\"}" |
39 | 26 |
|
40 | | -# Verify Docker is running |
41 | | -if ! "$DOCKER_CMD" info &>/dev/null; then |
42 | | - log "ERROR: Docker daemon is not running. Start Docker Desktop and retry." |
43 | | - emit '{"event": "error", "stage": "docker", "message": "Docker daemon not running"}' |
| 27 | +if [ "$PLATFORM" = "Linux" ]; then |
| 28 | + log "Linux: ensuring system packages are installed..." |
| 29 | + emit '{"event": "progress", "stage": "platform", "message": "Ensuring Linux dependencies..."}' |
| 30 | + sudo apt-get update >/dev/null 2>&1 || true |
| 31 | + sudo apt-get install -y --no-install-recommends \ |
| 32 | + python3 python3-pip python3-venv libusb-1.0-0 >/dev/null 2>&1 || true |
| 33 | +fi |
| 34 | + |
| 35 | +# ─── Step 2: Ensure Python 3 ──────────────────────────────────────────────── |
| 36 | + |
| 37 | +if ! command -v python3 &>/dev/null; then |
| 38 | + log "ERROR: Python 3 not found." |
| 39 | + emit '{"event": "error", "stage": "python", "message": "Python 3 not found"}' |
44 | 40 | exit 1 |
45 | 41 | fi |
46 | 42 |
|
47 | | -DOCKER_VER=$("$DOCKER_CMD" version --format '{{.Server.Version}}' 2>/dev/null || echo "unknown") |
48 | | -log "Using $DOCKER_CMD (version: $DOCKER_VER)" |
49 | | -emit "{\"event\": \"progress\", \"stage\": \"docker\", \"message\": \"Docker ready ($DOCKER_VER)\"}" |
| 43 | +PYTHON_CMD="python3" |
| 44 | +log "Using Python: $($PYTHON_CMD --version)" |
| 45 | +emit '{"event": "progress", "stage": "python", "message": "Python verified"}' |
50 | 46 |
|
51 | | -# ─── Step 2: Detect platform for USB access hints ─────────────────────────── |
| 47 | +# ─── Step 3: Create Virtual Environment ───────────────────────────────────── |
52 | 48 |
|
53 | | -PLATFORM="$(uname -s)" |
54 | | -ARCH="$(uname -m)" |
55 | | -USB_FLAG="" |
56 | | - |
57 | | -case "$PLATFORM" in |
58 | | - Linux) |
59 | | - USB_FLAG="--device /dev/bus/usb" |
60 | | - log "Platform: Linux — will use --device /dev/bus/usb" |
61 | | - ;; |
62 | | - Darwin) |
63 | | - log "Platform: macOS ($ARCH) — Docker Desktop 4.35+ USB/IP required" |
64 | | - log "Ensure Docker Desktop Settings → Features → USB devices is enabled" |
65 | | - # macOS Docker Desktop 4.35+ handles USB/IP transparently |
66 | | - # No --device flag needed, but privileged may be required |
67 | | - USB_FLAG="--privileged" |
68 | | - ;; |
69 | | - MINGW*|MSYS*|CYGWIN*) |
70 | | - log "Platform: Windows — Docker Desktop 4.35+ USB/IP or WSL2 backend" |
71 | | - USB_FLAG="--privileged" |
72 | | - ;; |
73 | | - *) |
74 | | - log "Platform: Unknown ($PLATFORM) — attempting with --privileged" |
75 | | - USB_FLAG="--privileged" |
76 | | - ;; |
77 | | -esac |
| 49 | +VENV_DIR="$SKILL_DIR/venv" |
| 50 | +log "Setting up virtual environment in $VENV_DIR..." |
| 51 | +emit '{"event": "progress", "stage": "build", "message": "Creating Python virtual environment..."}' |
78 | 52 |
|
79 | | -emit "{\"event\": \"progress\", \"stage\": \"platform\", \"message\": \"Platform: $PLATFORM/$ARCH\"}" |
| 53 | +"$PYTHON_CMD" -m venv "$VENV_DIR" |
80 | 54 |
|
81 | | -# ─── Step 3: Build Docker image ───────────────────────────────────────────── |
| 55 | +# Ensure the venv works |
| 56 | +if [ ! -f "$VENV_DIR/bin/python" ]; then |
| 57 | + log "ERROR: Failed to create virtual environment." |
| 58 | + emit '{"event": "error", "stage": "build", "message": "Failed to create venv"}' |
| 59 | + exit 1 |
| 60 | +fi |
82 | 61 |
|
83 | | -log "Building Docker image: $IMAGE_NAME:$IMAGE_TAG ..." |
84 | | -emit '{"event": "progress", "stage": "build", "message": "Building Docker image (this may take a few minutes)..."}' |
| 62 | +# ─── Step 4: Install Dependencies ─────────────────────────────────────────── |
85 | 63 |
|
86 | | -if "$DOCKER_CMD" build -t "$IMAGE_NAME:$IMAGE_TAG" "$SKILL_DIR" 2>&1 | while read -r line; do |
87 | | - log "$line" |
88 | | -done; then |
89 | | - log "Docker image built successfully" |
90 | | - emit '{"event": "progress", "stage": "build", "message": "Docker image ready"}' |
91 | | -else |
92 | | - log "ERROR: Docker build failed" |
93 | | - emit '{"event": "error", "stage": "build", "message": "Docker image build failed"}' |
| 64 | +log "Installing Python dependencies (this may take a minute)..." |
| 65 | +emit '{"event": "progress", "stage": "build", "message": "Installing ai-edge-litert and dependencies..."}' |
| 66 | + |
| 67 | +# Upgrade pip securely |
| 68 | +"$VENV_DIR/bin/python" -m pip install --upgrade pip >/dev/null 2>&1 || true |
| 69 | + |
| 70 | +# Install requirements |
| 71 | +if ! "$VENV_DIR/bin/python" -m pip install -r "$SKILL_DIR/requirements.txt"; then |
| 72 | + log "ERROR: Failed to install Python dependencies." |
| 73 | + emit '{"event": "error", "stage": "build", "message": "pip install failed"}' |
94 | 74 | exit 1 |
95 | 75 | fi |
96 | 76 |
|
97 | | -# ─── Step 4: Probe for Edge TPU devices ────────────────────────────────────── |
| 77 | +log "Dependencies installed successfully." |
| 78 | +emit '{"event": "progress", "stage": "build", "message": "Python environment ready"}' |
98 | 79 |
|
99 | | -log "Probing for Edge TPU devices..." |
100 | | -emit '{"event": "progress", "stage": "probe", "message": "Checking for Edge TPU devices..."}' |
| 80 | +# ─── Step 5: Probe for Edge TPU devices ────────────────────────────────────── |
| 81 | + |
| 82 | +log "Probing for Edge TPU devices natively..." |
| 83 | +emit '{"event": "progress", "stage": "probe", "message": "Checking for physical Edge TPU..."}' |
101 | 84 |
|
102 | 85 | TPU_FOUND=false |
103 | | -PROBE_OUTPUT=$("$DOCKER_CMD" run --rm $USB_FLAG \ |
104 | | - "$IMAGE_NAME:$IMAGE_TAG" python3 scripts/tpu_probe.py 2>/dev/null) || true |
| 86 | +# Run probe inside the venv |
| 87 | +PROBE_OUTPUT=$("$VENV_DIR/bin/python" "$SKILL_DIR/scripts/tpu_probe.py" 2>/dev/null) || true |
105 | 88 |
|
106 | 89 | if echo "$PROBE_OUTPUT" | grep -q '"available": true'; then |
107 | | - TPU_COUNT=$(echo "$PROBE_OUTPUT" | python3 -c "import sys,json; print(json.load(sys.stdin)['count'])" 2>/dev/null || echo "?") |
| 90 | + TPU_COUNT=$(echo "$PROBE_OUTPUT" | "$VENV_DIR/bin/python" -c "import sys,json; print(json.load(sys.stdin)['count'])" 2>/dev/null || echo "?") |
108 | 91 | TPU_FOUND=true |
109 | 92 | log "Edge TPU detected: $TPU_COUNT device(s)" |
110 | | - emit "{\"event\": \"progress\", \"stage\": \"probe\", \"message\": \"Found $TPU_COUNT Edge TPU device(s)\"}" |
| 93 | + emit "{\"event\": \"progress\", \"stage\": \"probe\", \"message\": \"Found $TPU_COUNT Edge TPU device(s) natively\"}" |
111 | 94 | else |
112 | 95 | log "WARNING: No Edge TPU detected — skill will run in CPU fallback mode" |
113 | 96 | emit '{"event": "progress", "stage": "probe", "message": "No Edge TPU detected — CPU fallback available"}' |
114 | 97 | fi |
115 | 98 |
|
116 | | -# ─── Step 5: Complete ──────────────────────────────────────────────────────── |
117 | | - |
118 | 99 | # ─── Step 6: Complete ──────────────────────────────────────────────────────── |
119 | 100 |
|
120 | 101 | if [ "$TPU_FOUND" = true ]; then |
121 | | - emit "{\"event\": \"complete\", \"status\": \"success\", \"tpu_found\": true, \"message\": \"Coral TPU skill installed — Edge TPU ready\"}" |
| 102 | + emit "{\"event\": \"complete\", \"status\": \"success\", \"tpu_found\": true, \"message\": \"Native Coral TPU skill installed — Edge TPU ready\"}" |
122 | 103 | log "Done! Edge TPU ready." |
123 | 104 | exit 0 |
124 | 105 | else |
125 | | - emit "{\"event\": \"complete\", \"status\": \"partial\", \"tpu_found\": false, \"message\": \"Coral TPU skill installed — no TPU detected (CPU fallback)\"}" |
| 106 | + emit "{\"event\": \"complete\", \"status\": \"partial\", \"tpu_found\": false, \"message\": \"Native Coral TPU skill installed — no TPU detected (CPU fallback)\"}" |
126 | 107 | log "Done with warning: no TPU detected. Connect Coral USB and restart." |
127 | 108 | exit 2 |
128 | 109 | fi |
0 commit comments