-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathstart.sh
More file actions
executable file
·393 lines (347 loc) · 12.9 KB
/
start.sh
File metadata and controls
executable file
·393 lines (347 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#!/bin/bash
# KubeStellar Console - Quick Start
#
# Up and running in under a minute.
# Downloads pre-built binaries and starts the console locally.
# No Go, Node.js, or build tools required — just curl.
#
# Usage:
# curl -sSL https://raw.githubusercontent.com/kubestellar/console/main/start.sh | bash
#
# Options:
# --version, -v <tag> Specific version to download (default: latest stable)
# --dir, -d <path> Install directory (default: ./kubestellar-console)
# --port, -p <port> Console port (default: 8080)
#
# kc-agent runs as a background daemon (survives Ctrl+C / terminal close).
# To stop it: kill $(cat ./kubestellar-console/kc-agent.pid)
# Logs: ./kubestellar-console/kc-agent.log
#
# To enable GitHub OAuth login, create a .env file:
# GITHUB_CLIENT_ID=your-client-id
# GITHUB_CLIENT_SECRET=your-client-secret
# FRONTEND_URL=http://localhost:8080
set -e
# --- Defaults ---
INSTALL_DIR="./kubestellar-console"
VERSION=""
PORT=8080
REPO="kubestellar/console"
GITHUB_API="https://api.github.com"
# --- Parse args ---
while [[ $# -gt 0 ]]; do
case $1 in
--version|-v) VERSION="$2"; shift 2 ;;
--dir|-d) INSTALL_DIR="$2"; shift 2 ;;
--port|-p) PORT="$2"; shift 2 ;;
*) shift ;;
esac
done
# --- Detect platform ---
detect_platform() {
local os arch
case "$(uname -s)" in
Linux*) os="linux" ;;
Darwin*) os="darwin" ;;
*)
echo "Error: Unsupported operating system: $(uname -s)"
exit 1
;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="amd64" ;;
aarch64|arm64) arch="arm64" ;;
*)
echo "Error: Unsupported architecture: $(uname -m)"
exit 1
;;
esac
echo "${os}_${arch}"
}
# --- Resolve version ---
resolve_version() {
if [ -n "$VERSION" ]; then
echo "$VERSION"
return
fi
echo "Resolving latest version..." >&2
local latest api_response http_code
# Try to get latest stable release (non-prerelease) via releases list
api_response=$(curl -sSL -w '\n%{http_code}' "${GITHUB_API}/repos/${REPO}/releases" 2>/dev/null)
http_code=$(echo "$api_response" | tail -1)
api_response=$(echo "$api_response" | sed '$d')
if [ "$http_code" = "200" ]; then
latest=$(echo "$api_response" \
| grep -o '"tag_name": *"[^"]*"' \
| head -20 \
| sed 's/"tag_name": *"//;s/"//' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| head -1)
fi
# Fall back to /releases/latest endpoint (includes prereleases)
if [ -z "$latest" ]; then
api_response=$(curl -sSL -w '\n%{http_code}' "${GITHUB_API}/repos/${REPO}/releases/latest" 2>/dev/null)
http_code=$(echo "$api_response" | tail -1)
api_response=$(echo "$api_response" | sed '$d')
if [ "$http_code" = "200" ]; then
latest=$(echo "$api_response" \
| grep -o '"tag_name": *"[^"]*"' \
| sed 's/"tag_name": *"//;s/"//')
fi
fi
# Fall back to git tags if API is unavailable (rate-limited, network issues)
if [ -z "$latest" ]; then
echo " API unavailable (HTTP $http_code), trying git ls-remote..." >&2
latest=$(git ls-remote --tags --sort=-v:refname "https://github.com/${REPO}.git" 'v*' 2>/dev/null \
| grep -o 'refs/tags/v[0-9]*\.[0-9]*\.[0-9]*$' \
| head -1 \
| sed 's|refs/tags/||')
fi
if [ -z "$latest" ]; then
echo "Error: Could not determine latest version." >&2
echo " This may be due to GitHub API rate limiting for unauthenticated requests." >&2
echo " Try specifying a version manually:" >&2
echo " curl -sSL https://raw.githubusercontent.com/${REPO}/main/start.sh | bash -s -- --version v0.3.14" >&2
exit 1
fi
echo "$latest"
}
# --- Download and extract ---
# Downloads to a temp file then atomically moves into place to prevent
# partial writes from corrupting a running binary.
download_binary() {
local name="$1" version="$2" platform="$3"
local url="https://github.com/${REPO}/releases/download/${version}/${name}_${version#v}_${platform}.tar.gz"
local tmp_extract_dir
tmp_extract_dir=$(mktemp -d)
echo " Downloading ${name} ${version} (${platform})..."
if ! curl -sSL --fail -o "/tmp/${name}.tar.gz" "$url" 2>/dev/null; then
echo " Warning: Failed to download ${name} from ${url}"
rm -rf "$tmp_extract_dir"
return 1
fi
# Extract to a temporary directory first
tar xzf "/tmp/${name}.tar.gz" -C "$tmp_extract_dir"
rm -f "/tmp/${name}.tar.gz"
# Move the binary into the install directory
chmod +x "$tmp_extract_dir/${name}" 2>/dev/null || true
mv -f "$tmp_extract_dir/${name}" "$INSTALL_DIR/${name}"
# Move web/dist/ if present (console tarball includes the built frontend)
if [ -d "$tmp_extract_dir/web/dist" ]; then
rm -rf "$INSTALL_DIR/web/dist"
mkdir -p "$INSTALL_DIR/web"
mv -f "$tmp_extract_dir/web/dist" "$INSTALL_DIR/web/dist"
fi
rm -rf "$tmp_extract_dir"
return 0
}
# --- Open browser ---
open_browser() {
local url="$1"
if command -v open &>/dev/null; then
open "$url"
elif command -v xdg-open &>/dev/null; then
xdg-open "$url"
else
echo " Open your browser to: $url"
fi
}
# --- Main ---
echo "=== KubeStellar Console — Up in Under a Minute ==="
echo ""
# Check prerequisites
if ! command -v curl &>/dev/null; then
echo "Error: curl is required but not found."
exit 1
fi
PLATFORM=$(detect_platform)
VERSION=$(resolve_version)
echo " Version: $VERSION"
echo " Platform: $PLATFORM"
echo " Directory: $INSTALL_DIR"
echo ""
# Create install directory
mkdir -p "$INSTALL_DIR"
# Download binaries
echo "Downloading binaries..."
download_binary "console" "$VERSION" "$PLATFORM"
# kc-agent is optional — it bridges the browser to local kubeconfig
if ! download_binary "kc-agent" "$VERSION" "$PLATFORM"; then
echo " (kc-agent is optional — local cluster features will be limited)"
fi
# Kill any existing console instance on the console port
EXISTING_PID=$(lsof -ti :"$PORT" 2>/dev/null || true)
if [ -n "$EXISTING_PID" ]; then
echo "Killing existing process on port $PORT (PID: $EXISTING_PID)..."
kill -TERM "$EXISTING_PID" 2>/dev/null || true
sleep 2
# Fall back to SIGKILL if process did not exit gracefully
kill -9 "$EXISTING_PID" 2>/dev/null || true
fi
# Note: kc-agent on port 8585 is managed via PID file — not force-killed here
# Load .env file if it exists
if [ -f "$INSTALL_DIR/.env" ]; then
echo "Loading .env file..."
while IFS='=' read -r key value; do
[[ $key =~ ^#.*$ ]] && continue
[[ -z "$key" ]] && continue
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
export "$key=$value"
done < "$INSTALL_DIR/.env"
elif [ -f ".env" ]; then
echo "Loading .env file..."
while IFS='=' read -r key value; do
[[ $key =~ ^#.*$ ]] && continue
[[ -z "$key" ]] && continue
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
export "$key=$value"
done < ".env"
fi
# Warn when GitHub OAuth credentials are not configured
if [ -z "$GITHUB_CLIENT_ID" ] || [ -z "$GITHUB_CLIENT_SECRET" ]; then
echo ""
echo "Note: No GitHub OAuth credentials found."
echo " Console will start in dev mode (auto-login, no GitHub authentication)."
echo " To enable GitHub login, create a .env file with:"
echo " GITHUB_CLIENT_ID=<your-client-id>"
echo " GITHUB_CLIENT_SECRET=<your-client-secret>"
echo ""
fi
# Cleanup on exit — console stops, kc-agent keeps running as a background service
CONSOLE_PID=""
cleanup() {
echo ""
echo "Shutting down console..."
[ -n "$CONSOLE_PID" ] && kill "$CONSOLE_PID" 2>/dev/null || true
if [ -f "$INSTALL_DIR/kc-agent.pid" ] && kill -0 "$(cat "$INSTALL_DIR/kc-agent.pid")" 2>/dev/null; then
echo " kc-agent continues running in the background (PID file: $INSTALL_DIR/kc-agent.pid)"
echo " To stop it: kill \$(cat $INSTALL_DIR/kc-agent.pid)"
else
echo " kc-agent has stopped."
fi
exit 0
}
trap cleanup SIGINT SIGTERM
# Start kc-agent as a background daemon (survives console/script exit)
AGENT_PORT=8585
if [ -x "$INSTALL_DIR/kc-agent" ]; then
AGENT_PID_FILE="$INSTALL_DIR/kc-agent.pid"
AGENT_LOG_FILE="$INSTALL_DIR/kc-agent.log"
# Check if kc-agent is already running — restart it with the new binary
if [ -f "$AGENT_PID_FILE" ]; then
EXISTING_AGENT_PID=$(cat "$AGENT_PID_FILE")
if kill -0 "$EXISTING_AGENT_PID" 2>/dev/null; then
echo "Restarting kc-agent (PID: $EXISTING_AGENT_PID) with updated binary..."
kill -TERM "$EXISTING_AGENT_PID" 2>/dev/null || true
sleep 2
# Fall back to SIGKILL if process did not exit gracefully
kill -9 "$EXISTING_AGENT_PID" 2>/dev/null || true
rm -f "$AGENT_PID_FILE"
else
echo "Stale PID file found, removing..."
rm -f "$AGENT_PID_FILE"
fi
fi
# Start kc-agent if not already running
if [ ! -f "$AGENT_PID_FILE" ]; then
echo "Starting kc-agent as background daemon..."
nohup "$INSTALL_DIR/kc-agent" >> "$AGENT_LOG_FILE" 2>&1 &
echo $! > "$AGENT_PID_FILE"
sleep 1
# Verify it started
if kill -0 "$(cat "$AGENT_PID_FILE")" 2>/dev/null; then
echo " kc-agent started (PID: $(cat "$AGENT_PID_FILE"), log: $AGENT_LOG_FILE)"
# Warn if Claude Code is running — it needs to be restarted to pick up MCP server changes
if pgrep -f "claude" > /dev/null 2>&1 && [ -f "$HOME/.claude/claude_desktop_config.json" ]; then
echo ""
echo " ⚠️ Claude Code is running in another session."
echo " If MCP servers appear as 'failed' in Claude Code, restart Claude Code"
echo " to pick up the new kubestellar-ops and kubestellar-deploy servers."
echo ""
fi
else
echo " Warning: kc-agent failed to start. Check $AGENT_LOG_FILE for details."
rm -f "$AGENT_PID_FILE"
fi
fi
fi
# Check for MCP tool binaries (kubestellar-ops, kubestellar-deploy)
# These are optional but required for full MCP integration
MCP_OPS_PATH="${KUBESTELLAR_OPS_PATH:-kubestellar-ops}"
MCP_DEPLOY_PATH="${KUBESTELLAR_DEPLOY_PATH:-kubestellar-deploy}"
MCP_MISSING=""
if ! command -v "$MCP_OPS_PATH" &>/dev/null; then
MCP_MISSING="kubestellar-ops"
fi
if ! command -v "$MCP_DEPLOY_PATH" &>/dev/null; then
if [ -n "$MCP_MISSING" ]; then
MCP_MISSING="$MCP_MISSING and kubestellar-deploy"
else
MCP_MISSING="kubestellar-deploy"
fi
fi
if [ -n "$MCP_MISSING" ]; then
echo ""
echo " Note: $MCP_MISSING not found on PATH."
echo " MCP tools (Kubernetes ops and deploy) will be unavailable."
echo " To install, follow Step 1 of the Quick Start guide:"
echo " https://kubestellar.io/docs/console/overview/quick-start#step-1-install-kubestellar-mcp-tools"
echo ""
fi
# Generate JWT_SECRET if not set (required in production mode)
if [ -z "$JWT_SECRET" ]; then
if command -v openssl &>/dev/null; then
export JWT_SECRET=$(openssl rand -hex 32)
else
export JWT_SECRET=$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')
fi
fi
# Start console (serves frontend from web/dist at the specified port)
echo "Starting console on port $PORT..."
cd "$INSTALL_DIR"
./console --port "$PORT" &
CONSOLE_PID=$!
# Wait for console to be ready
echo ""
echo "Waiting for console to start..."
MAX_WAIT=60
WAITED=0
while [ $WAITED -lt $MAX_WAIT ]; do
# Poll the root path — returns 200 only when Fiber is fully started and
# serving the SPA frontend (web/dist/index.html). The warmup phase may
# start a temporary listener that returns 404 for / before Fiber is ready.
HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:${PORT}/" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ]; then
break
fi
sleep 2
WAITED=$((WAITED + 2))
printf " %ds..." "$WAITED"
done
echo ""
if [ "$HTTP_CODE" = "200" ]; then
echo ""
echo "=== KubeStellar Console is running ==="
echo ""
echo " Console: http://localhost:${PORT}"
if [ -f "$INSTALL_DIR/kc-agent.pid" ] && kill -0 "$(cat "$INSTALL_DIR/kc-agent.pid")" 2>/dev/null; then
echo " kc-agent: http://localhost:${AGENT_PORT} (PID: $(cat "$INSTALL_DIR/kc-agent.pid"))"
fi
echo ""
open_browser "http://localhost:${PORT}"
echo "Press Ctrl+C to stop the console (kc-agent continues in background)"
echo ""
wait
else
echo ""
echo "Warning: Console did not respond within ${MAX_WAIT}s"
echo "Check if it's still starting: curl http://localhost:${PORT}"
echo ""
wait
fi