#!/usr/bin/env bash set -euo pipefail # ============================================================================= # Register an existing Changemaker Lite instance with a Control Panel (CCP) # # Usage: # bash scripts/register-with-ccp.sh # bash scripts/register-with-ccp.sh --ccp-url https://ccp.example.com --invite-code ABCD-1234 --agent-url https://myhost:7443 # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BASE_DIR="$(dirname "$SCRIPT_DIR")" ENV_FILE="$BASE_DIR/.env" # Colors RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' YELLOW='\033[1;33m' BOLD='\033[1m' NC='\033[0m' info() { echo -e "${CYAN}[INFO]${NC} $*"; } success() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERR]${NC} $*" >&2; } header() { echo "" echo -e "${BOLD}── $* ──${NC}" echo "" } update_env_var() { local key=$1 local value=$2 if grep -q "^${key}=" "$ENV_FILE"; then local tmpfile tmpfile=$(mktemp) while IFS= read -r line; do if [[ "$line" =~ ^${key}= ]]; then echo "${key}=${value}" >> "$tmpfile" else echo "$line" >> "$tmpfile" fi done < "$ENV_FILE" mv "$tmpfile" "$ENV_FILE" else echo "${key}=${value}" >> "$ENV_FILE" fi } # --- Parse args --- CCP_URL="" INVITE_CODE="" AGENT_URL="" UNREGISTER=false while [[ $# -gt 0 ]]; do case "$1" in --ccp-url) CCP_URL="$2"; shift 2 ;; --invite-code) INVITE_CODE="$2"; shift 2 ;; --agent-url) AGENT_URL="$2"; shift 2 ;; --unregister) UNREGISTER=true; shift ;; --help|-h) echo "Usage: bash scripts/register-with-ccp.sh [OPTIONS]" echo "" echo "Options:" echo " --ccp-url URL Control Panel URL (e.g., https://ccp.example.com)" echo " --invite-code CODE Invite code from CCP admin" echo " --agent-url URL How the CCP can reach this host (e.g., https://myhost:7443)" echo " --unregister Remove CCP registration and stop agent" echo " --help Show this help" echo "" echo "If options are omitted, you will be prompted interactively." exit 0 ;; *) error "Unknown option: $1" exit 1 ;; esac done # --- Verify .env exists --- if [[ ! -f "$ENV_FILE" ]]; then error ".env file not found at $ENV_FILE" error "Run config.sh first to initialize the environment." exit 1 fi # --- Unregister mode --- if [[ "$UNREGISTER" == "true" ]]; then header "Unregister from Control Panel" update_env_var "ENABLE_CCP_AGENT" "false" update_env_var "CCP_URL" "" update_env_var "CCP_INVITE_CODE" "" update_env_var "CCP_AGENT_URL" "" # Remove ccp-agent from COMPOSE_PROFILES existing_profiles=$(grep -oP 'COMPOSE_PROFILES=\K.*' "$ENV_FILE" 2>/dev/null || echo "") new_profiles=$(echo "$existing_profiles" | sed 's/,*ccp-agent//g; s/^,//; s/,$//') update_env_var "COMPOSE_PROFILES" "$new_profiles" # Stop the agent container if running info "Stopping ccp-agent container..." cd "$BASE_DIR" docker compose --profile ccp-agent stop ccp-agent 2>/dev/null || true docker compose --profile ccp-agent rm -f ccp-agent 2>/dev/null || true success "CCP registration removed. Agent stopped." exit 0 fi # --- Interactive prompts --- header "Register with Changemaker Control Panel" if [[ -z "$CCP_URL" ]]; then read -rp " Control Panel URL (e.g., https://ccp.example.com): " CCP_URL fi if [[ -z "$CCP_URL" ]]; then error "CCP URL is required." exit 1 fi if [[ -z "$INVITE_CODE" ]]; then read -rp " Invite code from CCP admin: " INVITE_CODE fi if [[ -z "$INVITE_CODE" ]]; then error "Invite code is required." exit 1 fi if [[ -z "$AGENT_URL" ]]; then echo "" info "The Agent URL is how the CCP will reach this machine." info "It must be accessible from the CCP server (e.g., via public IP, VPN, or Pangolin tunnel)." echo "" # Try to auto-detect local_ip=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "") if [[ -n "$local_ip" ]]; then info "Detected local IP: $local_ip" read -rp " Agent URL [https://${local_ip}:7443]: " AGENT_URL AGENT_URL="${AGENT_URL:-https://${local_ip}:7443}" else read -rp " Agent URL (e.g., https://this-host:7443): " AGENT_URL fi fi if [[ -z "$AGENT_URL" ]]; then error "Agent URL is required." exit 1 fi # --- Confirm --- echo "" info "Configuration:" echo " CCP URL: $CCP_URL" echo " Invite Code: $INVITE_CODE" echo " Agent URL: $AGENT_URL" echo "" read -rp "Proceed with registration? (y/n): " confirm if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then info "Registration cancelled." exit 0 fi # --- Update .env --- header "Updating Configuration" update_env_var "ENABLE_CCP_AGENT" "true" update_env_var "CCP_URL" "$CCP_URL" update_env_var "CCP_INVITE_CODE" "$INVITE_CODE" update_env_var "CCP_AGENT_URL" "$AGENT_URL" success "Environment variables set" # Add ccp-agent to compose profiles existing_profiles=$(grep -oP 'COMPOSE_PROFILES=\K.*' "$ENV_FILE" 2>/dev/null || echo "") if [[ "$existing_profiles" != *"ccp-agent"* ]]; then if [[ -n "$existing_profiles" ]]; then update_env_var "COMPOSE_PROFILES" "${existing_profiles},ccp-agent" else update_env_var "COMPOSE_PROFILES" "ccp-agent" fi success "Added ccp-agent to COMPOSE_PROFILES" fi # --- Start the agent --- header "Starting CCP Agent" cd "$BASE_DIR" docker compose --profile ccp-agent up -d ccp-agent success "CCP Agent container started" echo "" info "The agent is now phoning home to $CCP_URL" info "It will poll every 30 seconds until the CCP admin approves the registration." info "" info "Once approved, the agent will:" info " 1. Receive mTLS certificates automatically" info " 2. Restart with secure communication enabled" info " 3. Begin accepting management commands from the CCP" echo "" info "You can monitor the agent with:" echo " docker compose --profile ccp-agent logs -f ccp-agent" echo "" success "Registration initiated! Waiting for CCP admin approval..."