Skip to content

Commit cdfeac0

Browse files
committed
runc: split Pipe, Io, and PipedIo to async and sync modules
Signed-off-by: jiaxiao zhou <[email protected]>
1 parent d584728 commit cdfeac0

File tree

7 files changed

+314
-176
lines changed

7 files changed

+314
-176
lines changed

crates/runc/src/asynchronous/mod.rs

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
mod pipe;
18+
use std::{fmt::Debug, io::Result, os::fd::AsRawFd};
19+
20+
use log::debug;
21+
pub use pipe::Pipe;
22+
use tokio::io::{AsyncRead, AsyncWrite};
23+
24+
use crate::Command;
25+
26+
pub trait Io: Debug + Send + Sync {
27+
/// Return write side of stdin
28+
#[cfg(feature = "async")]
29+
fn stdin(&self) -> Option<Box<dyn AsyncWrite + Send + Sync + Unpin>> {
30+
None
31+
}
32+
33+
/// Return read side of stdout
34+
#[cfg(feature = "async")]
35+
fn stdout(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
36+
None
37+
}
38+
39+
/// Return read side of stderr
40+
#[cfg(feature = "async")]
41+
fn stderr(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
42+
None
43+
}
44+
45+
/// Set IO for passed command.
46+
/// Read side of stdin, write side of stdout and write side of stderr should be provided to command.
47+
fn set(&self, cmd: &mut Command) -> Result<()>;
48+
49+
/// Only close write side (should be stdout/err "from" runc process)
50+
fn close_after_start(&self);
51+
}
52+
53+
#[derive(Debug)]
54+
pub struct PipedIo {
55+
pub stdin: Option<Pipe>,
56+
pub stdout: Option<Pipe>,
57+
pub stderr: Option<Pipe>,
58+
}
59+
60+
impl Io for PipedIo {
61+
fn stdin(&self) -> Option<Box<dyn AsyncWrite + Send + Sync + Unpin>> {
62+
self.stdin.as_ref().and_then(|pipe| {
63+
let fd = pipe.wr.as_raw_fd();
64+
tokio_pipe::PipeWrite::from_raw_fd_checked(fd)
65+
.map(|x| Box::new(x) as Box<dyn AsyncWrite + Send + Sync + Unpin>)
66+
.ok()
67+
})
68+
}
69+
70+
fn stdout(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
71+
self.stdout.as_ref().and_then(|pipe| {
72+
let fd = pipe.rd.as_raw_fd();
73+
tokio_pipe::PipeRead::from_raw_fd_checked(fd)
74+
.map(|x| Box::new(x) as Box<dyn AsyncRead + Send + Sync + Unpin>)
75+
.ok()
76+
})
77+
}
78+
79+
fn stderr(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
80+
self.stderr.as_ref().and_then(|pipe| {
81+
let fd = pipe.rd.as_raw_fd();
82+
tokio_pipe::PipeRead::from_raw_fd_checked(fd)
83+
.map(|x| Box::new(x) as Box<dyn AsyncRead + Send + Sync + Unpin>)
84+
.ok()
85+
})
86+
}
87+
88+
// Note that this internally use [`std::fs::File`]'s `try_clone()`.
89+
// Thus, the files passed to commands will be not closed after command exit.
90+
fn set(&self, cmd: &mut Command) -> std::io::Result<()> {
91+
if let Some(p) = self.stdin.as_ref() {
92+
let pr = p.rd.try_clone()?;
93+
cmd.stdin(pr);
94+
}
95+
96+
if let Some(p) = self.stdout.as_ref() {
97+
let pw = p.wr.try_clone()?;
98+
cmd.stdout(pw);
99+
}
100+
101+
if let Some(p) = self.stderr.as_ref() {
102+
let pw = p.wr.try_clone()?;
103+
cmd.stdout(pw);
104+
}
105+
106+
Ok(())
107+
}
108+
109+
fn close_after_start(&self) {
110+
if let Some(p) = self.stdout.as_ref() {
111+
nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stdout: {}", e));
112+
}
113+
114+
if let Some(p) = self.stderr.as_ref() {
115+
nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stderr: {}", e));
116+
}
117+
}
118+
}

crates/runc/src/asynchronous/pipe.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
use std::os::unix::io::OwnedFd;
18+
19+
use tokio::net::unix::pipe;
20+
21+
/// Struct to represent a pipe that can be used to transfer stdio inputs and outputs.
22+
///
23+
/// With this Io driver, methods of [crate::Runc] may capture the output/error messages.
24+
/// When one side of the pipe is closed, the state will be represented with [`None`].
25+
#[derive(Debug)]
26+
pub struct Pipe {
27+
pub rd: OwnedFd,
28+
pub wr: OwnedFd,
29+
}
30+
31+
impl Pipe {
32+
pub fn new() -> std::io::Result<Self> {
33+
let (tx, rx) = pipe::pipe()?;
34+
let rd = tx.into_blocking_fd()?;
35+
let wr = rx.into_blocking_fd()?;
36+
Ok(Self { rd, wr })
37+
}
38+
}

