Command descriptors¶
reemote.commands defines the base Command, the raw StringCommand, the
TransferCommand base for descriptors that copy bytes over the connection
instead of running shell text, and the WaitCommand base for descriptors that
poll the host until a condition holds; the concrete typed descriptors live
beside the operations that yield them (reemote.modules.dnf.dnf,
reemote.modules.files.files, reemote.modules.server.server). They are dumb,
frozen value objects: an operation never executes anything, it only describes
what would have to run. The raw StringCommand carries shell text verbatim —
its shell() returns the command unchanged, so it runs (and takes the
doas/sudo/su prefixes) exactly like a typed shell descriptor; it is the vehicle
for a demo-side operation running a one-off command such as the sysctl
step of the
sysctl recipe
without a library operation. The typed descriptors exist so the test framework's
SimulatedHost (in tests/simulated_host.py) can dispatch on them in its
execute_command and apply the equivalent mutation; the library's
send_command forwards to that seam. On the
real transport a TransferCommand is dispatched on its base —
send_command hands the host to its transfer, which copies over the
connection's own protocol (asyncssh's scp) rather than through a shell, so
the doas/sudo/su escalation flags do not apply to it. A WaitCommand is
dispatched the same way — send_command awaits its wait, which polls the
host until its condition holds or raises WaitTimeoutError — and is likewise
unprivileged; see WaitCommand here and the
server.wait and
server.wait_service operations
that yield the concrete poll (both through the generic WaitForFactCommand,
which polls a fact class until a module-level predicate holds).
Reference¶
reemote.commands
¶
Command descriptors (design doc section 4.5).
Operations yield command descriptors, not strings, so the driver can
distinguish command types and handle them appropriately. Descriptors stay
dumb; the driver maps them onto host actions via send_command.
This module holds the base Command, the raw StringCommand, the
TransferCommand base for descriptors that copy bytes over the connection
instead of running shell text, and the WaitCommand base for descriptors
that poll the host until a condition holds; concrete typed descriptors live
beside the operations that yield them (modules.dnf.dnf,
modules.files.files, modules.server.server).
StringCommand
dataclass
¶
StringCommand()
A raw shell command (would be sent over SSH in a real implementation).
TransferCommand
dataclass
¶
TransferCommand()
Base for descriptors that transfer bytes rather than run shell text.
A transfer has no shell() rendering -- it is not executed through the
shell pipeline -- so send_command dispatches on this base and hands the
host to transfer, which performs the copy over the host's own
transport. The base lives here (not beside a concrete descriptor) so the
driver can dispatch on it without importing a namespace module, which
would be circular: modules.files.files imports core, and core
and the drivers sit above commands.
WaitCommand
dataclass
¶
WaitCommand()
Base for descriptors that poll the host until a condition holds.
The second kind of non-shell descriptor, beside TransferCommand: a
wait has no shell() rendering -- nothing is sent as shell text.
send_command dispatches on this base and hands the host to wait,
which polls (re-reading a fact directly, never through the per-step
FactCache, which would pin the first value) and sleeps between
attempts until the condition holds or the timeout expires, raising
WaitTimeoutError in the latter case. Like a transfer it is
unprivileged: the sudo/su flags do not apply to a poll.
Waiting lives in a descriptor rather than in the operation body because
the prepare phase never sends: an operation that polled inside its own
generator would spin forever against the prepare cache. The operation
only describes the wait; the driver performs it at send time. The base
lives here (not beside a concrete descriptor) for the same reason as
TransferCommand: the driver must dispatch on it without importing a
namespace module.
WaitTimeoutError
¶
Raised by a WaitCommand whose condition was not met within its timeout.
Propagates out of send_command and therefore out of run_apply --
a wait that never completes aborts the run, exactly as a failing shell
command does via CommandError.