| 1 | package legatus |
| 2 | |
| 3 | // Flow is an ordered, host-agnostic sequence of steps — a playbook. A Runner |
| 4 | // executes a Flow against each selected host, fanning out per host. |
| 5 | type Flow struct { |
| 6 | Name string |
| 7 | Steps []Step |
| 8 | } |
| 9 | |
| 10 | // Step is one unit of work. Check probes whether a change is needed (need=false |
| 11 | // reports Skipped and, in dry-run, ends the step). Apply performs the change and |
| 12 | // reports what it did. |
| 13 | type Step interface { |
| 14 | Name() string |
| 15 | Check(fc *FlowCtx) (need bool, err error) |
| 16 | Apply(fc *FlowCtx) (Outcome, error) |
| 17 | } |
| 18 | |
| 19 | // Outcome is what a step reports about what it did. The engine wraps this in a |
| 20 | // StepResult with timing and a derived Status. |
| 21 | type Outcome struct { |
| 22 | Changed bool |
| 23 | Message string |
| 24 | Data any |
| 25 | } |
| 26 | |
| 27 | // AlwaysApply embeds into steps with no meaningful check; Check always reports a |
| 28 | // change is needed. |
| 29 | type AlwaysApply struct{} |
| 30 | |
| 31 | // Check always reports need=true. |
| 32 | func (AlwaysApply) Check(*FlowCtx) (bool, error) { return true, nil } |
| 33 | |
| 34 | type stepFunc struct { |
| 35 | AlwaysApply |
| 36 | name string |
| 37 | fn func(*FlowCtx) (Outcome, error) |
| 38 | } |
| 39 | |
| 40 | func (s stepFunc) Name() string { return s.name } |
| 41 | func (s stepFunc) Apply(fc *FlowCtx) (Outcome, error) { return s.fn(fc) } |
| 42 | |
| 43 | // StepFunc adapts a function into a Step that always applies. |
| 44 | func StepFunc(name string, fn func(*FlowCtx) (Outcome, error)) Step { |
| 45 | return stepFunc{name: name, fn: fn} |
| 46 | } |
| 47 | |