mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-05-22 11:15:42 +00:00
wait for instance to be ready and return to manage screen
This commit is contained in:
parent
7103367640
commit
3be36993c3
2 changed files with 336 additions and 300 deletions
338
install.ps1
338
install.ps1
|
|
@ -327,6 +327,34 @@ function Get-NonEmptyLines {
|
|||
return @($lines | ForEach-Object { "$($_)".Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
||||
}
|
||||
|
||||
function Wait-ForReady {
|
||||
param([string]$Url)
|
||||
|
||||
$maxWait = 60
|
||||
$waited = 0
|
||||
|
||||
Write-Host "[INFO] Launching Agent Zero..." -ForegroundColor Green -NoNewline
|
||||
while ($waited -lt $maxWait) {
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop
|
||||
if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 400) {
|
||||
Write-Host ''
|
||||
print_ok "Agent Zero is ready at $Url"
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
Start-Sleep -Seconds 1
|
||||
$waited++
|
||||
Write-Host '.' -NoNewline
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
print_warn "Agent Zero did not respond within $maxWait seconds. It may still be starting up."
|
||||
return $false
|
||||
}
|
||||
|
||||
# Uses image name string matching instead of ancestor filter.
|
||||
# The ancestor filter matches by image ID, not name, so containers created
|
||||
# from a previous version of a tag become invisible after pulling a newer version.
|
||||
|
|
@ -652,32 +680,11 @@ function create_instance {
|
|||
throw 'Failed to start Agent Zero.'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '=========================================='
|
||||
Write-Host ' Installation Complete!' -ForegroundColor Green
|
||||
Write-Host '=========================================='
|
||||
Write-Host ''
|
||||
Write-Host " Image tag : $script:SelectedTag"
|
||||
Write-Host " Instance name : $containerName"
|
||||
Write-Host " Compose file : $composeFile"
|
||||
Write-Host " Data directory : $dataDir"
|
||||
Write-Host " Web UI : http://localhost:$port"
|
||||
if (-not [string]::IsNullOrWhiteSpace($authLogin)) {
|
||||
Write-Host ' Authentication : enabled'
|
||||
Write-Host " Login : $authLogin"
|
||||
Write-Host " Password : $authPassword"
|
||||
}
|
||||
else {
|
||||
Write-Host ' Authentication : none'
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host ' Useful commands:'
|
||||
Write-Host " docker compose -f `"$composeFile`" logs -f # View logs"
|
||||
Write-Host " docker compose -f `"$composeFile`" down # Stop"
|
||||
Write-Host " docker compose -f `"$composeFile`" up -d # Start"
|
||||
Write-Host " docker compose -f `"$composeFile`" pull # Update image"
|
||||
Write-Host ''
|
||||
print_info 'Happy automating with Agent Zero!'
|
||||
# Wait for the service to become ready
|
||||
Wait-ForReady -Url "http://localhost:$port"
|
||||
|
||||
# Store the created container name for the caller
|
||||
$script:CreatedContainerName = $containerName
|
||||
|
||||
return $true
|
||||
}
|
||||
|
|
@ -742,140 +749,149 @@ function manage_instances {
|
|||
$selectedRow = $containerRows[$selectedIndex]
|
||||
$selectedParts = $selectedRow -split '\|', 3
|
||||
$selectedName = if ($selectedParts.Count -ge 1) { $selectedParts[0] } else { '' }
|
||||
$selectedImage = if ($selectedParts.Count -ge 2) { $selectedParts[1] } else { '' }
|
||||
|
||||
# Inner action loop for the selected container
|
||||
while ($true) {
|
||||
$statusOutput = & docker ps -a --filter "name=^/$selectedName$" --format '{{.Status}}' 2>$null
|
||||
$selectedStatus = ((Get-NonEmptyLines $statusOutput) | Select-Object -First 1)
|
||||
manage_single_instance -ContainerName $selectedName
|
||||
}
|
||||
}
|
||||
|
||||
# If container no longer exists (e.g. after delete), go back to instance list
|
||||
if ([string]::IsNullOrWhiteSpace($selectedStatus)) {
|
||||
# Show the action menu for a single container (open, start, stop, restart, delete).
|
||||
# Can be called from manage_instances or directly after create_instance.
|
||||
function manage_single_instance {
|
||||
param([string]$ContainerName)
|
||||
|
||||
# Look up the image for display
|
||||
$selectedImage = ((Get-NonEmptyLines (& docker ps -a --filter "name=^/$ContainerName$" --format '{{.Image}}' 2>$null)) | Select-Object -First 1)
|
||||
|
||||
while ($true) {
|
||||
$statusOutput = & docker ps -a --filter "name=^/$ContainerName$" --format '{{.Status}}' 2>$null
|
||||
$selectedStatus = ((Get-NonEmptyLines $statusOutput) | Select-Object -First 1)
|
||||
|
||||
# If container no longer exists (e.g. after delete), return
|
||||
if ([string]::IsNullOrWhiteSpace($selectedStatus)) {
|
||||
break
|
||||
}
|
||||
|
||||
$isRunning = $selectedStatus -like 'Up*'
|
||||
$instanceHeader = "Selected: $ContainerName ($selectedImage, $selectedStatus)"
|
||||
|
||||
if ($isRunning) {
|
||||
$actionOptions = @('Open in browser', 'Restart', 'Stop', 'Delete', 'Back')
|
||||
$actionIndex = select_from_menu -Header $instanceHeader -Options $actionOptions
|
||||
switch ($actionIndex) {
|
||||
-1 { $actionKey = 'back' } # Escape/Backspace
|
||||
0 { $actionKey = 'open' }
|
||||
1 { $actionKey = 'restart' }
|
||||
2 { $actionKey = 'stop' }
|
||||
3 { $actionKey = 'delete' }
|
||||
4 { $actionKey = 'back' }
|
||||
default { $actionKey = 'invalid' }
|
||||
}
|
||||
}
|
||||
else {
|
||||
$actionOptions = @('Start', 'Delete', 'Back')
|
||||
$actionIndex = select_from_menu -Header $instanceHeader -Options $actionOptions
|
||||
switch ($actionIndex) {
|
||||
-1 { $actionKey = 'back' } # Escape/Backspace
|
||||
0 { $actionKey = 'start' }
|
||||
1 { $actionKey = 'delete' }
|
||||
2 { $actionKey = 'back' }
|
||||
default { $actionKey = 'invalid' }
|
||||
}
|
||||
}
|
||||
|
||||
switch ($actionKey) {
|
||||
'open' {
|
||||
$portOutput = & docker port $ContainerName '80/tcp' 2>$null
|
||||
$hostPort = ''
|
||||
|
||||
foreach ($line in (Get-NonEmptyLines $portOutput)) {
|
||||
if ($line -match ':(\d+)\s*$') {
|
||||
$hostPort = $Matches[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($hostPort)) {
|
||||
print_warn "Could not resolve a host port for '$ContainerName' on 80/tcp. Ensure it is running with a published port."
|
||||
}
|
||||
else {
|
||||
$targetUrl = "http://localhost:$hostPort"
|
||||
print_info "Opening $targetUrl"
|
||||
open_browser -Url $targetUrl
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'start' {
|
||||
print_info "Starting '$ContainerName'..."
|
||||
$startOutput = & docker start $ContainerName 2>&1
|
||||
# Verify actual container state
|
||||
$runCheck = & docker ps --filter "name=^/$ContainerName$" --filter 'status=running' --format '{{.Names}}' 2>$null
|
||||
if ((Get-NonEmptyLines $runCheck) -contains $ContainerName) {
|
||||
print_ok "Started '$ContainerName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to start '$ContainerName'."
|
||||
if ($startOutput) {
|
||||
Write-Host " $startOutput"
|
||||
}
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'stop' {
|
||||
print_info "Stopping '$ContainerName'..."
|
||||
& docker stop $ContainerName *> $null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
print_ok "Stopped '$ContainerName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to stop '$ContainerName'."
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'restart' {
|
||||
print_info "Restarting '$ContainerName'..."
|
||||
$restartOutput = & docker restart $ContainerName 2>&1
|
||||
# Verify actual container state
|
||||
$runCheck = & docker ps --filter "name=^/$ContainerName$" --filter 'status=running' --format '{{.Names}}' 2>$null
|
||||
if ((Get-NonEmptyLines $runCheck) -contains $ContainerName) {
|
||||
print_ok "Restarted '$ContainerName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to restart '$ContainerName'."
|
||||
if ($restartOutput) {
|
||||
Write-Host " $restartOutput"
|
||||
}
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'delete' {
|
||||
Write-Host "Are you sure you want to delete '$ContainerName'? [y/N]: " -NoNewline
|
||||
$confirmKey = [Console]::ReadKey($true)
|
||||
Write-Host ''
|
||||
if ($confirmKey.KeyChar -eq 'y' -or $confirmKey.KeyChar -eq 'Y') {
|
||||
# Stop first if running
|
||||
& docker stop $ContainerName *> $null
|
||||
& docker rm $ContainerName *> $null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
print_ok "Deleted '$ContainerName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to delete '$ContainerName'."
|
||||
}
|
||||
Wait-ForKeypress
|
||||
break # Container no longer exists
|
||||
}
|
||||
else {
|
||||
print_info 'Delete cancelled.'
|
||||
Wait-ForKeypress
|
||||
}
|
||||
}
|
||||
'back' {
|
||||
break
|
||||
}
|
||||
|
||||
$isRunning = $selectedStatus -like 'Up*'
|
||||
$instanceHeader = "Selected: $selectedName ($selectedImage, $selectedStatus)"
|
||||
|
||||
if ($isRunning) {
|
||||
$actionOptions = @('Open in browser', 'Restart', 'Stop', 'Delete', 'Back')
|
||||
$actionIndex = select_from_menu -Header $instanceHeader -Options $actionOptions
|
||||
switch ($actionIndex) {
|
||||
-1 { $actionKey = 'back' } # Escape/Backspace
|
||||
0 { $actionKey = 'open' }
|
||||
1 { $actionKey = 'restart' }
|
||||
2 { $actionKey = 'stop' }
|
||||
3 { $actionKey = 'delete' }
|
||||
4 { $actionKey = 'back' }
|
||||
default { $actionKey = 'invalid' }
|
||||
}
|
||||
}
|
||||
else {
|
||||
$actionOptions = @('Start', 'Delete', 'Back')
|
||||
$actionIndex = select_from_menu -Header $instanceHeader -Options $actionOptions
|
||||
switch ($actionIndex) {
|
||||
-1 { $actionKey = 'back' } # Escape/Backspace
|
||||
0 { $actionKey = 'start' }
|
||||
1 { $actionKey = 'delete' }
|
||||
2 { $actionKey = 'back' }
|
||||
default { $actionKey = 'invalid' }
|
||||
}
|
||||
}
|
||||
|
||||
switch ($actionKey) {
|
||||
'open' {
|
||||
$portOutput = & docker port $selectedName '80/tcp' 2>$null
|
||||
$hostPort = ''
|
||||
|
||||
foreach ($line in (Get-NonEmptyLines $portOutput)) {
|
||||
if ($line -match ':(\d+)\s*$') {
|
||||
$hostPort = $Matches[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($hostPort)) {
|
||||
print_warn "Could not resolve a host port for '$selectedName' on 80/tcp. Ensure it is running with a published port."
|
||||
}
|
||||
else {
|
||||
$targetUrl = "http://localhost:$hostPort"
|
||||
print_info "Opening $targetUrl"
|
||||
open_browser -Url $targetUrl
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'start' {
|
||||
print_info "Starting '$selectedName'..."
|
||||
$startOutput = & docker start $selectedName 2>&1
|
||||
# Verify actual container state
|
||||
$runCheck = & docker ps --filter "name=^/$selectedName$" --filter 'status=running' --format '{{.Names}}' 2>$null
|
||||
if ((Get-NonEmptyLines $runCheck) -contains $selectedName) {
|
||||
print_ok "Started '$selectedName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to start '$selectedName'."
|
||||
if ($startOutput) {
|
||||
Write-Host " $startOutput"
|
||||
}
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'stop' {
|
||||
print_info "Stopping '$selectedName'..."
|
||||
& docker stop $selectedName *> $null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
print_ok "Stopped '$selectedName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to stop '$selectedName'."
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'restart' {
|
||||
print_info "Restarting '$selectedName'..."
|
||||
$restartOutput = & docker restart $selectedName 2>&1
|
||||
# Verify actual container state
|
||||
$runCheck = & docker ps --filter "name=^/$selectedName$" --filter 'status=running' --format '{{.Names}}' 2>$null
|
||||
if ((Get-NonEmptyLines $runCheck) -contains $selectedName) {
|
||||
print_ok "Restarted '$selectedName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to restart '$selectedName'."
|
||||
if ($restartOutput) {
|
||||
Write-Host " $restartOutput"
|
||||
}
|
||||
}
|
||||
Wait-ForKeypress
|
||||
}
|
||||
'delete' {
|
||||
Write-Host "Are you sure you want to delete '$selectedName'? [y/N]: " -NoNewline
|
||||
$confirmKey = [Console]::ReadKey($true)
|
||||
Write-Host ''
|
||||
if ($confirmKey.KeyChar -eq 'y' -or $confirmKey.KeyChar -eq 'Y') {
|
||||
# Stop first if running
|
||||
& docker stop $selectedName *> $null
|
||||
& docker rm $selectedName *> $null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
print_ok "Deleted '$selectedName'."
|
||||
}
|
||||
else {
|
||||
print_error "Failed to delete '$selectedName'."
|
||||
}
|
||||
Wait-ForKeypress
|
||||
break # Back to instance list (container no longer exists)
|
||||
}
|
||||
else {
|
||||
print_info 'Delete cancelled.'
|
||||
Wait-ForKeypress
|
||||
}
|
||||
}
|
||||
'back' {
|
||||
break # Break inner loop, go back to instance selection
|
||||
}
|
||||
default {
|
||||
print_warn 'Invalid action. Please try again.'
|
||||
Wait-ForKeypress
|
||||
}
|
||||
default {
|
||||
print_warn 'Invalid action. Please try again.'
|
||||
Wait-ForKeypress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -894,11 +910,12 @@ function main_menu_for_existing {
|
|||
switch ($selectedIndex) {
|
||||
-1 { exit 0 } # Escape/Backspace - exit
|
||||
0 {
|
||||
$script:CreatedContainerName = ''
|
||||
$result = create_instance
|
||||
if ($result) {
|
||||
return # Install completed successfully
|
||||
manage_single_instance -ContainerName $script:CreatedContainerName
|
||||
}
|
||||
# Escape pressed during create - loop back to menu
|
||||
# Escape pressed during create or back from detail - loop back to menu
|
||||
}
|
||||
1 { manage_instances } # loops back to this menu after returning
|
||||
2 { exit 0 } # Exit option
|
||||
|
|
@ -907,11 +924,12 @@ function main_menu_for_existing {
|
|||
}
|
||||
else {
|
||||
# All containers were deleted - go straight to install
|
||||
$script:CreatedContainerName = ''
|
||||
$result = create_instance
|
||||
if (-not $result) {
|
||||
exit 0
|
||||
}
|
||||
return
|
||||
manage_single_instance -ContainerName $script:CreatedContainerName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -931,10 +949,12 @@ function main {
|
|||
else {
|
||||
# No existing containers - go straight to install.
|
||||
# If Escape pressed during create, exit gracefully.
|
||||
$script:CreatedContainerName = ''
|
||||
$result = create_instance
|
||||
if (-not $result) {
|
||||
exit 0
|
||||
}
|
||||
manage_single_instance -ContainerName $script:CreatedContainerName
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
298
install.sh
298
install.sh
|
|
@ -348,6 +348,28 @@ check_docker() {
|
|||
fi
|
||||
}
|
||||
|
||||
wait_for_ready() {
|
||||
URL="$1"
|
||||
MAX_WAIT=60
|
||||
WAITED=0
|
||||
|
||||
printf "${GREEN}[INFO]${NC} Launching Agent Zero..."
|
||||
while [ "$WAITED" -lt "$MAX_WAIT" ]; do
|
||||
HTTP_CODE="$(curl -s -o /dev/null -w '%{http_code}' "$URL" 2>/dev/null || true)"
|
||||
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
|
||||
printf "\n"
|
||||
print_ok "Agent Zero is ready at $URL"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
WAITED=$((WAITED + 1))
|
||||
printf "."
|
||||
done
|
||||
printf "\n"
|
||||
print_warn "Agent Zero did not respond within ${MAX_WAIT} seconds. It may still be starting up."
|
||||
return 1
|
||||
}
|
||||
|
||||
count_existing_agent_zero_containers() {
|
||||
docker ps -a --format '{{.Names}}|{{.Image}}' 2>/dev/null | awk -F'|' '$2 ~ /^agent0ai\/agent-zero(:|$)/ {count++} END {print count+0}'
|
||||
}
|
||||
|
|
@ -627,33 +649,12 @@ create_instance() {
|
|||
docker compose -f "$COMPOSE_FILE" up -d
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# 5. Done!
|
||||
# 5. Wait for the service to become ready
|
||||
# -----------------------------------------------------------
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
printf " ${GREEN}${BOLD}Installation Complete!${NC}\n"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo " 🏷️ Image tag : $SELECTED_TAG"
|
||||
echo " 📦 Instance name : $CONTAINER_NAME"
|
||||
echo " 🧩 Compose file : $COMPOSE_FILE"
|
||||
echo " 📁 Data directory : $DATA_DIR"
|
||||
echo " 🌐 Web UI : http://localhost:$PORT"
|
||||
if [ -n "$AUTH_LOGIN" ]; then
|
||||
echo " 🔐 Authentication : enabled"
|
||||
echo " 👤 Login : $AUTH_LOGIN"
|
||||
echo " 🔑 Password : $AUTH_PASSWORD"
|
||||
else
|
||||
echo " 🔓 Authentication : none"
|
||||
fi
|
||||
echo ""
|
||||
echo " Useful commands:"
|
||||
echo " docker compose -f $COMPOSE_FILE logs -f # View logs"
|
||||
echo " docker compose -f $COMPOSE_FILE down # Stop"
|
||||
echo " docker compose -f $COMPOSE_FILE up -d # Start"
|
||||
echo " docker compose -f $COMPOSE_FILE pull # Update image"
|
||||
echo ""
|
||||
print_info "Happy automating with Agent Zero! 🤖"
|
||||
wait_for_ready "http://localhost:$PORT"
|
||||
|
||||
# Store the created container name for the caller
|
||||
CREATED_CONTAINER_NAME="$CONTAINER_NAME"
|
||||
}
|
||||
|
||||
manage_instances() {
|
||||
|
|
@ -744,120 +745,131 @@ manage_instances() {
|
|||
SELECTED_IMAGE="$(printf "%s\n" "$SELECTED_ROW" | cut -d'|' -f2)"
|
||||
SELECTED_STATUS="$(printf "%s\n" "$SELECTED_ROW" | cut -d'|' -f3-)"
|
||||
|
||||
while :; do
|
||||
SELECTED_STATUS="$(docker ps -a --filter "name=^/${SELECTED_NAME}$" --format '{{.Status}}' 2>/dev/null | head -n 1)"
|
||||
manage_single_instance "$SELECTED_NAME"
|
||||
done
|
||||
}
|
||||
|
||||
# If container no longer exists (e.g. after delete), go back to instance list
|
||||
if [ -z "$SELECTED_STATUS" ]; then
|
||||
# Show the action menu for a single container (open, start, stop, restart, delete).
|
||||
# Can be called from manage_instances or directly after create_instance.
|
||||
manage_single_instance() {
|
||||
SELECTED_NAME="$1"
|
||||
|
||||
# Look up the image for display
|
||||
SELECTED_IMAGE="$(docker ps -a --filter "name=^/${SELECTED_NAME}$" --format '{{.Image}}' 2>/dev/null | head -n 1)"
|
||||
|
||||
while :; do
|
||||
SELECTED_STATUS="$(docker ps -a --filter "name=^/${SELECTED_NAME}$" --format '{{.Status}}' 2>/dev/null | head -n 1)"
|
||||
|
||||
# If container no longer exists (e.g. after delete), return
|
||||
if [ -z "$SELECTED_STATUS" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
case "$SELECTED_STATUS" in
|
||||
Up*) IS_RUNNING=1 ;;
|
||||
*) IS_RUNNING=0 ;;
|
||||
esac
|
||||
|
||||
INSTANCE_HEADER="Selected: $SELECTED_NAME ($SELECTED_IMAGE, $SELECTED_STATUS)"
|
||||
|
||||
if [ "$IS_RUNNING" -eq 1 ]; then
|
||||
ACTION_INDEX=$(select_from_menu "--header=$INSTANCE_HEADER" "Open in browser" "Restart" "Stop" "Delete" "Back") || true
|
||||
case "$ACTION_INDEX" in
|
||||
-1) ACTION_KEY="back" ;; # Escape/Backspace — go back
|
||||
0) ACTION_KEY="open" ;;
|
||||
1) ACTION_KEY="restart" ;;
|
||||
2) ACTION_KEY="stop" ;;
|
||||
3) ACTION_KEY="delete" ;;
|
||||
4) ACTION_KEY="back" ;;
|
||||
*) ACTION_KEY="invalid" ;;
|
||||
esac
|
||||
else
|
||||
ACTION_INDEX=$(select_from_menu "--header=$INSTANCE_HEADER" "Start" "Delete" "Back") || true
|
||||
case "$ACTION_INDEX" in
|
||||
-1) ACTION_KEY="back" ;; # Escape/Backspace — go back
|
||||
0) ACTION_KEY="start" ;;
|
||||
1) ACTION_KEY="delete" ;;
|
||||
2) ACTION_KEY="back" ;;
|
||||
*) ACTION_KEY="invalid" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "$ACTION_KEY" in
|
||||
open)
|
||||
PORT_OUTPUT="$(docker port "$SELECTED_NAME" 80/tcp 2>/dev/null || true)"
|
||||
HOST_PORT="$(printf "%s\n" "$PORT_OUTPUT" | sed -n 's/.*:\([0-9][0-9]*\)$/\1/p' | head -n 1)"
|
||||
|
||||
if [ -z "$HOST_PORT" ]; then
|
||||
print_warn "Could not resolve a host port for '$SELECTED_NAME' on 80/tcp. Ensure it is running with a published port."
|
||||
else
|
||||
TARGET_URL="http://localhost:$HOST_PORT"
|
||||
print_info "Opening $TARGET_URL"
|
||||
open_browser "$TARGET_URL"
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
start)
|
||||
print_info "Starting '$SELECTED_NAME'..."
|
||||
START_OUTPUT="$(docker start "$SELECTED_NAME" 2>&1)" || true
|
||||
if docker ps --filter "name=^/${SELECTED_NAME}$" --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -q "^${SELECTED_NAME}$"; then
|
||||
print_ok "Started '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to start '$SELECTED_NAME'."
|
||||
if [ -n "$START_OUTPUT" ]; then
|
||||
printf " %s\n" "$START_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
stop)
|
||||
print_info "Stopping '$SELECTED_NAME'..."
|
||||
if docker stop "$SELECTED_NAME" >/dev/null 2>&1; then
|
||||
print_ok "Stopped '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to stop '$SELECTED_NAME'."
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
restart)
|
||||
print_info "Restarting '$SELECTED_NAME'..."
|
||||
RESTART_OUTPUT="$(docker restart "$SELECTED_NAME" 2>&1)" || true
|
||||
if docker ps --filter "name=^/${SELECTED_NAME}$" --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -q "^${SELECTED_NAME}$"; then
|
||||
print_ok "Restarted '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to restart '$SELECTED_NAME'."
|
||||
if [ -n "$RESTART_OUTPUT" ]; then
|
||||
printf " %s\n" "$RESTART_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
delete)
|
||||
printf "Are you sure you want to delete '%s'? [y/N]: " "$SELECTED_NAME"
|
||||
IFS= read -rsn1 CONFIRM </dev/tty
|
||||
printf "\n"
|
||||
if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
|
||||
# Stop first if running
|
||||
docker stop "$SELECTED_NAME" >/dev/null 2>&1 || true
|
||||
if docker rm "$SELECTED_NAME" >/dev/null 2>&1; then
|
||||
print_ok "Deleted '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to delete '$SELECTED_NAME'."
|
||||
fi
|
||||
wait_for_keypress
|
||||
break # Container no longer exists
|
||||
else
|
||||
print_info "Delete cancelled."
|
||||
wait_for_keypress
|
||||
fi
|
||||
;;
|
||||
back)
|
||||
break
|
||||
fi
|
||||
|
||||
case "$SELECTED_STATUS" in
|
||||
Up*) IS_RUNNING=1 ;;
|
||||
*) IS_RUNNING=0 ;;
|
||||
esac
|
||||
|
||||
INSTANCE_HEADER="Selected: $SELECTED_NAME ($SELECTED_IMAGE, $SELECTED_STATUS)"
|
||||
|
||||
if [ "$IS_RUNNING" -eq 1 ]; then
|
||||
ACTION_INDEX=$(select_from_menu "--header=$INSTANCE_HEADER" "Open in browser" "Restart" "Stop" "Delete" "Back") || true
|
||||
case "$ACTION_INDEX" in
|
||||
-1) ACTION_KEY="back" ;; # Escape/Backspace — go back to instance list
|
||||
0) ACTION_KEY="open" ;;
|
||||
1) ACTION_KEY="restart" ;;
|
||||
2) ACTION_KEY="stop" ;;
|
||||
3) ACTION_KEY="delete" ;;
|
||||
4) ACTION_KEY="back" ;;
|
||||
*) ACTION_KEY="invalid" ;;
|
||||
esac
|
||||
else
|
||||
ACTION_INDEX=$(select_from_menu "--header=$INSTANCE_HEADER" "Start" "Delete" "Back") || true
|
||||
case "$ACTION_INDEX" in
|
||||
-1) ACTION_KEY="back" ;; # Escape/Backspace — go back to instance list
|
||||
0) ACTION_KEY="start" ;;
|
||||
1) ACTION_KEY="delete" ;;
|
||||
2) ACTION_KEY="back" ;;
|
||||
*) ACTION_KEY="invalid" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "$ACTION_KEY" in
|
||||
open)
|
||||
PORT_OUTPUT="$(docker port "$SELECTED_NAME" 80/tcp 2>/dev/null || true)"
|
||||
HOST_PORT="$(printf "%s\n" "$PORT_OUTPUT" | sed -n 's/.*:\([0-9][0-9]*\)$/\1/p' | head -n 1)"
|
||||
|
||||
if [ -z "$HOST_PORT" ]; then
|
||||
print_warn "Could not resolve a host port for '$SELECTED_NAME' on 80/tcp. Ensure it is running with a published port."
|
||||
else
|
||||
TARGET_URL="http://localhost:$HOST_PORT"
|
||||
print_info "Opening $TARGET_URL"
|
||||
open_browser "$TARGET_URL"
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
start)
|
||||
print_info "Starting '$SELECTED_NAME'..."
|
||||
START_OUTPUT="$(docker start "$SELECTED_NAME" 2>&1)" || true
|
||||
if docker ps --filter "name=^/${SELECTED_NAME}$" --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -q "^${SELECTED_NAME}$"; then
|
||||
print_ok "Started '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to start '$SELECTED_NAME'."
|
||||
if [ -n "$START_OUTPUT" ]; then
|
||||
printf " %s\n" "$START_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
stop)
|
||||
print_info "Stopping '$SELECTED_NAME'..."
|
||||
if docker stop "$SELECTED_NAME" >/dev/null 2>&1; then
|
||||
print_ok "Stopped '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to stop '$SELECTED_NAME'."
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
restart)
|
||||
print_info "Restarting '$SELECTED_NAME'..."
|
||||
RESTART_OUTPUT="$(docker restart "$SELECTED_NAME" 2>&1)" || true
|
||||
if docker ps --filter "name=^/${SELECTED_NAME}$" --filter "status=running" --format '{{.Names}}' 2>/dev/null | grep -q "^${SELECTED_NAME}$"; then
|
||||
print_ok "Restarted '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to restart '$SELECTED_NAME'."
|
||||
if [ -n "$RESTART_OUTPUT" ]; then
|
||||
printf " %s\n" "$RESTART_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
wait_for_keypress
|
||||
;;
|
||||
delete)
|
||||
printf "Are you sure you want to delete '%s'? [y/N]: " "$SELECTED_NAME"
|
||||
IFS= read -rsn1 CONFIRM </dev/tty
|
||||
printf "\n"
|
||||
if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
|
||||
# Stop first if running
|
||||
docker stop "$SELECTED_NAME" >/dev/null 2>&1 || true
|
||||
if docker rm "$SELECTED_NAME" >/dev/null 2>&1; then
|
||||
print_ok "Deleted '$SELECTED_NAME'."
|
||||
else
|
||||
print_error "Failed to delete '$SELECTED_NAME'."
|
||||
fi
|
||||
wait_for_keypress
|
||||
break # Back to instance list (container no longer exists)
|
||||
else
|
||||
print_info "Delete cancelled."
|
||||
wait_for_keypress
|
||||
fi
|
||||
;;
|
||||
back)
|
||||
break # Break inner loop, go back to instance selection
|
||||
;;
|
||||
*)
|
||||
print_warn "Invalid action. Please try again."
|
||||
wait_for_keypress
|
||||
;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
*)
|
||||
print_warn "Invalid action. Please try again."
|
||||
wait_for_keypress
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
|
@ -876,10 +888,11 @@ main_menu_for_existing() {
|
|||
case "$SELECTED_INDEX" in
|
||||
-1) exit 0 ;; # Escape/Backspace — exit
|
||||
0)
|
||||
CREATED_CONTAINER_NAME=""
|
||||
if create_instance; then
|
||||
return 0 # Install completed successfully
|
||||
manage_single_instance "$CREATED_CONTAINER_NAME"
|
||||
fi
|
||||
# Escape pressed during create — loop back to menu
|
||||
# Escape pressed during create or back from detail — loop back to menu
|
||||
;;
|
||||
1) manage_instances ;; # loops back to this menu after returning
|
||||
2) exit 0 ;; # Exit option
|
||||
|
|
@ -887,10 +900,11 @@ main_menu_for_existing() {
|
|||
esac
|
||||
else
|
||||
# All containers were deleted — go straight to install
|
||||
CREATED_CONTAINER_NAME=""
|
||||
if ! create_instance; then
|
||||
exit 0
|
||||
fi
|
||||
return 0
|
||||
manage_single_instance "$CREATED_CONTAINER_NAME"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
|
@ -909,9 +923,11 @@ main() {
|
|||
else
|
||||
# No existing containers — go straight to install.
|
||||
# If Escape pressed during create, exit gracefully.
|
||||
CREATED_CONTAINER_NAME=""
|
||||
if ! create_instance; then
|
||||
exit 0
|
||||
fi
|
||||
manage_single_instance "$CREATED_CONTAINER_NAME"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue