Skip to content

feat: make brigade cluster node count configurable#12

Merged
richardcase merged 1 commit into
mainfrom
feat/configurable-node-count
Jul 17, 2026
Merged

feat: make brigade cluster node count configurable#12
richardcase merged 1 commit into
mainfrom
feat/configurable-node-count

Conversation

@richardcase

Copy link
Copy Markdown
Member

What

Make the number of brigade cluster nodes (== flintlock host droplets) configurable via a new NODE_COUNT env var. Defaults to 2 (current behavior byte-for-byte); overridable locally and via the GitHub Actions dispatch workflow.

Why

The infra + bootstrap code was already generic over host count — droplet creation loops on droplet_count, host names derive as {tag}-host{i}, bootstrap iterates all droplets, and the Erlang mesh is built from every peer's private IP. But droplet_count was a dead knob: a dataclass field defaulting to 2 that load() never populated from the environment, so it could never change.

Changes

  • config.py — read NODE_COUNT (default 2) → droplet_count; validate >= 1. brigade_min_cluster_size now defaults to the node count (so an N-node run waits for all N to mesh); an explicit BRIGADE_MIN_CLUSTER_SIZE still wins.
  • .env.example — new NODE_COUNT=2 cluster section; note quorum follows it.
  • .github/workflows/e2e.yml — new node_count dispatch input mapped to NODE_COUNT.
  • docstring sweep — retire stale 2-node / both hosts / two nodes wording now that the count is variable (left test_placement.py's "two hosts" anti-span assertion intact).

Verification

Lint clean; offline suite tests/test_cleanup.py 9/9 green. Config load spot-checks:

env droplet_count brigade_min_cluster_size
(default) 2 2
NODE_COUNT=3 3 3
NODE_COUNT=3 BRIGADE_MIN_CLUSTER_SIZE=2 3 2
NODE_COUNT=0 ConfigError: must be >= 1

Full e2e (make test, real DO infra, costs money) not run. To exercise N>2 for real, dispatch the e2e workflow with node_count=3.

Expose NODE_COUNT (default 2) to size the brigade cluster / flintlock host
droplets. The infra and bootstrap paths were already generic over host count
(droplet loop on droplet_count, host names {tag}-host{i}, Erlang mesh built
from all peer IPs), but droplet_count was a dead knob: a dataclass field that
load() never populated from the environment.

Wire NODE_COUNT through load() into droplet_count, validate >= 1, and default
brigade_min_cluster_size to the node count so an N-node run waits for all N to
mesh (explicit BRIGADE_MIN_CLUSTER_SIZE still overrides). Add the knob to
.env.example and a node_count dispatch input to the e2e workflow.

Also de-hardcode stale "2-node" / "both hosts" wording in docstrings/comments
now that the count is variable.
Copilot AI review requested due to automatic review settings July 17, 2026 20:32
@richardcase
richardcase merged commit acb5790 into main Jul 17, 2026
1 check passed
@richardcase
richardcase deleted the feat/configurable-node-count branch July 17, 2026 20:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes the brigade cluster size (and corresponding flintlock host droplet count) configurable via a new NODE_COUNT environment variable, with a default of 2 to preserve current behavior. It also wires this through the GitHub Actions workflow dispatch input and updates documentation/comments to remove assumptions about a fixed 2-node cluster.

Changes:

  • Add NODE_COUNT parsing in liquidmetal_at/config.py, defaulting to 2 and using it to populate droplet_count and the default brigade_min_cluster_size.
  • Add a node_count input to the e2e workflow and map it to NODE_COUNT.
  • Update .env.example and various docstrings/comments to be N-node-aware.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
liquidmetal_at/config.py Introduces NODE_COUNT and updates defaults for droplet count and brigade quorum target.
.github/workflows/e2e.yml Adds workflow_dispatch input for node count and exports it as NODE_COUNT.
.env.example Documents new NODE_COUNT knob and notes quorum behavior.
liquidmetal_at/bootstrap/host.py Updates docstrings to remove “both hosts” assumption.
liquidmetal_at/bootstrap/__init__.py Updates package docstring to N-node language.
liquidmetal_at/bootstrap/templates/cloud_init.yaml.j2 Updates template comment to “all hosts”.
liquidmetal_at/flintlock/client.py Updates retry docstring language to no longer assume 2 nodes.
tests/conftest.py Updates fixture docstrings to no longer assume a 2-node mesh.
tests/test_ssh_reachability.py Updates helper docstring to cycle all hosts, not “both”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread liquidmetal_at/config.py
Comment on lines +158 to +163
# Number of flintlock host droplets == brigade cluster nodes. Quorum target
# (brigade_min_cluster_size) follows this unless overridden explicitly.
node_count = int(os.environ.get("NODE_COUNT", "2"))
if node_count < 1:
raise ConfigError(f"NODE_COUNT={node_count} must be >= 1")

Comment thread liquidmetal_at/config.py
Comment on lines 199 to 204
keep_infra_on_failure=_bool(os.environ.get("KEEP_INFRA_ON_FAILURE", "false")),
artifacts_dir=_expand(os.environ.get("ARTIFACTS_DIR", "./artifacts")),
droplet_count=node_count,
)
_validate_microvm_shape(cfg.microvm_mem_mb, cfg.microvm_vcpu, cfg.microvm_kernel_filename)
return cfg
Comment thread liquidmetal_at/config.py
Comment on lines +158 to +162
# Number of flintlock host droplets == brigade cluster nodes. Quorum target
# (brigade_min_cluster_size) follows this unless overridden explicitly.
node_count = int(os.environ.get("NODE_COUNT", "2"))
if node_count < 1:
raise ConfigError(f"NODE_COUNT={node_count} must be >= 1")
Comment thread .env.example
Comment on lines +43 to 44
# defaults to NODE_COUNT when unset
BRIGADE_MIN_CLUSTER_SIZE=2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants