Skip to content

OPNET-785: Add FRR peer-file rendering for BGP-based VIP management - #395

Open
mkowalski wants to merge 3 commits into
openshift:mainfrom
mkowalski:bgp-frr-peer-rendering
Open

OPNET-785: Add FRR peer-file rendering for BGP-based VIP management#395
mkowalski wants to merge 3 commits into
openshift:mainfrom
mkowalski:bgp-frr-peer-rendering

Conversation

@mkowalski

@mkowalski mkowalski commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Adds runtimecfg render --peer-file support for rendering FRR configuration from a JSON peer mapping, consumed by the frr-k8s static pod introduced by BGP-based VIP management (openshift/enhancements#1982):

  • FRR peer types + resolution (FRRPeerMapping: localASN, defaultPeers, hostOverrides keyed by short hostname, communities): per-node peer list resolution — hosts with an override use it, everything else falls back to the defaults. This is the two-phase rendering pattern keepalived uses today (identical file delivered to all nodes by MCO; node-specific config rendered locally at pod start).
  • --peer-file flag on render: when set, templates receive FRR-specific data (.Hostname, .RouterID, .LocalASN, .Peers, .Communities) instead of the standard Node struct. Works without a live API server (bootstrap-safe): cluster name/domain parse locally and the router-id comes from the node's non-virtual IP.
  • isIPv4/isIPv6 template functions for address-family-aware FRR templates.

The peer-file schema is shared verbatim with the installer-generated bgp-vip-config ConfigMap (extra keys are ignored), so one schema flows from install-config to the node.

Validation

Consumed end to end by the reference implementation of enhancement 1982 across 14 dev-scripts baremetal installs (bootstrap + day-2 rendering on all control plane nodes): https://github.com/mkowalski/bgp-vip-demo. Unit tests included; go test ./... green.

Part of OPNET-595; this repo's subtask: OPNET-785.

Summary by CodeRabbit

  • New Features

    • Added optional FRR peer mapping support for render operations through a peer configuration file.
    • Supports default peer settings with host-specific overrides.
    • FRR output now includes the appropriate hostname, router ID, peers, and communities.
  • Bug Fixes

    • Improved template rendering for IPv4 and IPv6 address classification.
    • Standard rendering behavior remains unchanged when no FRR peer file is provided.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 10, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: This pull request references OPNET-785 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

What

Adds runtimecfg render --peer-file support for rendering FRR configuration from a JSON peer mapping, consumed by the frr-k8s static pod introduced by BGP-based VIP management (openshift/enhancements#1982):

  • FRR peer types + resolution (FRRPeerMapping: localASN, defaultPeers, hostOverrides keyed by short hostname, communities): per-node peer list resolution — hosts with an override use it, everything else falls back to the defaults. This is the two-phase rendering pattern keepalived uses today (identical file delivered to all nodes by MCO; node-specific config rendered locally at pod start).
  • --peer-file flag on render: when set, templates receive FRR-specific data (.Hostname, .RouterID, .LocalASN, .Peers, .Communities) instead of the standard Node struct. Works without a live API server (bootstrap-safe): cluster name/domain parse locally and the router-id comes from the node's non-virtual IP.
  • isIPv4/isIPv6 template functions for address-family-aware FRR templates.

The peer-file schema is shared verbatim with the installer-generated bgp-vip-config ConfigMap (extra keys are ignored), so one schema flows from install-config to the node.

Validation

Consumed end to end by the reference implementation of enhancement 1982 across 14 dev-scripts baremetal installs (bootstrap + day-2 rendering on all control plane nodes): https://github.com/mkowalski/bgp-vip-demo. Unit tests included; go test ./... green.

Part of OPNET-595; this repo's subtask: OPNET-785.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Walkthrough

The render command adds optional FRR peer-file handling, new FRR configuration models and helpers, and template functions for IPv4 and IPv6 classification.

Changes

FRR rendering

Layer / File(s) Summary
FRR configuration models and helpers
pkg/config/node.go
Adds FRR peer, mapping, and render-context types, JSON loading, host-specific peer resolution, and node-based configuration construction.
Template parsing and IP helpers
pkg/render/render.go
Registers isIPv4 and isIPv6 template functions and derives template names from file basenames.
Render command FRR integration
cmd/runtimecfg/render.go
Adds --peer-file and selects FRR-specific or standard configuration data for rendering.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RenderCommand
  participant FRRPeerMapping
  participant FRRRenderConfig
  participant RenderFile
  RenderCommand->>FRRPeerMapping: Load FRR peer mapping
  RenderCommand->>FRRRenderConfig: Build FRR render configuration
  RenderCommand->>RenderFile: Render template with selected configuration
  RenderFile->>RenderFile: Apply IPv4 and IPv6 template helpers
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error RenderFile logs every rendered line, and the new FRR config carries peer Passwords into template data, so peer-file renders can emit plaintext BGP secrets. Redact secret fields before logging rendered output, or avoid logging full template contents for FRR renders.
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding FRR peer-file rendering for BGP-based VIP management.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed No test files were changed in this PR, and the existing Ginkgo titles in the touched areas are static and deterministic.
Test Structure And Quality ✅ Passed No Ginkgo tests were added or modified in this PR; the diff only changes cmd/runtimecfg/render.go, so the checklist is not applicable.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added in the changed files; this PR only updates render/config code.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added in the PR commits; only runtimecfg/config/render code changed.
Topology-Aware Scheduling Compatibility ✅ Passed Only runtimecfg/render and FRR config helpers changed; no deployment manifests, controllers, replicas, affinity, nodeSelector, or topology-spread scheduling logic were added.
Ote Binary Stdout Contract ✅ Passed Changed files add no stdout writes in process-level hooks; render logging uses logrus, whose default output is stderr.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the PR only changes render/runtime config files and the diff contains no It/Describe/Context/When test blocks.
No-Weak-Crypto ✅ Passed Touched code only adds FRR peer rendering and IPv4/IPv6 template helpers; searches found no weak crypto, custom crypto, or secret comparisons in changed files.
Container-Privileges ✅ Passed No changed files add privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation settings; the PR only updates Go rendering/config code.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci
openshift-ci Bot requested review from cybertron and emy July 10, 2026 08:30
@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mkowalski

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
pkg/render/render.go (1)

23-34: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Correct usage of template.New(name).Funcs(...).ParseFiles(...).

Naming the template by filepath.Base(templatePath) before ParseFiles ensures the parsed definition matches the root template used by Execute. Logic looks correct.

Minor: funcMap is rebuilt on every RenderFile call (once per template in Render's loop). It's cheap, but could be hoisted to a package-level var since it's stateless.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/render/render.go` around lines 23 - 34, Hoist the stateless template
function map out of RenderFile so it is not rebuilt for every render. Define a
package-level FuncMap containing the existing isIPv4 and isIPv6 functions, then
have RenderFile use that shared map when calling template.New(name).Funcs(...).
pkg/config/node.go (1)

1042-1052: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Confirm mapping is never nil at call sites.

BuildFRRRenderConfig dereferences mapping unconditionally; a nil mapping will panic. Current caller (cmd/runtimecfg/render.go) only calls this after a successful LoadFRRPeerMapping, so it's safe today, but there's no defensive nil-check here if future callers don't follow that contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/config/node.go` around lines 1042 - 1052, Verify every call to
BuildFRRRenderConfig, especially cmd/runtimecfg/render.go, passes a non-nil
mapping after successful LoadFRRPeerMapping; add or preserve validation at
caller boundaries and document the non-nil contract, or add defensive handling
in BuildFRRRenderConfig if future callers may provide nil.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/runtimecfg/render.go`:
- Around line 131-142: Handle the error returned by
cmd.Flags().GetString("peer-file") in the surrounding command logic, returning
it immediately if non-nil, consistent with the existing GetUint16 and
GetString("cluster-config") handling before using peerFilePath.

In `@pkg/config/node.go`:
- Around line 102-111: Prevent FRR peer passwords from being exposed by the
render pipeline: update render.RenderFile so rendered FRR configuration output
is not logged wholesale, or redact the Password value before each line is sent
to log.Info. Preserve the password in the template context and generated
configuration, while ensuring the FRRPeer-to-Peers path through
BuildFRRRenderConfig cannot emit plaintext secrets in logs.

---

Nitpick comments:
In `@pkg/config/node.go`:
- Around line 1042-1052: Verify every call to BuildFRRRenderConfig, especially
cmd/runtimecfg/render.go, passes a non-nil mapping after successful
LoadFRRPeerMapping; add or preserve validation at caller boundaries and document
the non-nil contract, or add defensive handling in BuildFRRRenderConfig if
future callers may provide nil.

In `@pkg/render/render.go`:
- Around line 23-34: Hoist the stateless template function map out of RenderFile
so it is not rebuilt for every render. Define a package-level FuncMap containing
the existing isIPv4 and isIPv6 functions, then have RenderFile use that shared
map when calling template.New(name).Funcs(...).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e93804a1-73e4-4b72-bea4-64b9b3a738e3

📥 Commits

Reviewing files that changed from the base of the PR and between 079091d and 15604c0.

📒 Files selected for processing (3)
  • cmd/runtimecfg/render.go
  • pkg/config/node.go
  • pkg/render/render.go

Comment thread cmd/runtimecfg/render.go
Comment on lines +131 to +142
// Check if FRR peer file is provided for FRR config rendering
peerFilePath, _ := cmd.Flags().GetString("peer-file")
if peerFilePath != "" {
peerMapping, err := config.LoadFRRPeerMapping(peerFilePath)
if err != nil {
return err
}
frrConfig := config.BuildFRRRenderConfig(cfg, peerMapping)
return render.Render(outDir, args[1:], frrConfig)
}

return render.Render(outDir, args[1:], cfg)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Ignored error from GetString("peer-file").

peerFilePath, _ := cmd.Flags().GetString("peer-file")

discards the error return. Other flags in this function (e.g. GetUint16, GetString("cluster-config")) properly check and return errors.

As per path instructions, "Never ignore error returns."

🐛 Proposed fix
-	peerFilePath, _ := cmd.Flags().GetString("peer-file")
+	peerFilePath, err := cmd.Flags().GetString("peer-file")
+	if err != nil {
+		return err
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/runtimecfg/render.go` around lines 131 - 142, Handle the error returned
by cmd.Flags().GetString("peer-file") in the surrounding command logic,
returning it immediately if non-nil, consistent with the existing GetUint16 and
GetString("cluster-config") handling before using peerFilePath.

Source: Path instructions

Comment thread pkg/config/node.go
Comment on lines +102 to +111
// FRRPeer defines a BGP peer for FRR configuration rendering.
type FRRPeer struct {
PeerAddress string `json:"peerAddress"`
PeerASN int64 `json:"peerASN"`
Password string `json:"password,omitempty"`
BFDEnabled string `json:"bfdEnabled,omitempty"`
EBGPMultiHop string `json:"ebgpMultiHop,omitempty"`
HoldTime string `json:"holdTime,omitempty"`
KeepaliveTime string `json:"keepaliveTime,omitempty"`
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

BGP peer Password will be leaked into logs via the render pipeline.

FRRPeer.Password is plumbed through BuildFRRRenderConfigPeers → the FRR template context, and pkg/render/render.go's RenderFile logs the entire rendered template output line-by-line via log.Info(line). If the frr.conf.tmpl template emits the neighbor password (which it must, to configure BGP session auth), the plaintext password will be written to application logs. Consider redacting secret fields before logging rendered output, or excluding FRR-config rendering from the full-buffer log dump.

As per coding guidelines, "Flag logging that may expose passwords, tokens, API keys, PII (email, SSN, credit card), session IDs, internal hostnames, or customer data."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/config/node.go` around lines 102 - 111, Prevent FRR peer passwords from
being exposed by the render pipeline: update render.RenderFile so rendered FRR
configuration output is not logged wholesale, or redact the Password value
before each line is sent to log.Info. Preserve the password in the template
context and generated configuration, while ensuring the FRRPeer-to-Peers path
through BuildFRRRenderConfig cannot emit plaintext secrets in logs.

Source: Coding guidelines

@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@mkowalski: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 15604c0 link true /test security
ci/prow/e2e-metal-ipi-ovn-ipv6 15604c0 link true /test e2e-metal-ipi-ovn-ipv6

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants