Skip to content

Commit 75c2a24

Browse files
committed
fix:fix exec log grow to burst
1 parent ae58ea3 commit 75c2a24

File tree

4 files changed

+83
-25
lines changed

4 files changed

+83
-25
lines changed

crates/runc-shim/src/runc.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
use std::{
18+
collections::HashMap,
1819
convert::TryFrom,
1920
os::{
2021
fd::{IntoRawFd, OwnedFd},
@@ -455,12 +456,19 @@ impl ProcessLifecycle<ExecProcess> for RuncExecLifecycle {
455456
async fn start(&self, p: &mut ExecProcess) -> containerd_shim::Result<()> {
456457
let bundle = self.bundle.to_string();
457458
let pid_path = Path::new(&bundle).join(format!("{}.pid", &p.id));
459+
let log_path = Path::new(&bundle).join(format!("{}-exec.log", &p.id));
460+
458461
let mut exec_opts = runc::options::ExecOpts {
459462
io: None,
463+
global_args: HashMap::from([(
464+
"--log".to_string(),
465+
log_path.to_string_lossy().into_owned(),
466+
)]),
460467
pid_file: Some(pid_path.to_owned()),
461468
console_socket: None,
462469
detach: true,
463470
};
471+
464472
let (socket, pio) = if p.stdio.terminal {
465473
let s = ConsoleSocket::new().await?;
466474
exec_opts.console_socket = Some(s.path.to_owned());
@@ -475,6 +483,7 @@ impl ProcessLifecycle<ExecProcess> for RuncExecLifecycle {
475483
.runtime
476484
.exec(&self.container_id, &self.spec, Some(&exec_opts))
477485
.await;
486+
let _ = tokio::fs::remove_file(log_path).await;
478487
if let Err(e) = exec_result {
479488
if let Some(s) = socket {
480489
s.clean().await;

crates/runc/src/asynchronous/runc.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
limitations under the License.
1515
*/
1616

17-
use std::{fmt::Debug, path::Path, process::ExitStatus};
17+
use std::{collections::HashMap, fmt::Debug, path::Path, process::ExitStatus};
1818

1919
use async_trait::async_trait;
2020
use log::debug;
@@ -138,11 +138,13 @@ impl Runc {
138138
pub async fn exec(&self, id: &str, spec: &Process, opts: Option<&ExecOpts>) -> Result<()> {
139139
let f = write_value_to_temp_file(spec).await?;
140140
let mut args = vec!["exec".to_string(), "--process".to_string(), f.clone()];
141+
let mut global_args: HashMap<String, String> = HashMap::new();
141142
if let Some(opts) = opts {
143+
global_args = opts.global_args.clone();
142144
args.append(&mut tc!(opts.args(), &f));
143145
}
144146
args.push(id.to_string());
145-
let mut cmd = self.command(&args)?;
147+
let mut cmd = self.command_with_global_args(&global_args, &args)?;
146148
match opts {
147149
Some(ExecOpts { io: Some(io), .. }) => {
148150
tc!(

crates/runc/src/lib.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
//! A crate for consuming the runc binary in your Rust applications, similar to
3939
//! [go-runc](https://github.com/containerd/go-runc) for Go.
4040
use std::{
41+
collections::HashMap,
4142
fmt::{self, Debug, Display},
4243
path::PathBuf,
4344
process::{ExitStatus, Stdio},
@@ -107,13 +108,49 @@ pub type Command = tokio::process::Command;
107108
#[derive(Debug, Clone)]
108109
pub struct Runc {
109110
command: PathBuf,
110-
args: Vec<String>,
111+
client_global_args: HashMap<String, String>,
111112
spawner: Arc<dyn Spawner + Send + Sync>,
112113
}
113114

114115
impl Runc {
115116
fn command(&self, args: &[String]) -> Result<Command> {
116-
let args = [&self.args, args].concat();
117+
let local_args = &self.client_global_args;
118+
let mut args_global = Vec::<String>::new();
119+
for (key, value) in local_args {
120+
args_global.push(key.to_string());
121+
args_global.push(value.to_string());
122+
}
123+
let args = [args_global, args.to_vec()].concat();
124+
let mut cmd = Command::new(&self.command);
125+
126+
// Default to piped stdio, and they may be override by command options.
127+
cmd.stdin(Stdio::null())
128+
.stdout(Stdio::piped())
129+
.stderr(Stdio::piped());
130+
131+
// NOTIFY_SOCKET introduces a special behavior in runc but should only be set if invoked from systemd
132+
cmd.args(&args).env_remove("NOTIFY_SOCKET");
133+
134+
Ok(cmd)
135+
}
136+
137+
#[allow(dead_code)]
138+
fn command_with_global_args(
139+
&self,
140+
custom_global_args: &HashMap<String, String>,
141+
args: &[String],
142+
) -> Result<Command> {
143+
let mut global_args_vec: Vec<String> = Vec::new();
144+
for (client_key, client_value) in &self.client_global_args {
145+
if let Some(value) = custom_global_args.get(client_key) {
146+
global_args_vec.push(client_key.to_string());
147+
global_args_vec.push(value.to_string());
148+
} else {
149+
global_args_vec.push(client_key.to_string());
150+
global_args_vec.push(client_value.to_string());
151+
}
152+
}
153+
let args = [global_args_vec, args.to_vec()].concat();
117154
let mut cmd = Command::new(&self.command);
118155

119156
// Default to piped stdio, and they may be override by command options.

crates/runc/src/options.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
*/
3535

3636
use std::{
37+
collections::HashMap,
3738
path::{Path, PathBuf},
3839
sync::Arc,
3940
time::Duration,
@@ -203,64 +204,60 @@ impl GlobalOpts {
203204
self.args()
204205
}
205206

206-
fn output(&self) -> Result<(PathBuf, Vec<String>), Error> {
207+
fn output(&self) -> Result<(PathBuf, HashMap<String, String>), Error> {
207208
let path = self
208209
.command
209210
.clone()
210211
.unwrap_or_else(|| PathBuf::from("runc"));
211212

212213
let command = utils::binary_path(path).ok_or(Error::NotFound)?;
213-
214-
let mut args = Vec::new();
214+
let mut global_args_map = HashMap::<String, String>::new();
215215

216216
// --root path : Set the root directory to store containers' state.
217217
if let Some(root) = &self.root {
218-
args.push(ROOT.into());
219-
args.push(utils::abs_string(root)?);
218+
global_args_map.insert(ROOT.into(), utils::abs_string(root)?);
220219
}
221220

222221
// --debug : Enable debug logging.
223222
if self.debug {
224-
args.push(DEBUG.into());
223+
global_args_map.insert(DEBUG.into(), String::new());
225224
}
226225

227226
// --log path : Set the log destination to path. The default is to log to stderr.
228227
if let Some(log_path) = &self.log {
229-
args.push(LOG.into());
230-
args.push(utils::abs_string(log_path)?);
228+
global_args_map.insert(LOG.into(), utils::abs_string(log_path)?);
231229
}
232230

233231
// --log-format text|json : Set the log format (default is text).
234-
args.push(LOG_FORMAT.into());
235-
args.push(self.log_format.to_string());
232+
global_args_map.insert(LOG_FORMAT.into(), self.log_format.to_string());
236233

237234
// --systemd-cgroup : Enable systemd cgroup support.
238235
if self.systemd_cgroup {
239-
args.push(SYSTEMD_CGROUP.into());
236+
global_args_map.insert(SYSTEMD_CGROUP.into(), String::new());
240237
}
241238

242239
// --rootless true|false|auto : Enable or disable rootless mode.
243240
if let Some(mode) = self.rootless {
244-
let arg = format!("{}={}", ROOTLESS, mode);
245-
args.push(arg);
241+
global_args_map.insert(ROOTLESS.to_string(), mode.to_string());
246242
}
247-
Ok((command, args))
243+
Ok((command, global_args_map))
248244
}
249245
}
250246

251247
impl Args for GlobalOpts {
252248
type Output = Result<Runc, Error>;
253249

254250
fn args(&self) -> Self::Output {
255-
let (command, args) = self.output()?;
251+
let (command, client_global_args) = self.output()?;
256252
let executor = if let Some(exec) = self.executor.clone() {
257253
exec
258254
} else {
259255
Arc::new(DefaultExecutor {})
260256
};
257+
261258
Ok(Runc {
262259
command,
263-
args,
260+
client_global_args,
264261
spawner: executor,
265262
})
266263
}
@@ -353,6 +350,7 @@ impl CreateOpts {
353350
#[derive(Clone, Default)]
354351
pub struct ExecOpts {
355352
pub io: Option<Arc<dyn Io>>,
353+
pub global_args: HashMap<String, String>,
356354
/// Path to where a pid file should be created.
357355
pub pid_file: Option<PathBuf>,
358356
/// Path to where a console socket should be created.
@@ -591,19 +589,30 @@ mod tests {
591589
assert_eq!(KillOpts::new().all(true).args(), vec!["--all".to_string()],);
592590
}
593591

592+
#[allow(dead_code)]
593+
fn map_to_vec(map: HashMap<String, String>) -> Vec<String> {
594+
let mut args = Vec::with_capacity(map.len() * 2);
595+
for (key, value) in map {
596+
args.push(key);
597+
args.push(value);
598+
}
599+
args
600+
}
594601
#[cfg(target_os = "linux")]
595602
#[test]
596603
fn global_opts_test() {
597604
let cfg = GlobalOpts::default().command("true");
598605
let runc = cfg.build().unwrap();
599-
let args = &runc.args;
606+
let args_map = &runc.client_global_args;
607+
608+
let args = map_to_vec(args_map.clone());
600609
assert_eq!(args.len(), 2);
601610
assert!(args.contains(&LOG_FORMAT.to_string()));
602611
assert!(args.contains(&TEXT.to_string()));
603612

604613
let cfg = GlobalOpts::default().command("/bin/true");
605614
let runc = cfg.build().unwrap();
606-
assert_eq!(runc.args.len(), 2);
615+
assert_eq!(map_to_vec(runc.client_global_args).len(), 2);
607616

608617
let cfg = GlobalOpts::default()
609618
.command("true")
@@ -614,16 +623,17 @@ mod tests {
614623
.systemd_cgroup(true)
615624
.rootless(true);
616625
let runc = cfg.build().unwrap();
617-
let args = &runc.args;
626+
let args = map_to_vec(runc.client_global_args);
618627
assert!(args.contains(&ROOT.to_string()));
619628
assert!(args.contains(&DEBUG.to_string()));
620629
assert!(args.contains(&"/tmp".to_string()));
621630
assert!(args.contains(&LOG.to_string()));
622631
assert!(args.contains(&"/tmp/runc.log".to_string()));
623632
assert!(args.contains(&LOG_FORMAT.to_string()));
624633
assert!(args.contains(&JSON.to_string()));
625-
assert!(args.contains(&"--rootless=true".to_string()));
634+
635+
assert!(args.contains(&"--rootless".to_string()));
626636
assert!(args.contains(&SYSTEMD_CGROUP.to_string()));
627-
assert_eq!(args.len(), 9);
637+
assert_eq!(args.len(), 12);
628638
}
629639
}

0 commit comments

Comments
 (0)