crates/runc/src/io.rs

+3-175
Original file line numberDiff line numberDiff line change
@@ -13,72 +13,19 @@
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16-
#[cfg(not(feature = "async"))]
17-
use std::io::{Read, Write};
16+
1817
use std::{
1918
fmt::Debug,
2019
fs::{File, OpenOptions},
2120
io::Result,
22-
os::unix::{
23-
fs::OpenOptionsExt,
24-
io::{AsRawFd, OwnedFd},
25-
},
21+
os::unix::{fs::OpenOptionsExt, io::AsRawFd},
2622
process::Stdio,
2723
sync::Mutex,
2824
};
2925

30-
use log::debug;
3126
use nix::unistd::{Gid, Uid};
32-
#[cfg(feature = "async")]
33-
use tokio::io::{AsyncRead, AsyncWrite};
34-
use tokio::net::unix::pipe;
35-
36-
use crate::Command;
37-
38-
pub trait Io: Debug + Send + Sync {
39-
/// Return write side of stdin
40-
#[cfg(not(feature = "async"))]
41-
fn stdin(&self) -> Option<Box<dyn Write + Send + Sync>> {
42-
None
43-
}
44-
45-
/// Return read side of stdout
46-
#[cfg(not(feature = "async"))]
47-
fn stdout(&self) -> Option<Box<dyn Read + Send>> {
48-
None
49-
}
50-
51-
/// Return read side of stderr
52-
#[cfg(not(feature = "async"))]
53-
fn stderr(&self) -> Option<Box<dyn Read + Send>> {
54-
None
55-
}
56-
57-
/// Return write side of stdin
58-
#[cfg(feature = "async")]
59-
fn stdin(&self) -> Option<Box<dyn AsyncWrite + Send + Sync + Unpin>> {
60-
None
61-
}
62-
63-
/// Return read side of stdout
64-
#[cfg(feature = "async")]
65-
fn stdout(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
66-
None
67-
}
68-
69-
/// Return read side of stderr
70-
#[cfg(feature = "async")]
71-
fn stderr(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
72-
None
73-
}
7427

75-
/// Set IO for passed command.
76-
/// Read side of stdin, write side of stdout and write side of stderr should be provided to command.
77-
fn set(&self, cmd: &mut Command) -> Result<()>;
78-
79-
/// Only close write side (should be stdout/err "from" runc process)
80-
fn close_after_start(&self);
81-
}
28+
use crate::{Command, Io, Pipe, PipedIo};
8229

8330
#[derive(Debug, Clone)]
8431
pub struct IOOption {
@@ -97,32 +44,6 @@ impl Default for IOOption {
9744
}
9845
}
9946

