difftreelog
build update to nixos release-25.05
in: trunk
34 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "abort-on-drop"
@@ -377,29 +377,6 @@
]
[[package]]
-name = "bindgen"
-version = "0.69.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
-dependencies = [
- "bitflags",
- "cexpr",
- "clang-sys",
- "itertools 0.12.1",
- "lazy_static",
- "lazycell",
- "log",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn",
- "which",
-]
-
-[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -488,15 +465,6 @@
]
[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom 7.1.3",
-]
-
-[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -556,17 +524,6 @@
"crypto-common",
"inout",
"zeroize",
-]
-
-[[package]]
-name = "clang-sys"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
-dependencies = [
- "glob",
- "libc",
- "libloading",
]
[[package]]
@@ -1242,12 +1199,6 @@
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
-[[package]]
-name = "glob"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "h2"
@@ -1332,15 +1283,6 @@
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
-]
-
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys 0.52.0",
]
[[package]]
@@ -1648,15 +1590,6 @@
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
-
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
[[package]]
name = "itertools"
@@ -1701,28 +1634,12 @@
]
[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
-[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
-name = "libloading"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
-dependencies = [
- "cfg-if",
- "windows-targets",
-]
-
-[[package]]
name = "libm"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1887,14 +1804,6 @@
"tokio-util",
"tracing",
"unindent",
-]
-
-[[package]]
-name = "nix-native-eval"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "nixrs",
]
[[package]]
@@ -1912,25 +1821,6 @@
]
[[package]]
-name = "nixrs"
-version = "0.1.0"
-source = "git+https://github.com/Anillc/nixrs#740fcf4048cc5b6de8c54d18254f12d53909a867"
-dependencies = [
- "libc",
- "nixrs-sys",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "nixrs-sys"
-version = "0.1.0"
-source = "git+https://github.com/Anillc/nixrs#740fcf4048cc5b6de8c54d18254f12d53909a867"
-dependencies = [
- "bindgen",
- "pkg-config",
-]
-
-[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2224,12 +2114,6 @@
"der",
"spki",
]
-
-[[package]]
-name = "pkg-config"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "poly1305"
@@ -3752,18 +3636,6 @@
dependencies = [
"js-sys",
"wasm-bindgen",
-]
-
-[[package]]
-name = "which"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-dependencies = [
- "either",
- "home",
- "once_cell",
- "rustix 0.38.40",
]
[[package]]
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,8 +2,8 @@
members = ["crates/*", "cmds/*"]
resolver = "2"
package.version = "0.1.0"
-package.edition = "2021"
-package.rust-version = "1.82.0"
+package.edition = "2024"
+package.rust-version = "1.86.0"
[workspace.dependencies]
better-command = { path = "./crates/better-command" }
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -1,15 +1,15 @@
use std::{env::current_dir, os::unix::fs::symlink, path::PathBuf};
-use anyhow::{anyhow, Result};
+use anyhow::{Result, anyhow};
use clap::Parser;
use fleet_base::{
- deploy::{deploy_task, upload_task, DeployAction},
+ deploy::{DeployAction, deploy_task, upload_task},
host::{Config, DeployKind, GenerationStorage},
opts::FleetOpts,
};
-use nix_eval::{nix_go, NixBuildBatch};
+use nix_eval::{NixBuildBatch, nix_go};
use tokio::task::LocalSet;
-use tracing::{error, field, info, info_span, warn, Instrument};
+use tracing::{Instrument, error, field, info, info_span, warn};
#[derive(Parser)]
pub struct Deploy {
@@ -167,11 +167,12 @@
self.action,
&host,
remote_path,
- if let Ok(v) = opts.action_attr(&host, "specialisation").await {
- v
- } else {
- error!("unreachable? failed to get specialization");
- return;
+ match opts.action_attr(&host, "specialisation").await {
+ Ok(v) => v,
+ _ => {
+ error!("unreachable? failed to get specialization");
+ return;
+ }
},
disable_rollback,
)
cmds/fleet/src/cmds/info.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/info.rs
+++ b/cmds/fleet/src/cmds/info.rs
@@ -1,6 +1,6 @@
use std::collections::BTreeSet;
-use anyhow::{ensure, Result};
+use anyhow::{Result, ensure};
use clap::Parser;
use fleet_base::host::Config;
use nix_eval::nix_go_json;
cmds/fleet/src/cmds/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/mod.rs
+++ b/cmds/fleet/src/cmds/mod.rs
@@ -1,6 +1,6 @@
pub mod build_systems;
pub mod complete;
pub mod info;
+pub mod rollback;
pub mod secrets;
pub mod tf;
-pub mod rollback;
\ No newline at end of file
cmds/fleet/src/cmds/rollback.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/rollback.rs
+++ b/cmds/fleet/src/cmds/rollback.rs
@@ -1,9 +1,9 @@
use std::collections::HashSet;
-use anyhow::{bail, Result};
+use anyhow::{Result, bail};
use clap::Parser;
use fleet_base::{
- deploy::{deploy_task, upload_task, DeployAction},
+ deploy::{DeployAction, deploy_task, upload_task},
host::{Config, ConfigHost, Generation, GenerationStorage},
opts::FleetOpts,
};
cmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -1,25 +1,25 @@
use std::{
collections::{BTreeMap, BTreeSet, HashSet},
- io::{self, stdin, stdout, Read, Write},
+ io::{self, Read, Write, stdin, stdout},
path::PathBuf,
};
use age::Recipient;
-use anyhow::{anyhow, bail, ensure, Context, Result};
+use anyhow::{Context, Result, anyhow, bail, ensure};
use chrono::{DateTime, Utc};
use clap::Parser;
use fleet_base::{
- fleetdata::{encrypt_secret_data, FleetSecret, FleetSecretPart, FleetSharedSecret},
+ fleetdata::{FleetSecret, FleetSecretPart, FleetSharedSecret, encrypt_secret_data},
host::Config,
opts::FleetOpts,
};
use fleet_shared::SecretData;
-use nix_eval::{nix_go, nix_go_json, NixBuildBatch, Value};
+use nix_eval::{NixBuildBatch, Value, nix_go, nix_go_json};
use owo_colors::OwoColorize;
use serde::Deserialize;
use tabled::{Table, Tabled};
use tokio::fs::read;
-use tracing::{error, info, info_span, warn, Instrument};
+use tracing::{Instrument, error, info, info_span, warn};
#[derive(Parser)]
pub enum Secret {
@@ -187,7 +187,9 @@
true
} else if set.difference(&expected_set).next().is_some() {
// TODO: Remove this warning for revokable secrets.
- warn!("host was removed from secret owners, but until this host rebuild, the secret will still be stored on it.");
+ warn!(
+ "host was removed from secret owners, but until this host rebuild, the secret will still be stored on it."
+ );
nix_go_json!(field.regenerateOnOwnerRemoved)
} else if expected_set.difference(&set).next().is_some() {
nix_go_json!(field.regenerateOnOwnerAdded)
@@ -296,8 +298,8 @@
let out_parent = host.mktemp_dir().await?;
let out = format!("{out_parent}/out");
- let mut gen = host.cmd(generator).await?;
- gen.env("out", &out);
+ let mut r#gen = host.cmd(generator).await?;
+ r#gen.env("out", &out);
if on.is_none() {
// This path is local, thus we can feed `OsString` directly to env var... But I don't think that's necessary to handle.
let project_path: String = config
@@ -306,9 +308,9 @@
.into_os_string()
.into_string()
.map_err(|s| anyhow!("fleet project path is not utf-8: {s:?}"))?;
- gen.env("FLEET_PROJECT", project_path);
+ r#gen.env("FLEET_PROJECT", project_path);
}
- gen.run().await.context("impure generator")?;
+ r#gen.run().await.context("impure generator")?;
{
let marker = host.read_file_text(format!("{out}/marker")).await?;
@@ -510,7 +512,9 @@
if !remove_machines.is_empty() {
// TODO: maybe force secret regeneration?
// Not that useful without revokation.
- warn!("secret will not be regenerated for removed machines, and until host rebuild, they will still possess the ability to decode secret");
+ warn!(
+ "secret will not be regenerated for removed machines, and until host rebuild, they will still possess the ability to decode secret"
+ );
}
Ok(target_machines)
}
@@ -596,7 +600,9 @@
part: part_name,
} => {
if config.has_secret(&machine, &name) && !replace && !merge {
- bail!("secret already defined.\nUse --replace to override, or --merge to add new parts to existing secret");
+ bail!(
+ "secret already defined.\nUse --replace to override, or --merge to add new parts to existing secret"
+ );
}
let mut out = if merge && !replace {
cmds/fleet/src/extra_args.rsdiffbeforeafterboth--- a/cmds/fleet/src/extra_args.rs
+++ b/cmds/fleet/src/extra_args.rs
@@ -1,6 +1,6 @@
use std::ffi::{OsStr, OsString};
-use anyhow::{anyhow, Result};
+use anyhow::{Result, anyhow};
pub fn parse_os(os: &OsStr) -> Result<Vec<OsString>> {
Ok(shlex::bytes::split(os.as_encoded_bytes())
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -6,27 +6,27 @@
use std::{ffi::OsString, process::ExitCode};
-use anyhow::{bail, Result};
+use anyhow::{Result, bail};
use clap::{CommandFactory, Parser};
use cmds::{
build_systems::{BuildSystems, Deploy},
- rollback::RollbackSingle,
complete::Complete,
info::Info,
+ rollback::RollbackSingle,
secrets::Secret,
tf::Tf,
};
use fleet_base::{host::Config, opts::FleetOpts};
-use futures::{future::LocalBoxFuture, stream::FuturesUnordered, TryStreamExt};
+use futures::{TryStreamExt, future::LocalBoxFuture, stream::FuturesUnordered};
// use host::Config;
#[cfg(feature = "indicatif")]
use human_repr::HumanCount;
#[cfg(feature = "indicatif")]
use indicatif::{ProgressState, ProgressStyle};
-use tracing::{error, info, info_span, Instrument};
+use tracing::{Instrument, error, info, info_span};
#[cfg(feature = "indicatif")]
use tracing_indicatif::IndicatifLayer;
-use tracing_subscriber::{prelude::*, EnvFilter};
+use tracing_subscriber::{EnvFilter, prelude::*};
#[derive(Parser)]
struct Prefetch {}
cmds/generator-helper/src/main.rsdiffbeforeafterboth--- a/cmds/generator-helper/src/main.rs
+++ b/cmds/generator-helper/src/main.rs
@@ -1,21 +1,22 @@
use std::{
env,
fs::{File, OpenOptions},
- io::{self, copy, stdin, stdout, Read, Write},
+ io::{self, Read, Write, copy, stdin, stdout},
str::FromStr,
};
use age::{
+ Encryptor, Recipient,
ssh::{ParseRecipientKeyError, Recipient as SshRecipient},
- Encryptor, Recipient,
};
-use anyhow::{anyhow, bail, ensure, Context, Result};
+use anyhow::{Context, Result, anyhow, bail, ensure};
use clap::{Parser, ValueEnum};
use ed25519_dalek::SecretKey;
use fleet_shared::SecretData;
use rand::{
+ RngCore,
distr::{Alphanumeric, Distribution, SampleString, Uniform},
- rng, RngCore,
+ rng,
};
fn write_output_file(out: &str) -> Result<File> {
@@ -78,7 +79,9 @@
let list = match list {
Ok(v) => v,
Err(env::VarError::NotPresent) => {
- bail!("gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities");
+ bail!(
+ "gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities"
+ );
}
Err(e) => bail!("somehow, identities list is not utf-8: {e}"),
};
@@ -254,13 +257,7 @@
write_private(
&recipients,
&private,
- &key[..{
- if no_embed_public {
- 32
- } else {
- 64
- }
- }],
+ &key[..{ if no_embed_public { 32 } else { 64 } }],
encoding,
)?;
}
cmds/install-secrets/src/main.rsdiffbeforeafterboth--- a/cmds/install-secrets/src/main.rs
+++ b/cmds/install-secrets/src/main.rs
@@ -5,20 +5,20 @@
iter,
os::unix::prelude::PermissionsExt,
path::{Path, PathBuf},
- str::{from_utf8, FromStr},
+ str::{FromStr, from_utf8},
};
use age::{
- ssh::{Identity as SshIdentity, Recipient as SshRecipient},
Decryptor, Encryptor, Identity, Recipient,
+ ssh::{Identity as SshIdentity, Recipient as SshRecipient},
};
-use anyhow::{anyhow, bail, ensure, Context, Result};
+use anyhow::{Context, Result, anyhow, bail, ensure};
use clap::Parser;
use fleet_shared::SecretData;
-use nix::unistd::{chown, Group, User};
+use nix::unistd::{Group, User, chown};
use serde::Deserialize;
use tracing::{error, info, info_span};
-use tracing_subscriber::{filter::LevelFilter, EnvFilter};
+use tracing_subscriber::{EnvFilter, filter::LevelFilter};
#[derive(Parser)]
#[clap(author)]
cmds/terraform-provider-fleet/src/main.rsdiffbeforeafterboth--- a/cmds/terraform-provider-fleet/src/main.rs
+++ b/cmds/terraform-provider-fleet/src/main.rs
@@ -1,3 +1,5 @@
fn main() {
- panic!("this is a stub, real provider is in development, I just don't want to keep it in different branch.")
+ panic!(
+ "this is a stub, real provider is in development, I just don't want to keep it in different branch."
+ )
}
crates/better-command/src/handler.rsdiffbeforeafterboth--- a/crates/better-command/src/handler.rs
+++ b/crates/better-command/src/handler.rs
@@ -7,7 +7,7 @@
use regex::Regex;
use serde::Deserialize;
-use tracing::{info, info_span, warn, Span};
+use tracing::{Span, info, info_span, warn};
#[cfg(feature = "indicatif")]
use tracing_indicatif::span_ext::IndicatifSpanExt as _;
@@ -112,9 +112,13 @@
match log {
NixLog::Msg { msg, raw_msg, .. } => {
#[allow(clippy::nonminimal_bool)]
- if !(msg.starts_with("\u{1b}[35;1mwarning:\u{1b}[0m Git tree '") && msg.ends_with("' is dirty"))
- && !msg.starts_with("\u{1b}[35;1mwarning:\u{1b}[0m not writing modified lock file of flake")
- && msg != "\u{1b}[35;1mwarning:\u{1b}[0m \u{1b}[31;1merror:\u{1b}[0m SQLite database '\u{1b}[35;1m/nix/var/nix/db/db.sqlite\u{1b}[0m' is busy" {
+ if !(msg.starts_with("\u{1b}[35;1mwarning:\u{1b}[0m Git tree '")
+ && msg.ends_with("' is dirty"))
+ && !msg.starts_with(
+ "\u{1b}[35;1mwarning:\u{1b}[0m not writing modified lock file of flake",
+ ) && msg
+ != "\u{1b}[35;1mwarning:\u{1b}[0m \u{1b}[31;1merror:\u{1b}[0m SQLite database '\u{1b}[35;1m/nix/var/nix/db/db.sqlite\u{1b}[0m' is busy"
+ {
if let Some(raw_msg) = raw_msg {
if !msg.is_empty() {
info!(target: "nix", "{}\n{}", raw_msg.trim_end(), msg.trim_end())
@@ -156,8 +160,12 @@
id,
..
} if typ == 100 && fields.len() >= 3 => {
- if let [LogField::String(drv), LogField::String(from), LogField::String(to), ..] =
- &fields[..]
+ if let [
+ LogField::String(drv),
+ LogField::String(from),
+ LogField::String(to),
+ ..,
+ ] = &fields[..]
{
let mut drv = drv.as_str();
@@ -289,8 +297,12 @@
}
NixLog::Result { fields, id, typ } if typ == 105 && fields.len() >= 4 => {
if let Some(span) = self.spans.get(&id) {
- if let [LogField::Num(done), LogField::Num(expected), LogField::Num(_running), LogField::Num(_failed)] =
- &fields[..4]
+ if let [
+ LogField::Num(done),
+ LogField::Num(expected),
+ LogField::Num(_running),
+ LogField::Num(_failed),
+ ] = &fields[..4]
{
#[cfg(feature = "indicatif")]
{
crates/fleet-base/src/command.rsdiffbeforeafterboth--- a/crates/fleet-base/src/command.rs
+++ b/crates/fleet-base/src/command.rs
@@ -1,6 +1,6 @@
use std::{ffi::OsStr, pin, process::Stdio, sync::Arc, task::Poll};
-use anyhow::{anyhow, Result};
+use anyhow::{Result, anyhow};
use better_command::{Handler, NixHandler, PlainHandler};
use futures::StreamExt;
use itertools::Either;
@@ -68,10 +68,9 @@
}
}
fn new_here(&self, cmd: impl AsRef<OsStr>) -> Self {
- if let Some(ssh_session) = self.ssh_session.clone() {
- Self::new_on(self.escalation, cmd, ssh_session)
- } else {
- Self::new(self.escalation, cmd)
+ match self.ssh_session.clone() {
+ Some(ssh_session) => Self::new_on(self.escalation, cmd, ssh_session),
+ _ => Self::new(self.escalation, cmd),
}
}
@@ -139,15 +138,18 @@
out
}
fn into_command(self) -> Result<Either<Command, openssh::OwningCommand<Arc<Session>>>> {
- Ok(if let Some(session) = self.ssh_session.clone() {
- let cmd = self.translate_env_into_env().into_command_unchecked_local();
- Either::Right(
- cmd.over_ssh(session)
- .map_err(|e| anyhow!("ssh error: {e}"))?,
- )
- } else {
- let cmd = self.into_command_unchecked_local();
- Either::Left(cmd)
+ Ok(match self.ssh_session.clone() {
+ Some(session) => {
+ let cmd = self.translate_env_into_env().into_command_unchecked_local();
+ Either::Right(
+ cmd.over_ssh(session)
+ .map_err(|e| anyhow!("ssh error: {e}"))?,
+ )
+ }
+ _ => {
+ let cmd = self.into_command_unchecked_local();
+ Either::Left(cmd)
+ }
})
}
pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
crates/fleet-base/src/deploy.rsdiffbeforeafterboth--- a/crates/fleet-base/src/deploy.rs
+++ b/crates/fleet-base/src/deploy.rs
@@ -1,10 +1,10 @@
use std::{path::PathBuf, time::Duration};
-use anyhow::{anyhow, bail, Context as _, Result};
+use anyhow::{Context as _, Result, anyhow, bail};
use clap::ValueEnum;
use itertools::Itertools;
use tokio::time::sleep;
-use tracing::{error, info, info_span, warn, Instrument as _};
+use tracing::{Instrument as _, error, info, info_span, warn};
use crate::host::{Config, ConfigHost, DeployKind, Generation, GenerationStorage};
@@ -221,7 +221,9 @@
.in_current_span()
.await
{
- error!("failed to remove rollback marker. This is bad, as the system will be rolled back by watchdog: {e}")
+ error!(
+ "failed to remove rollback marker. This is bad, as the system will be rolled back by watchdog: {e}"
+ )
}
}
info!("disarming watchdog, just in case");
@@ -233,12 +235,17 @@
error!("failed to disarm rollback run: {e}");
}
}
- } else if let Err(_e) = host
- .rm_file("/etc/fleet_rollback_marker", true)
- .in_current_span()
- .await
- {
- // Marker might not exist, yet better try to remove it.
+ } else {
+ match host
+ .rm_file("/etc/fleet_rollback_marker", true)
+ .in_current_span()
+ .await
+ {
+ Err(_e) => {
+ // Marker might not exist, yet better try to remove it.
+ }
+ _ => {}
+ }
}
}
Ok(())
crates/fleet-base/src/fleetdata.rsdiffbeforeafterboth--- a/crates/fleet-base/src/fleetdata.rs
+++ b/crates/fleet-base/src/fleetdata.rs
@@ -10,7 +10,7 @@
distr::{Alphanumeric, SampleString as _},
rng,
};
-use serde::{de::Error, Deserialize, Serialize};
+use serde::{Deserialize, Serialize, de::Error};
use serde_json::Value;
#[derive(Serialize, Deserialize, Default)]
crates/fleet-base/src/host.rsdiffbeforeafterboth1use std::{2 cell::OnceCell,3 collections::BTreeSet,4 ffi::{OsStr, OsString},5 fmt::Display,6 io::Write,7 ops::Deref,8 path::PathBuf,9 str::FromStr,10 sync::{Arc, Mutex, MutexGuard, OnceLock},11};1213use anyhow::{anyhow, bail, ensure, Context, Result};14use fleet_shared::SecretData;15use nix_eval::{nix_go, nix_go_json, util::assert_warn, NixSession, Value};16use openssh::SessionBuilder;17use serde::de::DeserializeOwned;18use tabled::Tabled;19use tempfile::NamedTempFile;20use time::{format_description, UtcDateTime};21use tracing::warn;2223use crate::{24 command::MyCommand,25 fleetdata::{FleetData, FleetSecret, FleetSharedSecret},26};2728pub struct FleetConfigInternals {29 /// Fleet project directory, containing fleet.nix file.30 pub directory: PathBuf,31 /// builtins.currentSystem32 pub local_system: String,33 pub data: Mutex<FleetData>,34 pub nix_args: Vec<OsString>,35 /// fleet_config.config36 pub config_field: Value,37 // TODO: Remove with connectivity refactor38 pub localhost: String,3940 /// import nixpkgs {system = local};41 pub default_pkgs: Value,42 /// inputs.nixpkgs43 pub nixpkgs: Value,4445 pub nix_session: NixSession,46}4748// TODO: Make field not pub49#[derive(Clone)]50pub struct Config(pub Arc<FleetConfigInternals>);5152impl Deref for Config {53 type Target = FleetConfigInternals;5455 fn deref(&self) -> &Self::Target {56 &self.057 }58}5960#[derive(Clone, Copy, Debug)]61pub enum EscalationStrategy {62 Sudo,63 Run0,64 Su,65}6667#[derive(Clone, PartialEq, Copy, Debug)]68pub enum DeployKind {69 /// NixOS => NixOS managed by fleet70 UpgradeToFleet,71 /// NixOS managed by fleet => NixOS managed by fleet72 Fleet,73 /// Remote host has /mnt, /mnt/boot mounted,74 /// generated config is added to fleet configuration.75 NixosInstall,76 /// Remote host has some system and nix installed in multi-user mode (/nix is owned by root),77 /// generated config is added to fleet configuration,78 /// and /etc/NIXOS_LUSTRATE exists, fleet will perform the rest.79 NixosLustrate,80}8182impl FromStr for DeployKind {83 type Err = anyhow::Error;84 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {85 match s {86 "upgrade-to-fleet" => Ok(Self::UpgradeToFleet),87 "fleet" => Ok(Self::Fleet),88 "nixos-install" => Ok(Self::NixosInstall),89 "nixos-lustrate" => Ok(Self::NixosLustrate),90 v => bail!("unknown deploy_kind: {v}; expected on of \"upgrade-to-fleet\", \"fleet\", \"nixos-install\", \"nixos-lustrate\""),91 }92 }93}94pub struct ConfigHost {95 config: Config,96 pub name: String,97 groups: OnceCell<Vec<String>>,9899 deploy_kind: OnceCell<DeployKind>,100101 pub host_config: Option<Value>,102 pub nixos_config: OnceCell<Value>,103 pub nixos_unchecked_config: OnceCell<Value>,104 pub pkgs_override: Option<Value>,105106 // TODO: Move command helpers away with connectivity refactor107 pub local: bool,108 pub session: OnceLock<Arc<openssh::Session>>,109}110111#[derive(Debug, Clone, Copy)]112pub enum GenerationStorage {113 Deployer,114 Machine,115 Pusher,116}117impl GenerationStorage {118 fn prefix(&self) -> &'static str {119 match self {120 GenerationStorage::Deployer => "deployer.",121 GenerationStorage::Machine => "",122 GenerationStorage::Pusher => "pusher.",123 }124 }125}126127#[derive(Tabled, Debug)]128pub struct Generation {129 #[tabled(rename = "ID", format("{}", self.rollback_id()))]130 pub id: u32,131 #[tabled(rename = "Current")]132 pub current: bool,133 #[tabled(rename = "Created at")]134 pub datetime: UtcDateTime,135 #[tabled(format = "{:?}")]136 pub store_path: PathBuf,137 #[tabled(skip)]138 pub location: GenerationStorage,139}140impl Generation {141 pub fn rollback_id(&self) -> String {142 format!("{}{}", self.location.prefix(), self.id)143 }144}145146fn parse_generation_line(g: &str) -> Option<Generation> {147 let mut parts = g.split_whitespace();148 let id = parts.next()?;149 let id: u32 = id.parse().ok()?;150 let date = parts.next()?;151 let time = parts.next()?;152 let current = if let Some(current) = parts.next() {153 if current == "(current)" {154 Some(true)155 } else {156 None157 }158 } else {159 Some(false)160 };161 let current = current?;162 if parts.next().is_some() {163 warn!("unexpected text after generation: {g}");164 }165166 let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")167 .expect("valid format");168 let datetime = UtcDateTime::parse(&format!("{date} {time}"), &format).ok()?;169170 Some(Generation {171 id,172 current,173 datetime,174 store_path: PathBuf::new(),175 location: GenerationStorage::Machine,176 })177}178// TODO: Move command helpers away with connectivity refactor179impl ConfigHost {180 pub async fn list_generations(&self, profile: &str) -> Result<Vec<Generation>> {181 let mut cmd = self.cmd("nix-env").await?;182 cmd.comparg("--profile", format!("/nix/var/nix/profiles/{profile}"))183 .arg("--list-generations")184 .env("TZ", "UTC");185 // Sudo is required because --list-generations tries to acquire profile lock186 let data = cmd.sudo().run_string().await?;187 let mut generations = data188 .split('\n')189 .map(|e| e.trim())190 .filter(|&l| !l.is_empty())191 .filter_map(|g| {192 let gen = parse_generation_line(g);193 if gen.is_none() {194 warn!("bad generation: {g}");195 };196 gen197 })198 .collect::<Vec<_>>();199 for ele in generations.iter_mut() {200 let mut cmd = self.cmd("readlink").await?;201 cmd.arg("--")202 .arg(format!("/nix/var/nix/profiles/{profile}-{}-link", ele.id));203 let path = cmd.run_string().await?;204 ele.store_path = PathBuf::from(path.trim_end_matches("\n"));205 }206207 Ok(generations)208 }209210 pub fn set_deploy_kind(&self, kind: DeployKind) {211 self.deploy_kind212 .set(kind)213 .ok()214 .expect("deploy kind is already set");215 }216 pub async fn deploy_kind(&self) -> Result<DeployKind> {217 if let Some(kind) = self.deploy_kind.get() {218 return Ok(kind.clone());219 }220 let is_fleet_managed = match self.file_exists("/etc/FLEET_HOST").await {221 Ok(v) => v,222 Err(e) => {223 bail!("failed to query remote system kind: {}", e);224 }225 };226 if !is_fleet_managed {227 bail!(indoc::indoc! {"228 host is not marked as managed by fleet229 if you're not trying to lustrate/install system from scratch,230 you should either231 1. manually create /etc/FLEET_HOST file on the target host,232 2. use ?deploy_kind=fleet host argument if you're upgrading from older version of fleet233 3. use ?deploy_kind=upgrade_to_fleet if you're upgrading from plain nixos to fleet-managed nixos234 "});235 }236 // TOCTOU is possible237 let _ = self.deploy_kind.set(DeployKind::Fleet);238 Ok(self239 .deploy_kind240 .get()241 .expect("deploy kind is just set")242 .clone())243 }244 pub async fn escalation_strategy(&self) -> Result<EscalationStrategy> {245 // Prefer sudo, as run0 has some gotchas with polkit246 // and too many repeating prompts.247 if (self.find_in_path("sudo").await).is_ok() {248 return Ok(EscalationStrategy::Sudo);249 }250 if (self.find_in_path("run0").await).is_ok() {251 return Ok(EscalationStrategy::Run0);252 }253 Ok(EscalationStrategy::Su)254 }255 async fn open_session(&self) -> Result<Arc<openssh::Session>> {256 assert!(!self.local, "do not open ssh connection to local session");257 // FIXME: TOCTOU258 if let Some(session) = &self.session.get() {259 return Ok((*session).clone());260 };261 let session = SessionBuilder::default();262 let session = session263 .connect(&self.name)264 .await265 .map_err(|e| anyhow!("ssh error while connecting to {}: {e:#?}", self.name))?;266 let session = Arc::new(session);267 self.session.set(session.clone()).expect("TOCTOU happened");268 Ok(session)269 }270 pub async fn mktemp_dir(&self) -> Result<String> {271 let mut cmd = self.cmd("mktemp").await?;272 cmd.arg("-d");273 let path = cmd.run_string().await?;274 Ok(path.trim_end().to_owned())275 }276 pub async fn file_exists(&self, path: impl AsRef<OsStr>) -> Result<bool> {277 let mut cmd = self.cmd("sh").await?;278 cmd.arg("-c")279 .arg("test -e \"$1\" && echo true || echo false")280 .arg("_")281 .arg(path);282 Ok(cmd.run_value().await?)283 }284 pub async fn read_file_bin(&self, path: impl AsRef<OsStr>) -> Result<Vec<u8>> {285 let mut cmd = self.cmd("cat").await?;286 cmd.arg(path);287 cmd.run_bytes().await288 }289 pub async fn read_file_text(&self, path: impl AsRef<OsStr>) -> Result<String> {290 let mut cmd = self.cmd("cat").await?;291 cmd.arg(path);292 cmd.run_string().await293 }294 pub async fn read_dir(&self, path: impl AsRef<OsStr>) -> Result<Vec<String>> {295 let mut cmd = self.cmd("ls").await?;296 cmd.arg(path);297 let out = cmd.run_string().await?;298 let mut lines = out.split('\n');299 if let Some(last) = lines.next_back() {300 ensure!(last.is_empty(), "output of ls should end with newline");301 }302 Ok(lines.map(ToOwned::to_owned).collect())303 }304 #[allow(dead_code)]305 pub async fn read_file_json<D: DeserializeOwned>(&self, path: impl AsRef<OsStr>) -> Result<D> {306 let text = self.read_file_text(path).await?;307 Ok(serde_json::from_str(&text)?)308 }309 pub async fn read_env(&self, env: &str) -> Result<String> {310 let mut cmd = self.cmd("printenv").await?;311 cmd.arg(env);312 cmd.run_string().await313 }314 pub async fn find_in_path(&self, command: &str) -> Result<String> {315 // // `which` is not a part of coreutils, and it might not exist on machine.316 // let path = self.read_env("PATH").await?;317 // // Assuming delimiter is :, we don't work with windows host, this check will be much318 // // more sophisticated in remowt backend (and quicker, since actual PATH search will be done on remote machine)319 // for ele in path.split(':') {320 // let test_path = format!("{ele}/{cmd}");321 // test -x etc322 // }323 // let mut cmd = self.cmd("printenv").await?;324 // cmd.arg(env);325 // Ok(cmd.run_string().await?)326 // Assuming this is an environment issue if which doesn't exist, will be fixed with remowt.327 let mut cmd = self328 .cmd_escalation(329 // Not used330 EscalationStrategy::Su,331 "which",332 )333 .await?;334 cmd.arg(command);335 cmd.run_string().await336 }337 pub async fn read_file_value<D: FromStr>(&self, path: impl AsRef<OsStr>) -> Result<D>338 where339 <D as FromStr>::Err: Display,340 {341 let text = self.read_file_text(path).await?;342 D::from_str(&text).map_err(|e| anyhow!("failed to parse value: {e}"))343 }344 pub async fn cmd(&self, cmd: impl AsRef<OsStr>) -> Result<MyCommand> {345 self.cmd_escalation(self.escalation_strategy().await?, cmd)346 .await347 }348 pub async fn cmd_escalation(349 &self,350 escalation: EscalationStrategy,351 cmd: impl AsRef<OsStr>,352 ) -> Result<MyCommand> {353 if self.local {354 Ok(MyCommand::new(escalation, cmd))355 } else {356 let session = self.open_session().await?;357 Ok(MyCommand::new_on(escalation, cmd, session))358 }359 }360 pub async fn nix_cmd(&self) -> Result<MyCommand> {361 let mut nix = self.cmd("nix").await?;362 nix.args([363 "--extra-experimental-features",364 "nix-command",365 "--extra-experimental-features",366 "flakes",367 ]);368 Ok(nix)369 }370371 pub async fn decrypt(&self, data: SecretData) -> Result<Vec<u8>> {372 ensure!(data.encrypted, "secret is not encrypted");373 let mut cmd = self.cmd("fleet-install-secrets").await?;374 cmd.arg("decrypt").eqarg("--secret", data.to_string());375 let encoded = cmd376 .sudo()377 .run_string()378 .await379 .context("failed to call remote host for decrypt")?;380 let data: SecretData = encoded.parse().map_err(|e| anyhow!("{e}"))?;381 ensure!(!data.encrypted, "secret came out encrypted");382 Ok(data.data)383 }384 pub async fn reencrypt(&self, data: SecretData, targets: Vec<String>) -> Result<SecretData> {385 ensure!(data.encrypted, "secret is not encrypted");386 let mut cmd = self.cmd("fleet-install-secrets").await?;387 cmd.arg("reencrypt").eqarg("--secret", data.to_string());388 for target in targets {389 let key = self.config.key(&target).await?;390 cmd.eqarg("--targets", key);391 }392 let encoded = cmd393 .sudo()394 .run_string()395 .await396 .context("failed to call remote host for decrypt")?;397 let data: SecretData = encoded.parse().map_err(|e| anyhow!("{e}"))?;398 ensure!(data.encrypted, "secret came out not encrypted");399 Ok(data)400 }401 /// Returns path for futureproofing, as path might change i.e on conversion to CA402 pub async fn remote_derivation(&self, path: &PathBuf) -> Result<PathBuf> {403 if self.local {404 // Path is located locally, thus already trusted.405 return Ok(path.to_owned());406 }407 let mut nix = MyCommand::new(408 // Not used409 EscalationStrategy::Su,410 "nix",411 );412 nix.arg("copy").arg("--substitute-on-destination");413414 match self.deploy_kind().await? {415 DeployKind::Fleet | DeployKind::UpgradeToFleet | DeployKind::NixosLustrate => {416 nix.comparg("--to", format!("ssh-ng://{}", self.name));417 }418 DeployKind::NixosInstall => {419 nix420 // Signature checking makes no sense with remote-store store argument set, as we're not even interacting with remote nix daemon421 .arg("--no-check-sigs")422 .comparg(423 "--to",424 format!("ssh-ng://root@{}?remote-store=/mnt", self.name),425 );426 }427 }428 nix.arg(path);429 nix.run_nix().await.context("nix copy")?;430 Ok(path.to_owned())431 }432 pub async fn systemctl_stop(&self, name: &str) -> Result<()> {433 let mut cmd = self.cmd("systemctl").await?;434 cmd.arg("stop").arg(name);435 cmd.sudo().run().await436 }437 pub async fn systemctl_start(&self, name: &str) -> Result<()> {438 let mut cmd = self.cmd("systemctl").await?;439 cmd.arg("start").arg(name);440 cmd.sudo().run().await441 }442443 pub async fn rm_file(&self, path: impl AsRef<OsStr>, sudo: bool) -> Result<()> {444 let mut cmd = self.cmd("rm").await?;445 cmd.arg("-f").arg(path);446 if sudo {447 cmd = cmd.sudo()448 }449 cmd.run().await450 }451}452impl ConfigHost {453 // TOCTOU is possible here in case if config is changed, but this case is not handled anywhere anyway,454 // assuming getting tags always returns the same value.455 pub async fn tags(&self) -> Result<Vec<String>> {456 if let Some(v) = self.groups.get() {457 return Ok(v.clone());458 }459 let Some(host_config) = &self.host_config else {460 return Ok(vec![]);461 };462 let tags: Vec<String> = nix_go_json!(host_config.tags);463464 let _ = self.groups.set(tags.clone());465466 Ok(tags)467 }468 pub async fn nixos_config(&self) -> Result<Value> {469 if let Some(v) = self.nixos_config.get() {470 return Ok(v.clone());471 }472 let Some(host_config) = &self.host_config else {473 bail!("local host has no nixos_config");474 };475 let nixos_config = nix_go!(host_config.nixos.config);476 assert_warn("nixos config evaluation", &nixos_config).await?;477478 let _ = self.nixos_config.set(nixos_config.clone());479480 Ok(nixos_config)481 }482 pub async fn nixos_unchecked_config(&self) -> Result<Value> {483 if let Some(v) = self.nixos_unchecked_config.get() {484 return Ok(v.clone());485 }486 let Some(host_config) = &self.host_config else {487 bail!("local host has no nixos_config");488 };489 let nixos_config = nix_go!(host_config.nixos_unchecked.config);490491 let _ = self.nixos_unchecked_config.set(nixos_config.clone());492493 Ok(nixos_config)494 }495496 pub async fn list_configured_secrets(&self) -> Result<Vec<String>> {497 let nixos = self.nixos_unchecked_config().await?;498 let secrets = nix_go!(nixos.secrets);499 let mut out = Vec::new();500 for name in secrets.list_fields().await? {501 let secret = nix_go!(secrets[{ name }]);502 let is_shared: bool = nix_go_json!(secret.shared);503 if is_shared {504 continue;505 }506 out.push(name);507 }508 Ok(out)509 }510 pub async fn secret_field(&self, name: &str) -> Result<Value> {511 let nixos = self.nixos_unchecked_config().await?;512 Ok(nix_go!(nixos.secrets[{ name }]))513 }514515 /// Packages for this host, resolved with nixpkgs overlays516 pub async fn pkgs(&self) -> Result<Value> {517 if let Some(value) = &self.pkgs_override {518 return Ok(value.clone());519 }520 let Some(host_config) = &self.host_config else {521 bail!("local host has no host_config");522 };523 // TODO: Should nixos.options be cached?524 Ok(nix_go!(host_config.nixos.options._module.args.value.pkgs))525 }526}527528impl Config {529 pub async fn tagged_hostnames(&self, tag: &str) -> Result<Vec<String>> {530 let config = &self.config_field;531 let tagged: Vec<String> = nix_go_json!(config.taggedWith[{ tag }]);532 Ok(tagged)533 }534 pub async fn expand_owner_set(&self, owners: Vec<String>) -> Result<BTreeSet<String>> {535 let mut out = BTreeSet::new();536 for owner in owners {537 if let Some(tag) = owner.strip_prefix('@') {538 let hosts = self.tagged_hostnames(tag).await?;539 out.extend(hosts);540 } else {541 out.insert(owner);542 }543 }544 Ok(out)545 }546 pub fn local_host(&self) -> ConfigHost {547 ConfigHost {548 config: self.clone(),549 name: "<virtual localhost>".to_owned(),550 host_config: None,551 nixos_config: OnceCell::new(),552 nixos_unchecked_config: OnceCell::new(),553 groups: {554 let cell = OnceCell::new();555 let _ = cell.set(vec![]);556 cell557 },558 pkgs_override: Some(self.default_pkgs.clone()),559560 local: true,561 session: OnceLock::new(),562 deploy_kind: OnceCell::new(),563 }564 }565566 pub async fn host(&self, name: &str) -> Result<ConfigHost> {567 let config = &self.config_field;568 let host_config = nix_go!(config.hosts[{ name }]);569570 Ok(ConfigHost {571 config: self.clone(),572 name: name.to_owned(),573 host_config: Some(host_config),574 nixos_config: OnceCell::new(),575 nixos_unchecked_config: OnceCell::new(),576 groups: OnceCell::new(),577 pkgs_override: None,578579 // TODO: Remove with connectivit refactor580 local: self.localhost == name,581 session: OnceLock::new(),582 deploy_kind: OnceCell::new(),583 })584 }585 pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {586 let config = &self.config_field;587 let names = nix_go!(config.hosts).list_fields().await?;588 let mut out = vec![];589 for name in names {590 out.push(self.host(&name).await?);591 }592 Ok(out)593 }594 // TODO: Replace usages with .host().nixos_config595 pub async fn system_config(&self, host: &str) -> Result<Value> {596 let fleet_field = &self.config_field;597 Ok(nix_go!(fleet_field.hosts[{ host }].nixos.config))598 }599600 /// Shared secrets configured in fleet.nix or in flake601 pub async fn list_configured_shared(&self) -> Result<Vec<String>> {602 let config_field = &self.config_field;603 Ok(nix_go!(config_field.sharedSecrets).list_fields().await?)604 }605 /// Shared secrets configured in fleet.nix606 pub fn list_shared(&self) -> Vec<String> {607 let data = self.data();608 data.shared_secrets.keys().cloned().collect()609 }610 pub fn has_shared(&self, name: &str) -> bool {611 let data = self.data();612 data.shared_secrets.contains_key(name)613 }614 pub fn replace_shared(&self, name: String, shared: FleetSharedSecret) {615 let mut data = self.data_mut();616 data.shared_secrets.insert(name.to_owned(), shared);617 }618 pub fn remove_shared(&self, secret: &str) {619 let mut data = self.data_mut();620 data.shared_secrets.remove(secret);621 }622623 pub fn list_secrets(&self, host: &str) -> Vec<String> {624 let data = self.data();625 let Some(secrets) = data.host_secrets.get(host) else {626 return Vec::new();627 };628 secrets.keys().cloned().collect()629 }630631 pub fn has_secret(&self, host: &str, secret: &str) -> bool {632 let data = self.data();633 let Some(host_secrets) = data.host_secrets.get(host) else {634 return false;635 };636 host_secrets.contains_key(secret)637 }638 pub fn insert_secret(&self, host: &str, secret: String, value: FleetSecret) {639 let mut data = self.data_mut();640 let host_secrets = data.host_secrets.entry(host.to_owned()).or_default();641 host_secrets.insert(secret, value);642 }643644 pub fn host_secret(&self, host: &str, secret: &str) -> Result<FleetSecret> {645 let data = self.data();646 let Some(host_secrets) = data.host_secrets.get(host) else {647 bail!("no secrets for machine {host}");648 };649 let Some(secret) = host_secrets.get(secret) else {650 bail!("machine {host} has no secret {secret}");651 };652 Ok(secret.clone())653 }654 pub fn shared_secret(&self, secret: &str) -> Result<FleetSharedSecret> {655 let data = self.data();656 let Some(secret) = data.shared_secrets.get(secret) else {657 bail!("no shared secret {secret}");658 };659 Ok(secret.clone())660 }661 pub async fn shared_secret_expected_owners(&self, secret: &str) -> Result<Vec<String>> {662 let config_field = &self.config_field;663 Ok(nix_go_json!(664 config_field.sharedSecrets[{ secret }].expectedOwners665 ))666 }667668 // TODO: Should this be something modifiable from other processes?669 // E.g terraform provider might want to update FleetData (e.g secrets),670 // and current implementation assumes only one process holds current fleet.nix671 // Given that it is no longer needs to be a file for nix evaluation,672 // maybe it can be a .nix file for persistence, but accessible only673 // thru some shared state controller? Might it be stored in terraform674 // state provider?675 pub fn data(&self) -> MutexGuard<FleetData> {676 self.data.lock().unwrap()677 }678 pub fn data_mut(&self) -> MutexGuard<FleetData> {679 self.data.lock().unwrap()680 }681 pub fn save(&self) -> Result<()> {682 let mut tempfile = NamedTempFile::new_in(self.directory.clone()).context("failed to create updated version of fleet.nix in the same directory as original.\nDo you have write access to it? Access only to the fleet.nix won't be enough, the directory is used for atomic overwrite operation.\nIt is not recommended to use fleet by root anyway, move fleet project to your home directory.")?;683 let data = nixlike::serialize(&self.data() as &FleetData)?;684 tempfile.write_all(685 format!(686 "# This file contains fleet state and shouldn't be edited by hand\n\n{}\n\n# vim: ts=2 et nowrap\n",687 data688 )689 .as_bytes(),690 )?;691 let mut fleet_data_path = self.directory.clone();692 fleet_data_path.push("fleet.nix");693 tempfile.persist(fleet_data_path)?;694 Ok(())695 }696}crates/fleet-base/src/keys.rsdiffbeforeafterboth--- a/crates/fleet-base/src/keys.rs
+++ b/crates/fleet-base/src/keys.rs
@@ -1,7 +1,7 @@
use std::str::FromStr as _;
use age::Recipient;
-use anyhow::{anyhow, Result};
+use anyhow::{Result, anyhow};
use futures::{StreamExt as _, TryStreamExt as _};
use itertools::Itertools as _;
use tracing::warn;
@@ -39,12 +39,12 @@
}
}
/// Insecure, requires root
- pub async fn recipient(&self, host: &str) -> anyhow::Result<impl Recipient> {
+ pub async fn recipient(&self, host: &str) -> anyhow::Result<impl Recipient + use<>> {
let key = self.key(host).await?;
age::ssh::Recipient::from_str(&key).map_err(|e| anyhow!("parse recipient error: {:?}", e))
}
- pub async fn recipients(&self, hosts: Vec<String>) -> Result<Vec<impl Recipient>> {
+ pub async fn recipients(&self, hosts: Vec<String>) -> Result<Vec<impl Recipient + use<>>> {
let hosts = self.expand_owner_set(hosts).await?;
futures::stream::iter(hosts.iter())
.then(|m| self.recipient(m.as_ref()))
crates/fleet-base/src/lib.rsdiffbeforeafterboth--- a/crates/fleet-base/src/lib.rs
+++ b/crates/fleet-base/src/lib.rs
@@ -1,6 +1,6 @@
pub mod command;
+pub mod deploy;
pub mod fleetdata;
pub mod host;
mod keys;
pub mod opts;
-pub mod deploy;
\ No newline at end of file
crates/fleet-base/src/opts.rsdiffbeforeafterboth--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -6,15 +6,15 @@
sync::{Arc, Mutex},
};
-use anyhow::{bail, Context, Result};
-use nix_eval::{nix_go, util::assert_warn, NixSessionPool, Value};
+use anyhow::{Context, Result, bail};
+use nix_eval::{NixSessionPool, Value, nix_go, util::assert_warn};
use nom::{
+ Parser,
bytes::complete::take_while1,
character::complete::char,
combinator::{map, opt},
multi::separated_list1,
sequence::{preceded, separated_pair},
- Parser,
};
use crate::{
@@ -44,7 +44,8 @@
let (input, name) = map(
take_while1(|v| v != ',' && v != '?' && v != '@'),
str::to_owned,
- ).parse_complete(input)
+ )
+ .parse_complete(input)
.map_err(err_to_string)?;
let kw_item = separated_pair(
crates/fleet-shared/src/encoding.rsdiffbeforeafterboth--- a/crates/fleet-shared/src/encoding.rs
+++ b/crates/fleet-shared/src/encoding.rs
@@ -3,8 +3,8 @@
str::FromStr,
};
-use base64::engine::{general_purpose::STANDARD_NO_PAD, Engine};
-use serde::{de::Error, Deserialize, Deserializer, Serialize};
+use base64::engine::{Engine, general_purpose::STANDARD_NO_PAD};
+use serde::{Deserialize, Deserializer, Serialize, de::Error};
use unicode_categories::UnicodeCategories;
#[derive(Debug, PartialEq, Clone)]
crates/nix-eval/src/pool.rsdiffbeforeafterboth--- a/crates/nix-eval/src/pool.rs
+++ b/crates/nix-eval/src/pool.rs
@@ -5,7 +5,7 @@
use r2d2::Pool;
-use crate::{session::NixSessionInner, Error, NixSession, Result};
+use crate::{Error, NixSession, Result, session::NixSessionInner};
pub struct NixSessionPool(Pool<NixSessionPoolInner>);
impl NixSessionPool {
crates/nix-eval/src/session.rsdiffbeforeafterboth--- a/crates/nix-eval/src/session.rs
+++ b/crates/nix-eval/src/session.rs
@@ -3,16 +3,16 @@
use better_command::{ClonableHandler, Handler, NixHandler, NoopHandler};
use futures::StreamExt;
use itertools::Itertools as _;
-use serde::{de::DeserializeOwned, Deserialize};
+use serde::{Deserialize, de::DeserializeOwned};
use thiserror::Error;
use tokio::{
io::AsyncWriteExt,
process::{ChildStderr, ChildStdin, ChildStdout, Command},
select,
- sync::{mpsc, oneshot, Mutex},
+ sync::{Mutex, mpsc, oneshot},
};
use tokio_util::codec::{FramedRead, LinesCodec};
-use tracing::{debug, error, warn, Level};
+use tracing::{Level, debug, error, warn};
#[derive(Error, Debug, Clone)]
pub enum Error {
crates/nix-eval/src/util.rsdiffbeforeafterboth--- a/crates/nix-eval/src/util.rs
+++ b/crates/nix-eval/src/util.rs
@@ -3,7 +3,7 @@
use anyhow::bail;
use tracing::{debug, warn};
-use crate::{nix_go_json, Value};
+use crate::{Value, nix_go_json};
#[tracing::instrument(level = "info", skip(val))]
pub async fn assert_warn(action: &str, val: &Value) -> anyhow::Result<()> {
crates/nix-eval/src/value.rsdiffbeforeafterboth--- a/crates/nix-eval/src/value.rs
+++ b/crates/nix-eval/src/value.rs
@@ -1,9 +1,9 @@
use std::{collections::HashMap, fmt, path::PathBuf, sync::Arc};
use better_command::NixHandler;
-use serde::{de::DeserializeOwned, Serialize};
+use serde::{Serialize, de::DeserializeOwned};
-use crate::{macros::NixExprBuilder, nix_go, Error, NixBuildBatch, NixSession, Result};
+use crate::{Error, NixBuildBatch, NixSession, Result, macros::NixExprBuilder, nix_go};
#[derive(Clone)]
pub enum Index {
crates/nix-native-eval/Cargo.tomldiffbeforeafterboth--- a/crates/nix-native-eval/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "nix-native-eval"
-version.workspace = true
-edition.workspace = true
-rust-version.workspace = true
-
-[dependencies]
-anyhow.workspace = true
-
-nixrs = { git = "https://github.com/Anillc/nixrs", version = "0.1.0" }
crates/nix-native-eval/src/lib.rsdiffbeforeafterboth--- a/crates/nix-native-eval/src/lib.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use anyhow::Result;
-use nixrs::{State, Store};
-
-pub fn init() -> Result<()> {
- nixrs::init()?;
- let store = Store::new("daemon")?;
- let state = State::new(store)?;
- let _ = state;
-
- Ok(())
-}
crates/nixlike/fuzz/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/fuzz/Cargo.toml
+++ b/crates/nixlike/fuzz/Cargo.toml
@@ -4,7 +4,7 @@
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
-edition = "2021"
+edition = "2024"
[package.metadata]
cargo-fuzz = true
crates/nixlike/src/de_impl.rsdiffbeforeafterboth--- a/crates/nixlike/src/de_impl.rs
+++ b/crates/nixlike/src/de_impl.rs
@@ -2,8 +2,8 @@
use linked_hash_map::LinkedHashMap;
use serde::{
+ Deserializer,
de::{self, MapAccess, SeqAccess},
- Deserializer,
};
use crate::{Error, Value};
@@ -28,11 +28,12 @@
where
K: de::DeserializeSeed<'de>,
{
- if let Some((k, v)) = self.iter.next() {
- let _ = self.value.insert(v);
- Ok(Some(seed.deserialize(Value::String(k))?))
- } else {
- Ok(None)
+ match self.iter.next() {
+ Some((k, v)) => {
+ let _ = self.value.insert(v);
+ Ok(Some(seed.deserialize(Value::String(k))?))
+ }
+ _ => Ok(None),
}
}
@@ -62,10 +63,9 @@
where
T: de::DeserializeSeed<'de>,
{
- if let Some(v) = self.iter.next() {
- Ok(Some(seed.deserialize(v)?))
- } else {
- Ok(None)
+ match self.iter.next() {
+ Some(v) => Ok(Some(seed.deserialize(v)?)),
+ _ => Ok(None),
}
}
}
crates/nixlike/src/se_impl.rsdiffbeforeafterboth--- a/crates/nixlike/src/se_impl.rs
+++ b/crates/nixlike/src/se_impl.rs
@@ -2,11 +2,11 @@
use linked_hash_map::LinkedHashMap;
use serde::{
+ Serializer,
ser::{
self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
SerializeTupleStruct, SerializeTupleVariant,
},
- Serializer,
};
use crate::{Error, Value};
@@ -90,9 +90,7 @@
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(Value::Object(
- vec![(self.0, Value::Array(self.1 .0))]
- .into_iter()
- .collect(),
+ vec![(self.0, Value::Array(self.1.0))].into_iter().collect(),
))
}
}
flake.lockdiffbeforeafterboth--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"crane": {
"locked": {
- "lastModified": 1739936662,
- "narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=",
+ "lastModified": 1750266157,
+ "narHash": "sha256-tL42YoNg9y30u7zAqtoGDNdTyXTi8EALDeCB13FtbQA=",
"owner": "ipetkov",
"repo": "crane",
- "rev": "19de14aaeb869287647d9461cbd389187d8ecdb7",
+ "rev": "e37c943371b73ed87faf33f7583860f81f1d5a48",
"type": "github"
},
"original": {
@@ -22,11 +22,11 @@
]
},
"locked": {
- "lastModified": 1738453229,
- "narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
+ "lastModified": 1749398372,
+ "narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
+ "rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569",
"type": "github"
},
"original": {
@@ -37,16 +37,16 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1740339700,
- "narHash": "sha256-cbrw7EgQhcdFnu6iS3vane53bEagZQy/xyIkDWpCgVE=",
+ "lastModified": 1750895632,
+ "narHash": "sha256-EPZWiRmaSTxoBArK5dQyRlSNVLXiBt2hmsYIPgMf3zk=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "04ef94c4c1582fd485bbfdb8c4a8ba250e359195",
+ "rev": "6ac57ce7fee0d80226095a57ccb7519855ad7c5e",
"type": "github"
},
"original": {
"owner": "nixos",
- "ref": "release-24.11",
+ "ref": "release-25.05",
"repo": "nixpkgs",
"type": "github"
}
@@ -68,11 +68,11 @@
]
},
"locked": {
- "lastModified": 1740277845,
- "narHash": "sha256-NNU0CdiaSbAeZ8tpDG4aFi9qtcdlItRvk8Xns9oBrVU=",
+ "lastModified": 1750819193,
+ "narHash": "sha256-XvkupGPZqD54HuKhN/2WhbKjAHeTl1UEnWspzUzRFfA=",
"owner": "oxalica",
"repo": "rust-overlay",
- "rev": "f933070c29f9c1c5457447a51903f27f76ebb519",
+ "rev": "1ba3b9c59b68a4b00156827ad46393127b51b808",
"type": "github"
},
"original": {
@@ -103,11 +103,11 @@
]
},
"locked": {
- "lastModified": 1744961264,
- "narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=",
+ "lastModified": 1749194973,
+ "narHash": "sha256-eEy8cuS0mZ2j/r/FE0/LYBSBcIs/MKOIVakwHVuqTfk=",
"owner": "numtide",
"repo": "treefmt-nix",
- "rev": "8d404a69efe76146368885110f29a2ca3700bee6",
+ "rev": "a05be418a1af1198ca0f63facb13c985db4cb3c5",
"type": "github"
},
"original": {
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -2,7 +2,7 @@
description = "NixOS cluster configuration management";
inputs = {
- nixpkgs.url = "github:nixos/nixpkgs/release-24.11";
+ nixpkgs.url = "github:nixos/nixpkgs/release-25.05";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
@@ -156,7 +156,7 @@
bacon
nil
rustPlatform.bindgenHook
- nixVersions.nix_2_22
+ # nixVersions.nix_2_22
];
environment.PROTOC = "${pkgs.protobuf}/bin/protoc";
};
rust-toolchain.tomldiffbeforeafterboth--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,3 @@
[toolchain]
-channel = "1.85.0"
+channel = "1.86.0"
components = ["rustfmt", "clippy", "rust-analyzer", "rust-src"]
rustfmt.tomldiffbeforeafterboth--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,3 +1,3 @@
hard_tabs = true
-imports_granularity = "Crate"
-group_imports = "StdExternalCrate"
+# imports_granularity = "Crate"
+# group_imports = "StdExternalCrate"