Config Tracking

10.3.3.1 Config Tracking

The configurator does not just generate a one-time config archive — it continuously monitors the live database configuration and tracks drift between what replication-manager expects to be deployed and what is actually running. This lets you detect unplanned changes, preserve intentional deviations, and keep config in a known state across rolling restarts and node replacements.


10.3.3.2 Three-Layer Config System

Each server's data directory contains three override files that sit in etc/mysql/custom.d/ inside the config archive (read after all tag-generated fragments):

{datadir}/{cluster}/{host_port}/
├── 01_preserved.cnf    server-specific locked values
├── 02_delta.cnf        calculated drift (expected vs deployed)
└── 03_agreed.cnf       manually accepted deviations

These files are not generated from tags — they represent the state of the deployed server relative to the configurator's expectations, and are managed by replication-manager automatically (with overrides you can set via API or GUI).

10.3.3.2.1 01_preserved.cnf — Server-specific locked values

Variables listed here are frozen for this server. The configurator will not attempt to change them during regeneration. Use this for server-specific paths, hardware-specific tuning, or any setting that legitimately differs from the rest of the cluster.

Example: a server with a different disk layout needs a custom innodb_data_home_dir:

[mysqld]
# Preserved — non-standard disk layout on this host
innodb_data_home_dir = /data2/mysql

10.3.3.2.2 02_delta.cnf — Calculated drift

Written automatically by replication-manager on every monitoring tick. It contains variables where the deployed (on-disk) value differs from the expected (tag-generated) value. This file tells you exactly what diverged and by how much.

The delta file has a 4-layer safety framework for writing runtime values:

  1. Empty values are never written
  2. Read-only variables (e.g. version, have_ssl) are excluded
  3. Only whitelisted runtime-fallback variables are included
  4. Failed servers are excluded to avoid partial state

If the delta is empty after a config regeneration and restart, the server is fully converged.

10.3.3.2.3 03_agreed.cnf — Accepted compliance values (internal tracking)

When an operator clicks Accept on a delta variable, it means "I agree with the compliance value — apply it on next restart." The variable is removed from 02_delta.cnf and tracked in 03_agreed.cnf so it doesn't reappear in delta before the database restarts.

agreed.cnf is NOT deployed to the database config. An empty agreed.cnf is written to custom.d/ to overwrite any stale entries from previous versions. The real agreed.cnf stays in replication-manager's data directory as internal state.

After the database restarts, the compliance value takes effect (nothing overrides it), the runtime matches compliance, and the agreed entry is no longer needed.

agreed.cnf also surfaces unknown variables — variables in the compliance tags that the database doesn't recognize. These are detected by the dbjobs validation (mariadbd --help --verbose) and shown with a red "UNKNOWN" badge so the operator can fix the compliance tag (e.g. add loose_ prefix).

Accepting a variable via API:

POST /api/clusters/{clusterName}/servers/{serverName}/variables-accept?variableName=max_connections

10.3.3.3 How the Variable Diff Is Computed

The variable diff — the heart of config tracking — compares two snapshots: what the compliance module expects the config to be, and what the database server actually has deployed. Understanding when and how these snapshots are generated is key to using the configurator effectively.

10.3.3.3.1 The Two Config Snapshots

Each server's data directory contains two temporary files used for comparison:

{datadir}/{cluster}/{host_port}/
├── dummy.cnf      ← "expected" config (what tags generate)
├── current.cnf    ← "deployed" config (what the server is running)

dummy.cnf — Expected config:

Generated by running mariadbd --defaults-file=<dummy> --print-defaults against a synthetic config file that includes only the tag-generated conf.d/ fragments. This produces the full list of variables as the compliance module would configure them — without any preserved/delta/agreed overrides. The dbjobs script fetches a fresh copy of the config tarball, creates a dummy my.cnf that includes only conf.d/, and sends the output to replication-manager via TCP.

current.cnf — Deployed config:

Generated by running mariadbd --defaults-file=<actual my.cnf> --print-defaults on the database host. This reads the server's real config file chain (including conf.d/ from tags + custom.d/ from preserved/delta/agreed overrides) and produces the full list of variables the server would start with. Also sent to replication-manager via TCP by the dbjobs script.

10.3.3.3.2 When Snapshots Are Refreshed

The snapshots are refreshed when a config refresh cookie is set. This happens:

Trigger When
Server init First time replication-manager connects to a server
Config change detected Checksum of deployed config files changes
Tag added/removed Operator modifies DB tags in the configurator
Compliance accepted New compliance module applied
Manual refresh Operator clicks refresh config in the GUI
Variable preserved/accepted After any variable state change

