feat: rename rails/ to tools/ and add service tool suites
Rename the `rails/` directory to `tools/` for agent discoverability — agents frequently failed to locate helper scripts due to the non-intuitive directory name. Add backward-compat symlink `rails/ → tools/`. New tool suites: - Authentik: auth-token, user-list, user-create, group-list, app-list, flow-list, admin-status (8 scripts) - Coolify: team-list, project-list, service-list, service-status, deploy, env-set (7 scripts) - Woodpecker: pipeline-list, pipeline-status, pipeline-trigger (3 stubs) - GLPI: session-init, computer-list, ticket-list, ticket-create, user-list (6 scripts) - Health: stack-health.sh — stack-wide connectivity check Infrastructure: - Shared credential loader at tools/_lib/credentials.sh - install.sh creates symlink + chmod on tool scripts - All ~253 rails/ path references updated across 68+ files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
65
tools/coolify/README.md
Normal file
65
tools/coolify/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Coolify Tool Suite
|
||||
|
||||
Manage Coolify container deployment platform (projects, services, deployments, environment variables).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `jq` and `curl` installed
|
||||
- Coolify credentials in `~/src/jarvis-brain/credentials.json` (or `$MOSAIC_CREDENTIALS_FILE`)
|
||||
- Required fields: `coolify.url`, `coolify.app_token`
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `team-list.sh` | List teams |
|
||||
| `project-list.sh` | List projects |
|
||||
| `service-list.sh` | List all services |
|
||||
| `service-status.sh` | Get service details and status |
|
||||
| `deploy.sh` | Trigger service deployment |
|
||||
| `env-set.sh` | Set environment variable on a service |
|
||||
|
||||
## Common Options
|
||||
|
||||
- `-f json` — JSON output (default: table)
|
||||
- `-u uuid` — Service UUID (for service-specific operations)
|
||||
- `-h` — Show help
|
||||
|
||||
## API Reference
|
||||
|
||||
- Base URL: `http://10.1.1.44:8000`
|
||||
- API prefix: `/api/v1/`
|
||||
- Auth: Bearer token in `Authorization` header
|
||||
- Rate limit: 200 requests per interval
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- **FQDN updates on compose sub-apps not supported via API.** Workaround: update directly in Coolify's PostgreSQL DB (`coolify-db` container, `service_applications` table).
|
||||
- **Compose must be base64-encoded** in `docker_compose_raw` field when creating services via API.
|
||||
- **Don't send `type` with `docker_compose_raw`** — API rejects payloads with both fields.
|
||||
|
||||
## Coolify Magic Variables
|
||||
|
||||
Coolify reads special env vars from compose files:
|
||||
- `SERVICE_FQDN_{NAME}_{PORT}` — assigns a domain to a compose service
|
||||
- `SERVICE_URL_{NAME}_{PORT}` — internal URL reference
|
||||
- Must use list-style env syntax (`- SERVICE_FQDN_API_3001`), NOT dict-style.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# List all projects
|
||||
~/.config/mosaic/tools/coolify/project-list.sh
|
||||
|
||||
# List services as JSON
|
||||
~/.config/mosaic/tools/coolify/service-list.sh -f json
|
||||
|
||||
# Check service status
|
||||
~/.config/mosaic/tools/coolify/service-status.sh -u <uuid>
|
||||
|
||||
# Set an env var
|
||||
~/.config/mosaic/tools/coolify/env-set.sh -u <uuid> -k DATABASE_URL -v "postgres://..."
|
||||
|
||||
# Deploy a service
|
||||
~/.config/mosaic/tools/coolify/deploy.sh -u <uuid>
|
||||
```
|
||||
61
tools/coolify/deploy.sh
Executable file
61
tools/coolify/deploy.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# deploy.sh — Trigger Coolify service deployment
|
||||
#
|
||||
# Usage: deploy.sh -u <uuid> [-f]
|
||||
#
|
||||
# Options:
|
||||
# -u uuid Service UUID (required)
|
||||
# -f Force restart (stop then start)
|
||||
# -h Show this help
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
UUID=""
|
||||
FORCE=false
|
||||
|
||||
while getopts "u:fh" opt; do
|
||||
case $opt in
|
||||
u) UUID="$OPTARG" ;;
|
||||
f) FORCE=true ;;
|
||||
h) head -11 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 -u <uuid> [-f]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$UUID" ]]; then
|
||||
echo "Error: -u uuid is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORCE" == "true" ]]; then
|
||||
echo "Stopping service $UUID..."
|
||||
curl -s -o /dev/null -w "" \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/services/${UUID}/stop"
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
echo "Starting service $UUID..."
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/services/${UUID}/start")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" && "$http_code" != "201" && "$http_code" != "202" ]]; then
|
||||
echo "Error: Deployment failed (HTTP $http_code)" >&2
|
||||
echo "$body" | jq -r '.' 2>/dev/null >&2 || echo "$body" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Deployment triggered successfully for service $UUID"
|
||||
echo "$body" | jq -r '.message // empty' 2>/dev/null || true
|
||||
65
tools/coolify/env-set.sh
Executable file
65
tools/coolify/env-set.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# env-set.sh — Set environment variable on a Coolify service
|
||||
#
|
||||
# Usage: env-set.sh -u <uuid> -k <key> -v <value> [--preview]
|
||||
#
|
||||
# Options:
|
||||
# -u uuid Service UUID (required)
|
||||
# -k key Environment variable name (required)
|
||||
# -v value Environment variable value (required)
|
||||
# --preview Set as preview-only variable
|
||||
# -h Show this help
|
||||
#
|
||||
# Note: Changes take effect on next deploy/restart.
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
UUID=""
|
||||
KEY=""
|
||||
VALUE=""
|
||||
IS_PREVIEW="false"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-u) UUID="$2"; shift 2 ;;
|
||||
-k) KEY="$2"; shift 2 ;;
|
||||
-v) VALUE="$2"; shift 2 ;;
|
||||
--preview) IS_PREVIEW="true"; shift ;;
|
||||
-h) head -15 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 -u <uuid> -k <key> -v <value> [--preview]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$UUID" || -z "$KEY" || -z "$VALUE" ]]; then
|
||||
echo "Error: -u uuid, -k key, and -v value are required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
payload=$(jq -n \
|
||||
--arg key "$KEY" \
|
||||
--arg value "$VALUE" \
|
||||
--argjson preview "$IS_PREVIEW" \
|
||||
'{key: $key, value: $value, is_preview: $preview}')
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"${COOLIFY_URL}/api/v1/services/${UUID}/envs")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" && "$http_code" != "201" ]]; then
|
||||
echo "Error: Failed to set environment variable (HTTP $http_code)" >&2
|
||||
echo "$body" | jq -r '.' 2>/dev/null >&2 || echo "$body" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Set $KEY on service $UUID"
|
||||
echo "Note: Redeploy the service to apply the change"
|
||||
52
tools/coolify/project-list.sh
Executable file
52
tools/coolify/project-list.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# project-list.sh — List Coolify projects
|
||||
#
|
||||
# Usage: project-list.sh [-f format]
|
||||
#
|
||||
# Options:
|
||||
# -f format Output format: table (default), json
|
||||
# -h Show this help
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
FORMAT="table"
|
||||
|
||||
while getopts "f:h" opt; do
|
||||
case $opt in
|
||||
f) FORMAT="$OPTARG" ;;
|
||||
h) head -10 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 [-f format]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/projects")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" ]]; then
|
||||
echo "Error: Failed to list projects (HTTP $http_code)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORMAT" == "json" ]]; then
|
||||
echo "$body" | jq '.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "UUID NAME DESCRIPTION"
|
||||
echo "------------------------------------ ---------------------------- ----------------------------------------"
|
||||
echo "$body" | jq -r '.[] | [
|
||||
.uuid,
|
||||
.name,
|
||||
(.description // "—")
|
||||
] | @tsv' | while IFS=$'\t' read -r uuid name desc; do
|
||||
printf "%-36s %-28s %s\n" "$uuid" "${name:0:28}" "${desc:0:40}"
|
||||
done
|
||||
53
tools/coolify/service-list.sh
Executable file
53
tools/coolify/service-list.sh
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# service-list.sh — List Coolify services
|
||||
#
|
||||
# Usage: service-list.sh [-f format]
|
||||
#
|
||||
# Options:
|
||||
# -f format Output format: table (default), json
|
||||
# -h Show this help
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
FORMAT="table"
|
||||
|
||||
while getopts "f:h" opt; do
|
||||
case $opt in
|
||||
f) FORMAT="$OPTARG" ;;
|
||||
h) head -10 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 [-f format]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/services")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" ]]; then
|
||||
echo "Error: Failed to list services (HTTP $http_code)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORMAT" == "json" ]]; then
|
||||
echo "$body" | jq '.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "UUID NAME TYPE STATUS"
|
||||
echo "------------------------------------ ---------------------------- ------------ ----------"
|
||||
echo "$body" | jq -r '.[] | [
|
||||
.uuid,
|
||||
.name,
|
||||
(.type // "unknown"),
|
||||
(.status // "unknown")
|
||||
] | @tsv' | while IFS=$'\t' read -r uuid name type status; do
|
||||
printf "%-36s %-28s %-12s %s\n" "$uuid" "${name:0:28}" "${type:0:12}" "$status"
|
||||
done
|
||||
62
tools/coolify/service-status.sh
Executable file
62
tools/coolify/service-status.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# service-status.sh — Get Coolify service status and details
|
||||
#
|
||||
# Usage: service-status.sh -u <uuid> [-f format]
|
||||
#
|
||||
# Options:
|
||||
# -u uuid Service UUID (required)
|
||||
# -f format Output format: table (default), json
|
||||
# -h Show this help
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
UUID=""
|
||||
FORMAT="table"
|
||||
|
||||
while getopts "u:f:h" opt; do
|
||||
case $opt in
|
||||
u) UUID="$OPTARG" ;;
|
||||
f) FORMAT="$OPTARG" ;;
|
||||
h) head -12 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 -u <uuid> [-f format]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$UUID" ]]; then
|
||||
echo "Error: -u uuid is required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/services/${UUID}")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" ]]; then
|
||||
echo "Error: Failed to get service status (HTTP $http_code)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORMAT" == "json" ]]; then
|
||||
echo "$body" | jq '.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Service Details"
|
||||
echo "==============="
|
||||
echo "$body" | jq -r '
|
||||
" UUID: \(.uuid)\n" +
|
||||
" Name: \(.name)\n" +
|
||||
" Type: \(.type // "unknown")\n" +
|
||||
" Status: \(.status // "unknown")\n" +
|
||||
" FQDN: \(.fqdn // "none")\n" +
|
||||
" Created: \(.created_at // "unknown")\n" +
|
||||
" Updated: \(.updated_at // "unknown")"
|
||||
'
|
||||
52
tools/coolify/team-list.sh
Executable file
52
tools/coolify/team-list.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# team-list.sh — List Coolify teams
|
||||
#
|
||||
# Usage: team-list.sh [-f format]
|
||||
#
|
||||
# Options:
|
||||
# -f format Output format: table (default), json
|
||||
# -h Show this help
|
||||
set -euo pipefail
|
||||
|
||||
MOSAIC_HOME="${MOSAIC_HOME:-$HOME/.config/mosaic}"
|
||||
source "$MOSAIC_HOME/tools/_lib/credentials.sh"
|
||||
load_credentials coolify
|
||||
|
||||
FORMAT="table"
|
||||
|
||||
while getopts "f:h" opt; do
|
||||
case $opt in
|
||||
f) FORMAT="$OPTARG" ;;
|
||||
h) head -10 "$0" | grep "^#" | sed 's/^# \?//'; exit 0 ;;
|
||||
*) echo "Usage: $0 [-f format]" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
response=$(curl -s -w "\n%{http_code}" \
|
||||
-H "Authorization: Bearer $COOLIFY_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${COOLIFY_URL}/api/v1/teams")
|
||||
|
||||
http_code=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | sed '$d')
|
||||
|
||||
if [[ "$http_code" != "200" ]]; then
|
||||
echo "Error: Failed to list teams (HTTP $http_code)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$FORMAT" == "json" ]]; then
|
||||
echo "$body" | jq '.'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "ID NAME DESCRIPTION"
|
||||
echo "---- ---------------------------- ----------------------------------------"
|
||||
echo "$body" | jq -r '.[] | [
|
||||
(.id | tostring),
|
||||
.name,
|
||||
(.description // "—")
|
||||
] | @tsv' | while IFS=$'\t' read -r id name desc; do
|
||||
printf "%-4s %-28s %s\n" "$id" "${name:0:28}" "${desc:0:40}"
|
||||
done
|
||||
Reference in New Issue
Block a user