plesty.server.services.nodes
Reaching the nodes a master drives.
The console has always managed the bench it runs on. A master
(plesty.server.model.agent) also shows the devices of the benches it
declares as peers, and acts on them — so it needs, for the first time on this
side, a client of another bench. That client already exists and is already
what plesty-bench uses: plesty.bench.BenchClient. This module is
the thin layer between it and the presenter.
One link per node, kept open. A poll every three seconds is not worth a connection each; the link reconnects on its own when a request times out.
A link is called from a thread pool, so every request holds the link’s lock: a ZMQ socket belongs to one thread at a time, and the window’s workers make no promise about which of them asks.
A node that does not answer is a state, not a failure. It keeps its row,
its devices go unreachable, and NodeLink.trouble says why — a console
that dropped the rows of a bench somebody rebooted would be reporting that the
devices are gone.
Attributes
Exceptions
A node could not be reached, or refused what it was asked. |
Classes
This master's link to one node's agent. |
|
One device of a node, on a connection this handle owns. |
|
Every node a master drives, one |
Functions
|
Module Contents
- plesty.server.services.nodes.POLL_TIMEOUT_MS = 3000
- plesty.server.services.nodes.ACTION_TIMEOUT_MS = 120000
- plesty.server.services.nodes.Connect
- exception plesty.server.services.nodes.NodeError
Bases:
RuntimeErrorA node could not be reached, or refused what it was asked.
Initialize self. See help(type(self)) for accurate signature.
- plesty.server.services.nodes._connect(peer: plesty.server.model.Peer) plesty.bench.BenchClient
- Parameters:
peer (plesty.server.model.Peer)
- Return type:
- class plesty.server.services.nodes.NodeLink(peer: plesty.server.model.Peer, connect: Connect | None = None)
This master’s link to one node’s agent.
Bind to peer; the socket opens on the first request.
- Parameters:
peer (plesty.server.model.Peer) – The node’s name, address and secret.
connect (Connect | None) – Builds the client; injected by the tests.
- peer
- _connect
- _client: plesty.bench.BenchClient | None = None
- _lock
- _trouble: str = ''
- property name: str
The node’s name — what the Host column shows.
- Return type:
str
- property trouble: str
Why the last request failed, or empty after one that worked.
- Return type:
str
- property reachable: bool
Whether the last request got an answer.
- Return type:
bool
- close() None
Drop the connection; a later request opens a new one.
- Return type:
None
- run(argv: collections.abc.Sequence[str], timeout_ms: int = ACTION_TIMEOUT_MS) str
Run
plesty-server <argv>on the node and return its output.- Parameters:
argv (collections.abc.Sequence[str]) – The command line, as the local CLI would take it.
timeout_ms (int) – Reply timeout.
- Returns:
Standard output, stripped.
- Raises:
NodeError – When the node did not answer, or the command failed — carrying what the node said, since it is the node that knows.
- Return type:
str
- devices() list[dict[str, Any]]
Every device the node declares, as
list --jsonreports them.The same document the local
list --jsonprints, so one call carries the declaration, the installed version, the source line and the state — everything a row needs, in one round trip per node per refresh.- Raises:
NodeError – When the node did not answer or gave no JSON.
- Return type:
list[dict[str, Any]]
- device(name: str) NodeDevice
A handle on one running device of the node, for a control panel.
On a connection of its own, not the one this link polls with. A panel drives its handle from its own worker thread while the device table keeps polling on ours, and a ZMQ socket belongs to one thread at a time: sharing one would let a panel’s reply answer a poll, and every request after that would return the one before it.
- Parameters:
name (str)
- Return type:
- class plesty.server.services.nodes.NodeDevice(peer: plesty.server.model.Peer, name: str, connect: Connect)
One device of a node, on a connection this handle owns.
What a control panel drives. It is the four calls of plesty-lib’s
DeviceHandle—describe,query,write,call— delegated to aplesty.bench.RemoteDevice, plus the one thing that handle cannot offer: aclosethat actually releases something.plesty.bench.RemoteDevicecloses nothing by design, because its connection belongs to theBenchClientthat made it. A panel needs the opposite — a connection of its own, released when the panel goes — so that the console’s poll and the panel never share a socket, and so that the console’s_releasehas something to close.The client connects lazily, so the socket is made by whichever thread makes the first call. That is the panel’s worker, which is the thread that must own it.
Open a handle on name at peer.
- Parameters:
peer (plesty.server.model.Peer) – The node the device runs on.
name (str) – The declared device.
connect (Connect) – Builds the client; injected by the tests.
- name
- peer
- _client
- _device: Any
- describe() dict[str, Any]
The device’s methods and its serialized doc model.
- Return type:
dict[str, Any]
- query(key: str) Any
Read configuration parameter key.
- Parameters:
key (str)
- Return type:
Any
- write(key: str, value: Any) Any
Write value to configuration parameter key.
- Parameters:
key (str)
value (Any)
- Return type:
Any
- call(op: str, **kwargs: Any) Any
Run operation op.
- Parameters:
op (str)
kwargs (Any)
- Return type:
Any
- close() None
Release this handle’s own connection.
- Return type:
None
- class plesty.server.services.nodes.Nodes(peers: collections.abc.Iterable[plesty.server.model.Peer] = (), connect: Connect | None = None)
Every node a master drives, one
NodeLinkeach.Hold a link per peer.
- Parameters:
peers (collections.abc.Iterable[plesty.server.model.Peer]) – The declared nodes.
connect (Connect | None) – Builds each client; injected by the tests.
- _connect = None
- refresh(peers: collections.abc.Iterable[plesty.server.model.Peer]) None
Make the links match peers, keeping the connections still wanted.
A peer whose address or secret changed is reconnected; one that is simply still there keeps the socket it has, so editing the list does not cost every other node its connection.
- Parameters:
peers (collections.abc.Iterable[plesty.server.model.Peer])
- Return type:
None
- property names: list[str]
The node names.
- Return type:
list[str]
- close() None
Drop every connection.
- Return type:
None