Logical State
Logical state is the part of an item that is:
- Implementor / user definable
- Controllable by automation
- Deterministic
Uses
There are three uses of logical state:
- Representing current state.
- Representing goal state.
- Computing state difference.
let params = data.params();
// `dest` references the actual item that is being managed.
// e.g. calculate content hash of actual file being written to.
let state_current = params.dest().read();
// `src` references the *specification* of what the item is intended to be.
// e.g. retrieve content hash from a source file.
let state_goal = params.src().read();
// We can only compute the `diff` when both `src` and `dest` are available.
let state_diff = state_goal - state_current;
Discovery Constraints
In an item's parameters, there must be the following categories of information:
-
src
: information of what the item should be, or where to look up that information.Thus,
src
is a reference to where to look upstate_goal
. -
dest
: reference to where the actual item should be.dest
is a reference to where to pushstate_current
.
Both src
and dest
may reference resources that are ensured by predecessor items. Meaning sometimes state_goal
and state_current
cannot be discovered because they rely on the predecessors' completions.
Examples
- A list of files in a zip file cannot be read, if the zip file is not downloaded.
- A file on a server cannot be read, if the server doesn't exist.
- A server cannot have a domain name assigned to it, if the server doesn't exist.
Implications
-
If
dest
is not available, thenstate_current
may simply be "does not exist". -
If
src
is not available, and we want to showstate_goal
that is not just "we can't look it up", thensrc
must be defined in terms of something readable during discovery. -
If that is not possible, or is too expensive, then one or more of the following has to be chosen:
-
Item::state_goal
functions have to always cater forsrc
not being available.It incurs mental effort to always cater for
src
not being available – i.e. implementing an item would need knowledge beyond itself. -
the
peace
framework defaults to not runningstate_current_fn
for items that have a logical dependency on things thatItem::apply_check
returnsExecRequired
For this to work, when the current state is requested,
peace
will:- For each non-parent item, run
state_current
,state_goal
,state_diff
, andapply_check
. - If
apply_check
returnsApplyCheck::ExecNotRequired
, then successor items can be processed as well.
- For each non-parent item, run
-
state_current
could returnResult<Option<Status>, E>
:-
Ok(None)
: State cannot be discovered, likely because predecessor hasn't run -
Ok(Some(State<_, _>))
: State cannot be discovered. -
Err(E)
: An error happened when discovering state.May be difficult to distinguish some cases from
Ok(None)
, e.g. failed to connect to server, is it because the server doesn't exist, or because the address is incorrect.Should we have two
state_current
s? Or pass in whether it's being called fromDiscover
vsEnsure
– i.e. some information that says "err when failing to connect because the predecessor has been ensured".
-
Option 2 may be something we have to do anyway – we will not be able to provide current state to run
Item::apply
for successors for the same reason.Option 3 may coexist with option 2.
Note: State discovery may be expensive, so it is important to be able to show a stored copy of what is discovered.
-