Update onboard_client.sh — full API automation, Proxmox vars, dynamic key IDs
This commit is contained in:
@@ -13,12 +13,19 @@ usage() {
|
|||||||
echo " -b, --billing Billing model (hybrid|per-host|time-saved|tiered) default: hybrid"
|
echo " -b, --billing Billing model (hybrid|per-host|time-saved|tiered) default: hybrid"
|
||||||
echo " -e, --estimate Human time estimate seconds (default: 2700)"
|
echo " -e, --estimate Human time estimate seconds (default: 2700)"
|
||||||
echo " -v, --vpn VPN type (ipsec|openvpn) default: ipsec"
|
echo " -v, --vpn VPN type (ipsec|openvpn) default: ipsec"
|
||||||
echo " -h, --hypervisor Hypervisor type (proxmox|xcpng) default: proxmox"
|
echo " -H, --hypervisor Hypervisor type (proxmox|xcpng) default: proxmox"
|
||||||
|
echo " --proxmox-host Proxmox host IP (optional)"
|
||||||
|
echo " --proxmox-token-id Proxmox API token ID (e.g. ansible@pve!token-name)"
|
||||||
|
echo " --proxmox-token-secret Proxmox API token secret"
|
||||||
echo " --semaphore-url Semaphore base URL (default: http://localhost:3000)"
|
echo " --semaphore-url Semaphore base URL (default: http://localhost:3000)"
|
||||||
echo " --semaphore-token Semaphore API token"
|
echo " --semaphore-token Semaphore API token"
|
||||||
|
echo " --gitea-url Gitea repo SSH URL"
|
||||||
|
echo " --project-name Semaphore project name (default: 'Client - <n>')"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Example:"
|
echo "Example:"
|
||||||
echo " $0 -i DFA-001 -n 'DFA Tech Colo' -s dfa_tech -w https://n8n.voice1.me/webhook/xxx"
|
echo " $0 -i ACME-001 -n 'Acme Corp' -s acme_corp -w https://n8n.voice1.me/webhook/xxx \\"
|
||||||
|
echo " --proxmox-host 10.1.2.3 --proxmox-token-id ansible@pve!ansible-token \\"
|
||||||
|
echo " --proxmox-token-secret abc123"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +36,12 @@ VPN="ipsec"
|
|||||||
HYPERVISOR="proxmox"
|
HYPERVISOR="proxmox"
|
||||||
SEMAPHORE_URL="http://localhost:3000"
|
SEMAPHORE_URL="http://localhost:3000"
|
||||||
REPO_DIR="/opt/ansible-msp-automations"
|
REPO_DIR="/opt/ansible-msp-automations"
|
||||||
|
GITEA_DEPLOY_KEY="/root/.ssh/gitea_ansible"
|
||||||
|
GITEA_REPO_URL="ssh://git@172.31.10.8:2222/VOICE1/ansible-msp-automations.git"
|
||||||
|
PROXMOX_HOST=""
|
||||||
|
PROXMOX_TOKEN_ID=""
|
||||||
|
PROXMOX_TOKEN_SECRET=""
|
||||||
|
PROJECT_NAME_OVERRIDE=""
|
||||||
|
|
||||||
# ─── Parse args ──────────────────────────────────────────────────────────────
|
# ─── Parse args ──────────────────────────────────────────────────────────────
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@@ -40,19 +53,34 @@ while [[ $# -gt 0 ]]; do
|
|||||||
-b|--billing) BILLING="$2"; shift 2 ;;
|
-b|--billing) BILLING="$2"; shift 2 ;;
|
||||||
-e|--estimate) ESTIMATE="$2"; shift 2 ;;
|
-e|--estimate) ESTIMATE="$2"; shift 2 ;;
|
||||||
-v|--vpn) VPN="$2"; shift 2 ;;
|
-v|--vpn) VPN="$2"; shift 2 ;;
|
||||||
-h|--hypervisor) HYPERVISOR="$2"; shift 2 ;;
|
-H|--hypervisor) HYPERVISOR="$2"; shift 2 ;;
|
||||||
|
--proxmox-host) PROXMOX_HOST="$2"; shift 2 ;;
|
||||||
|
--proxmox-token-id) PROXMOX_TOKEN_ID="$2"; shift 2 ;;
|
||||||
|
--proxmox-token-secret) PROXMOX_TOKEN_SECRET="$2"; shift 2 ;;
|
||||||
--semaphore-url) SEMAPHORE_URL="$2"; shift 2 ;;
|
--semaphore-url) SEMAPHORE_URL="$2"; shift 2 ;;
|
||||||
--semaphore-token) SEMAPHORE_TOKEN="$2"; shift 2 ;;
|
--semaphore-token) SEMAPHORE_TOKEN="$2"; shift 2 ;;
|
||||||
|
--gitea-url) GITEA_REPO_URL="$2"; shift 2 ;;
|
||||||
|
--project-name) PROJECT_NAME_OVERRIDE="$2"; shift 2 ;;
|
||||||
*) usage ;;
|
*) usage ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# ─── Validate required args ──────────────────────────────────────────────────
|
# ─── Validate required args ──────────────────────────────────────────────────
|
||||||
if [[ -z "$CLIENT_ID" || -z "$CLIENT_NAME" || -z "$CLIENT_SLUG" || -z "$WEBHOOK_URL" ]]; then
|
if [[ -z "${CLIENT_ID:-}" || -z "${CLIENT_NAME:-}" || -z "${CLIENT_SLUG:-}" || -z "${WEBHOOK_URL:-}" ]]; then
|
||||||
echo "ERROR: --id, --name, --slug, and --webhook are required"
|
echo "ERROR: --id, --name, --slug, and --webhook are required"
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Load SEMAPHORE_TOKEN from env file if not passed as arg
|
||||||
|
if [[ -z "${SEMAPHORE_TOKEN:-}" && -f "/root/.semaphore_env" ]]; then
|
||||||
|
source /root/.semaphore_env
|
||||||
|
fi
|
||||||
|
|
||||||
|
PROJECT_NAME="${PROJECT_NAME_OVERRIDE:-Client - ${CLIENT_NAME}}"
|
||||||
|
KEY_FILE="/root/.ssh/client_${CLIENT_SLUG}"
|
||||||
|
INVENTORY_DIR="$REPO_DIR/inventories/client_${CLIENT_SLUG}"
|
||||||
|
INVENTORY_REPO_PATH="inventories/client_${CLIENT_SLUG}/hosts.yml"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo " Onboarding client: $CLIENT_NAME ($CLIENT_ID)"
|
echo " Onboarding client: $CLIENT_NAME ($CLIENT_ID)"
|
||||||
@@ -60,8 +88,7 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
|
|||||||
|
|
||||||
# ─── Step 1: Generate SSH key ─────────────────────────────────────────────────
|
# ─── Step 1: Generate SSH key ─────────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "[ 1/5 ] Generating SSH key..."
|
echo "[ 1/6 ] Generating SSH key..."
|
||||||
KEY_FILE="/root/.ssh/client_${CLIENT_SLUG}"
|
|
||||||
if [[ -f "$KEY_FILE" ]]; then
|
if [[ -f "$KEY_FILE" ]]; then
|
||||||
echo " ⚠ Key already exists at $KEY_FILE — skipping generation"
|
echo " ⚠ Key already exists at $KEY_FILE — skipping generation"
|
||||||
else
|
else
|
||||||
@@ -71,21 +98,19 @@ fi
|
|||||||
echo ""
|
echo ""
|
||||||
echo " ┌─ Deploy this public key to all client hosts ───────────────────────"
|
echo " ┌─ Deploy this public key to all client hosts ───────────────────────"
|
||||||
echo " │"
|
echo " │"
|
||||||
cat "$KEY_FILE.pub" | sed 's/^/ │ /'
|
sed 's/^/ │ /' "$KEY_FILE.pub"
|
||||||
echo " │"
|
echo " │"
|
||||||
echo " └────────────────────────────────────────────────────────────────────"
|
echo " └────────────────────────────────────────────────────────────────────"
|
||||||
|
|
||||||
# ─── Step 2: Create inventory from template ───────────────────────────────────
|
# ─── Step 2: Create inventory from template ───────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "[ 2/5 ] Creating inventory from template..."
|
echo "[ 2/6 ] Creating inventory from template..."
|
||||||
INVENTORY_DIR="$REPO_DIR/inventories/client_${CLIENT_SLUG}"
|
|
||||||
|
|
||||||
if [[ -d "$INVENTORY_DIR" ]]; then
|
if [[ -d "$INVENTORY_DIR" ]]; then
|
||||||
echo " ⚠ Inventory directory already exists — skipping"
|
echo " ⚠ Inventory directory already exists — skipping"
|
||||||
else
|
else
|
||||||
cp -r "$REPO_DIR/inventories/client_template" "$INVENTORY_DIR"
|
cp -r "$REPO_DIR/inventories/client_template" "$INVENTORY_DIR"
|
||||||
|
|
||||||
# Write hosts.yml
|
|
||||||
cat > "$INVENTORY_DIR/hosts.yml" << HOSTSEOF
|
cat > "$INVENTORY_DIR/hosts.yml" << HOSTSEOF
|
||||||
---
|
---
|
||||||
all:
|
all:
|
||||||
@@ -119,7 +144,6 @@ all:
|
|||||||
ansible_port: 5986
|
ansible_port: 5986
|
||||||
HOSTSEOF
|
HOSTSEOF
|
||||||
|
|
||||||
# Write group_vars/all.yml
|
|
||||||
cat > "$INVENTORY_DIR/group_vars/all.yml" << VARSEOF
|
cat > "$INVENTORY_DIR/group_vars/all.yml" << VARSEOF
|
||||||
---
|
---
|
||||||
# Client: ${CLIENT_NAME} (${CLIENT_ID})
|
# Client: ${CLIENT_NAME} (${CLIENT_ID})
|
||||||
@@ -136,7 +160,7 @@ fi
|
|||||||
|
|
||||||
# ─── Step 3: Commit and push to Gitea ────────────────────────────────────────
|
# ─── Step 3: Commit and push to Gitea ────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "[ 3/5 ] Committing to Gitea..."
|
echo "[ 3/6 ] Committing to Gitea..."
|
||||||
cd "$REPO_DIR"
|
cd "$REPO_DIR"
|
||||||
git add .
|
git add .
|
||||||
git commit -m "Onboard client: ${CLIENT_NAME} (${CLIENT_ID}) — inventory scaffold" \
|
git commit -m "Onboard client: ${CLIENT_NAME} (${CLIENT_ID}) — inventory scaffold" \
|
||||||
@@ -146,82 +170,184 @@ echo " ✓ Pushed to Gitea"
|
|||||||
|
|
||||||
# ─── Step 4: Create Semaphore project via API ─────────────────────────────────
|
# ─── Step 4: Create Semaphore project via API ─────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "[ 4/5 ] Creating Semaphore project via API..."
|
echo "[ 4/6 ] Creating Semaphore project via API..."
|
||||||
|
|
||||||
if [[ -z "$SEMAPHORE_TOKEN" ]]; then
|
if [[ -z "${SEMAPHORE_TOKEN:-}" ]]; then
|
||||||
echo " ⚠ No --semaphore-token provided — skipping Semaphore API setup"
|
echo " ✗ No semaphore token available."
|
||||||
echo " Create the project manually in Semaphore UI"
|
echo " Set SEMAPHORE_TOKEN in /root/.semaphore_env or pass --semaphore-token"
|
||||||
else
|
exit 1
|
||||||
# Create project
|
|
||||||
PROJECT_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/projects" \
|
|
||||||
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"name\": \"Client - ${CLIENT_NAME}\", \"alert\": false, \"max_parallel_tasks\": 0}")
|
|
||||||
|
|
||||||
PROJECT_ID=$(echo "$PROJECT_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])" 2>/dev/null)
|
|
||||||
|
|
||||||
if [[ -z "$PROJECT_ID" ]]; then
|
|
||||||
echo " ✗ Failed to create project — check token and Semaphore URL"
|
|
||||||
echo " Response: $PROJECT_RESPONSE"
|
|
||||||
else
|
|
||||||
echo " ✓ Project created (ID: $PROJECT_ID)"
|
|
||||||
|
|
||||||
# Add gitea-deploy key to project key store
|
|
||||||
GITEA_KEY=$(cat /root/.ssh/gitea_ansible)
|
|
||||||
curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/keys" \
|
|
||||||
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"name\": \"gitea-deploy\", \"type\": \"ssh\", \"ssh\": {\"private_key\": $(echo "$GITEA_KEY" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")}}" > /dev/null
|
|
||||||
echo " ✓ Gitea deploy key added"
|
|
||||||
|
|
||||||
# Add client SSH key
|
|
||||||
CLIENT_KEY=$(cat "$KEY_FILE")
|
|
||||||
curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/keys" \
|
|
||||||
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"name\": \"client-${CLIENT_SLUG}-ssh\", \"type\": \"ssh\", \"ssh\": {\"private_key\": $(echo "$CLIENT_KEY" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")}}" > /dev/null
|
|
||||||
echo " ✓ Client SSH key added to Key Store"
|
|
||||||
|
|
||||||
# Add repository
|
|
||||||
REPO_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/repositories" \
|
|
||||||
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"name\": \"ansible-msp-automations\", \"project_id\": $PROJECT_ID, \"git_url\": \"ssh://git@172.31.10.8:2222/VOICE1/ansible-msp-automations.git\", \"git_branch\": \"main\", \"ssh_key_id\": 1}")
|
|
||||||
REPO_ID=$(echo "$REPO_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])" 2>/dev/null)
|
|
||||||
echo " ✓ Repository linked (ID: $REPO_ID)"
|
|
||||||
|
|
||||||
# Add variable group
|
|
||||||
curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/environment" \
|
|
||||||
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "{\"name\": \"${CLIENT_SLUG}-vars\", \"project_id\": $PROJECT_ID, \"json\": \"{\\\"N8N_WEBHOOK_URL\\\": \\\"${WEBHOOK_URL}\\\", \\\"CLIENT_ID\\\": \\\"${CLIENT_ID}\\\", \\\"CLIENT_NAME\\\": \\\"${CLIENT_NAME}\\\", \\\"BILLING_MODEL\\\": \\\"${BILLING}\\\", \\\"HUMAN_ESTIMATE_SECONDS\\\": \\\"${ESTIMATE}\\\"}\"}" > /dev/null
|
|
||||||
echo " ✓ Variable group created"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo " Semaphore project ID: $PROJECT_ID"
|
|
||||||
echo " Still needed manually:"
|
|
||||||
echo " - Add inventory (File type → inventories/client_${CLIENT_SLUG}/hosts.yml)"
|
|
||||||
echo " - Create task templates"
|
|
||||||
echo " - Add hosts to inventory file in Gitea"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ─── Step 5: Summary ──────────────────────────────────────────────────────────
|
# 4a. Create project
|
||||||
|
PROJECT_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/projects" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"name\": \"$PROJECT_NAME\", \"alert\": false, \"max_parallel_tasks\": 0}")
|
||||||
|
PROJECT_ID=$(echo "$PROJECT_RESPONSE" | jq -r '.id')
|
||||||
|
|
||||||
|
if [[ "$PROJECT_ID" == "null" || -z "$PROJECT_ID" ]]; then
|
||||||
|
echo " ✗ Failed to create project"
|
||||||
|
echo " Response: $PROJECT_RESPONSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " ✓ Project created: $PROJECT_NAME (ID: $PROJECT_ID)"
|
||||||
|
|
||||||
|
# 4b. Add gitea-deploy key — dynamically read key file, jq for safe JSON encoding
|
||||||
|
GITEA_KEY_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/keys" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"gitea-deploy\",
|
||||||
|
\"type\": \"ssh\",
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"ssh\": {
|
||||||
|
\"login\": \"\",
|
||||||
|
\"passphrase\": \"\",
|
||||||
|
\"private_key\": $(jq -Rs . < "$GITEA_DEPLOY_KEY")
|
||||||
|
}
|
||||||
|
}")
|
||||||
|
GITEA_KEY_ID=$(echo "$GITEA_KEY_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ gitea-deploy key added (ID: $GITEA_KEY_ID)"
|
||||||
|
|
||||||
|
# 4c. Add client SSH key
|
||||||
|
CLIENT_KEY_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/keys" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"client-${CLIENT_SLUG}-ssh\",
|
||||||
|
\"type\": \"ssh\",
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"ssh\": {
|
||||||
|
\"login\": \"\",
|
||||||
|
\"passphrase\": \"\",
|
||||||
|
\"private_key\": $(jq -Rs . < "$KEY_FILE")
|
||||||
|
}
|
||||||
|
}")
|
||||||
|
CLIENT_KEY_ID=$(echo "$CLIENT_KEY_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ Client SSH key added (ID: $CLIENT_KEY_ID)"
|
||||||
|
|
||||||
|
# 4d. Add None key (required for inventory become_key_id)
|
||||||
|
NONE_KEY_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/keys" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"None\",
|
||||||
|
\"type\": \"none\",
|
||||||
|
\"project_id\": $PROJECT_ID
|
||||||
|
}")
|
||||||
|
NONE_KEY_ID=$(echo "$NONE_KEY_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ None key added (ID: $NONE_KEY_ID)"
|
||||||
|
|
||||||
|
# 4e. Add repository — uses dynamically obtained GITEA_KEY_ID (not hardcoded)
|
||||||
|
REPO_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/repositories" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"ansible-msp-automations\",
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"git_url\": \"$GITEA_REPO_URL\",
|
||||||
|
\"git_branch\": \"main\",
|
||||||
|
\"ssh_key_id\": $GITEA_KEY_ID
|
||||||
|
}")
|
||||||
|
REPO_ID=$(echo "$REPO_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ Repository linked (ID: $REPO_ID)"
|
||||||
|
|
||||||
|
# 4f. Add variable group with all vars including Proxmox
|
||||||
|
VARS_JSON=$(jq -n \
|
||||||
|
--arg webhook "$WEBHOOK_URL" \
|
||||||
|
--arg cid "$CLIENT_ID" \
|
||||||
|
--arg cname "$CLIENT_NAME" \
|
||||||
|
--arg billing "$BILLING" \
|
||||||
|
--arg estimate "$ESTIMATE" \
|
||||||
|
--arg phost "$PROXMOX_HOST" \
|
||||||
|
--arg ptid "$PROXMOX_TOKEN_ID" \
|
||||||
|
--arg ptsecret "$PROXMOX_TOKEN_SECRET" \
|
||||||
|
'{
|
||||||
|
N8N_WEBHOOK_URL: $webhook,
|
||||||
|
CLIENT_ID: $cid,
|
||||||
|
CLIENT_NAME: $cname,
|
||||||
|
BILLING_MODEL: $billing,
|
||||||
|
HUMAN_ESTIMATE_SECONDS: $estimate,
|
||||||
|
PROXMOX_HOST: $phost,
|
||||||
|
PROXMOX_TOKEN_ID: $ptid,
|
||||||
|
PROXMOX_TOKEN_SECRET: $ptsecret
|
||||||
|
}')
|
||||||
|
|
||||||
|
ENV_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/environment" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"${CLIENT_SLUG}-vars\",
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"json\": $(echo "$VARS_JSON" | jq -Rs .),
|
||||||
|
\"env\": \"{}\"
|
||||||
|
}")
|
||||||
|
ENV_ID=$(echo "$ENV_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ Variable group created (ID: $ENV_ID)"
|
||||||
|
|
||||||
|
# 4g. Add inventory (file type, pointing to Git repo path)
|
||||||
|
INVENTORY_RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/inventory" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"name\": \"client-${CLIENT_SLUG}\",
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"inventory\": \"$INVENTORY_REPO_PATH\",
|
||||||
|
\"ssh_key_id\": $CLIENT_KEY_ID,
|
||||||
|
\"become_key_id\": $NONE_KEY_ID,
|
||||||
|
\"type\": \"file\",
|
||||||
|
\"repository_id\": $REPO_ID
|
||||||
|
}")
|
||||||
|
INVENTORY_ID=$(echo "$INVENTORY_RESPONSE" | jq -r '.id')
|
||||||
|
echo " ✓ Inventory created (ID: $INVENTORY_ID)"
|
||||||
|
|
||||||
|
# ─── Step 5: Create task templates ───────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[ 5/6 ] Creating task templates..."
|
||||||
|
|
||||||
|
create_template() {
|
||||||
|
local TNAME="$1"
|
||||||
|
local PLAYBOOK="$2"
|
||||||
|
local DESC="$3"
|
||||||
|
RESPONSE=$(curl -s -X POST "$SEMAPHORE_URL/api/project/$PROJECT_ID/templates" \
|
||||||
|
-H "Authorization: Bearer $SEMAPHORE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"project_id\": $PROJECT_ID,
|
||||||
|
\"inventory_id\": $INVENTORY_ID,
|
||||||
|
\"repository_id\": $REPO_ID,
|
||||||
|
\"environment_id\": $ENV_ID,
|
||||||
|
\"name\": \"$TNAME\",
|
||||||
|
\"playbook\": \"$PLAYBOOK\",
|
||||||
|
\"arguments\": \"[]\",
|
||||||
|
\"allow_override_args_in_task\": false,
|
||||||
|
\"description\": \"$DESC\",
|
||||||
|
\"app\": \"ansible\"
|
||||||
|
}")
|
||||||
|
echo " ✓ $(echo "$RESPONSE" | jq -r '"Template: \(.name) (ID: \(.id))"')"
|
||||||
|
}
|
||||||
|
|
||||||
|
create_template "Preflight Check" "playbooks/site_preflight.yml" "Run safety checks on all hosts before maintenance"
|
||||||
|
create_template "Snapshot Test" "playbooks/snapshot_pre.yml" "Test pre-patch snapshot creation via Proxmox API"
|
||||||
|
create_template "Linux Patch" "playbooks/linux_patch.yml" "Full Linux patch run with version tracking"
|
||||||
|
create_template "Full Maintenance" "playbooks/site_maintenance.yml" "Full maintenance: snapshot, preflight, patch"
|
||||||
|
|
||||||
|
# ─── Step 6: Summary ──────────────────────────────────────────────────────────
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo " ✓ Client onboarding complete: $CLIENT_NAME"
|
echo " ✓ Client onboarding complete: $CLIENT_NAME"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
echo ""
|
echo ""
|
||||||
echo " SSH public key to deploy to client hosts:"
|
echo " Semaphore project ID: $PROJECT_ID"
|
||||||
echo " $KEY_FILE.pub"
|
echo " Inventory file: $INVENTORY_DIR/hosts.yml"
|
||||||
echo ""
|
|
||||||
echo " Inventory file to populate with hosts:"
|
|
||||||
echo " $INVENTORY_DIR/hosts.yml"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " Next steps:"
|
echo " Next steps:"
|
||||||
echo " 1. Deploy SSH public key to all client hosts"
|
echo " 1. Add hosts to: $INVENTORY_DIR/hosts.yml"
|
||||||
echo " 2. Add hosts to inventory file in Gitea"
|
echo " 2. git add . && git commit -m 'Add hosts for ${CLIENT_NAME}' && git push origin main"
|
||||||
echo " 3. Add inventory entry in Semaphore (File type)"
|
echo " 3. Semaphore → $PROJECT_NAME → Preflight Check → ▶ Run"
|
||||||
echo " 4. Create task templates in Semaphore"
|
echo " 4. Semaphore → $PROJECT_NAME → Snapshot Test → ▶ Run"
|
||||||
echo " 5. Run preflight check"
|
echo " 5. Semaphore → $PROJECT_NAME → Linux Patch → ▶ Run"
|
||||||
|
echo ""
|
||||||
|
echo " Public key to deploy to client hosts:"
|
||||||
|
sed 's/^/ /' "$KEY_FILE.pub"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user