git.delta.rocks / jrsonnet / refs/commits / 3972fee37ee3

difftreelog

feat explicitly mark hosts as managed by fleet

Lach2025-04-05parent: #a1a72ce.patch.diff
in: trunk

7 files changed

modifiedCargo.lockdiffbeforeafterboth
924 "hostname",924 "hostname",
925 "human-repr",925 "human-repr",
926 "indicatif",926 "indicatif",
927 "indoc",
927 "itertools 0.13.0",928 "itertools 0.13.0",
928 "nix-eval",929 "nix-eval",
929 "nixlike",930 "nixlike",
1536 "web-time",1537 "web-time",
1537]1538]
1539
1540[[package]]
1541name = "indoc"
1542version = "2.0.6"
1543source = "registry+https://github.com/rust-lang/crates.io-index"
1544checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
15381545
1539[[package]]1546[[package]]
1540name = "inout"1547name = "inout"
modifiedcmds/fleet/Cargo.tomldiffbeforeafterboth
47nix-eval.workspace = true47nix-eval.workspace = true
48nom = "7.1.3"48nom = "7.1.3"
49fleet-base = { version = "0.1.0", path = "../../crates/fleet-base" }49fleet-base = { version = "0.1.0", path = "../../crates/fleet-base" }
50indoc = "2.0.6"
5051
51[features]52[features]
52default = ["indicatif"]53default = ["indicatif"]
modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
1use std::{env::current_dir, os::unix::fs::symlink, path::PathBuf, time::Duration};1use std::{env::current_dir, os::unix::fs::symlink, path::PathBuf, str::FromStr, time::Duration};
22
3use anyhow::{anyhow, Result};3use anyhow::{anyhow, bail, Result};
4use clap::{Parser, ValueEnum};4use clap::{Parser, ValueEnum};
5use fleet_base::{5use fleet_base::{
6 host::{Config, ConfigHost},6 host::{Config, ConfigHost},
332 }333 }
333}334}
335
336#[derive(Clone, PartialEq, Copy)]
337enum DeployKind {
338 // NixOS => NixOS managed by fleet
339 UpgradeToFleet,
340 // NixOS managed by fleet => NixOS managed by fleet
341 Fleet,
342}
343impl FromStr for DeployKind {
344 type Err = anyhow::Error;
345 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
346 match s {
347 "upgrade-to-fleet" => Ok(Self::UpgradeToFleet),
348 "fleet" => Ok(Self::Fleet),
349 v => bail!("unknown deploy_kind: {v}; expected on of \"upgrade-to-fleet\", \"fleet\""),
350 }
351 }
352}
334353
335impl Deploy {354impl Deploy {
336 pub async fn run(self, config: &Config, opts: &FleetOpts) -> Result<()> {355 pub async fn run(self, config: &Config, opts: &FleetOpts) -> Result<()> {
348 let local_host = config.local_host();367 let local_host = config.local_host();
349 let opts = opts.clone();368 let opts = opts.clone();
350 let batch = batch.clone();369 let batch = batch.clone();
370 let mut deploy_kind: Option<DeployKind> =
371 opts.action_attr(&host, "deploy_kind").await?;
351372
352 set.spawn_local(373 set.spawn_local(
353 (async move {374 (async move {
356 {377 {
357 Ok(path) => path,378 Ok(path) => path,
358 Err(e) => {379 Err(e) => {
359 error!("failed to deploy host: {}", e);380 error!("failed to build host system closure: {}", e);
360 return;381 return;
361 }382 }
362 };383 };
384 if deploy_kind == None {
385 let is_fleet_managed = match host.file_exists("/etc/FLEET_HOST").await {
386 Ok(v) => v,
387 Err(e) => {
388 error!("failed to query remote system kind: {}", e);
389 return;
390 },
391 };
392 if !is_fleet_managed {
393 error!(indoc::indoc!{"
394 host is not marked as managed by fleet
395 if you're not trying to lustrate/install system from scratch,
396 you should either
397 1. manually create /etc/FLEET_HOST file on the target host,
398 2. use ?deploy_kind=fleet host argument if you're upgrading from older version of fleet
399 3. use ?deploy_kind=upgrade_to_fleet if you're upgrading from plain nixos to fleet-managed nixos
400 "});
401 return;
402 }
403 deploy_kind = Some(DeployKind::Fleet);
404 }
405 let deploy_kind = deploy_kind.expect("deploy_kind is set");
406
407 // TODO: Make disable_rollback a host attribute instead
408 let mut disable_rollback = self.disable_rollback;
409 if !disable_rollback && deploy_kind != DeployKind::Fleet {
410 warn!("disabling rollback, as not supported by non-fleet deployment kinds");
411 disable_rollback = true;
412 }
413
363 if !opts.is_local(&hostname) {414 if !opts.is_local(&hostname) {
364 info!("uploading system closure");415 info!("uploading system closure");
411 error!("unreachable? failed to get specialization");462 error!("unreachable? failed to get specialization");
412 return;463 return;
413 },464 },
414 self.disable_rollback,465 disable_rollback,
415 )466 )
416 .await467 .await
417 {468 {
modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
6666
67#[derive(Parser)]67#[derive(Parser)]
68enum Opts {68enum Opts {
69 /// Prepare systems for deployments69 /// Build system closures
70 BuildSystems(BuildSystems),70 BuildSystems(BuildSystems),
7171 /// Upload and switch system closures
72 Deploy(Deploy),72 Deploy(Deploy),
73 /// Secret management73 /// Secret management
74 #[clap(subcommand)]74 #[clap(subcommand)]
modifiedcrates/fleet-base/src/command.rsdiffbeforeafterboth
5use futures::StreamExt;5use futures::StreamExt;
6use itertools::Either;6use itertools::Either;
7use openssh::{OverSsh, OwningCommand, Session};7use openssh::{OverSsh, OwningCommand, Session};
8use serde::de::DeserializeOwned;
8use tokio::{io::AsyncRead, process::Command, select};9use tokio::{io::AsyncRead, process::Command, select};
9use tokio_util::codec::{BytesCodec, FramedRead, LinesCodec};10use tokio_util::codec::{BytesCodec, FramedRead, LinesCodec};
10use tracing::debug;11use tracing::debug;
230 let bytes = self.run_bytes().await?;231 let bytes = self.run_bytes().await?;
231 Ok(String::from_utf8(bytes)?)232 Ok(String::from_utf8(bytes)?)
232 }233 }
234 pub async fn run_value<T: DeserializeOwned>(self) -> Result<T> {
235 let v = self.run_string().await?;
236 Ok(serde_json::from_str(&v)?)
237 }
233 pub async fn run_bytes(self) -> Result<Vec<u8>> {238 pub async fn run_bytes(self) -> Result<Vec<u8>> {
234 let str = self.clone().into_string();239 let str = self.clone().into_string();
235 let cmd = self.wrap_sudo_if_needed().into_command()?;240 let cmd = self.wrap_sudo_if_needed().into_command()?;
modifiedcrates/fleet-base/src/host.rsdiffbeforeafterboth
105 let path = cmd.run_string().await?;105 let path = cmd.run_string().await?;
106 Ok(path.trim_end().to_owned())106 Ok(path.trim_end().to_owned())
107 }107 }
108 pub async fn file_exists(&self, path: impl AsRef<OsStr>) -> Result<bool> {
109 let mut cmd = self.cmd("sh").await?;
110 cmd.arg("-c")
111 .arg("test -e \"$1\" && echo true || echo false")
112 .arg("_")
113 .arg(path);
114 Ok(cmd.run_value().await?)
115 }
108 pub async fn read_file_bin(&self, path: impl AsRef<OsStr>) -> Result<Vec<u8>> {116 pub async fn read_file_bin(&self, path: impl AsRef<OsStr>) -> Result<Vec<u8>> {
109 let mut cmd = self.cmd("cat").await?;117 let mut cmd = self.cmd("cat").await?;
110 cmd.arg(path);118 cmd.arg(path);
modifiedmodules/nixos/meta.nixdiffbeforeafterboth
12 ] "network is now defined at the host level, not the nixos system level")
7 ];13 ];
14
15 # Version of environment (fleet scripts such as rollback) already installed on the host
16 config.environment.etc.FLEET_HOST.text = "1";
8}17}
918