diff --git a/tech_docs/its_the_new_style_design.md b/tech_docs/its_the_new_style_design.md index a5c9f32..6e93608 100644 --- a/tech_docs/its_the_new_style_design.md +++ b/tech_docs/its_the_new_style_design.md @@ -1,3 +1,259 @@ +Next logical step: **turn the meta-themes into a *migration-ready manifest*** so the *next* DNS/DHCP engine (Kea + BIND or NetBox) can **inherit the haiku without re-typing it**. + +We only touch three artefacts: + +1. **Single JSON file** that *is* the schema (machine-readable, human-poetic). +2. **One Jinja2 template pack** that consumes the JSON and spits out **Kea**, **BIND**, **NetBox YAML**, **Ansible inventory**, **Terraform**, *or* raw `dnsmasq` again—zero drift. +3. **A one-shot linter** that refuses any hostname, IP, or cert that violates the eight axioms. + +--- + +### 1. Schema manifest (`mycorp-haiku.json`) +```jsonc +{ + "axioms": { + "clock_face": { + "static_half": [1, 126], + "dhcp_half": [129, 254], + "silent": 127 + }, + "palette": { + "infra": { "colour": "black", "prefix": "ns", "len": 2 }, + "lan": { "colour": "red", "prefix": "work", "len": 4 }, + "dmz": { "colour": "blue", "prefix": "web", "len": 3 } + }, + "primes": [2,3,5,7,11,13,17,19,23], + "max_glyph": 3, + "haiku_syllables": [5,7,5] + }, + "zones": [ + { + "name": "lan.mycorp.net", + "network": "10.0.0.0/24", + "gateway": "10.0.0.1", + "roles": { + "gw": { "seq": 1 }, + "wifi": { "seq": [1,2] }, + "prnt": { "seq": [1,9] } + } + }, + { + "name": "dmz.mycorp.net", + "network": "10.0.1.0/24", + "gateway": "10.0.1.1", + "roles": { + "web": { "seq": [1,5] }, + "db": { "seq": [1,3] } + } + }, + { + "name": "infra.mycorp.net", + "network": "10.0.255.0/28", + "roles": { + "ns": { "seq": 1 } + } + } + ] +} +``` +This file **never changes**—future engines only *render* it. + +--- + +### 2. Template pack (`templates/`) +``` +templates/ +├── kea.conf.j2 +├── named.conf.j2 +├── netbox-device.yml.j2 +├── ansible-inventory.j2 +└── acme-renew.sh.j2 +``` + +Example (Kea leases hook): +```jinja2 +{# kea.conf.j2 snippet #} +"interfaces-config": { + "interfaces": [ "eth0/{{ zone.network }}" ] +}, +"valid-lifetime": {{ 86400 if zone.name.endswith('lan') else 43200 }}, +"reservations": [ +{% for role, meta in zone.roles.items() %} +{% for n in (meta.seq if meta.seq is sequence else [meta.seq]) %} + { + "hostname": "{{ role }}-{{ '%02d'|format(n) }}.{{ zone.name }}", + "ip-address": "{{ zone.network|ipaddr(n) }}" + }{% if not loop.last %},{% endif %} +{% endfor %} +{% endfor %} +] +``` + +--- + +### 3. Linter (`haiku-lint`) +```bash +#!/usr/bin/env python3 +import json, re, sys, ipaddress, pathlib +schema = json.load(open(sys.argv[1])) +fail = 0 +for zone in schema['zones']: + net = ipaddress.IPv4Network(zone['network']) + for role, meta in zone['roles'].items(): + for n in (meta['seq'] if isinstance(meta['seq'], list) else [meta['seq']]): + fqdn = f"{role}-{n:02d}.{zone['name']}" + if len(role) + 3 > schema['axioms']['max_glyph'] + 1: + print(f"FAIL: {fqdn} exceeds glyph limit"); fail += 1 + if not re.fullmatch(r'^[a-z]{2,4}-\d{2}\.[a-z\.]+$', fqdn): + print(f"FAIL: {fqdn} breaks pattern"); fail += 1 +exit(fail) +``` +Drop it in CI; every PR must pass `haiku-lint mycorp-haiku.json`. + +--- + +### Migration workflow +1. Edit *only* `mycorp-haiku.json` (add new roles, bump sequences). +2. `jinja2 templates/kea.conf.j2 mycorp-haiku.json > /etc/kea/kea.conf` +3. `systemctl reload kea` (or `named`, or push to NetBox API). +4. `haiku-lint mycorp-haiku.json` → green or bust. + +Your **meta-themes survive any backend**—Kea, BIND, NetBox, or the next shiny tool—because the *source of truth* is the haiku file, not the config syntax. + +--- + +Meta-themes for the naming schema +(The *reason* the rules exist, not the rules themselves) + +1. **Clock-face Symmetry** + Every `/24` is a **12-hour dial**: + • `.1`–`.12` → the “noon-to-midnight” static hand + • `.129`–`.254` → the mirrored “midnight-to-noon” DHCP hand + • `.127` is the **invisible 6 o’clock tick** (never used, keeps the dial clean). + +2. **Piano-key Palette** + Roles are **white keys only** (C-D-E-F…). + Sequence numbers are the **black keys** that sit between. + You never need more than 88 hosts in any one role/zone, so the metaphor holds. + +3. **Monospaced Zen** + All tokens are chosen so that a fixed-width font renders every FQDN as a **perfect rectangle**—no ragged right edge in logs. + +4. **Prime-number Silence** + IP addresses ending in prime numbers are **reserved for silence** (unused). + Primes are the negative space that makes the symmetry *feel* intentional. + +5. **Roman-serial Minimalism** + Hostnames never exceed **three visual glyphs** before the first dot: + • a 2- or 4-letter role + • a dash + • two digits + Everything after the first dot is **context, not identity**. + +6. **Mirror-fold DNS** + Forward and reverse zones are **palindromic**: + `ns-01.infra.mycorp.net ↔ 1.255.0.10.in-addr.arpa` + Read either direction and the cadence is identical. + +7. **Mondrian Palette** + Only **four colours** (zones) exist: + • infra — black + • lan — red + • dmz — blue + • (future guest) — yellow + No other zones will ever be introduced, preserving visual balance. + +8. **Haiku Length** + Every fully-qualified hostname has **≤ 17 syllables** when spoken aloud, ensuring the schema *sounds* symmetrical as well as looking it. + +Pick whichever themes resonate; they all point back to the same four axioms, but give the cold mechanics a poetic reason to exist. + +--- + +Here is a **naming-only** cheat-sheet that keeps the **meta-level symmetry** you love, but adds a few **OCD-friendly** rules so you never have to think twice again. + +--- + +### 🧩 **Four absolute naming axioms** + +| Axiom | Rule | Example | +|---|---|---| +| **1. Directional symmetry** | Left-to-right order is always: *role* `-` *sequence* `.` *zone* `.` *root* | `web-03.dmz.mycorp.net` | +| **2. Zero-padded counters** | Sequence numbers start at **01**, never **1**, so columns line up | `work-01`, `work-02` … `work-99` | +| **3. Role lexicon ≤ 8 chars** | Every role word has the same length (or is padded to 8) | `router`, `switch`, `camera` → `cam-01` | +| **4. Immutable separators** | Only two separators are ever allowed: **dash** inside hostname, **dot** between labels | never `work_01`, never `work01.lan` | + +--- + +### 🧮 **Role dictionary (canonical 8-letter slots)** + +| Slot | Purpose | Canonical Token | Short alias | +|---|---|---|---| +| `gateway` | L3 router / firewall | `gw` | (fixed 2-char) | +| `dns-serv` | Authoritative DNS | `ns` | (fixed 2-char) | +| `workstn` | End-user devices | `work` | 4-char | +| `printer` | Print devices | `prnt` | 4-char | +| `storage` | NAS / SAN | `stor` | 4-char | +| `camera` | IP cameras | `cam` | 3-char *(pad to 4 with dash)* | +| `web-serv` | Web servers | `web` | 3-char *(pad to 4)* | +| `db-serv` | Database servers | `db` | 2-char *(pad to 4)* | + +> Every token is either **exactly 4 chars long** or **2 chars long** (`gw`, `ns`). +> This keeps vertical alignment in lists/monospaced logs. + +--- + +### 📏 **Sequence rules** + +| Scope | Sequence starts | Max hosts | Appearance | +|---|---|---|---| +| Per role & zone | `01` | `99` | `web-01.dmz`, `web-02.dmz` | +| Infrastructure /28 | `01` | `14` | `ns-01.infra`, `ns-02.infra` (if HA) | + +--- + +### 🌐 **Reverse-zone mirror trick** + +Because your reverse zones are **exact** mirrors, the PTR always looks like: + +``` +1.255.0.10.in-addr.arpa → ns-01.infra.mycorp.net +``` + +No extra dashes, no surprises. + +--- + +### 🏷️ **Quick mnemonic rhyme** + +> *“Role, dash, two-digit, dot, zone, dot, root — never reorder, never deviate.”* + +--- + +### 🎨 **Visual sanity check** + +Everything should stack like this in `/etc/hosts` or NetBox: + +``` +10.0.0.1 gw-01.lan.mycorp.net +10.0.0.2 wifi-01.lan.mycorp.net +10.0.0.10 prnt-01.lan.mycorp.net +10.0.1.1 gw-01.dmz.mycorp.net +10.0.1.5 web-01.dmz.mycorp.net +10.0.1.6 db-01.dmz.mycorp.net +10.0.255.1 ns-01.infra.mycorp.net +``` + +Columns line up → your OCD smiles. + +--- + +### 🪞 **Meta-guarantee** + +If you obey the four axioms above, any future technology (Kubernetes, NetBox, Ansible inventory, Terraform) can auto-generate these names without breaking the symmetry. + +--- + ────────────────────────────── MyCorp “One-Box Wonder” – Complete & Idempotent deploy.sh ──────────────────────────────