tawasuyu

tawasuyu/brahman

Rust 492TOML 194Markdown 53JSON 176939 Definiciones

⎇ 53dbdf0f1deea10d6fc567ea2b43e1e75d6d60cd crates/core/ente-machined-compat/src/main.rs Rust · 186 líneas · 6.6 KB Historia Quién tocó qué crudo

chore: monorepo inicial con arje + minga + yahweh absorbidos 53dbdf0f1 · Sergio ·

1//! ente-machined-compat: shim de `org.freedesktop.machine1`.
2//!
3//! systemd-machined trackea VMs y containers (typically managed por systemd-nspawn).
4//! En el fractal cada Ente con namespaces es candidato a "machine", pero la
5//! correspondencia no es 1:1 — un Ente puede tener menos aislamiento que una
6//! container completa.
7//!
8//! Este shim devuelve listas vacías para no romper clientes (gnome-boxes,
9//! virt-manager, etc) que llaman a `ListMachines` durante boot. Métodos de
10//! mutación (RegisterMachine, KillMachine) se aceptan como no-op con audit
11//! log via tracing.
12//!
13//! Producción real: integrar con el graph del fractal — ListMachines query
14//! BusRequest::ListEntes filtrado por `card.soma.namespaces.pid`.
15
16use ente_bus::{BusClient, BusRequest, BusResponse};
17use ente_card::Capability;
18use std::collections::HashMap;
19use tokio::signal::unix::{signal, SignalKind};
20use tracing::{info, warn};
21use tracing_subscriber::EnvFilter;
22use zbus::{fdo, interface, zvariant::OwnedValue};
23
24const BUS_NAME: &str = "org.freedesktop.machine1";
25const OBJ_PATH: &str = "/org/freedesktop/machine1";
26
27#[tokio::main(flavor = "current_thread")]
28async fn main() -> anyhow::Result<()> {
29    init_tracing();
30    info!("ente-machined-compat: arrancando");
31    announce_to_fractal().await;
32
33    let manager = MachineManager;
34    let conn_result = zbus::connection::Builder::system()
35        .and_then(|b| b.name(BUS_NAME))
36        .and_then(|b| b.serve_at(OBJ_PATH, manager));
37    match conn_result {
38        Ok(builder) => match builder.build().await {
39            Ok(_conn) => {
40                info!(name = BUS_NAME, "name acquired, sirviendo");
41                wait_for_term().await
42            }
43            Err(e) => { warn!(?e, "build conn falló — modo idle"); wait_for_term().await }
44        },
45        Err(e) => { warn!(?e, "builder D-Bus falló — modo idle"); wait_for_term().await }
46    }
47}
48
49struct MachineManager;
50
51/// Tipo del wire format de ListMachines: `(s, s, s, u, ay, ay, t, ay)` —
52/// name, class, service, leader_pid, root_directory_path, id_unix, time_obtained,
53/// machine_id_bytes. systemd usa este struct simplificado.
54type Machine = (String, String, String, u32, String);
55
56#[interface(name = "org.freedesktop.machine1.Manager")]
57impl MachineManager {
58    /// Lista vacía — no trackeamos containers todavía.
59    async fn list_machines(&self) -> fdo::Result<Vec<Machine>> {
60        Ok(vec![])
61    }
62
63    /// Devuelve siempre NotFound — sin machines registradas.
64    async fn get_machine(&self, name: String) -> fdo::Result<zbus::zvariant::OwnedObjectPath> {
65        Err(fdo::Error::Failed(format!("machine '{name}' no encontrada")))
66    }
67
68    async fn get_machine_by_pid(&self, pid: u32) -> fdo::Result<zbus::zvariant::OwnedObjectPath> {
69        Err(fdo::Error::Failed(format!("PID {pid} no asociado a ninguna machine")))
70    }
71
72    async fn register_machine(
73        &self,
74        name: String,
75        _id: Vec<u8>,
76        _service: String,
77        class: String,
78        _leader_pid: u32,
79        _root_directory: String,
80    ) -> fdo::Result<zbus::zvariant::OwnedObjectPath> {
81        info!(%name, %class, "RegisterMachine (no-op)");
82        Err(fdo::Error::NotSupported(
83            "RegisterMachine no implementado — usar Cards del fractal".into()
84        ))
85    }
86
87    async fn register_machine_with_network(
88        &self,
89        name: String,
90        id: Vec<u8>,
91        service: String,
92        class: String,
93        leader_pid: u32,
94        root_directory: String,
95        _network_interfaces: Vec<i32>,
96    ) -> fdo::Result<zbus::zvariant::OwnedObjectPath> {
97        self.register_machine(name, id, service, class, leader_pid, root_directory).await
98    }
99
100    async fn create_machine(
101        &self,
102        name: String,
103        _id: Vec<u8>,
104        _service: String,
105        class: String,
106        _leader_pid: u32,
107        _root_directory: String,
108        _scope_properties: Vec<(String, OwnedValue)>,
109    ) -> fdo::Result<zbus::zvariant::OwnedObjectPath> {
110        info!(%name, %class, "CreateMachine (no-op)");
111        Err(fdo::Error::NotSupported(
112            "CreateMachine no implementado".into()
113        ))
114    }
115
116    async fn terminate_machine(&self, name: String) -> fdo::Result<()> {
117        info!(%name, "TerminateMachine (no-op)");
118        Ok(())
119    }
120
121    async fn kill_machine(&self, name: String, _who: String, _signal: i32) -> fdo::Result<()> {
122        info!(%name, "KillMachine (no-op)");
123        Ok(())
124    }
125
126    async fn get_machine_address(&self, name: String) -> fdo::Result<Vec<(i32, Vec<u8>)>> {
127        warn!(%name, "GetMachineAddress (sin tracking, devuelvo vacío)");
128        Ok(vec![])
129    }
130
131    async fn get_machine_osrelease(&self, name: String) -> fdo::Result<HashMap<String, String>> {
132        warn!(%name, "GetMachineOSRelease (sin tracking)");
133        Ok(HashMap::new())
134    }
135
136    /// Operaciones sobre la "host machine" (PID 1 namespace) — siempre
137    /// disponibles. Usamos el path canónico `/org/freedesktop/machine1/machine/_host`.
138    async fn open_machine_login(&self, _name: String) -> fdo::Result<(zbus::zvariant::OwnedObjectPath, zbus::zvariant::OwnedFd)> {
139        Err(fdo::Error::NotSupported(
140            "OpenMachineLogin no implementado".into()
141        ))
142    }
143
144    async fn open_machine_shell(
145        &self,
146        _name: String,
147        _user: String,
148        _path: String,
149        _args: Vec<String>,
150        _environment: Vec<String>,
151    ) -> fdo::Result<(zbus::zvariant::OwnedObjectPath, zbus::zvariant::OwnedFd)> {
152        Err(fdo::Error::NotSupported("OpenMachineShell no implementado".into()))
153    }
154}
155
156async fn announce_to_fractal() {
157    if let Ok(mut client) = BusClient::from_env().await {
158        let req = BusRequest::Announce {
159            capabilities: vec![Capability::Endpoint {
160                interface: ente_card::InterfaceId([0xa5; 16]),
161                version: 1,
162            }],
163        };
164        match client.call(req).await {
165            Ok(BusResponse::Ok) => info!("Announce → bus interno OK"),
166            Ok(other) => warn!(?other, "Announce respuesta inesperada"),
167            Err(e) => warn!(?e, "Announce falló"),
168        }
169    }
170}
171
172async fn wait_for_term() -> anyhow::Result<()> {
173    let mut term = signal(SignalKind::terminate())?;
174    let mut int_ = signal(SignalKind::interrupt())?;
175    tokio::select! {
176        _ = term.recv() => info!("SIGTERM"),
177        _ = int_.recv() => info!("SIGINT"),
178    }
179    Ok(())
180}
181
182fn init_tracing() {
183    let filter = EnvFilter::try_from_default_env()
184        .unwrap_or_else(|_| EnvFilter::new("ente_machined_compat=info"));
185    tracing_subscriber::fmt().with_env_filter(filter).with_target(true).init();
186}