Files
DevLab/Devlab-after-install.sh
2026-06-09 21:38:35 +00:00

192 lines
6.2 KiB
Bash

#!/usr/bin/env bash
# =============================================================================
# devlab — DevLab Management CLI
# Usage: devlab <command> [args]
#
# Install to PATH: sudo cp devlab.sh /usr/local/bin/devlab && chmod +x /usr/local/bin/devlab
# =============================================================================
set -euo pipefail
CONFIG_FILE="/opt/lab/.devlab-config"
[[ -f "$CONFIG_FILE" ]] && source "$CONFIG_FILE"
LAB_ROOT="${LAB_ROOT:-/opt/lab}"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
SERVICES=(caddy code-server gitea gitea-runner ollama open-webui portainer watchtower)
cmd_help() {
cat <<EOF
${BOLD}devlab${RESET} — DevLab Management CLI
${BOLD}COMMANDS${RESET}
status Show status of all services
start Start all services
stop Stop all services
restart [name] Restart all or a specific service
logs <name> Tail logs for a service
update Pull latest images and recreate containers
backup Run a manual backup now
models List downloaded Ollama models
pull <model> Pull an Ollama model (e.g. codellama:34b)
remove <model> Remove an Ollama model
urls Print all service URLs
compose up <file> Start a test environment from a compose file
compose down <file> Stop a test environment
compose ls List running compose stacks
${BOLD}SERVICES${RESET}
${SERVICES[*]}
${BOLD}EXAMPLES${RESET}
devlab status
devlab logs gitea
devlab pull mistral:latest
devlab compose up /opt/lab/compose/examples/lamp-stack.yml
devlab restart code-server
EOF
}
cmd_status() {
echo -e "\n${BOLD}DevLab Service Status${RESET}\n"
printf "%-20s %-12s %s\n" "CONTAINER" "STATUS" "IMAGE"
printf '%.0s─' {1..60}; echo
for svc in "${SERVICES[@]}"; do
local info
info=$(docker inspect "$svc" --format '{{.State.Status}} {{.Config.Image}}' 2>/dev/null) || {
printf "%-20s ${RED}%-12s${RESET} %s\n" "$svc" "not found" "-"
continue
}
local status="${info%% *}"
local image="${info#* }"
local color="$RED"
[[ "$status" == "running" ]] && color="$GREEN"
printf "%-20s ${color}%-12s${RESET} %s\n" "$svc" "$status" "$image"
done
echo ""
}
cmd_start() {
for svc in "${SERVICES[@]}"; do
docker start "$svc" 2>/dev/null && \
echo -e " ${GREEN}${RESET} ${svc}" || \
echo -e " ${RED}${RESET} ${svc} (not found)"
done
}
cmd_stop() {
read -rp "Stop all DevLab services? [y/N]: " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Aborted."; return; }
for svc in "${SERVICES[@]}"; do
docker stop "$svc" 2>/dev/null && \
echo -e " ${YELLOW}${RESET} ${svc} stopped" || true
done
}
cmd_restart() {
local target="${1:-all}"
if [[ "$target" == "all" ]]; then
for svc in "${SERVICES[@]}"; do
docker restart "$svc" 2>/dev/null && \
echo -e " ${GREEN}${RESET} ${svc}" || true
done
else
docker restart "$target" && echo -e " ${GREEN}${RESET} ${target} restarted"
fi
}
cmd_logs() {
local svc="${1:-}"
[[ -z "$svc" ]] && { echo "Usage: devlab logs <service>"; exit 1; }
docker logs -f --tail=100 "$svc"
}
cmd_update() {
echo -e "${CYAN}Pulling latest images...${RESET}"
for svc in "${SERVICES[@]}"; do
local image
image=$(docker inspect "$svc" --format '{{.Config.Image}}' 2>/dev/null) || continue
echo -e " Updating ${image}..."
docker pull "$image" || true
docker restart "$svc" || true
done
echo -e "${GREEN}Update complete.${RESET}"
}
cmd_backup() {
[[ -x "${LAB_ROOT}/backup.sh" ]] || { echo "Backup script not found."; exit 1; }
"${LAB_ROOT}/backup.sh"
}
cmd_models() {
docker exec ollama ollama list
}
cmd_pull() {
local model="${1:-}"
[[ -z "$model" ]] && { echo "Usage: devlab pull <model>"; exit 1; }
docker exec ollama ollama pull "$model"
}
cmd_remove_model() {
local model="${1:-}"
[[ -z "$model" ]] && { echo "Usage: devlab remove <model>"; exit 1; }
docker exec ollama ollama rm "$model"
}
cmd_urls() {
echo ""
echo -e "${BOLD}DevLab Service URLs${RESET}"
echo -e " Web IDE → ${GREEN}https://${CODE_HOST:-code.yourdomain.com}${RESET}"
echo -e " Git → ${GREEN}https://${GIT_HOST:-git.yourdomain.com}${RESET}"
echo -e " AI Chat → ${GREEN}https://${AI_HOST:-ai.yourdomain.com}${RESET}"
echo -e " Portainer → ${GREEN}https://${PM_HOST:-portainer.yourdomain.com}${RESET}"
echo ""
}
cmd_compose() {
local action="${1:-}"
shift
case "$action" in
up)
local file="${1:-}"
[[ -z "$file" ]] && { echo "Usage: devlab compose up <file.yml>"; exit 1; }
docker compose -f "$file" up -d
echo -e "${GREEN}Stack started.${RESET}"
;;
down)
local file="${1:-}"
[[ -z "$file" ]] && { echo "Usage: devlab compose down <file.yml>"; exit 1; }
docker compose -f "$file" down
;;
ls)
docker compose ls
;;
*)
echo "Usage: devlab compose {up|down|ls} [file]"
;;
esac
}
# ─── Router ──────────────────────────────────────────────────────────────────
COMMAND="${1:-help}"
shift 2>/dev/null || true
case "$COMMAND" in
status) cmd_status ;;
start) cmd_start ;;
stop) cmd_stop ;;
restart) cmd_restart "$@" ;;
logs) cmd_logs "$@" ;;
update) cmd_update ;;
backup) cmd_backup ;;
models) cmd_models ;;
pull) cmd_pull "$@" ;;
remove) cmd_remove_model "$@" ;;
urls) cmd_urls ;;
compose) cmd_compose "$@" ;;
help|--help|-h) cmd_help ;;
*) echo "Unknown command: ${COMMAND}. Run: devlab help" && exit 1 ;;
esac