Add infra-ops-toolkit plugin: topology diagram, html-to-pdf, teleport onboarding skills
Distills patterns from the Teleport access topology work: verified-data diagram building, as-displayed HTML-to-PDF export via headless Chromium, and container-scoped/host/database onboarding into an existing Teleport cluster. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R3ZTfgQrkR3q8DSEoZAmvs
This commit is contained in:
56
plugins/infra-ops-toolkit/skills/topology-diagram/SKILL.md
Normal file
56
plugins/infra-ops-toolkit/skills/topology-diagram/SKILL.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: topology-diagram
|
||||
description: Build or update the MBU Group SSH/database access topology diagram (a light-theme HTML+SVG page mirrored into a .drawio.xml file). Use when asked to visualize, draw, update, or "perbarui" the infra access topology, network diagram, or Teleport topology — including adding a new provider/host/database, correcting IPs or specs, or fixing arrow/layout issues. Always re-verify every value against live infra before writing it; never hand-type an IP, spec, or resource name from memory.
|
||||
---
|
||||
|
||||
# Topology Diagram
|
||||
|
||||
Two files always ship together and must stay in sync:
|
||||
- `topologi-ssh-teleport.html` — the primary, richly-styled artifact (what people actually read)
|
||||
- `topologi-ssh-teleport.drawio.xml` — an editable mirror for the team, generated from the same coordinates/content, one visual generation behind on cosmetic-only details (see "drawio limitations" below)
|
||||
|
||||
Ask the user where these live in their vault/Downloads if unknown — don't assume a path.
|
||||
|
||||
## Golden rule: verify before you draw
|
||||
|
||||
Never write an IP, spec, capacity number, or resource name from memory or from the diagram's own prior state. Before touching the file, pull fresh data from the actual source:
|
||||
- Droplets/VMs: `doctl compute droplet list --format Name,PublicIPv4,PrivateIPv4,Memory,VCPUs,Disk,Region,Status`
|
||||
- Managed databases: `doctl databases list -o json` (get `storage_size_mib`, `size` slug, `num_nodes` — the list view alone omits storage)
|
||||
- AWS compute: `aws ec2 describe-instances` (loop every region if the primary region search comes up empty — check with `aws ec2 describe-regions`)
|
||||
- AWS databases: `aws rds describe-db-instances`
|
||||
- Teleport's own view: `tsh ls`, `tsh db ls -f json`, `tsh app ls` — this is what's *actually* registered, which can differ from what a droplet list implies
|
||||
- Cluster roles/config: `tctl get roles --format=json` (see teleport-onboard skill for where tctl actually runs)
|
||||
|
||||
If a resource shows up in the diagram's current text but you can't re-confirm it from a live source, don't silently trust it — flag it as unverified in the diagram itself (dashed border + a short "perlu verifikasi manual" note) rather than deleting it or leaving it looking equally confident as verified data. This has caught real bugs: a database name that looked like a duplicate turned out to be a distinct self-hosted DB reachable only via `tsh db ls`, not `doctl`.
|
||||
|
||||
## Design system (HTML)
|
||||
|
||||
Everything is driven by CSS custom properties on `:root` — change the palette in one place:
|
||||
```css
|
||||
--bg, --surface, --line, --line-soft, --text, --text-dim, --text-faint /* neutrals */
|
||||
--accent /* the single ingress chokepoint (e.g. the proxy/gateway) — spend this color deliberately, once */
|
||||
--user, --core, --agent, --do, --db, --wire, --legacy, --aws /* one hue per semantic category, reused everywhere: node icon, node border stripe, matching edges, zone eyebrow labels */
|
||||
```
|
||||
Pick a light or dark ground deliberately; light was chosen last for readability and print/PDF friendliness. Typography: a display sans (Archivo) for titles, a mono face (JetBrains Mono) for every IP/port/command/capacity number — the mono choice is not decorative, it's because the subject is literally terminal/IP data.
|
||||
|
||||
**Node card pattern** (repeated ~30×): a `<path>` (not `<rect>`) drawing a rectangle rounded *only on the right* (left corners stay square, matching the left accent stripe):
|
||||
```
|
||||
M{x},{y} L{x2-r},{y} A{r},{r} 0 0 1 {x2},{y+r} L{x2},{y2-r} A{r},{r} 0 0 1 {x2-r},{y2} L{x},{y2} Z
|
||||
```
|
||||
plus a thin `<rect>` (`width:3-4, rx:0`) at the same x/y as the left accent stripe in the category color, plus a `<foreignObject>` holding real HTML (icon svg + `<b>` title + `.n-meta` lines, one of which is usually `.faint` for the least-important line). foreignObject is what makes rich HTML-in-SVG possible at all — don't try to hand-roll the same layout with plain `<text>` elements.
|
||||
|
||||
**Zone headers**: a small mono eyebrow label + a thin `<line>` rule spanning the full content width — not a big tinted background band (tried first, looked muddy). **Provider containers** (DigitalOcean / Biznet / AWS): white fill, 2px border in that provider's category color, not a pastel fill.
|
||||
|
||||
**Edges**: orthogonal `<path>`s in the category color of what they represent (not what they connect), each with an arrow `<marker>` in `<defs>`. Labels are centered pills: wrap the label text in a flex-centered `<div>` inside a `<foreignObject>` sized/positioned at the edge's true midpoint, styled as `border-radius:999px; background:var(--surface); border:1px solid var(--line);` — this reads as a chip floating on the line, not text mashed into the background.
|
||||
|
||||
**Layout discipline**: when adding a new column (a new provider, a new agent lane), recenter it under its own container and re-run the numbers for every sibling that shares a header divider or trunk edge — don't leave one column narrower/off-center while others got the treatment. Widen the `viewBox` and extend header `<line>` rules to the new right margin; don't leave them stopping short.
|
||||
|
||||
**Print/PDF**: add an `@media print` block (`@page{size:landscape}`, `.layout{display:block}`, `page-break-after` on the diagram frame) so a *browser's own* print dialog doesn't crush a wide multi-column layout into an unreadable thumbnail. But if the user wants a PDF that matches the *on-screen* view exactly (not a print-reflowed one), that's a different tool — see the `html-to-pdf` skill instead of fighting the print dialog further.
|
||||
|
||||
## drawio mirror
|
||||
|
||||
drawio's `mxCell` style language can't do per-corner rounding, arbitrary SVG icon paths, or CSS-variable-driven theming. Don't hand-edit 30+ `mxCell` blocks for a structural change — write a small Python generator with helper functions (`node()`, `container()`, `edge()`, `eyebrow()`) that takes the *same* coordinate/color/text data as the HTML and emits the XML. This is far less error-prone than manual edits and keeps the two files derivable from one source of truth even though they're not literally the same code.
|
||||
|
||||
Known, accepted gaps versus the HTML (state these to the user rather than silently mismatching): symmetric `arcSize` rounding on all four corners (not right-only), no custom icons (title + category color + left stripe carries the scanability instead), edge labels approximated via a child "edgeLabel" vertex with `rounded=1;arcSize=100` for the pill look.
|
||||
|
||||
After any edit to either file: validate XML with `python3 -c "import xml.etree.ElementTree as ET; ET.parse('file.xml')"`, check `<foreignObject>`/`<g>` tag balance in the HTML, then `open <path>` to eyeball it in a browser before calling it done.
|
||||
Reference in New Issue
Block a user