mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
fix(worktree): derive the swarm lab subnet without an octet overflow
scripts/system/worktree/up.sh pinned INFINITO_SWARM_LAB_SUBNET to 192.168.$((244 + slot)).0/24. From slot 12 on that third octet exceeds 255, so every worktree past slot 11 carries an invalid subnet (192.168.358.0/24 for slot 114), and make swarm-zombie dies at the lab network creation with `invalid subnet: netip.ParsePrefix(...)`. The lab prefix is now 10.244.<slot>, valid and distinct for every slot up to max_slot 255, and outside both the primary lab subnet 192.168.244.0/24 and the 172.30.0.0/16 worktree subnets. The host daemon allocates nothing from 10.0.0.0/8. A new lint renders the prefix for every slot and fails on an invalid, repeated or overlapping subnet; against the old derivation it fails 247 of 255 slots. Worktrees that were pinned before this fix keep their custom.env; the ones at slot 12 or above need their INFINITO_SWARM_*_IP and INFINITO_SWARM_LAB_SUBNET pins rewritten to 10.244.<slot>.x and a make dotenv before they can run swarm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4f641f0322
commit
a7685e3b21
2 files changed
+74
-13
No files matched your search
@@ -53,7 +53,7 @@ git worktree add "${path}" "${branch}"
|
||||
|
||||
git_common_dir="$(git rev-parse --path-format=absolute --git-common-dir)"
|
||||
|
||||
lab_octet="$((244 + slot))"
|
||||
lab_prefix="10.244.${slot}"
|
||||
|
||||
echo ">>> Pinning slot ${slot} in ${path}/custom.env"
|
||||
cat >"${path}/custom.env" <<PINS
|
||||
@@ -64,12 +64,12 @@ INFINITO_GATEWAY=172.30.${slot}.1
|
||||
INFINITO_DNS_IP=172.30.${slot}.53
|
||||
INFINITO_IP4=172.30.${slot}.10
|
||||
INFINITO_BIND_IP=127.0.0.$((slot + 1))
|
||||
INFINITO_SWARM_LAB_SUBNET=192.168.${lab_octet}.0/24
|
||||
INFINITO_SWARM_MGR_IP=192.168.${lab_octet}.10
|
||||
INFINITO_SWARM_WRK1_IP=192.168.${lab_octet}.11
|
||||
INFINITO_SWARM_WRK2_IP=192.168.${lab_octet}.12
|
||||
INFINITO_SWARM_NFS_IP=192.168.${lab_octet}.13
|
||||
INFINITO_SWARM_BACKUP_IP=192.168.${lab_octet}.14
|
||||
INFINITO_SWARM_LAB_SUBNET=${lab_prefix}.0/24
|
||||
INFINITO_SWARM_MGR_IP=${lab_prefix}.10
|
||||
INFINITO_SWARM_WRK1_IP=${lab_prefix}.11
|
||||
INFINITO_SWARM_WRK2_IP=${lab_prefix}.12
|
||||
INFINITO_SWARM_NFS_IP=${lab_prefix}.13
|
||||
INFINITO_SWARM_BACKUP_IP=${lab_prefix}.14
|
||||
INFINITO_RUNNER_PREFIX=infinito-${slug}
|
||||
INFINITO_CONTAINER=infinito_nexus_${slug//[.-]/_}
|
||||
INFINITO_CACHE_NETWORK=${cache_network}
|
||||
@@ -86,12 +86,12 @@ env -i -C "${path}" \
|
||||
INFINITO_DNS_IP="172.30.${slot}.53" \
|
||||
INFINITO_IP4="172.30.${slot}.10" \
|
||||
INFINITO_BIND_IP="127.0.0.$((slot + 1))" \
|
||||
INFINITO_SWARM_LAB_SUBNET="192.168.${lab_octet}.0/24" \
|
||||
INFINITO_SWARM_MGR_IP="192.168.${lab_octet}.10" \
|
||||
INFINITO_SWARM_WRK1_IP="192.168.${lab_octet}.11" \
|
||||
INFINITO_SWARM_WRK2_IP="192.168.${lab_octet}.12" \
|
||||
INFINITO_SWARM_NFS_IP="192.168.${lab_octet}.13" \
|
||||
INFINITO_SWARM_BACKUP_IP="192.168.${lab_octet}.14" \
|
||||
INFINITO_SWARM_LAB_SUBNET="${lab_prefix}.0/24" \
|
||||
INFINITO_SWARM_MGR_IP="${lab_prefix}.10" \
|
||||
INFINITO_SWARM_WRK1_IP="${lab_prefix}.11" \
|
||||
INFINITO_SWARM_WRK2_IP="${lab_prefix}.12" \
|
||||
INFINITO_SWARM_NFS_IP="${lab_prefix}.13" \
|
||||
INFINITO_SWARM_BACKUP_IP="${lab_prefix}.14" \
|
||||
INFINITO_RUNNER_PREFIX="infinito-${slug}" \
|
||||
INFINITO_CACHE_NETWORK="${cache_network}" \
|
||||
python3 -m cli.meta.env
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"""Every worktree slot must pin a valid swarm lab subnet of its own.
|
||||
|
||||
`scripts/system/worktree/up.sh` derives `INFINITO_SWARM_LAB_SUBNET` from the
|
||||
slot. A derivation that overflows an octet yields an address Docker rejects at
|
||||
network creation, so `make swarm-zombie` dies in every worktree past that slot.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ipaddress
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from utils.cache.files import read_text
|
||||
from utils.env.parser import parse_static_env
|
||||
|
||||
from . import PROJECT_ROOT
|
||||
|
||||
_UP_SH = PROJECT_ROOT / "scripts/system/worktree/up.sh"
|
||||
_MAX_SLOT_RE = re.compile(r"^max_slot=(?P<value>\d+)$", re.MULTILINE)
|
||||
_LAB_PREFIX_RE = re.compile(r'^lab_prefix="(?P<template>[^"]+)"$', re.MULTILINE)
|
||||
_LAB_SUBNET_RE = re.compile(
|
||||
r"^INFINITO_SWARM_LAB_SUBNET=\$\{lab_prefix\}\.0/24$", re.MULTILINE
|
||||
)
|
||||
|
||||
|
||||
class TestWorktreeSwarmLabSubnet(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
source = read_text(str(_UP_SH))
|
||||
max_slot = _MAX_SLOT_RE.search(source)
|
||||
lab_prefix = _LAB_PREFIX_RE.search(source)
|
||||
self.assertIsNotNone(max_slot, f"{_UP_SH} declares no max_slot")
|
||||
self.assertIsNotNone(lab_prefix, f"{_UP_SH} declares no lab_prefix")
|
||||
self.assertRegex(source, _LAB_SUBNET_RE)
|
||||
self.max_slot = int(max_slot.group("value"))
|
||||
self.template = lab_prefix.group("template")
|
||||
|
||||
def _subnet(self, slot: int) -> ipaddress.IPv4Network:
|
||||
prefix = self.template.replace("${slot}", str(slot))
|
||||
return ipaddress.ip_network(f"{prefix}.0/24")
|
||||
|
||||
def test_every_slot_pins_a_valid_distinct_lab_subnet(self) -> None:
|
||||
primary = ipaddress.ip_network(
|
||||
parse_static_env(PROJECT_ROOT / "default.env")["INFINITO_SWARM_LAB_SUBNET"]
|
||||
)
|
||||
worktree_subnets = ipaddress.ip_network("172.30.0.0/16")
|
||||
seen: dict[ipaddress.IPv4Network, int] = {}
|
||||
for slot in range(1, self.max_slot + 1):
|
||||
with self.subTest(slot=slot):
|
||||
subnet = self._subnet(slot)
|
||||
self.assertFalse(subnet.overlaps(primary), f"slot {slot} overlaps {primary}")
|
||||
self.assertFalse(
|
||||
subnet.overlaps(worktree_subnets),
|
||||
f"slot {slot} overlaps the worktree subnets {worktree_subnets}",
|
||||
)
|
||||
self.assertNotIn(subnet, seen, f"slot {slot} repeats slot {seen.get(subnet)}")
|
||||
seen[subnet] = slot
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user