When the cookie is set, the dbjobs script (via SSH or container entrypoint) detects it via need-config-refresh API, runs the print-defaults for both dummy and current configs, and streams the results back to replication-manager.

10.3.3.3.3 The Diff Calculation

After both dummy.cnf and current.cnf are received:

  1. Parse both files — each variable name is normalized (hyphens → underscores, loose_ prefix stripped) and stored in a VariablesMap with two values per variable: Config (from dummy.cnf) and Deployed (from current.cnf)

  2. Compare — for each variable, IsEqual() checks if Config.String() == Deployed.String(). A variable is "in diff" if:

    • Config and Deployed both exist but have different values
    • Config exists but Deployed doesn't (variable expected but missing)
    • Deployed exists but Config doesn't (variable present on server but not in compliance — may be deprecated)
  3. Apply preserved state — variables in 01_preserved.cnf (server-specific) and preserved_variables.cnf (cluster-wide) are loaded. Preserved variables are excluded from the delta.

  4. Write delta — remaining differences are written to 02_delta.cnf. Variables with no Config counterpart (deployed but not in compliance) are prefixed with loose_ so they remain valid across version upgrades.

  5. Copy to tarball01_preserved.cnf and 02_delta.cnf are included in the next config.tar.gz generation under etc/mysql/custom.d/, where MariaDB reads them after the tag-generated conf.d/. An empty 03_agreed.cnf is also written to overwrite any stale entries from previous versions — the real agreed.cnf stays in replication-manager's data directory as internal state.

10.3.3.3.4 Variable States in the GUI

Each variable in the diff view has one of these states:

State Meaning File Deployed to DB
Delta Deployed differs from expected, no action taken yet 02_delta.cnf Yes — protects current DB value
Preserved Operator chose to keep the deployed value 01_preserved.cnf Yes — overrides compliance tag
Accepted Operator chose to accept the compliance value 03_agreed.cnf No — internal tracking only
Unknown Variable in compliance not recognized by DB 03_agreed.cnf No — scrubbed from delta/preserved
Dropped Variable was deprecated and operator accepted removal dropped_variables.json No

10.3.3.3.5 The loose_ Prefix — Safe Variable Naming

MariaDB and MySQL handle the loose_ prefix specially:

  • Known variable: strips loose_, applies the value normally
  • Unknown variable: silently ignores it instead of refusing to start

This makes loose_ essential for cross-vendor compatibility (MySQL-only variables on MariaDB, or vice versa) and version safety (variables removed in newer versions).

Where replication-manager uses loose_:

Context When loose_ is added
02_delta.cnf Variables with delta:no-config (deployed but not in compliance) are automatically prefixed with loose_
01_preserved.cnf Variables with no compliance counterpart (Config == nil) get loose_ prefix
Compliance tags Tag authors should use loose_ for any variable that may not exist on all target DB versions/vendors

Without loose_, unknown variables crash the database on restart. This is the most common cause of failed rolling restarts after compliance tag changes.

Example — MySQL vs MariaDB:

A compliance tag that works on both vendors:

[mysqld]
# MySQL-only — MariaDB ignores it silently
loose_binlog_rows_query_log_events = 1

[mariadb]
# MariaDB-only — MySQL ignores the [mariadb] section entirely
loose_binlog_annotate_row_events = 1

Without the loose_ prefix, deploying binlog_rows_query_log_events to a MariaDB server would prevent it from starting.

Unknown variable detection: The dbjobs script runs mariadbd --help --verbose to detect variables in the compliance config that the database doesn't recognize. These are flagged in the configurator's agreed panel with a red "UNKNOWN" badge. The fix is to either add loose_ prefix to the variable in the compliance tag, or remove it entirely.

When replication-manager reads cnf files back, normalizeConfigVarName() strips the loose_ prefix so the variable name matches correctly for comparison across all three files.


10.3.3.4 How It Works — Variable Lifecycle

When the configurator detects a difference between the compliance tags and the running database, the variable enters the delta. From there, the operator decides what to do:

Accept — "The compliance value is correct, apply it on next restart."

  • Variable removed from delta (compliance tag takes effect on restart since nothing overrides it)
  • Tracked in agreed.cnf to suppress delta regeneration until restart
  • After restart: runtime matches compliance, diff gone, agreed entry no longer needed

Preserve — "My DB value is correct, keep it permanently."

  • Variable moves to 01_preserved.cnf (deployed to DB, overrides compliance tag)
  • Removed from delta
  • Survives tag changes — the preserved value always wins

