Class: Mt::Wall::Reconciler
- Inherits:
-
Object
- Object
- Mt::Wall::Reconciler
- Defined in:
- lib/mt/wall/reconciler.rb
Overview
Orchestrates the Terraform-style workflow for a single device:
1. Compiler turns the Configuration into the DESIRED DesiredState.
2. Transport#fetch reads the CURRENT DesiredState (DesiredState::MANAGED_PATHS).
3. Plan.diff produces the (identity-matched, order-aware) change set.
4. (apply only) Transport#apply executes the Plan under commit-confirm.
‘#plan` is read-only and safe to run anywhere (e.g. CI on a PR). `#apply` mutates the device and should run only on the trusted path (e.g. CI on merge to the main branch).
FAIL-SAFE APPLY: because mt-wall owns and replaces the whole filter/nat table over a network path that runs THROUGH that very firewall, apply uses a DEVICE-SIDE commit-confirm envelope (see Transport::Base) — client-side rollback is undeliverable if the link drops. The envelope is:
1. ARM: transport.arm_auto_revert(snapshot, timeout:) — back up the
managed tables on the device and schedule a self-restore after timeout;
2. APPLY: transport.apply(plan.operations) in fail-safe order (open
access + mgmt-protect BEFORE tightening; create-before-delete;
default-drop LAST — encoded in the Plan, re-asserted here);
3. HEALTH-CHECK: the manager re-reaches the device to confirm the
session survived;
4. CONFIRM: transport.confirm(handle) cancels the scheduled revert. If
the health-check fails or the link is lost, CONFIRM never runs and the
device-side job auto-reverts at timeout.
Constant Summary collapse
- DEFAULT_REVERT_TIMEOUT =
Default seconds the device-side auto-revert waits before self-restoring if the manager never confirms. Overridable per device via ‘options`.
120- HEALTH_CHECK_MAX_ATTEMPTS =
Post-apply health-check resilience. A box that has just had its filter table replaced can briefly drop a probe (sessions re-establishing, connection-tracking settling) before it is genuinely reachable. The check therefore RETRIES a bounded number of times with a short backoff before declaring the apply unhealthy (and letting the device-side auto-revert fire). Kept small and time-boxed so it never blocks long: at most MAX_ATTEMPTS probes, never exceeding TOTAL_TIMEOUT seconds.
3- HEALTH_CHECK_BACKOFF =
0.5- HEALTH_CHECK_TOTAL_TIMEOUT =
5.0
Instance Method Summary collapse
-
#apply(plan = nil) ⇒ Plan
Apply the plan under the device-side commit-confirm envelope (arm_auto_revert -> apply -> health-check -> confirm; auto-revert fires on the device if confirm never runs).
-
#initialize(configuration:, device:, transport:, sleeper: method(:sleep)) ⇒ Reconciler
constructor
A new instance of Reconciler.
-
#plan ⇒ Plan
The changes needed to converge the device (no mutation).
Constructor Details
#initialize(configuration:, device:, transport:, sleeper: method(:sleep)) ⇒ Reconciler
Returns a new instance of Reconciler.
49 50 51 52 53 54 |
# File 'lib/mt/wall/reconciler.rb', line 49 def initialize(configuration:, device:, transport:, sleeper: method(:sleep)) @configuration = configuration @device = device @transport = transport @sleeper = sleeper end |
Instance Method Details
#apply(plan = nil) ⇒ Plan
Apply the plan under the device-side commit-confirm envelope (arm_auto_revert -> apply -> health-check -> confirm; auto-revert fires on the device if confirm never runs).
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/mt/wall/reconciler.rb', line 67 def apply(plan = nil) plan ||= self.plan return plan if plan.empty? # nothing to converge: skip the whole envelope # 1. ARM the device-side auto-revert. A nil handle => offline/no-op # transport (e.g. Rsc): apply and return, no envelope to run. handle = @transport.arm_auto_revert(DesiredState::MANAGED_PATHS, timeout: revert_timeout) # 2. APPLY (operations are pre-sorted by Plan for fail-safe ordering). # If the link drops here the exception propagates and CONFIRM never # runs, so the device self-reverts at timeout. @transport.apply(plan.operations) # 3. HEALTH-CHECK + 4. CONFIRM (skipped for an offline/no-op transport). confirm_or_revert(handle) unless handle.nil? plan end |