100-
/// Struct to represent a pipe that can be used to transfer stdio inputs and outputs.
101-
///
102-
/// With this Io driver, methods of [crate::Runc] may capture the output/error messages.
103-
/// When one side of the pipe is closed, the state will be represented with [`None`].
104-
#[derive(Debug)]
105-
pub struct Pipe {
106-
rd: OwnedFd,
107-
wr: OwnedFd,
108-
}
109-
110-
#[derive(Debug)]
111-
pub struct PipedIo {
112-
stdin: Option<Pipe>,
113-
stdout: Option<Pipe>,
114-
stderr: Option<Pipe>,
115-
}
116-
117-
impl Pipe {
118-
fn new() -> std::io::Result<Self> {
119-
let (tx, rx) = pipe::pipe()?;
120-
let rd = tx.into_blocking_fd()?;
121-
let wr = rx.into_blocking_fd()?;
122-
Ok(Self { rd, wr })
123-
}
124-
}
125-
12647
impl PipedIo {
12748
pub fn new(uid: u32, gid: u32, opts: &IOOption) -> std::io::Result<Self> {
12849
Ok(Self {
@@ -156,99 +77,6 @@ impl PipedIo {
15677
}
15778
}
15879

159-
impl Io for PipedIo {
160-
#[cfg(not(feature = "async"))]
161-
fn stdin(&self) -> Option<Box<dyn Write + Send + Sync>> {
162-
self.stdin.as_ref().and_then(|pipe| {
163-
pipe.wr
164-
.try_clone()
165-
.map(|x| Box::new(x) as Box<dyn Write + Send + Sync>)
166-
.ok()
167-
})
168-
}
169-
170-
#[cfg(feature = "async")]
171-
fn stdin(&self) -> Option<Box<dyn AsyncWrite + Send + Sync + Unpin>> {
172-
self.stdin.as_ref().and_then(|pipe| {
173-
let fd = pipe.wr.as_raw_fd();
174-
tokio_pipe::PipeWrite::from_raw_fd_checked(fd)
175-
.map(|x| Box::new(x) as Box<dyn AsyncWrite + Send + Sync + Unpin>)
176-
.ok()
177-
})
178-
}
179-
180-
#[cfg(not(feature = "async"))]
181-
fn stdout(&self) -> Option<Box<dyn Read + Send>> {
182-
self.stdout.as_ref().and_then(|pipe| {
183-
pipe.rd
184-
.try_clone()
185-
.map(|x| Box::new(x) as Box<dyn Read + Send>)
186-
.ok()
187-
})
188-
}
189-
190-
#[cfg(feature = "async")]
191-
fn stdout(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
192-
self.stdout.as_ref().and_then(|pipe| {
193-
let fd = pipe.rd.as_raw_fd();
194-
tokio_pipe::PipeRead::from_raw_fd_checked(fd)
195-
.map(|x| Box::new(x) as Box<dyn AsyncRead + Send + Sync + Unpin>)
196-
.ok()
197-
})
198-
}
199-
200-
#[cfg(not(feature = "async"))]
201-
fn stderr(&self) -> Option<Box<dyn Read + Send>> {
202-
self.stderr.as_ref().and_then(|pipe| {
203-
pipe.rd
204-
.try_clone()
205-
.map(|x| Box::new(x) as Box<dyn Read + Send>)
206-
.ok()
207-
})
208-
}
209-
210-
#[cfg(feature = "async")]
211-
fn stderr(&self) -> Option<Box<dyn AsyncRead + Send + Sync + Unpin>> {
212-
self.stderr.as_ref().and_then(|pipe| {
213-
let fd = pipe.rd.as_raw_fd();
214-
tokio_pipe::PipeRead::from_raw_fd_checked(fd)
215-
.map(|x| Box::new(x) as Box<dyn AsyncRead + Send + Sync + Unpin>)
216-
.ok()
217-
})
218-
}
219-
220-
// Note that this internally use [`std::fs::File`]'s `try_clone()`.
221-
// Thus, the files passed to commands will be not closed after command exit.
222-
fn set(&self, cmd: &mut Command) -> std::io::Result<()> {
223-
if let Some(p) = self.stdin.as_ref() {
224-
let pr = p.rd.try_clone()?;
225-
cmd.stdin(pr);
226-
}
227-
228-
if let Some(p) = self.stdout.as_ref() {
229-
let pw = p.wr.try_clone()?;
230-
cmd.stdout(pw);
231-
}
232-
233-
if let Some(p) = self.stderr.as_ref() {
234-
let pw = p.wr.try_clone()?;
235-
cmd.stdout(pw);
236-
}
237-
238-
Ok(())
239-
}
240-
241-
fn close_after_start(&self) {
242-
if let Some(p) = self.stdout.as_ref() {
243-
nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stdout: {}", e));
244-
}
245-
246-
if let Some(p) = self.stderr.as_ref() {
247-
nix::unistd::close(p.wr.as_raw_fd()).unwrap_or_else(|e| debug!("close stderr: {}", e));
248-
}
249-
}
250-
}
251-
25280
/// IO driver to direct output/error messages to /dev/null.
25381
///
25482
/// With this Io driver, all methods of [crate::Runc] can't capture the output/error messages.

crates/runc/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,22 @@ use async_trait::async_trait;
5050
use log::debug;
5151
use oci_spec::runtime::{LinuxResources, Process};
5252

53+
#[cfg(feature = "async")]
54+
pub use crate::asynchronous::*;
55+
#[cfg(not(feature = "async"))]
56+
pub use crate::synchronous::*;
5357
use crate::{container::Container, error::Error, options::*, utils::write_value_to_temp_file};
5458

59+
#[cfg(feature = "async")]
60+
pub mod asynchronous;
5561
pub mod container;
5662
pub mod error;
5763
pub mod events;
5864
pub mod io;
5965
#[cfg(feature = "async")]
6066
pub mod monitor;
6167
pub mod options;
68+
pub mod synchronous;
6269
pub mod utils;
6370

6471
pub type Result<T> = std::result::Result<T, crate::error::Error>;

crates/runc/src/options.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use std::{
3939
time::Duration,
4040
};
4141

42-
use crate::{error::Error, io::Io, utils, DefaultExecutor, LogFormat, Runc, Spawner};
42+
use crate::{error::Error, utils, DefaultExecutor, Io, LogFormat, Runc, Spawner};
4343

4444
// constants for log format
4545
pub const JSON: &str = "json";

0 commit comments

Comments
 (0)