Example — encryption setup:

  1. You add the encryption tag to enable table encryption
  2. Rolling restart deploys the encryption config
  3. You remove the encryption tag (tag was only needed for initial setup)
  4. Delta shows all encryption variables (innodb_encrypt_tables, etc.) as delta:no-config
  5. You click Preserve on each — the encryption settings move to 01_preserved.cnf
  6. Delta is clean. Encryption persists even without the tag.

10.3.3.5 Dependency on dbjobs

The config tracking system requires the dbjobs script running on each database host. The configurator cannot compute the delta on its own — it needs dbjobs to:

  1. Fetch the compliance config from replication-manager and run mariadbd --print-defaults to produce dummy.cnf (what the tags expect)
  2. Read the running config via mariadbd --print-defaults on the actual my.cnf to produce current.cnf (what the DB is running)
  3. Validate for unknown variables via mariadbd --help --verbose to detect variables the DB doesn't recognize
  4. Stream both outputs back to replication-manager via TCP

Without dbjobs, the dummy.cnf and current.cnf files are empty, the delta is empty, and the configurator shows no differences. The dbjobs script runs automatically on provisioned servers (via container entrypoint or SSH). For on-premise setups, ensure dbjobs is scheduled via cron or systemd.

Unknown variable detection: during step 3, dbjobs checks whether the database binary recognizes all variables in the compliance config. Variables that are unknown (e.g. MySQL-only variable on MariaDB, or a variable removed in a newer version) are flagged with # unknown:varname=value markers. Replication-manager receives these markers and:

  • Removes the variable from preserved if it was there (would crash DB on restart)
  • Excludes it from delta (would crash DB on restart)
  • Surfaces it in agreed.cnf with a red "UNKNOWN — not recognized by DB" badge

The operator should fix the compliance tag (add loose_ prefix or remove the variable) to resolve the issue.


10.3.3.6 Preserved Variables — Three Levels

Preserved variables can be defined at three levels. When they conflict, higher priority wins:

Priority Level Where stored How to manage
1 (highest) Per-server {datadir}/{cluster}/{host_port}/01_preserved.cnf Variables tab → Preserve button on a specific server
2 Cluster-wide {working-dir}/{cluster-name}/preserved_variables.cnf Settings → Preserved Variables Editor, or API
3 (lowest) Legacy config prov-db-config-preserve-vars in TOML Settings → Preserved Configs tab (deprecated)

10.3.3.4.1 Per-Server Preserved Variables (Priority 1)

Set from the Variables tab in the ClusterDB page. When you click "Preserve" on a variable for a specific server, the value is written to that server's 01_preserved.cnf. This overrides any cluster-wide setting for the same variable on this server.

API:

POST /api/clusters/{cluster}/servers/{server}/variables-preserve?variableName=max_connections
POST /api/clusters/{cluster}/servers/{server}/variables-accept?variableName=max_connections
POST /api/clusters/{cluster}/servers/{server}/variables-clear?variableName=max_connections

10.3.3.4.2 Cluster-Wide Preserved Variables (Priority 2)

Stored in preserved_variables.cnf in the cluster's working directory. These apply to all servers in the cluster unless a server has its own per-server override or is explicitly excluded.

The file format is a [mysqld] section with optional per-server exclusions:

[mysqld]
# Preserved across all servers
max_connections = 500
innodb_buffer_pool_size = 4G

# Exclude specific servers from this variable
# max_connections.exclude = db1234567890,db9876543210

Managed via:

  • GUI: Settings → Preserved Variables Editor
  • API: GET /POST /api/clusters/{cluster}/settings/preserved-variables-cnf

Changes are applied immediately — replication-manager reloads preserved variables without restart.

10.3.3.4.3 Legacy Config Key (Priority 3 — deprecated)

prov-db-config-preserve-vars = "innodb_data_home_dir=/var/lib/mysql;max_connections=1000"

Semicolon-separated list in the TOML config. Still functional but deprecated. On first boot, if preserved_variables.cnf doesn't exist yet and this key is set, replication-manager automatically migrates the values to preserved_variables.cnf. Variable names are normalized (lowercase, hyphens to underscores, loose_ prefix stripped) during migration.

After migration, the preserved_variables.cnf takes priority and the legacy key can be removed from the TOML.

10.3.3.4.4 How Preserved Variables Are Applied

