Class: Mt::Wall::Plan
- Inherits:
-
Object
- Object
- Mt::Wall::Plan
- Defined in:
- lib/mt/wall/plan.rb
Overview
The diff between a desired and a current DesiredState: an ordered list of operations. A Plan is both printable (for ‘mt-wall plan`) and executable (handed to a Transport by `apply`).
IDENTITY MATCHING — ‘(tag, ordinal)`: filter/nat rows are matched desired<->current by their content-only `mt-wall:<stable-hash>` identity tag (in `comment`), never by the opaque device `.id`. The tag is content-only, so two rows CAN legitimately share a tag (different position, same content). Matching therefore keys on the pair `(tag, ordinal)` where `ordinal` is the 0-based occurrence index of that tag within its (path, chain), assigned in document order on each side. The Compiler collapses EXACT duplicates (same content + chain) into ONE row, so a surviving ordinal > 0 is a deliberate, semantically distinct repeat. Match outcomes per `(tag, ordinal)`:
* present in desired, absent in current => :create;
* a current mt-wall-tagged `(tag, ordinal)` absent from desired => :delete;
* matched pair, differing normalized payload => :update;
* matched pair in the wrong position => :move.
The ‘.id` is carried in the payload of :update/:delete/:move only so the transport can address the existing row (PATCH/DELETE/move target it by id).
ORDERING IS FIRST-CLASS because mt-wall owns the whole filter/nat table and rule order is semantically load-bearing (RouterOS evaluates top-down). Operations therefore include explicit placement; the place-before anchor is resolved against the ‘(tag, ordinal)` of the row it must precede:
* :create carries `position` (place-before anchor) so a new rule lands
at the right index;
* :move reorders an existing row to sit before `position`.
APPLY-ORDER INVARIANTS (the Plan is emitted already sorted so a transport can execute it verbatim; see Reconciler):
1. create/insert the stateful preamble, accept rules and the
management-protection rule BEFORE any tightening;
2. create-before-delete (never delete an old rule before its
replacement exists);
3. install default-DROP policy rows LAST.
Defined Under Namespace
Constant Summary collapse
- ID_KEY =
RouterOS row handle. Lives ONLY on fetched current rows; carried into the payload of :update/:delete/:move so the transport can address the row.
:".id"
Instance Attribute Summary collapse
-
#operations ⇒ Object
readonly
Returns the value of attribute operations.
-
#path ⇒ Object
readonly
RouterOS resource path (managed table).
-
#position ⇒ Object
readonly
place-before anchor: the ‘(tag, ordinal)` pair (or `.id`) of the row this one must precede; nil = append at the table’s tail.
Class Method Summary collapse
-
.diff(desired:, current:) ⇒ Plan
Build a Plan by diffing two DesiredState instances.
Instance Method Summary collapse
-
#action(value) ⇒ Object
:create, :update, :delete or :move.
- #empty? ⇒ Boolean
-
#initialize(operations = []) ⇒ Plan
constructor
A new instance of Plan.
-
#payload(value) ⇒ Object
the resource attributes; for :update/:delete/:move it also carries the existing row’s ‘.id`.
Constructor Details
#initialize(operations = []) ⇒ Plan
Returns a new instance of Plan.
65 66 67 |
# File 'lib/mt/wall/plan.rb', line 65 def initialize(operations = []) @operations = operations end |
Instance Attribute Details
#operations ⇒ Object (readonly)
Returns the value of attribute operations.
63 64 65 |
# File 'lib/mt/wall/plan.rb', line 63 def operations @operations end |
#path ⇒ Object (readonly)
RouterOS resource path (managed table)
53 54 55 56 57 |
# File 'lib/mt/wall/plan.rb', line 53 Operation = Data.define(:action, :path, :payload, :position) do def initialize(action:, path:, payload: {}, position: nil) super end end |
#position ⇒ Object (readonly)
place-before anchor: the ‘(tag, ordinal)` pair (or `.id`) of the row this one must precede; nil = append at the table’s tail
53 54 55 56 57 |
# File 'lib/mt/wall/plan.rb', line 53 Operation = Data.define(:action, :path, :payload, :position) do def initialize(action:, path:, payload: {}, position: nil) super end end |
Class Method Details
.diff(desired:, current:) ⇒ Plan
Build a Plan by diffing two DesiredState instances. Matches rows by the ‘(tag, ordinal)` key (filter/nat) or the natural key (address-list), and normalizes both sides (string-coerced values, `dynamic` rows excluded) before comparing. Emits operations already sorted per the apply-order invariants above.
82 83 84 |
# File 'lib/mt/wall/plan.rb', line 82 def self.diff(desired:, current:) Differ.new(desired: desired, current: current).call end |
Instance Method Details
#action=(value) ⇒ Object
:create, :update, :delete or :move
53 54 55 56 57 |
# File 'lib/mt/wall/plan.rb', line 53 Operation = Data.define(:action, :path, :payload, :position) do def initialize(action:, path:, payload: {}, position: nil) super end end |
#empty? ⇒ Boolean
69 70 71 |
# File 'lib/mt/wall/plan.rb', line 69 def empty? @operations.empty? end |
#payload=(value) ⇒ Object
the resource attributes; for :update/:delete/:move it also carries the existing row’s ‘.id`
53 54 55 56 57 |
# File 'lib/mt/wall/plan.rb', line 53 Operation = Data.define(:action, :path, :payload, :position) do def initialize(action:, path:, payload: {}, position: nil) super end end |