Skip to content

Commit

Permalink
Fix arg0 and argv for hook
Browse files Browse the repository at this point in the history
  • Loading branch information
yihuaf committed Aug 14, 2021
1 parent 29ff22d commit d462bd9
Showing 1 changed file with 47 additions and 29 deletions.
76 changes: 47 additions & 29 deletions src/hooks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{bail, Context, Result};
use nix::{sys::signal, unistd::Pid};
use oci_spec::Hook;
use std::{collections::HashMap, fmt, process, thread, time};
use std::{collections::HashMap, fmt, os::unix::prelude::CommandExt, process, thread, time};

use crate::{container::Container, utils};
// A special error used to signal a timeout. We want to differenciate between a
Expand All @@ -16,43 +16,54 @@ impl fmt::Display for HookTimeoutError {
}

pub fn run_hooks(hooks: Option<&Vec<Hook>>, container: Option<&Container>) -> Result<()> {
if container.is_none() {
bail!("container state is required to run hook");
}

let state = &container.unwrap().state;

if let Some(hooks) = hooks {
for hook in hooks {
log::debug!("running hooks: {:?}", hook);
log::debug!("run_hooks: running {:?}", hook);
let envs: HashMap<String, String> = if let Some(env) = hook.env.as_ref() {
utils::parse_env(env)
} else {
HashMap::new()
};
let args = if let Some(args) = hook.args.clone() {
args
log::debug!("run_hooks envs: {:?}", envs);

// The hooks.arg follows the same semantics as argv, so the argv[0]
// is the path of the executable. By default, this is the same as
// the path of the executable being called, but it can be set to
// something different. Therefore, we have to take care of these
// special cases here. In addition, Rustlang process::Command
// doesn't provide us an API to pass argv directly. Instead, we have
// to seperate arg0 and the rest of the args.
let (arg0, args) = if let Some(mut args) = hook.args.clone() {
let arg0 = args.remove(0);
(arg0, args)
} else {
vec![]
(hook.path.as_path().display().to_string(), vec![])
};
log::debug!("run_hooks args: {:?}", args);

let mut hook_command = process::Command::new(&hook.path)
.args(&args)
.arg0(&arg0)
.env_clear()
.envs(envs)
.stdin(if container.is_some() {
process::Stdio::piped()
} else {
process::Stdio::null()
})
.stdout(process::Stdio::null())
.stderr(process::Stdio::null())
.stdin(process::Stdio::piped())
.spawn()
.with_context(|| "Failed to execute hook")?;
let hook_command_pid = Pid::from_raw(hook_command.id() as i32);
// Based on the OCI spec, we need to pipe the container state into
// the hook command through stdin.
if hook_command.stdin.is_some() {
let stdin = hook_command.stdin.take().unwrap();
if let Some(container) = &container {
serde_json::to_writer(stdin, &container.state)?;
}
serde_json::to_writer(stdin, state)?;
}

if let Some(timeout_sec) = hook.timeout {
let res = if let Some(timeout_sec) = hook.timeout {
// Rust does not make it easy to handle executing a command and
// timeout. Here we decided to wait for the command in a
// different thread, so the main thread is not blocked. We use a
Expand All @@ -69,18 +80,7 @@ pub fn run_hooks(hooks: Option<&Vec<Hook>>, container: Option<&Container>) -> Re
let _ = s.send(res);
});
match r.recv_timeout(time::Duration::from_secs(timeout_sec as u64)) {
Ok(res) => {
match res {
Ok(exit_status) => {
if !exit_status.success() {
bail!("Failed to execute hook command. Non-zero return code. {:?}", exit_status);
}
}
Err(e) => {
bail!("Failed to execute hook command: {:?}", e);
}
}
}
Ok(res) => res,
Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
// Kill the process. There is no need to further clean
// up because we will be error out.
Expand All @@ -92,7 +92,25 @@ pub fn run_hooks(hooks: Option<&Vec<Hook>>, container: Option<&Container>) -> Re
}
}
} else {
hook_command.wait()?;
hook_command.wait()
};

match res {
Ok(exit_status) => match exit_status.code() {
Some(0) => {}
Some(exit_code) => {
bail!(
"Failed to execute hook command. Non-zero return code. {:?}",
exit_code
);
}
None => {
bail!("Process is killed by signal");
}
},
Err(e) => {
bail!("Failed to execute hook command: {:?}", e);
}
}
}
}
Expand Down

0 comments on commit d462bd9

Please sign in to comment.