git.delta.rocks / fleet / refs/commits / 7bc4be6bcef6

difftreelog

source

crates/remowt-fleet/src/lib.rs3.2 KiBsourcehistory
1use std::path::PathBuf;23use anyhow::{Context as _, Result};4use bifrostlink::Config;5use bifrostlink::declarative::endpoints;6use camino::Utf8PathBuf;7use remowt_client::Remowt;8use remowt_endpoints::nix_daemon::NixDaemonClient;9use serde::{Deserialize, Serialize};10use tokio::net::UnixListener;11use tracing::error;1213pub struct Nix;14pub use nix_eval::{init_libraries, init_tokio_for_nix};1516#[derive(Serialize, Deserialize, Debug, thiserror::Error)]17pub enum NixError {18	#[error("nix daemon unavailable: {0}")]19	DaemonUnavailable(String),20	#[error("tunnel socket unavailable: {0}")]21	Tunnel(String),22	#[error("profile switch failed: {0}")]23	Profile(String),24	#[error("signing failed: {0}")]25	Sign(String),26	#[error("listing generations failed: {0}")]27	ListGenerations(String),28}2930#[endpoints(ns = 91)]31impl Nix {32	#[endpoints(id = 3)]33	async fn switch_profile(34		&self,35		profile: String,36		store_path: Utf8PathBuf,37	) -> Result<(), NixError> {38		tokio::task::spawn_blocking(move || nix_eval::switch_profile(&profile, &store_path))39			.await40			.map_err(|e| NixError::Profile(e.to_string()))?41			.map_err(|e| NixError::Profile(e.to_string()))42	}4344	#[endpoints(id = 4)]45	async fn sign_closure(46		&self,47		store_path: Utf8PathBuf,48		key_file: Utf8PathBuf,49	) -> Result<(), NixError> {50		tokio::task::spawn_blocking(move || {51			nix_eval::sign_closure(store_path.as_str(), key_file.as_str())52		})53		.await54		.map_err(|e| NixError::Sign(e.to_string()))?55		.map_err(|e| NixError::Sign(e.to_string()))56	}5758	#[endpoints(id = 5)]59	async fn list_generations(60		&self,61		profile: String,62	) -> Result<Vec<nix_eval::ProfileGeneration>, NixError> {63		tokio::task::spawn_blocking(move || {64			nix_eval::list_generations(&format!("/nix/var/nix/profiles/{profile}"))65		})66		.await67		.map_err(|e| NixError::ListGenerations(e.to_string()))?68		.map_err(|e| NixError::ListGenerations(e.to_string()))69	}70}7172pub async fn nix_store_socket(conn: Remowt, store: &str) -> Result<PathBuf> {73	let store = store.to_owned();74	let path = std::env::temp_dir().join(format!("fleet-nix-{}.sock", uuid::Uuid::new_v4()));75	let _ = std::fs::remove_file(&path);76	let listener = UnixListener::bind(&path)?;77	tokio::spawn(async move {78		if let Err(e) = serve(conn, listener, store).await {79			error!("nix daemon proxy failed: {e}");80		}81	});82	Ok(path)83}8485async fn serve(conn: Remowt, listener: UnixListener, store: String) -> Result<()> {86	let nix = conn.endpoints::<NixDaemonClient<_>>();87	loop {88		let (mut local, _) = listener.accept().await?;8990		let (rx, remote_sock) = match conn.bind_runtime_unix("nix-daemon").await {91			Ok(rx) => rx,92			Err(e) => {93				error!("streamlocal_forward failed: {e}");94				continue;95			}96		};97		let sock_str = remote_sock.as_str().to_owned();98		match nix.serve_store(store.clone(), sock_str).await {99			Ok(Ok(())) => {}100			Ok(Err(e)) => {101				error!("nix bridge: {e}");102				continue;103			}104			Err(e) => {105				error!("nix bridge rpc failed: {e}");106				continue;107			}108		}109110		let mut channel = rx111			.accept()112			.await113			.context("failed to accept remote nix connection")?;114		tokio::spawn(async move {115			if let Err(e) = tokio::io::copy_bidirectional(&mut local, &mut channel).await {116				tracing::debug!("nix tunnel ended: {e}");117			}118		});119	}120}