Skip to content

Commit 056ced4

Browse files
committed
Check for child exit during all requests
I am seeing the proxy seeming to exit during a request. We need to also monitor the child process while making a request.
1 parent cd6f617 commit 056ced4

File tree

1 file changed

+26
-36
lines changed

1 file changed

+26
-36
lines changed

src/imageproxy.rs

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
//! More information: <https://github.com/containers/skopeo/pull/1476>
66
77
use anyhow::{anyhow, Context, Result};
8-
use futures_util::{Future, FutureExt, TryFutureExt};
8+
use futures_util::Future;
99
use nix::sys::socket::{self as nixsocket, ControlMessageOwned};
1010
use nix::sys::uio::IoVec;
1111
use serde::{Deserialize, Serialize};
1212
use std::fs::File;
1313
use std::os::unix::io::AsRawFd;
1414
use std::os::unix::prelude::{FromRawFd, RawFd};
1515
use std::pin::Pin;
16-
use std::process::{ExitStatus, Stdio};
16+
use std::process::Stdio;
1717
use std::sync::{Arc, Mutex};
1818
use tokio::io::{AsyncBufRead, AsyncReadExt};
1919

@@ -65,13 +65,12 @@ struct Reply {
6565
value: serde_json::Value,
6666
}
6767

68-
type JoinFuture<T> = Pin<Box<dyn Future<Output = Result<Result<T>>>>>;
68+
type ChildFuture = Pin<Box<dyn Future<Output = std::io::Result<std::process::Output>>>>;
6969

7070
/// Manage a child process proxy to fetch container images.
7171
pub struct ImageProxy {
7272
sockfd: Arc<Mutex<File>>,
73-
stderr: JoinFuture<String>,
74-
procwait: Pin<Box<dyn Future<Output = Result<ExitStatus>>>>,
73+
childwait: ChildFuture,
7574
}
7675

7776
impl std::fmt::Debug for ImageProxy {
@@ -117,20 +116,8 @@ impl ImageProxy {
117116
c.stdin(Stdio::from(theirsock));
118117
let mut c = tokio::process::Command::from(c);
119118
c.kill_on_drop(true);
120-
let mut proc = c.spawn().context("Failed to spawn skopeo")?;
121-
122-
// Safety: We passed `Stdio::piped()` above
123-
let mut child_stderr = proc.stderr.take().unwrap();
124-
125-
let stderr = tokio::spawn(async move {
126-
let mut buf = String::new();
127-
child_stderr.read_to_string(&mut buf).await?;
128-
Ok(buf)
129-
})
130-
.map_err(anyhow::Error::msg)
131-
.boxed();
132-
133-
let mut procwait = Box::pin(async move { proc.wait().map_err(anyhow::Error::msg).await });
119+
let child = c.spawn().context("Failed to spawn skopeo")?;
120+
let mut childwait = Box::pin(child.wait_with_output());
134121

135122
let sockfd = Arc::new(Mutex::new(mysock));
136123

@@ -141,9 +128,10 @@ impl ImageProxy {
141128
r = protoreq => {
142129
r?.0
143130
}
144-
r = &mut procwait => {
145-
let errmsg = stderr.await??;
146-
return Err(anyhow!("skopeo exited unexpectedly (no support for `experimental-image-proxy`?): {}\n{}", r?, errmsg));
131+
r = &mut childwait => {
132+
let r = r?;
133+
let stderr = String::from_utf8_lossy(&r.stderr);
134+
return Err(anyhow!("skopeo exited unexpectedly (no support for `experimental-image-proxy`?): {}\n{}", r.status, stderr));
147135
}
148136
};
149137
let protover = semver::Version::parse(protover.as_str())?;
@@ -156,11 +144,7 @@ impl ImageProxy {
156144
));
157145
}
158146

159-
let r = Self {
160-
stderr,
161-
sockfd,
162-
procwait,
163-
};
147+
let r = Self { sockfd, childwait };
164148
Ok(r)
165149
}
166150

@@ -225,8 +209,17 @@ impl ImageProxy {
225209
T: IntoIterator<Item = I>,
226210
I: Into<serde_json::Value>,
227211
{
228-
let req = Request::new(method, args);
229-
Self::impl_request_raw(Arc::clone(&self.sockfd), req).await
212+
let req = Self::impl_request_raw(Arc::clone(&self.sockfd), Request::new(method, args));
213+
tokio::select! {
214+
r = req => {
215+
Ok(r?)
216+
}
217+
r = &mut self.childwait => {
218+
let r = r?;
219+
let stderr = String::from_utf8_lossy(&r.stderr);
220+
return Err(anyhow::anyhow!("proxy unexpectedly exited during request method {}: {}\n{}", method, r.status, stderr))
221+
}
222+
}
230223
}
231224

232225
async fn finish_pipe(&mut self, pipeid: u32) -> Result<()> {
@@ -293,13 +286,10 @@ impl ImageProxy {
293286
let sockfd = Arc::try_unwrap(self.sockfd).unwrap().into_inner().unwrap();
294287
nixsocket::send(sockfd.as_raw_fd(), &sendbuf, nixsocket::MsgFlags::empty())?;
295288
drop(sendbuf);
296-
let status = self.procwait.await?;
297-
if !status.success() {
298-
if let Some(stderr) = self.stderr.await.map(|v| v.ok()).ok().flatten() {
299-
anyhow::bail!("proxy failed: {}\n{}", status, stderr)
300-
} else {
301-
anyhow::bail!("proxy failed: {} (failed to fetch stderr)", status)
302-
}
289+
let output = self.childwait.await?;
290+
if !output.status.success() {
291+
let stderr = String::from_utf8_lossy(&output.stderr);
292+
anyhow::bail!("proxy failed: {}\n{}", output.status, stderr)
303293
}
304294
Ok(())
305295
}

0 commit comments

Comments
 (0)