On every config refresh cycle:

  1. Load per-server 01_preserved.cnf → mark variables as PreservedSource: "server-specific" (Priority 1)
  2. Load cluster-wide preserved_variables.cnf → apply only to variables NOT already set by per-server (Priority 2). Check server exclusions.
  3. Load legacy prov-db-config-preserve-vars → apply only to variables NOT already set by either of the above (Priority 3)
  4. Write delta 02_delta.cnf → all remaining differences (not preserved, not accepted, not dropped)

10.3.3.5 Configuration Keys

prov-db-config
Description Enable the configurator's config tracking and deployment. When false, dbjobs skips all config-related work (no print-defaults, no delta computation, no config push). All other dbjobs features (backups, optimize, log collection) continue to work normally. Use this when you manage your own my.cnf and don't use the tag-based configurator.
Type Boolean
Default true

Available as a toggle in Settings > Scheduler > Enable Configurator.

prov-db-config-preserve
Description Include the override files (01_preserved.cnf, 02_delta.cnf, and an empty 03_agreed.cnf) in the generated config.tar.gz under custom.d/. When false, the config tarball only contains tag-generated fragments — a clean config with no overrides. Only relevant when prov-db-config is true.
Type Boolean
Default true
prov-db-config-preserve-vars (deprecated)
Description Semicolon-separated list of variable names (or name=value pairs) to preserve. Deprecated — use preserved_variables.cnf instead. Values are auto-migrated to preserved_variables.cnf on first boot if the file doesn't exist yet.
Type String
Default ""

10.3.3.6 GUI Actions on Variables

Variable actions can be performed from two places in the GUI, both working per-server:

10.3.3.6.1 Configurator Tab — Config Override Files

The Config Override Files panel in the Configurator tab shows the three config files (01_preserved.cnf, 02_delta.cnf, 03_agreed.cnf) for each server. Select a server from the dropdown to view its config state.

Each variable in the delta panel has two action buttons:

Button Action Effect
Accept (checkmark) Accept the compliance value Variable removed from delta. Compliance tag value applies on next DB restart. Tracked in agreed.cnf until restart.
Preserve (lock) Keep the current DB value Variable moves to 01_preserved.cnf (deployed to DB). Removed from delta. DB keeps its current value across restarts.

Variables in the preserved panel have a Remove (trash) button that clears the preservation and returns the variable to delta.

10.3.3.6.2 Server Variables Tab — Runtime vs Compliance

The Variables tab in the ClusterDB page (per-server view) shows every runtime variable alongside its compliance value. This gives a complete side-by-side view of what the server is running vs what the configurator expects.

From this tab you can:

  • Preserve a variable — keeps the current runtime value, overrides compliance
  • Accept a variable — agrees with the compliance value, applies on next restart
  • Edit a variable value — set a custom preserved value

This is useful for reviewing the full variable list rather than just the differences, and for acting on variables that may not appear in the delta (e.g. variables where the values match but you want to lock them).


10.3.3.7 Unknown Variable Detection

The dbjobs script validates the compliance config against the database binary after fetching it. It runs mariadbd --help --verbose to detect variables that the database doesn't recognize.

Unknown variables are:

  • Scrubbed from preserved (would crash DB on restart)
  • Excluded from delta (would crash DB on restart)
  • Shown in agreed with a red "UNKNOWN — not recognized by DB" badge

Common causes:

  • MySQL-only variable on a MariaDB server (or vice versa)
  • Variable removed in a newer database version
  • Typo in the compliance tag

To fix: add loose_ prefix to the variable in the compliance tag (makes the DB ignore it silently if unrecognized), or remove it from the tag.


10.3.3.9 Monitoring Config Changes

replication-manager detects when the deployed config changes on disk (checksum comparison). When a change is detected:

  1. A config refresh cookie is set for the affected server
  2. The dbjobs script re-runs mariadbd --print-defaults for both dummy and current configs
  3. Preserved variables are reloaded from all three levels
  4. The delta file (02_delta.cnf) is recalculated
  5. A log entry is written at INFO level

This happens within the normal monitoring loop interval (monitoring-ticker), so config drift is detected quickly without polling overhead.


10.3.3.10 Reading Variables from Config Files

Before the database is running (e.g., during provisioning or after a crash), replication-manager can read configuration values directly from the deployed .cnf files rather than from SHOW VARIABLES. This allows it to know the intended configuration even for offline servers.

The read order mirrors MySQL's include chain:

  1. Main my.cnf with includedir directives
  2. conf.d/ fragments (tag-generated)
  3. custom.d/ overrides (preserved, delta, agreed)

Variables read this way are used for topology decisions, failover calculations, and provisioning validation.