Skip to content

chore(release): prepare v0.22.1 - #304

Merged
lance0 merged 1 commit into
mainfrom
release/v0.22.1
Oct 22, 2026
Merged

lance0 merged 1 commit into
mainfrom
release/v0.22.1

Conversation

@lance0

@lance0 lance0 commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Prepares the v0.22.1 patch release from main at 407c234. It ships the change from #303: the controller exports the pre-registered metric series at zero from startup, and PrefixdBlackholeReplaced clears an hour after the last replacement instead of latching.

This PR changes:

  • Cargo.toml and Cargo.lock: the version is 0.22.1, and only the prefixd lock entry changed.
  • CHANGELOG.md: the [0.22.1] - 2026-10-22 section, with a summary, upgrade notes linking the new guide section, and known limitations. The PR 303 entry is split: the alert change stays under Changed, and the startup zero series moved to Fixed.
  • docs/how-to/upgrading.md: a new v0.22.0 → 0.22.1 section and an updated intro. Existing anchors are unchanged.
  • README.md: the Status line names v0.22.1.
  • docs/reference/cli.md: the version example is 0.22.1.

Preconditions

just gate

flock <lock> taskset -c 24-31,56-63 env CARGO_BUILD_JOBS=16 PREFIXD_TEST_CPUSET=24-31,56-63 VITEST_MAX_WORKERS=8 just gate

The run exited 101, at its last stage. These stages passed:

  • fmt, python and alerts (promtool v3.15.0: 5 rules, unit tests SUCCESS)
  • proto
  • both Clippy feature sets
  • both test feature sets: GoBGP-only 493 + 246, all-features 530 + 246
  • MSRV 1.89.0
  • the release build
  • the frontend: lint, typecheck, 462 tests in 41 files, and the build
  • cargo audit, ignoring only RUSTSEC-2023-0071 as CI does
  • bun audit: no vulnerabilities
  • cargo deny: advisories, bans, licenses and sources ok
  • the GoBGP speaker fixtures

In the rustbgpd 0.79.0 fixtures, live_rustbgpd_leased_blackhole_renewal_restart_and_expiry failed with Client(StopContainer(RequestTimeoutError)) at its stop_with_timeout(Some(0)) call. The Docker daemon did not answer that stop request in time. That fixture run took 249 s, against about 40 s normally, and no test assertion failed. This PR changes no code. I kept the log and reran the speaker stage once:

PREFIXD_RUSTBGPD_TEST_VERSION=0.79.0 scripts/test-rustbgpd.sh

The rerun passed: integration_rustbgpd 12/12 in 39.8 s, and integration_rustbgpd_peer 4/4. The peer suite had not run in the gate, because cargo stopped after the failing binary.

Fixture pins

  • rustbgpd ghcr.io/lance0/rustbgpd:0.79.0@sha256:b2054d0ce98f3c8299b8de5be1920cd88a1ab2c85e02766927e487be0c60f8ff (source 60cb5c9910eb1380661dd4c80d55563b2d80099a). This is the only pin in ci.yml's rustbgpd matrix.
  • GoBGP jauderho/gobgp@sha256:42b8d0017237e388c55936efe1f23632365b24a31751f6e8815f93e12c4d18c2 (gobgpd 4.10.0): 8/8 integration tests and 9/9 e2e tests passed.

Upgrade proof: 0.22.0 → 0.22.1

