Introduce make lint-shell / fmt-shell with shellcheck and shfmt (-i 2 -ci -bn), normalize first-party scripts, and document the new targets. Keep them out of make lint / fmt. Signed-off-by: Ludovic Vielle <ludovic@probo.com>
195 lines
4.6 KiB
Bash
Executable File
195 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
TEMPLATE="${SCRIPT_DIR}/probo.yaml"
|
|
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
WORKTREE_NAME="$(basename "${REPO_ROOT}")"
|
|
VM_NAME="probo-${WORKTREE_NAME}"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0") <command> [options]
|
|
|
|
Commands:
|
|
create [--cpus C] [--memory M] [--disk D] Create a new sandbox VM
|
|
start Start a stopped sandbox
|
|
boot-logs Show boot logs
|
|
stop Stop the sandbox
|
|
restart Stop + start the sandbox
|
|
delete Delete the sandbox entirely
|
|
ssh Open interactive shell in /workspace
|
|
exec -- CMD Run a command in the sandbox
|
|
status Show sandbox state, IP, and services
|
|
list List all probo-* VMs
|
|
|
|
VM name: ${VM_NAME} (derived from worktree directory)
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
get_vm_ip() {
|
|
limactl shell "${VM_NAME}" ip -4 -j addr show dev lima0 2>/dev/null \
|
|
| jq -r '.[0].addr_info[0].local // empty' 2>/dev/null || true
|
|
}
|
|
|
|
get_vm_status() {
|
|
local status
|
|
status=$(limactl list --json 2>/dev/null \
|
|
| jq -r "select(.name == \"${VM_NAME}\") | .status" 2>/dev/null) || true
|
|
echo "${status:-NotFound}"
|
|
}
|
|
|
|
cmd_create() {
|
|
local cpus="" memory="" disk=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--cpus)
|
|
cpus="$2"
|
|
shift 2
|
|
;;
|
|
--memory)
|
|
memory="$2"
|
|
shift 2
|
|
;;
|
|
--disk)
|
|
disk="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "Creating sandbox: ${VM_NAME}"
|
|
echo "Worktree: ${REPO_ROOT}"
|
|
|
|
local -a create_args=(
|
|
--name "${VM_NAME}"
|
|
--tty=false
|
|
--set ".mounts = [{\"location\": \"${REPO_ROOT}\", \"mountPoint\": \"/workspace\", \"writable\": true},{\"location\": \"${HOME}/go\", \"mountPoint\": \"/home/${USER}.guest/go\", \"writable\": true}]"
|
|
--mount-type virtiofs
|
|
)
|
|
|
|
if [[ -n "${cpus}" ]]; then
|
|
create_args+=(--cpus "${cpus}")
|
|
fi
|
|
if [[ -n "${memory}" ]]; then
|
|
create_args+=(--memory "${memory}")
|
|
fi
|
|
if [[ -n "${disk}" ]]; then
|
|
create_args+=(--disk "${disk}")
|
|
fi
|
|
|
|
limactl create "${create_args[@]}" "${TEMPLATE}"
|
|
}
|
|
|
|
cmd_start() {
|
|
echo "Starting sandbox: ${VM_NAME}"
|
|
limactl start "${VM_NAME}"
|
|
echo ""
|
|
cmd_status
|
|
}
|
|
|
|
cmd_boot_logs() {
|
|
limactl shell "${VM_NAME}" -- sudo tail -f /var/log/cloud-init-output.log
|
|
}
|
|
|
|
cmd_stop() {
|
|
echo "Stopping sandbox: ${VM_NAME}"
|
|
limactl stop "${VM_NAME}"
|
|
echo "Sandbox stopped."
|
|
}
|
|
|
|
cmd_restart() {
|
|
cmd_stop
|
|
echo ""
|
|
cmd_start
|
|
}
|
|
|
|
cmd_delete() {
|
|
echo "Deleting sandbox: ${VM_NAME}"
|
|
limactl delete --force "${VM_NAME}"
|
|
echo "Sandbox deleted."
|
|
}
|
|
|
|
cmd_ssh() {
|
|
exec limactl shell --workdir /workspace "${VM_NAME}"
|
|
}
|
|
|
|
cmd_exec() {
|
|
limactl shell --workdir /workspace "${VM_NAME}" "$@"
|
|
}
|
|
|
|
cmd_status() {
|
|
local status ip
|
|
status="$(get_vm_status)"
|
|
ip="$(get_vm_ip)"
|
|
|
|
echo "Sandbox: ${VM_NAME}"
|
|
echo "State: ${status}"
|
|
echo "IP: ${ip:-"-"}"
|
|
|
|
if [[ "${status}" == "Running" && -n "${ip}" ]]; then
|
|
echo ""
|
|
echo "Services (use VM IP to access from host):"
|
|
echo " Console: http://${ip}:5173"
|
|
echo " Compliance Portal: http://${ip}:5174"
|
|
echo " API: http://${ip}:8080"
|
|
echo " Grafana: http://${ip}:3001"
|
|
echo " Mailpit: http://${ip}:8025"
|
|
echo " Keycloak: http://${ip}:8082"
|
|
echo " PostgreSQL: psql -h ${ip} -U probod"
|
|
fi
|
|
}
|
|
|
|
cmd_list() {
|
|
printf "%-25s %-12s %s\n" "NAME" "STATE" "IP"
|
|
|
|
limactl list --json 2>/dev/null | jq -r '
|
|
select(.name | startswith("probo-")) |
|
|
[.name, .status] | @tsv
|
|
' | while IFS=$'\t' read -r name status; do
|
|
local ip="-"
|
|
if [[ "${status}" == "Running" ]]; then
|
|
ip=$(limactl shell "${name}" ip -4 -j addr show dev lima0 2>/dev/null \
|
|
| jq -r '.[0].addr_info[0].local // "-"' 2>/dev/null || echo "-")
|
|
fi
|
|
printf "%-25s %-12s %s\n" "${name}" "${status}" "${ip}"
|
|
done
|
|
}
|
|
|
|
if [[ $# -lt 1 ]]; then
|
|
usage
|
|
fi
|
|
|
|
command="$1"
|
|
shift
|
|
|
|
case "${command}" in
|
|
create) cmd_create "$@" ;;
|
|
start) cmd_start ;;
|
|
boot-logs) cmd_boot_logs ;;
|
|
stop) cmd_stop ;;
|
|
restart) cmd_restart ;;
|
|
delete) cmd_delete ;;
|
|
ssh) cmd_ssh ;;
|
|
exec)
|
|
if [[ "${1:-}" == "--" ]]; then shift; fi
|
|
cmd_exec "$@"
|
|
;;
|
|
status) cmd_status ;;
|
|
list) cmd_list ;;
|
|
*)
|
|
echo "Unknown command: ${command}"
|
|
usage
|
|
;;
|
|
esac
|