git.delta.rocks / fleet / refs/commits / 78bc9187eaae

difftreelog

source

crates/remowt-fleet/src/lib.rs3.2 KiBsourcehistory
1use std::path::PathBuf;23use anyhow::{Context as _, Result};4use bifrostlink::declarative::endpoints;5use bifrostlink::Config;6use camino::Utf8PathBuf;7use nix_eval::eval_store;8use remowt_client::Remowt;9use remowt_endpoints::nix_daemon::NixDaemonClient;10use serde::{Deserialize, Serialize};11use tokio::net::UnixListener;12use tokio::task::spawn_blocking;13use tracing::error;1415pub struct Nix;16pub use nix_eval::{init_libraries, init_tokio_for_nix};1718#[derive(Serialize, Deserialize, Debug, thiserror::Error)]19pub enum NixError {20	#[error("nix daemon unavailable: {0}")]21	DaemonUnavailable(String),22	#[error("tunnel socket unavailable: {0}")]23	Tunnel(String),24	#[error("profile switch failed: {0}")]25	Profile(String),26	#[error("signing failed: {0}")]27	Sign(String),28	#[error("listing generations failed: {0}")]29	ListGenerations(String),30}3132#[endpoints(ns = 91)]33impl Nix {34	#[endpoints(id = 3)]35	async fn switch_profile(36		&self,37		profile: String,38		store_path: Utf8PathBuf,39	) -> Result<(), NixError> {40		let store = eval_store();41		spawn_blocking(move || store.switch_profile(&profile, &store_path))42			.await43			.expect("switch_profile panicked")44			.map_err(|e| NixError::Profile(e.to_string()))45	}4647	#[endpoints(id = 4)]48	async fn sign_closure(49		&self,50		store_path: Utf8PathBuf,51		key_file: Utf8PathBuf,52	) -> Result<(), NixError> {53		spawn_blocking(move || {54			let store = eval_store();55			store.sign_closure(&store_path, &key_file)56		})57		.await58		.expect("store signing panicked")59		.map_err(|e| NixError::Sign(e.to_string()))60	}6162	#[endpoints(id = 5)]63	async fn list_generations(64		&self,65		profile: String,66	) -> Result<Vec<nix_eval::ProfileGeneration>, NixError> {67		spawn_blocking(move || {68			nix_eval::list_generations(&format!("/nix/var/nix/profiles/{profile}"))69		})70		.await71		.expect("generation listing panicked")72		.map_err(|e| NixError::ListGenerations(e.to_string()))73	}74}7576pub async fn nix_store_socket(conn: Remowt, store: &str) -> Result<PathBuf> {77	let store = store.to_owned();78	let path = std::env::temp_dir().join(format!("fleet-nix-{}.sock", uuid::Uuid::new_v4()));79	let _ = std::fs::remove_file(&path);80	let listener = UnixListener::bind(&path)?;81	tokio::spawn(async move {82		if let Err(e) = serve(conn, listener, store).await {83			error!("nix daemon proxy failed: {e}");84		}85	});86	Ok(path)87}8889async fn serve(conn: Remowt, listener: UnixListener, store: String) -> Result<()> {90	let nix = conn.endpoints::<NixDaemonClient<_>>();91	loop {92		let (mut local, _) = listener.accept().await?;9394		let (rx, remote_sock) = match conn.bind_runtime_unix("nix-daemon").await {95			Ok(rx) => rx,96			Err(e) => {97				error!("streamlocal_forward failed: {e}");98				continue;99			}100		};101		let sock_str = remote_sock.as_str().to_owned();102		match nix.serve_store(store.clone(), sock_str).await {103			Ok(Ok(())) => {}104			Ok(Err(e)) => {105				error!("nix bridge: {e}");106				continue;107			}108			Err(e) => {109				error!("nix bridge rpc failed: {e}");110				continue;111			}112		}113114		let mut channel = rx115			.accept()116			.await117			.context("failed to accept remote nix connection")?;118		tokio::spawn(async move {119			if let Err(e) = tokio::io::copy_bidirectional(&mut local, &mut channel).await {120				tracing::debug!("nix tunnel ended: {e}");121			}122		});123	}124}