From 9a72c8d3ec461af238213858aa78daca976f3c32 Mon Sep 17 00:00:00 2001 From: centra Date: Fri, 19 Dec 2025 08:14:44 +0900 Subject: [PATCH] fix(nix): Bind REST APIs to 0.0.0.0 for cluster join MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - chainfire.nix: CHAINFIRE__NETWORK__HTTP_ADDR env var - flaredb.nix: FLAREDB_HTTP_ADDR env var - first-boot-automation.nix: jq-based config reading Fixes ChainFire crash: "unexpected argument '--http-addr' found" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- nix/modules/chainfire.nix | 11 +++++++++ nix/modules/first-boot-automation.nix | 33 +++++++++++++++++++-------- nix/modules/flaredb.nix | 10 ++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/nix/modules/chainfire.nix b/nix/modules/chainfire.nix index 11f45a6..7f6216b 100644 --- a/nix/modules/chainfire.nix +++ b/nix/modules/chainfire.nix @@ -25,6 +25,12 @@ in description = "Port for chainfire gossip protocol"; }; + httpPort = lib.mkOption { + type = lib.types.port; + default = 8081; + description = "Port for chainfire HTTP/admin API (used for cluster join)"; + }; + dataDir = lib.mkOption { type = lib.types.path; default = "/var/lib/chainfire"; @@ -61,6 +67,11 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; + environment = { + # Set HTTP admin address via environment variable (config-rs format: CHAINFIRE__NETWORK__HTTP_ADDR) + CHAINFIRE__NETWORK__HTTP_ADDR = "0.0.0.0:${toString cfg.httpPort}"; + }; + serviceConfig = { Type = "simple"; User = "chainfire"; diff --git a/nix/modules/first-boot-automation.nix b/nix/modules/first-boot-automation.nix index e0af24b..b326da7 100644 --- a/nix/modules/first-boot-automation.nix +++ b/nix/modules/first-boot-automation.nix @@ -76,6 +76,19 @@ let log "INFO" "Starting cluster join process for ${serviceName}" + # Read cluster config at runtime + CONFIG_FILE="${cfg.configFile}" + if [ -f "$CONFIG_FILE" ]; then + IS_BOOTSTRAP=$(${pkgs.jq}/bin/jq -r '.bootstrap // false' "$CONFIG_FILE") + LEADER_URL=$(${pkgs.jq}/bin/jq -r '.leader_url // "https://localhost:${toString port}"' "$CONFIG_FILE") + NODE_ID=$(${pkgs.jq}/bin/jq -r '.node_id // "unknown"' "$CONFIG_FILE") + RAFT_ADDR=$(${pkgs.jq}/bin/jq -r '.raft_addr // "127.0.0.1:${toString (port + 1)}"' "$CONFIG_FILE") + log "INFO" "Loaded config: bootstrap=$IS_BOOTSTRAP, node_id=$NODE_ID" + else + log "ERROR" "Config file not found: $CONFIG_FILE" + exit 1 + fi + # Wait for local service health log "INFO" "Waiting for local ${serviceName} to be healthy" @@ -91,7 +104,7 @@ let exit 1 fi - HTTP_CODE=$(${pkgs.curl}/bin/curl -k -s -o /dev/null -w "%{http_code}" "${healthUrl}" 2>/dev/null || echo "000") + HTTP_CODE=$(${pkgs.curl}/bin/curl -s -o /dev/null -w "%{http_code}" "${healthUrl}" 2>/dev/null || echo "000") if [ "$HTTP_CODE" = "200" ]; then log "INFO" "Local ${serviceName} is healthy" @@ -103,7 +116,7 @@ let done # Check if this is a bootstrap node - if [ "${toString isBootstrap}" = "true" ]; then + if [ "$IS_BOOTSTRAP" = "true" ]; then log "INFO" "Bootstrap node detected, cluster already initialized" # Create marker to indicate initialization complete @@ -121,7 +134,7 @@ let # Join existing cluster log "INFO" "Attempting to join existing cluster" - log "INFO" "Leader URL: ${leaderUrl}, Node ID: ${nodeId}, Raft Addr: ${raftAddr}" + log "INFO" "Leader URL: $LEADER_URL, Node ID: $NODE_ID, Raft Addr: $RAFT_ADDR" MAX_ATTEMPTS=5 RETRY_DELAY=10 @@ -131,10 +144,10 @@ let # Make join request RESPONSE_FILE=$(mktemp) - HTTP_CODE=$(${pkgs.curl}/bin/curl -k -s -w "%{http_code}" -o "$RESPONSE_FILE" \ - -X POST "${leaderUrl}${leaderUrlPath}" \ + HTTP_CODE=$(${pkgs.curl}/bin/curl -s -w "%{http_code}" -o "$RESPONSE_FILE" \ + -X POST "$LEADER_URL${leaderUrlPath}" \ -H "Content-Type: application/json" \ - -d "{\"id\":\"${nodeId}\",\"raft_addr\":\"${raftAddr}\"}" 2>/dev/null || echo "000") + -d "{\"id\":\"$NODE_ID\",\"raft_addr\":\"$RAFT_ADDR\"}" 2>/dev/null || echo "000") RESPONSE_BODY=$(cat "$RESPONSE_FILE" 2>/dev/null || echo "") rm -f "$RESPONSE_FILE" @@ -242,7 +255,7 @@ in systemd.services.chainfire-cluster-join = lib.mkIf cfg.enableChainfire ( mkClusterJoinService { serviceName = "chainfire"; - healthUrl = "https://localhost:${toString cfg.chainfirePort}/health"; + healthUrl = "http://localhost:8081/health"; # Health endpoint on admin port leaderUrlPath = "/admin/member/add"; port = cfg.chainfirePort; description = "Chainfire"; @@ -253,7 +266,7 @@ in systemd.services.flaredb-cluster-join = lib.mkIf cfg.enableFlareDB ( mkClusterJoinService { serviceName = "flaredb"; - healthUrl = "https://localhost:${toString cfg.flaredbPort}/health"; + healthUrl = "http://localhost:8082/health"; # Health endpoint on admin port leaderUrlPath = "/admin/member/add"; port = cfg.flaredbPort; description = "FlareDB"; @@ -378,7 +391,7 @@ in # Check Chainfire if systemctl is-active chainfire.service > /dev/null 2>&1; then - HTTP_CODE=$(${pkgs.curl}/bin/curl -k -s -o /dev/null -w "%{http_code}" "https://localhost:${toString cfg.chainfirePort}/health" 2>/dev/null || echo "000") + HTTP_CODE=$(${pkgs.curl}/bin/curl -s -o /dev/null -w "%{http_code}" "http://localhost:8081/health" 2>/dev/null || echo "000") if [ "$HTTP_CODE" = "200" ]; then log "INFO" "Chainfire health check: PASSED" @@ -390,7 +403,7 @@ in # Check FlareDB if systemctl is-active flaredb.service > /dev/null 2>&1; then - HTTP_CODE=$(${pkgs.curl}/bin/curl -k -s -o /dev/null -w "%{http_code}" "https://localhost:${toString cfg.flaredbPort}/health" 2>/dev/null || echo "000") + HTTP_CODE=$(${pkgs.curl}/bin/curl -s -o /dev/null -w "%{http_code}" "http://localhost:8082/health" 2>/dev/null || echo "000") if [ "$HTTP_CODE" = "200" ]; then log "INFO" "FlareDB health check: PASSED" diff --git a/nix/modules/flaredb.nix b/nix/modules/flaredb.nix index 9767baa..471065e 100644 --- a/nix/modules/flaredb.nix +++ b/nix/modules/flaredb.nix @@ -19,6 +19,12 @@ in description = "Port for flaredb Raft protocol"; }; + httpPort = lib.mkOption { + type = lib.types.port; + default = 8082; + description = "Port for flaredb HTTP/admin API (used for cluster join)"; + }; + dataDir = lib.mkOption { type = lib.types.path; default = "/var/lib/flaredb"; @@ -56,6 +62,10 @@ in after = [ "network.target" "chainfire.service" ]; requires = [ "chainfire.service" ]; + environment = { + FLAREDB_HTTP_ADDR = "0.0.0.0:${toString cfg.httpPort}"; + }; + serviceConfig = { Type = "simple"; User = "flaredb";