Peer templates: share policy chains and BGP options across many peers - #21
Open
floreabogdan wants to merge 6 commits into
Open
Peer templates: share policy chains and BGP options across many peers#21floreabogdan wants to merge 6 commits into
floreabogdan wants to merge 6 commits into
Conversation
A peer template is a peer without an identity: role, policy chains, import limit, transport safeguards and export transforms, captured once and linked from many peers. Linked peers carry a full copy of the governed columns and a template save rewrites every one of them in the same transaction, so the renderer, the linter and every "in use" count keep reading plain peer rows. Schema version 38: peer_templates and template_policies, plus a nullable template_id and a template_overrides list on peers. Existing peers are untouched and unlinked. - PeerTemplate.ApplyTo / TemplateFromPeer are the two halves of the split clone already makes; a reflection test fails when a peer field is added without being classified as identity or shape. - Peer.Validate's shape checks move to validateShape so a template is held to exactly the rules a peer is. - DeletePolicy also refuses while a template chains the policy; the chain helpers are generalised over the two chain tables. - Peer names new/seed/preview/templates are refused: they are pages under /peers/ the router serves before the name wildcard. Part of #20. Claude-Session: https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX
Peers → Templates lists every template with its chains, limit and how many peers link to it. The editor is the peer form with the identity card removed; it previews the shape on a sample neighbor and says how many peers a save rewrites. On the peer form a Template picker fills the governed controls from the template and greys them out; choosing None detaches the peer and leaves the values in place. The server re-applies the template on every save and preview, so what the form posts for a governed field never matters. "Save as template" captures an existing peer's shape and can link that peer in the same step; "Add peer" on a template's row starts a session already linked; the peers list carries a chip and a ?template= filter. A linked peer's protocol block carries a comment naming its template; unlinked peers render byte-for-byte as before. Closes #20. Claude-Session: https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX
…tach, lint folding - A linked peer can keep its own import limit: "Use this peer's own import limit" on the form writes the importLimit override the store already honoured, so the one oversized IX peer needs no template of its own. An unlinked peer carries no overrides; Validate clears the list. - Import from BIRD offers a template per row (plus one control to set every checked row). A session imported with a template arrives with its role, shape and chains — a plain seed never had chains, since the socket says nothing about what the filters were meant to do. - The peers list gains a bulk bar: tick peers, attach them to a template or detach them. Store.DetachPeer keeps the values and drops the link. - Lint folds identical findings about peers of one template into a single line attributed to the template; per-peer and unlinked findings stay. - The peer form's other-role checkbox group was visible greyed out instead of hidden (.checks' flex beat the hidden attribute) — pre-existing, fixed. - "attach" joins the reserved peer names. Claude-Session: https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX
A template at least one peer links to now renders as a template bgp block carrying the session options its peers share — multihop, passive, BFD, GTSM, graceful restart, the RFC 9234 role, route reflection — and each linked peer is declared "protocol bgp X from TEMPLATE". What stays in the peer's block is everything peers differ in: neighbor, password, the filters (they embed the peer's own ASN and transforms) and the channel, whose family follows the neighbor and whose import limit is the one thing a peer may override. A template nobody links to is not written, so creating one changes nothing until a peer uses it; a linked peer whose template is missing from the input renders in full. Unlinked peers are byte-for-byte unchanged. The per-peer preview is assembled from sections now (the template block first, then the peer's own), which also retires the marker-based slicing that skipped iBGP filters. Template files sit with the policies in birdy.d/ (08-templates-*.conf), ahead of the peers that inherit them. Verified against BIRD 2.15.1 in a Docker lab: bird -p accepts the output, an apply over four live sessions caused no flap, template edits fan out to every linked peer on the daemon, and the armed revert restores a template change that breaks its sessions. Claude-Session: https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX
- Templates list shows each template's safeguards as chips (first AS, origin only, RFC 9234, GTSM, BFD, passive, multihop, prepend). - A linked peer's Role says "Set by the template"; the template editor's "N peers linked" note is informational rather than a warning, its lint findings are attributed to the template, and its chain headings speak of "these peers". - README gains a screenshot row (templates list, linked peer), USAGE and the CHANGELOG describe the native template bgp rendering, and the TestPreview scaffold renders the new pages from fixture data. Claude-Session: https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Fixes #20.
At an IX you can have thirty peers that need the same import/export chains and the same BGP options; today each is set by hand and a policy change is repeated thirty times. This adds peer templates — Cisco's peer groups, fitted to how birdy already works.
A template is a peer without an identity: the role, policy chains, import limit, transport safeguards and export transforms a kind of session should have, kept once under Peers → Templates. Peers link to it and take that shape; save the template and every linked peer is rewritten in one transaction, then reviewed on the Changes page behind
bird -p, lint and the armed auto-revert like any other edit. Each peer keeps its own name, neighbor, AS, password and the enabled/drain switches.The split is exactly the one Clone a peer already makes (and the
peer_templatestablePLAN.mddesigned and never built).Design decisions
bird.conf. Linked peer rows hold a full copy of the governed columns andpeer_policies; saving a template fans out inside the transaction, so the renderer, lint, previews, the policies page's "in use" counts and the delete guards keep reading plain peer rows. In the rendered config a template in use is BIRD's owntemplate bgp NAME { … }carrying the shared session options (multihop, passive, BFD, GTSM, graceful restart, RFC 9234 role, route reflection), and each linked peer isprotocol bgp X from NAME. Filters, identity and the channel stay per peer — the filters embed the peer's ASN and transforms, the channel's family follows the neighbor, and its import limit is the one override. A template nobody links to is not written. Unlinked peers render byte-for-byte as before.peer_templatestable rather than a flag onpeers— everySELECT … FROM peers(poller, dashboard, seed) stays a peer query.peers.template_overrides) with the import limit as its only entry: the one thing that genuinely differs between thirty otherwise identical IX peers.What's in the PR
peer_templates,template_policies,peers.template_id(nullable FK, RESTRICT),peers.template_overrides.PeerTemplate.ApplyTo/TemplateFromPeer, fan-out onUpdatePeerTemplate,LinkPeerToTemplate/DetachPeer, delete guards that name what stands in the way.Peer.Validate's shape checks move to a sharedvalidateShape. A reflection test fails whenever a peer field is added without being classified as identity or shape.template bgpblocks (filed asbirdy.d/08-templates-*.conf, ahead of the peers),fromdeclarations, fallbacks for unused/missing templates; the per-peer preview is assembled from sections (template block first)./peers/templateslist with chains, limit, safeguard chips and usage; an editor that reuses the peer form minus the identity card, previews on a sample neighbor and states how many peers a save rewrites. On the peer form a Template picker fills and greys the governed controls ("Set by the template"); None detaches and leaves the values in place. The server re-applies the template on every save and preview. Save as template captures an existing peer (optionally linking it); Add peer on a template row starts a session already linked; the peers list carries a chip and a?template=filter.IX_PEERS (30 peers)).new,seed,preview,templates,attachare refused.TestPreviewscaffold, documentation ranges), CHANGELOG, PLAN.md note.Verified end to end on real BIRD
Docker lab (
alpine:3.20bird2.15.1, the same package the image bundles): two birdy-managed routers and four plain BIRD peers on one bridge.bird -paccepts the templated config; the three IX sessions do not flap; routes flow both ways; on disk08-templates-IX_PEERS.confandprotocol bgp rs1 from IX_PEERS.IX_PEERS→ all three peers see65551 65551 65551, transit untouched.Import limit: 1 [HIT] / warnwhile rs1 keeps 100.IX_PEERS (2 peers) No import limit…(the overridden peer stays out of the fold).FROM_CUSTOMERand re-exported to the IX peers, the full table down to the customer; A observes B through the multi-instance dashboard.Checklist
gofmt -l .prints nothing,go vet ./...andgolangci-lint runpassgo test ./...passes; behavior changes come with tests (no C toolchain on the dev box for-race; CI runs it)https://claude.ai/code/session_01C7cpvZpZxb2GYEj6jBHKQX