Add per-node random regions and AWS parallel provisioning to WEBRUNNER

Each node chunk now carries its own region field, assigned round-robin
across the full provider region list unless the user pinned a specific
region. AWS uses the same async/poll:0 pattern as Linode but with a
serial per-unique-region setup phase (key import + SG) before firing all
creates in parallel. Teardown uses hostvars ec2_region per node so
multi-region AWS teardowns hit the right endpoint. Infisical replaces
interactive credential prompts for both providers. Linode vars.yaml
instance type corrected to g6-nanode-1.
This commit is contained in:
n0mad1k
2026-04-30 23:48:36 -04:00
parent 3f2bc447a4
commit 78da72e9f6
4 changed files with 246 additions and 104 deletions
+38 -6
View File
@@ -305,19 +305,51 @@ def gather_webrunner_parameters() -> dict | None:
all_cidrs.extend(cc_cidrs.get(cc.upper(), []))
chunks = chunk_cidrs(all_cidrs, chunk_size)
node_chunks = [
{
# Build per-provider region pools for round-robin assignment
provider_regions: dict[str, list[str]] = {}
for p in providers:
if p == 'linode':
provider_regions[p] = config.get('linode_regions', [config.get('linode_region', 'us-east')])
elif p == 'aws':
provider_regions[p] = config.get('aws_regions', [config.get('aws_region', 'us-east-1')])
elif p == 'flokinet':
provider_regions[p] = [config.get('flokinet_region', 'default')]
else:
provider_regions[p] = ['default']
provider_counters: dict[str, int] = {p: 0 for p in providers}
node_chunks = []
for i, chunk in enumerate(chunks):
provider = providers[i % len(providers)]
regions = provider_regions[provider]
region = regions[provider_counters[provider] % len(regions)]
provider_counters[provider] += 1
node_chunks.append({
'idx': i,
'node_name': f"{config['webrunner_name']}-{i + 1:02d}",
'provider': providers[i % len(providers)],
'provider': provider,
'region': region,
'cidrs': chunk['cidrs'],
'ip_count': chunk['ip_count'],
}
for i, chunk in enumerate(chunks)
]
})
config['node_chunks'] = node_chunks
print(f"{COLORS['GREEN']}Nodes: {len(node_chunks)} ({preset_key}, {fmt_ip_count(chunk_size)}/node){COLORS['RESET']}")
# Warn if any provider's node count exceeds safe per-region quota
_PROVIDER_CAPS = {'linode': 20, 'aws': 32, 'flokinet': 10}
provider_node_counts: dict[str, int] = {}
for nc in node_chunks:
provider_node_counts[nc['provider']] = provider_node_counts.get(nc['provider'], 0) + 1
for p, count in provider_node_counts.items():
n_regions = len(provider_regions.get(p, ['default']))
cap = _PROVIDER_CAPS.get(p, 20)
per_region = (count + n_regions - 1) // n_regions
if per_region > cap:
print(f"{COLORS['YELLOW']} Warning: {count} {PROVIDER_LABELS[p]} nodes across {n_regions} region(s) "
f"= ~{per_region}/region; default quota is ~{cap}/region.{COLORS['RESET']}")
# Operator IP
config['operator_ip'] = get_public_ip()
if config['operator_ip']: