#!/usr/bin/env bash set -euo pipefail # ============================================================================= # NetBox Diode Project - Bootstrap Script # Generates secrets, writes configs, and prepares all services for startup. # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" NETBOX_DOCKER_DIR="/home/user/netbox-docker" HOST_IP="172.19.77.160" echo "==> Generating secrets..." gen_secret() { openssl rand -hex 32 } REDIS_PASSWORD="$(gen_secret)" DIODE_DB_PASSWORD="$(gen_secret)" HYDRA_DB_PASSWORD="$(gen_secret)" HYDRA_SYSTEM_SECRET="$(gen_secret)" # OAuth2 client secrets (used by Diode services and Orb Agent) INGESTER_CLIENT_SECRET="$(gen_secret)" RECONCILER_CLIENT_SECRET="$(gen_secret)" NETBOX_TO_DIODE_CLIENT_SECRET="$(gen_secret)" echo "==> Writing .env file..." cat > "${SCRIPT_DIR}/.env" < Writing OAuth2 client credentials..." cat > "${SCRIPT_DIR}/oauth2/client/client-credentials.json" < Writing OAuth2 bootstrap script..." cat > "${SCRIPT_DIR}/oauth2/client/bootstrap-clients.sh" <<'BOOTSTRAP_EOF' #!/usr/bin/env sh set -e HYDRA_ADMIN_URL="${HYDRA_ADMIN_URL:-http://hydra:4445}" CREDENTIALS_FILE="/client-credentials/client-credentials.json" echo "Waiting for Hydra to be ready..." until wget -qO- "${HYDRA_ADMIN_URL}/health/ready" 2>/dev/null | grep -q '"status":"ok"'; do echo " Hydra not ready yet, retrying in 3s..." sleep 3 done echo "Hydra is ready." CLIENT_COUNT=$(cat "${CREDENTIALS_FILE}" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))") for i in $(seq 0 $((CLIENT_COUNT - 1))); do CLIENT_JSON=$(cat "${CREDENTIALS_FILE}" | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin)[$i]))") CLIENT_ID=$(echo "${CLIENT_JSON}" | python3 -c "import sys,json; print(json.load(sys.stdin)['client_id'])") echo "Checking client: ${CLIENT_ID}" # Check if client already exists HTTP_CODE=$(wget -qO/dev/null -S "${HYDRA_ADMIN_URL}/admin/clients/${CLIENT_ID}" 2>&1 | grep "HTTP/" | tail -1 | awk '{print $2}') if [ "${HTTP_CODE}" = "200" ]; then echo " Client '${CLIENT_ID}' already exists, skipping." continue fi echo " Registering client '${CLIENT_ID}'..." wget -qO- --header="Content-Type: application/json" \ --post-data="${CLIENT_JSON}" \ "${HYDRA_ADMIN_URL}/admin/clients" || { echo " ERROR: Failed to register client '${CLIENT_ID}'" exit 1 } echo "" echo " Client '${CLIENT_ID}' registered successfully." done echo "All OAuth2 clients registered." BOOTSTRAP_EOF chmod +x "${SCRIPT_DIR}/oauth2/client/bootstrap-clients.sh" echo "==> Writing Orb Agent config..." cat > "${SCRIPT_DIR}/orb-agent/agent.yaml" < Writing nginx.conf..." mkdir -p "${SCRIPT_DIR}/nginx" cat > "${SCRIPT_DIR}/nginx/nginx.conf" <<'NGINX_EOF' worker_processes 1; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; upstream ingester_grpc { server diode-ingester:8081; } upstream reconciler_grpc { server diode-reconciler:8081; } upstream auth_grpc { server diode-auth:8081; } server { listen 8080 http2; # Diode Ingester gRPC location /diode.v1.IngesterService/ { grpc_pass grpc://ingester_grpc; } # Diode Reconciler gRPC location /diode.v1.ReconcilerService/ { grpc_pass grpc://reconciler_grpc; } # Diode Auth gRPC location /diode.v1.AuthService/ { grpc_pass grpc://auth_grpc; } # Health check location /health { return 200 'OK'; add_header Content-Type text/plain; } } } NGINX_EOF echo "==> Updating NetBox plugins.py..." PLUGINS_FILE="${NETBOX_DOCKER_DIR}/configuration/plugins.py" cat > "${PLUGINS_FILE}" < Creating NetBox Diode plugin Dockerfile..." cat > "${NETBOX_DOCKER_DIR}/Dockerfile.diode-plugin" <<'DOCKERFILE_EOF' FROM netboxcommunity/netbox:v4.5-4.0.1 # Install the Diode NetBox plugin RUN /usr/local/bin/uv pip install --python /opt/netbox/venv/bin/python netboxlabs-diode-netbox-plugin==1.7.0 DOCKERFILE_EOF echo "==> Updating NetBox docker-compose.override.yml..." cat > "${NETBOX_DOCKER_DIR}/docker-compose.override.yml" <<'OVERRIDE_EOF' services: netbox: &netbox-override build: context: . dockerfile: Dockerfile.diode-plugin ports: - "8000:8080" environment: SKIP_SUPERUSER: "false" SUPERUSER_API_TOKEN: "0123456789abcdef0123456789abcdef01234567" SUPERUSER_EMAIL: "admin@example.com" SUPERUSER_NAME: "admin" SUPERUSER_PASSWORD: "admin" ALLOWED_HOSTS: "*" extra_hosts: - "host.docker.internal:host-gateway" netbox-worker: <<: *netbox-override ports: [] OVERRIDE_EOF echo "" echo "============================================================" echo " Setup complete!" echo "============================================================" echo "" echo "Generated files:" echo " ${SCRIPT_DIR}/.env" echo " ${SCRIPT_DIR}/nginx/nginx.conf" echo " ${SCRIPT_DIR}/oauth2/client/client-credentials.json" echo " ${SCRIPT_DIR}/oauth2/client/bootstrap-clients.sh" echo " ${SCRIPT_DIR}/orb-agent/agent.yaml" echo " ${NETBOX_DOCKER_DIR}/Dockerfile.diode-plugin" echo " ${NETBOX_DOCKER_DIR}/docker-compose.override.yml" echo " ${NETBOX_DOCKER_DIR}/configuration/plugins.py" echo "" echo "Next steps:" echo " 1. cd ${NETBOX_DOCKER_DIR} && docker compose build --no-cache && docker compose up -d" echo " 2. docker compose exec netbox python /opt/netbox/netbox/manage.py migrate netbox_diode_plugin" echo " 3. cd ${SCRIPT_DIR} && docker compose up -d" echo ""