13use anyhow::{Context, Result, anyhow, bail, ensure};13use anyhow::{Context, Result, anyhow, bail, ensure};
14use fleet_shared::SecretData;14use fleet_shared::SecretData;
15use nix_eval::{Value, nix_go, nix_go_json, util::assert_warn};15use nix_eval::{Value, nix_go, nix_go_json, util::assert_warn};
16use openssh::SessionBuilder;16use openssh::{ControlPersist, SessionBuilder};
17use serde::de::DeserializeOwned;17use serde::de::DeserializeOwned;
18use tabled::Tabled;18use tabled::Tabled;
19use tempfile::NamedTempFile;19use tempfile::NamedTempFile;
99 99
100 deploy_kind: OnceCell<DeployKind>,100 deploy_kind: OnceCell<DeployKind>,
101 session_destination: OnceCell<String>,101 session_destination: OnceCell<String>,
102 legacy_ssh_store: OnceCell<bool>,
102103
103 pub host_config: Option<Value>,104 pub host_config: Option<Value>,
104 pub nixos_config: OnceCell<Value>,105 pub nixos_config: OnceCell<Value>,
219 .set(kind)220 .set(kind)
220 .expect("deploy kind is already set");221 .expect("deploy kind is already set");
221 }222 }
223 pub fn set_legacy_ssh_store(&self, legacy: bool) {
224 self.legacy_ssh_store
225 .set(legacy)
226 .expect("legacy ssh store is already set")
227 }
222 pub async fn deploy_kind(&self) -> Result<DeployKind> {228 pub async fn deploy_kind(&self) -> Result<DeployKind> {
223 if let Some(kind) = self.deploy_kind.get() {229 if let Some(kind) = self.deploy_kind.get() {
224 return Ok(*kind);230 return Ok(*kind);
263 if let Some(session) = &self.session.get() {269 if let Some(session) = &self.session.get() {
264 return Ok((*session).clone());270 return Ok((*session).clone());
265 };271 };
266 let session = SessionBuilder::default();272 let mut session = SessionBuilder::default();
273 session.control_persist(ControlPersist::ClosedAfterInitialConnection);
267274
268 let dest = self.session_destination.get().unwrap_or(&self.name);275 let dest = self.session_destination.get().unwrap_or(&self.name);
269 let session = session276 let session = session
418 );425 );
419 nix.arg("copy").arg("--substitute-on-destination");426 nix.arg("copy").arg("--substitute-on-destination");
427
428 let proto = if self.legacy_ssh_store.get().cloned().unwrap_or(false) {
429 "ssh"
430 } else {
431 "ssh-ng"
432 };
420433
421 match self.deploy_kind().await? {434 match self.deploy_kind().await? {
422 DeployKind::Fleet | DeployKind::UpgradeToFleet | DeployKind::NixosLustrate => {435 DeployKind::Fleet | DeployKind::UpgradeToFleet | DeployKind::NixosLustrate => {
423 nix.comparg("--to", format!("ssh-ng://{}", self.name));436 nix.comparg("--to", format!("{proto}://{}", self.name));
424 }437 }
425 DeployKind::NixosInstall => {438 DeployKind::NixosInstall => {
426 nix439 nix
427 440
428 .arg("--no-check-sigs")441 .arg("--no-check-sigs")
429 .comparg(442 .comparg(
430 "--to",443 "--to",
431 format!("ssh-ng://root@{}?remote-store=/mnt", self.name),444 format!("{proto}://root@{}?remote-store=/mnt", self.name),
432 );445 );
433 }446 }
434 }447 }
568 session: OnceLock::new(),581 session: OnceLock::new(),
569 deploy_kind: OnceCell::new(),582 deploy_kind: OnceCell::new(),
570 session_destination: OnceCell::new(),583 session_destination: OnceCell::new(),
584 legacy_ssh_store: OnceCell::new(),
571 }585 }
572 }586 }
573587
589 session: OnceLock::new(),603 session: OnceLock::new(),
590 deploy_kind: OnceCell::new(),604 deploy_kind: OnceCell::new(),
591 session_destination: OnceCell::new(),605 session_destination: OnceCell::new(),
606 legacy_ssh_store: OnceCell::new(),
592 })607 })
593 }608 }
594 pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {609 pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {