Просмотр исходного кода

fix: use run_ssh_long_running for docker save|load pipe (no inactivity timeout)

Alexander Korolev 3 месяцев назад
Родитель
Сommit
7d4253fe26
2 измененных файлов с 41 добавлено и 2 удалено
  1. 2 2
      src/docker/sync.rs
  2. 39 0
      src/ssh.rs

+ 2 - 2
src/docker/sync.rs

@@ -1,5 +1,5 @@
 use crate::config::{Cluster, Config, Node};
-use crate::ssh::run_ssh;
+use crate::ssh::{run_ssh, run_ssh_long_running};
 use anyhow::Result;
 
 use tracing::info;
@@ -64,7 +64,7 @@ pub async fn sync_image_to_nodes(
             config.ssh_user,
             target.ssh_ip
         );
-        run_ssh(config, source, pipe_cmd, false).await?;
+        run_ssh_long_running(config, source, pipe_cmd, false).await?;
         let verify = get_image_digest(config, target, image).await?;
         if verify.as_deref() != Some(source_digest) {
             anyhow::bail!(

+ 39 - 0
src/ssh.rs

@@ -174,6 +174,45 @@ pub async fn run_ssh_follow(
     Ok(())
 }
 
+/// Runs a command via SSH with no inactivity timeout — suitable for long,
+/// streaming commands like `docker save | ssh docker load`.
+pub async fn run_ssh_long_running(
+    config: &Config,
+    node: &Node,
+    command: String,
+    dry_run: bool,
+) -> Result<String> {
+    if dry_run {
+        println!(
+            "  ssh {}@{}: {} (long-running)",
+            config.ssh_user, node.ssh_ip, command
+        );
+        return Ok(String::new());
+    }
+    let session = ssh_session_follow(config, node).await?;
+    let mut channel = session.channel_open_session().await?;
+    channel.exec(true, command.as_bytes()).await?;
+    let mut output = String::new();
+    let mut exit_status: Option<u32> = None;
+    while let Some(msg) = channel.wait().await {
+        match msg {
+            ChannelMsg::Data { data } => output.push_str(&String::from_utf8_lossy(&data)),
+            ChannelMsg::ExitStatus { exit_status: s } => exit_status = Some(s),
+            _ => {}
+        }
+    }
+    match exit_status {
+        Some(0) | None => Ok(output),
+        Some(code) => Err(anyhow::anyhow!(
+            "ssh {}@{}: command exited with status {}\n  command: {}",
+            config.ssh_user,
+            node.ssh_ip,
+            code,
+            command
+        )),
+    }
+}
+
 /// Fetches the SSH host key fingerprint from a node.
 pub async fn fetch_host_key(config: &Config, node: &Node) -> Result<String> {
     use std::sync::Mutex;