[PR #5925] Add NETBIRD_SKIP_MIGRATIONS env var to gate AutoMigrate (HA / multi-master) #28758

Open
opened 2026-08-05 08:06:53 -04:00 by saavagebueno · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/netbirdio/netbird/pull/5925
Author: @dfarrel1
Created: 4/19/2026
Status: 🔄 Open

Base: mainHead: skip-migrations-env-var


📝 Commits (1)

  • 00f3b92 [management] Add NETBIRD_SKIP_MIGRATIONS env var to gate AutoMigrate

📊 Changes

2 files changed (+19 additions, -7 deletions)

View changed files

📝 management/internals/server/boot.go (+2 -1)
📝 management/server/activity/store/sql_store.go (+17 -6)

📄 Description

What

Adds support for an opt-in env var NETBIRD_SKIP_MIGRATIONS=true that suppresses gorm.AutoMigrate() calls at the two production call sites:

  • management/internals/server/boot.go — main store (netbird DB)
  • management/server/activity/store/sql_store.go — activity / events store (netbird_events DB)

Default behavior is unchanged: env var unset → AutoMigrate runs. Single-instance deployments are entirely unaffected.

The internal skipMigration bool plumbing already exists in store.NewStore and store.NewSqlStore — every production caller hardcodes false. This PR exposes the existing hook via env var and adds equivalent gating to the activity store, which had no skipMigration parameter at all.

Why

Operators running multi-master Postgres logical replication (Spock, pgactive, BDR) need to control which node runs DDL during a coordinated upgrade. Logical replication replicates DML but not DDL — if every node runs AutoMigrate simultaneously on startup of a new version, races on DDL execution and partial-schema replication conflicts can break the cluster.

The standard pattern (documented by pgEdge: "Managing DDL Migrations in a Multi-master Database") is to gate ORM auto-migrations behind an env var and run them from one node only during an upgrade window.

This is opt-in. Single-instance Netbird users do not encounter the env var and see no behavior change. Only operators who explicitly choose multi-master (a topology Netbird does not officially support — see #1584) will set it.

Affected paths

  • management/internals/server/boot.go (1 line + 1 import)
  • management/server/activity/store/sql_store.go (5 lines, 1 log message — os already imported)

Geolocation / GeoIP

management/server/geolocation/database.go:importCsvToSqlite also calls AutoMigrate, but uses SQLite per-instance for GeoIP CSV import — not shared across sites — so it does not need gating for multi-master.

Tests

Existing tests pass skipMigration: false explicitly in calls to NewStore / NewSqlStore. The new env-var read in boot.go is at the production call site only (not test code), so test behavior is preserved. The activity-store gate is internal to NewSqlStore; tests that need to run against a fresh DB simply leave NETBIRD_SKIP_MIGRATIONS unset (default).

Risk

  • Operator misuse on single-instance: setting the env var on a single-node deployment skips schema upgrades; queries against new columns fail. Mitigation: the activity-store path logs an info message at startup when the flag is active; documentation should call out that this var is only for multi-master operators.
  • Forgotten flag: operator sets it for an upgrade, forgets to unset. Mitigation: the recommended deployment pattern is a wrapper entrypoint that sets the env var per-startup based on a marker file (so persistent env-var state is not the norm). Out of scope for this PR.

These risks already exist in any multi-master Postgres deployment. This PR gives operators a tool to manage them; it does not create them.

Out of scope

  • Documenting multi-master HA. That conversation belongs in #1584.
  • A higher-level "upgrade orchestration" feature inside the management server. The env var keeps orchestration responsibility with the operator's tooling (Ansible / k8s / etc.).

Relates to

  • #1584 — Netbird Management HA (community discussion)

Summary by CodeRabbit

  • New Features
    • Added support for the NETBIRD_SKIP_MIGRATIONS environment variable: when set to "true", startup will skip database schema migrations (applies to activity store with Postgres engine).
    • Emits an informational log when migrations are intentionally skipped.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/netbirdio/netbird/pull/5925 **Author:** [@dfarrel1](https://github.com/dfarrel1) **Created:** 4/19/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `skip-migrations-env-var` --- ### 📝 Commits (1) - [`00f3b92`](https://github.com/netbirdio/netbird/commit/00f3b9299b4e779d24fa0ba2bb1ed580684f4ae6) [management] Add NETBIRD_SKIP_MIGRATIONS env var to gate AutoMigrate ### 📊 Changes **2 files changed** (+19 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `management/internals/server/boot.go` (+2 -1) 📝 `management/server/activity/store/sql_store.go` (+17 -6) </details> ### 📄 Description ### What Adds support for an opt-in env var `NETBIRD_SKIP_MIGRATIONS=true` that suppresses `gorm.AutoMigrate()` calls at the two production call sites: - `management/internals/server/boot.go` — main store (`netbird` DB) - `management/server/activity/store/sql_store.go` — activity / events store (`netbird_events` DB) Default behavior is unchanged: env var unset → AutoMigrate runs. Single-instance deployments are entirely unaffected. The internal `skipMigration bool` plumbing already exists in `store.NewStore` and `store.NewSqlStore` — every production caller hardcodes `false`. This PR exposes the existing hook via env var and adds equivalent gating to the activity store, which had no `skipMigration` parameter at all. ### Why Operators running multi-master Postgres logical replication (Spock, pgactive, BDR) need to control which node runs DDL during a coordinated upgrade. Logical replication replicates DML but **not** DDL — if every node runs `AutoMigrate` simultaneously on startup of a new version, races on DDL execution and partial-schema replication conflicts can break the cluster. The standard pattern (documented by pgEdge: ["Managing DDL Migrations in a Multi-master Database"](https://www.pgedge.com/blog/managing-ddl-migrations-in-a-multi-master-database)) is to gate ORM auto-migrations behind an env var and run them from one node only during an upgrade window. This is opt-in. Single-instance Netbird users do not encounter the env var and see no behavior change. Only operators who explicitly choose multi-master (a topology Netbird does not officially support — see #1584) will set it. ### Affected paths - `management/internals/server/boot.go` (1 line + 1 import) - `management/server/activity/store/sql_store.go` (5 lines, 1 log message — `os` already imported) ### Geolocation / GeoIP `management/server/geolocation/database.go:importCsvToSqlite` also calls `AutoMigrate`, but uses **SQLite per-instance** for GeoIP CSV import — not shared across sites — so it does not need gating for multi-master. ### Tests Existing tests pass `skipMigration: false` explicitly in calls to `NewStore` / `NewSqlStore`. The new env-var read in `boot.go` is at the production call site only (not test code), so test behavior is preserved. The activity-store gate is internal to `NewSqlStore`; tests that need to run against a fresh DB simply leave `NETBIRD_SKIP_MIGRATIONS` unset (default). ### Risk - *Operator misuse on single-instance:* setting the env var on a single-node deployment skips schema upgrades; queries against new columns fail. Mitigation: the activity-store path logs an info message at startup when the flag is active; documentation should call out that this var is only for multi-master operators. - *Forgotten flag:* operator sets it for an upgrade, forgets to unset. Mitigation: the recommended deployment pattern is a wrapper entrypoint that sets the env var per-startup based on a marker file (so persistent env-var state is not the norm). Out of scope for this PR. These risks already exist in any multi-master Postgres deployment. This PR gives operators a tool to manage them; it does not create them. ### Out of scope - Documenting multi-master HA. That conversation belongs in #1584. - A higher-level "upgrade orchestration" feature inside the management server. The env var keeps orchestration responsibility with the operator's tooling (Ansible / k8s / etc.). ### Relates to - #1584 — Netbird Management HA (community discussion) --- <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for the NETBIRD_SKIP_MIGRATIONS environment variable: when set to "true", startup will skip database schema migrations (applies to activity store with Postgres engine). * Emits an informational log when migrations are intentionally skipped. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
saavagebueno added the pull-request label 2026-08-05 08:06:53 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#28758