difftreelog
refactor(build-systems) host abstraction
in: trunk
1 file changed
src/cmds/build_systems.rsdiffbeforeafterboth1use std::process::Command;23use crate::{4 command::CommandExt,5 db::{keys::list_hosts, secret::SecretDb, Db, DbData},6 nix::SYSTEMS_ATTRIBUTE,7};8use anyhow::Result;9use clap::Clap;10use log::{info, warn};1112#[derive(Clap)]13#[clap(group = clap::ArgGroup::new("target"))]14pub struct BuildSystems {15 /// Hosts to skip16 #[clap(long, number_of_values = 1, group = "target")]17 skip: Vec<String>,18 /// Hosts to build19 #[clap(long, number_of_values = 1, group = "target")]20 only: Vec<String>,21 /// Host, which should be threaten as localhost22 #[clap(long, env = "FLEET_LOCALHOST")]23 localhost: Option<String>,24 /// --builders arg for nix25 #[clap(long)]26 builders: Option<String>,27 /// Jobs to run locally28 #[clap(long)]29 jobs: Option<usize>,30 /// Do not continue on error31 #[clap(long)]32 fail_fast: bool,33 #[clap(subcommand)]34 subcommand: Option<Subcommand>,35}3637#[derive(Clap)]38enum Subcommand {39 /// Switch to built system until reboot40 Test,41 /// Switch to built system after reboot42 Boot,43 /// test + boot44 Switch,45}46impl Subcommand {47 fn should_switch_profile(&self) -> bool {48 matches!(self, Self::Test | Self::Switch)49 }50 fn name(&self) -> &'static str {51 match self {52 Self::Test => "test",53 Self::Boot => "boot",54 Self::Switch => "switch",55 }56 }57}5859impl BuildSystems {60 pub fn run(self) -> Result<()> {61 let db = Db::new(".fleet")?;62 let hosts = list_hosts()?;63 let data = SecretDb::open(&db)?.generate_nix_data()?;6465 for host in hosts.iter() {66 if self.only.len() > 0 && !self.only.contains(host) || self.skip.contains(host) {67 warn!("Skipping host {}", host);68 continue;69 }70 let is_local = Some(host) == self.localhost.as_ref();71 info!("Building host {}", host);72 let built = {73 let dir = tempfile::tempdir()?;74 dir.path().to_owned()75 };7677 let mut nix_build = Command::new("nix");78 nix_build79 .args(&["build", "--impure", "--no-link", "--out-link"])80 .arg(&built)81 .arg(format!(82 "{}.{}.config.system.build.toplevel",83 SYSTEMS_ATTRIBUTE, host,84 ))85 .env("SECRET_DATA", data.clone());8687 if let Some(builders) = &self.builders {88 println!("Using builders: {}", builders);89 nix_build.arg("--builders").arg(builders);90 }91 if let Some(jobs) = &self.jobs {92 nix_build.arg("--max-jobs");93 nix_build.arg(format!("{}", jobs));94 }95 if !self.fail_fast {96 nix_build.arg("--keep-going");97 }9899 nix_build.inherit_stdio().run()?;100 let built = std::fs::canonicalize(built)?;101 info!("Built closure: {:?}", built);102 if !is_local {103 info!("Uploading system closure");104 Command::new("nix")105 .args(&["copy", "--to"])106 .arg(format!("ssh://root@{}", host))107 .arg(&built)108 .inherit_stdio()109 .run()?;110 }111 if let Some(subcommand) = &self.subcommand {112 if subcommand.should_switch_profile() {113 info!("Switching generation");114 if !is_local {115 Command::ssh_on(host, "sudo")116 } else {117 Command::new("sudo")118 }119 .args(&["nix-env", "-p", "/nix/var/nix/profiles/system", "--set"])120 .arg(&built)121 .inherit_stdio()122 .run()?;123 }124 info!("Executing activation script");125 let mut switch_script = built.clone();126 switch_script.push("bin");127 switch_script.push("switch-to-configuration");128 info!("{:?}", switch_script);129 if !is_local {130 Command::ssh_on(host, "sudo")131 } else {132 Command::new("sudo")133 }134 .arg(switch_script)135 .arg(subcommand.name())136 .inherit_stdio()137 .run()?;138 }139 }140 Ok(())141 }142}1use std::process::Command;23use crate::{4 command::CommandExt,5 db::{secret::SecretDb, Db, DbData},6 host::FleetOpts,7 nix::SYSTEMS_ATTRIBUTE,8};9use anyhow::Result;10use clap::Clap;11use log::{info, warn};1213#[derive(Clap)]14#[clap(group = clap::ArgGroup::new("target"))]15pub struct BuildSystems {16 #[clap(flatten)]17 fleet_opts: FleetOpts,18 /// --builders arg for nix19 #[clap(long)]20 builders: Option<String>,21 /// Jobs to run locally22 #[clap(long)]23 jobs: Option<usize>,24 /// Do not continue on error25 #[clap(long)]26 fail_fast: bool,27 #[clap(long)]28 privileged_build: bool,29 #[clap(subcommand)]30 subcommand: Option<Subcommand>,31}3233#[derive(Clap)]34enum Subcommand {35 /// Switch to built system until reboot36 Test,37 /// Switch to built system after reboot38 Boot,39 /// test + boot40 Switch,41}42impl Subcommand {43 fn should_switch_profile(&self) -> bool {44 matches!(self, Self::Test | Self::Switch)45 }46 fn name(&self) -> &'static str {47 match self {48 Self::Test => "test",49 Self::Boot => "boot",50 Self::Switch => "switch",51 }52 }53}5455impl BuildSystems {56 pub fn run(self) -> Result<()> {57 let fleet = self.fleet_opts.build()?;58 let db = Db::new(".fleet")?;59 let hosts = fleet.list_hosts()?;60 let data = SecretDb::open(&db)?.generate_nix_data()?;6162 for host in hosts.iter() {63 if host.skip() {64 warn!("Skipping host {}", host.hostname);65 continue;66 }67 info!("Building host {}", host.hostname);68 let built = {69 let dir = tempfile::tempdir()?;70 dir.path().to_owned()71 };7273 let mut nix_build = if self.privileged_build {74 let mut out = Command::new("sudo");75 out.arg("nix");76 out77 } else {78 Command::new("nix")79 };80 nix_build81 .args(&["build", "--impure", "--no-link", "--out-link"])82 .arg(&built)83 .arg(format!(84 "{}.{}.config.system.build.toplevel",85 SYSTEMS_ATTRIBUTE, host.hostname,86 ))87 .env("SECRET_DATA", data.clone());8889 if let Some(builders) = &self.builders {90 println!("Using builders: {}", builders);91 nix_build.arg("--builders").arg(builders);92 }93 if let Some(jobs) = &self.jobs {94 nix_build.arg("--max-jobs");95 nix_build.arg(format!("{}", jobs));96 }97 if !self.fail_fast {98 nix_build.arg("--keep-going");99 }100101 nix_build.inherit_stdio().run()?;102 let built = std::fs::canonicalize(built)?;103 info!("Built closure: {:?}", built);104 if !host.is_local() {105 info!("Uploading system closure");106 Command::new("nix")107 .args(&["copy", "--to"])108 .arg(format!("ssh://root@{}", host.hostname))109 .arg(&built)110 .inherit_stdio()111 .run()?;112 }113 if let Some(subcommand) = &self.subcommand {114 if subcommand.should_switch_profile() {115 info!("Switching generation");116 host.command_on("nix-env", true)117 .args(&["-p", "/nix/var/nix/profiles/system", "--set"])118 .arg(&built)119 .inherit_stdio()120 .run()?;121 }122 info!("Executing activation script");123 let mut switch_script = built.clone();124 switch_script.push("bin");125 switch_script.push("switch-to-configuration");126 info!("{:?}", switch_script);127 host.command_on(switch_script, true)128 .arg(subcommand.name())129 .inherit_stdio()130 .run()?;131 }132 }133 Ok(())134 }135}