Skip to main content

monitord/varlink/
machine.rs

1//! Varlink proxy for systemd-machined's io.systemd.Machine interface.
2//! Adapted from the interface definition in systemd's
3//! `src/shared/varlink-io.systemd.Machine.c`. machined gained this API in
4//! systemd v257.
5
6use serde::{Deserialize, Serialize};
7use zlink::{proxy, ReplyError};
8
9use crate::varlink::unit::ProcessId;
10
11pub const MACHINE_SOCKET_PATH: &str = "/run/systemd/machine/io.systemd.Machine";
12
13/// Proxy trait for calling methods on the io.systemd.Machine interface.
14#[proxy("io.systemd.Machine")]
15pub trait Machine {
16    /// List every registered machine, one reply per machine.
17    /// [Requires 'more' flag]
18    #[zlink(more)]
19    async fn list(
20        &mut self,
21    ) -> zlink::Result<
22        impl futures_util::Stream<Item = zlink::Result<Result<ListOutput, MachineError>>>,
23    >;
24}
25
26/// Output parameters for the List method.
27///
28/// Only the fields monitord consumes are declared; serde drops the rest.
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ListOutput {
31    /// Name of the machine, e.g. "testbox" or ".host".
32    pub name: String,
33    /// The class of this machine: "container", "vm" or "host".
34    pub class: String,
35    /// Leader process of this machine.
36    pub leader: Option<ProcessId>,
37}
38
39/// Errors that can occur in the io.systemd.Machine interface.
40#[derive(Debug, Clone, PartialEq, ReplyError)]
41#[zlink(interface = "io.systemd.Machine")]
42pub enum MachineError {
43    /// No machine matches the request (also what an empty List returns).
44    NoSuchMachine,
45    /// The request is not supported for this machine.
46    NotSupported,
47}
48
49impl std::fmt::Display for MachineError {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            MachineError::NoSuchMachine => write!(f, "No such machine"),
53            MachineError::NotSupported => write!(f, "Not supported"),
54        }
55    }
56}
57
58impl std::error::Error for MachineError {}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_list_output_deserialize() {
66        // A real reply from systemd 259's machined, trimmed to one machine.
67        let json = r#"{"name":"testbox","id":"76c418060ef042fdb8b579e755988736","class":"container","service":"systemd-nspawn","unit":"systemd-nspawn@testbox.service","leader":{"pid":7430,"pidfdId":5367,"bootId":"6e68bb3ad68f43838ea71e746325e67b"},"timestamp":{"realtime":1789561088882217,"monotonic":86182609},"UID":0}"#;
68        let machine: ListOutput = serde_json::from_str(json).unwrap();
69        assert_eq!(machine.name, "testbox");
70        assert_eq!(machine.class, "container");
71        assert_eq!(machine.leader.and_then(|l| l.pid), Some(7430));
72    }
73}