Update tech_docs/its_the_new_style_design.md
This commit is contained in:
@@ -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
|
MyCorp “One-Box Wonder” – Complete & Idempotent deploy.sh
|
||||||
──────────────────────────────
|
──────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user