git.delta.rocks / fleet / refs/heads / push-kyumtlkprzyo

difftreelog

source

crates/remowt-fleet/src/lib.rs3.8 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 remowt_link_shared::iroh_tunnel::TunnelAddr;11use serde::{Deserialize, Serialize};12use tokio::net::UnixListener;13use tokio::task::spawn_blocking;14use tracing::error;1516pub struct Nix;17pub use nix_eval::{init_libraries, init_tokio_for_nix};1819#[derive(Serialize, Deserialize, Debug, thiserror::Error)]20pub enum NixError {21	#[error("nix daemon unavailable: {0}")]22	DaemonUnavailable(String),23	#[error("tunnel socket unavailable: {0}")]24	Tunnel(String),25	#[error("profile switch failed: {0}")]26	Profile(String),27	#[error("signing failed: {0}")]28	Sign(String),29	#[error("listing generations failed: {0}")]30	ListGenerations(String),31	#[error("substitution failed: {0}")]32	Substitute(String),33}3435#[endpoints(ns = 91)]36impl Nix {37	#[endpoints(id = 3)]38	async fn switch_profile(39		&self,40		profile: String,41		store_path: Utf8PathBuf,42	) -> Result<(), NixError> {43		let store = eval_store();44		spawn_blocking(move || store.switch_profile(&profile, &store_path))45			.await46			.expect("switch_profile panicked")47			.map_err(|e| NixError::Profile(e.to_string()))48	}4950	#[endpoints(id = 4)]51	async fn sign_closure(52		&self,53		store_path: Utf8PathBuf,54		key_file: Utf8PathBuf,55	) -> Result<(), NixError> {56		spawn_blocking(move || {57			let store = eval_store();58			store.sign_closure(&store_path, &key_file)59		})60		.await61		.expect("store signing panicked")62		.map_err(|e| NixError::Sign(e.to_string()))63	}6465	/// Download the given paths (and their closures) into the local store using66	/// the configured substituters. Used to fetch closures that were uploaded to67	/// a binary cache (e.g. attic) instead of copied over the nix daemon tunnel.68	#[endpoints(id = 6)]69	async fn substitute(&self, paths: Vec<Utf8PathBuf>) -> Result<Vec<Utf8PathBuf>, NixError> {70		spawn_blocking(move || {71			let store = eval_store();72			store.substitute_paths(&paths)73		})74		.await75		.expect("substitution panicked")76		.map_err(|e| NixError::Substitute(e.to_string()))77	}7879	#[endpoints(id = 5)]80	async fn list_generations(81		&self,82		profile: String,83	) -> Result<Vec<nix_eval::ProfileGeneration>, NixError> {84		spawn_blocking(move || {85			nix_eval::list_generations(&format!("/nix/var/nix/profiles/{profile}"))86		})87		.await88		.expect("generation listing panicked")89		.map_err(|e| NixError::ListGenerations(e.to_string()))90	}91}9293pub async fn nix_store_socket(conn: Remowt, store: &str) -> Result<PathBuf> {94	let store = store.to_owned();95	let path = std::env::temp_dir().join(format!("fleet-nix-{}.sock", uuid::Uuid::new_v4()));96	let _ = std::fs::remove_file(&path);97	let listener = UnixListener::bind(&path)?;98	tokio::spawn(async move {99		if let Err(e) = serve(conn, listener, store).await {100			error!("nix daemon proxy failed: {e}");101		}102	});103	Ok(path)104}105106async fn serve(conn: Remowt, listener: UnixListener, store: String) -> Result<()> {107	let nix = conn.endpoints::<NixDaemonClient<_>>();108	loop {109		let (mut local, _) = listener.accept().await?;110111		let (rx, remote_sock) = match conn.bind_runtime_unix("nix-daemon").await {112			Ok(rx) => rx,113			Err(e) => {114				error!("streamlocal_forward failed: {e}");115				continue;116			}117		};118		match nix119			.serve_store(store.clone(), TunnelAddr::Unix(remote_sock))120			.await121		{122			Ok(Ok(())) => {}123			Ok(Err(e)) => {124				error!("nix bridge: {e}");125				continue;126			}127			Err(e) => {128				error!("nix bridge rpc failed: {e}");129				continue;130			}131		}132133		let mut channel = rx134			.accept()135			.await136			.context("failed to accept remote nix connection")?;137		tokio::spawn(async move {138			if let Err(e) = tokio::io::copy_bidirectional(&mut local, &mut channel).await {139				tracing::debug!("nix tunnel ended: {e}");140			}141		});142	}143}