The proof stack was the v0.22.0 tag's Compose file with the rustbgpd profile, run as a dedicated project with every container pinned to cpuset 24-31,56-63. The configuration was enforced mode with bearer auth. It ran:

  • ghcr.io/lance0/prefixd:0.22.0@sha256:1a395ada8535f0fae30bb6aef1f93412c4a70879df817819a28e57ac72211875
  • PostgreSQL 16.15 (postgres:16-alpine)
  • rustbgpd 0.79.0
  1. Seed on 0.22.0:

    • three manual mitigations: police UDP/53, discard TCP/80,443, and discard UDP/123;
    • two FastNetMon detector events: an ICMP flood and a SYN flood on 443;
    • one withdrawal of the UDP/123 mitigation.

    The result was 4 active mitigations (2 manual, 2 detector), 1 withdrawn, and 4 FlowSpec routes in rustbgpd. Health was healthy at version 0.22.0.

  2. Baseline: I captured the mitigation rows (ID, status, action, victim, origin mode, match, action parameters, expiry), the pending withdrawals (0), the migration list (1–18) and the normalized local FlowSpec RIB. I also took a pg_dump and a /metrics snapshot.

  3. Upgrade: I followed the guide's Compose step 4, replacing only the controller with the 0.22.1 build. That image is the repository Dockerfile's runtime stage around the gate's locked release binaries, which report prefixd 0.22.1.

  4. Results:

    • Migrations: unchanged. Startup logged versions: [1, ..., 18], and prefixdctl migrations lists 18, all applied at the original 0.22.0 start.
    • Fence: acquired.
    • Health: healthy, version 0.22.1. prefixdctl status showed daemon 0.79.0 ready and peer observation connected.
    • /openapi.json: info.version is 0.22.1.
    • Reconciliation: the first two passes (runs_total{status="success"} 1 → 2) made no repairs: reconciliation_repairs_total was 0/0 and unknown_local_routes{kind="flowspec"} was 0. The repair/failure grep printed nothing, and the controller logged no WARN or ERROR lines.
    • State: the mitigation rows, pending withdrawals, migration list and normalized RIB are identical to the baseline. The same five mitigation IDs are present with the same statuses.
    • Zero series: right after the 0.22.1 start, with no blackholes and so no possible replacement, /metrics showed:
      prefixd_blackhole_replaced_total{pop="iad1"} 0
      prefixd_injection_lease_renewals_total{result="error|not_live|success"} 0
      prefixd_injection_lease_state{state="expired|live|none|not_renewing|renewal_failing"} 0
      prefixd_reconciliation_repairs_total{status="error|success"} 0
      prefixd_reconciliation_runs_total{status="error"} 0
      
    • Negative control: the 0.22.0 baseline /metrics had none of prefixd_blackhole_replaced_total, prefixd_injection_lease_renewals_total, prefixd_injection_lease_state or prefixd_reconciliation_repairs_total. It had only reconciliation_runs_total{status="success"}. The new metric families in 0.22.1 are blackhole_replaced_total, injection_lease_renewals_total, injection_lease_state, mitigations_active, reconciliation_repairs_total and signal_group_decay_refreshes_total.
  5. Teardown: I removed every container, volume and network of the proof project, and the candidate image.

Release-notes preview (scripts/release-notes.py 0.22.1)

prefixd 0.22.1 makes `PrefixdBlackholeReplaced` clear an hour after the last replacement instead of latching until prefixd restarts, and exports the pre-registered metric series at zero from startup, as the metrics reference already described. It adds no migration, keeps rustbgpd 0.79.0 and loads an unchanged 0.22.0 configuration.

### Upgrade notes

- Follow [v0.22.0 → 0.22.1](https://github.com/lance0/prefixd/blob/v0.22.1/docs/how-to/upgrading.md#v0220--0221) in the upgrade guide: replace the controller and dashboard, then copy the new `grafana/prometheus-alerts.yml` to your Prometheus or recreate the Compose Prometheus. No migration or adoption step runs, the configuration is unchanged and rustbgpd stays at 0.79.0.

### Known limitations

- TTL expiry needs the running controller. Unleased FlowSpec rules and blackholes stay announced if prefixd stops while the speaker stays up; the leased modes, which bound that to one lease, are opt-in and rustbgpd-only.
- The replacement counter is local to the process. A restart resets it without firing or clearing a replacement still inside the alert's hour, and a replacement before Prometheus first scrapes the process is not alerted.
- The 0.22.0 known limitations otherwise still apply, except that `PrefixdBlackholeReplaced` no longer latches.

### Changed

- `PrefixdBlackholeReplaced` no longer latches until prefixd restarts. It fires on a replacement within the last hour and clears an hour after the last one. prefixd exports `prefixd_blackhole_replaced_total{pop}` for its configured POP at zero from startup, so the first replacement fires the alert. Copy the new `grafana/prometheus-alerts.yml` to your Prometheus.

### Fixed

- The controller now exports the pre-registered metric series, such as lease renewal and state, export disposition, unexported reason and reconciliation status, at zero from startup, as the metrics reference already described. Before, each series appeared only at its first event.

Known limitations

These are as stated in the notes above. The 0.22.0 latching limitation is removed. The process-local reset and the pre-first-scrape gap of the new rule are listed explicitly; both are already documented in the Grafana guide. The guide's downgrade note says to restore the 0.22.0 alert file when rolling back, because 0.22.0 creates the POP series only at the first replacement.

The CHANGELOG date is 2026-10-22 UTC. Correct it if this merges on a later UTC day.

Bump the version to 0.22.1 and roll the CHANGELOG. Add the v0.22.0 to
0.22.1 upgrade guide section, point the README status and intro at it,
and move the CLI version example.
@lance0
lance0 marked this pull request as ready for review October 22, 2026 02:02
@lance0
lance0 merged commit 87a225c into main Oct 22, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant