Merge pull request #634 from alexlarsson/conmon-no-numstdio-fds

conmon: Change how we detect container exit
This commit is contained in:
Mrunal Patel 2017-06-30 12:08:31 -07:00 committed by GitHub
commit 39a5203a1d

View file

@ -468,11 +468,11 @@ static void end_argv(GPtrArray *argv_array)
/* Global state */ /* Global state */
static int runtime_status = -1; static int runtime_status = -1;
static int container_status = -1;
static int masterfd_stdin = -1; static int masterfd_stdin = -1;
static int masterfd_stdout = -1; static int masterfd_stdout = -1;
static int masterfd_stderr = -1; static int masterfd_stderr = -1;
static int num_stdio_fds = 0;
/* Used for attach */ /* Used for attach */
static int conn_sock = -1; static int conn_sock = -1;
@ -504,52 +504,103 @@ static void conn_sock_shutdown(int how)
} }
} }
static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data) static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data);
static gboolean tty_hup_timeout_scheduled = false;
static gboolean tty_hup_timeout_cb (G_GNUC_UNUSED gpointer user_data)
{
tty_hup_timeout_scheduled = false;
g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE));
return G_SOURCE_REMOVE;
}
static bool read_stdio(int fd, stdpipe_t pipe, bool *eof)
{ {
#define STDIO_BUF_SIZE 8192 /* Sync with redirectResponseToOutputStreams() */ #define STDIO_BUF_SIZE 8192 /* Sync with redirectResponseToOutputStreams() */
/* We use one extra byte at the start, which we don't read into, instead /* We use one extra byte at the start, which we don't read into, instead
we use that for marking the pipe when we write to the attached socket */ we use that for marking the pipe when we write to the attached socket */
char real_buf[STDIO_BUF_SIZE + 1]; char real_buf[STDIO_BUF_SIZE + 1];
char *buf = real_buf + 1; char *buf = real_buf + 1;
stdpipe_t pipe = GPOINTER_TO_INT(user_data);
ssize_t num_read = 0; ssize_t num_read = 0;
if ((condition & G_IO_IN) != 0) { if (eof)
num_read = read(fd, buf, BUF_SIZE); *eof = false;
if (num_read < 0) {
nwarn("stdio_input read failed %s", strerror(errno)); num_read = read(fd, buf, STDIO_BUF_SIZE);
if (num_read == 0) {
if (eof)
*eof = true;
return false;
} else if (num_read < 0) {
nwarn("stdio_input read failed %s", strerror(errno));
return false;
} else {
if (write_k8s_log(log_fd, pipe, buf, num_read) < 0) {
nwarn("write_k8s_log failed");
return G_SOURCE_CONTINUE; return G_SOURCE_CONTINUE;
} }
if (num_read > 0) { real_buf[0] = pipe;
if (write_k8s_log(log_fd, pipe, buf, num_read) < 0) { if (conn_sock_writable && write_all(conn_sock, real_buf, num_read+1) < 0) {
nwarn("write_k8s_log failed"); nwarn("Failed to write to socket");
return G_SOURCE_CONTINUE; conn_sock_shutdown(SHUT_WR);
} }
return true;
}
}
real_buf[0] = pipe; static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data)
if (conn_sock_writable && write_all(conn_sock, real_buf, num_read+1) < 0) { {
nwarn("Failed to write to socket"); stdpipe_t pipe = GPOINTER_TO_INT(user_data);
conn_sock_shutdown(SHUT_WR); bool read_eof = false;
} bool has_input = (condition & G_IO_IN) != 0;
bool has_hup = (condition & G_IO_HUP) != 0;
/* When we get here, condition can be G_IO_IN and/or G_IO_HUP.
IN means there is some data to read.
HUP means the other side closed the fd. In the case of a pine
this in final, and we will never get more data. However, in the
terminal case this just means that nobody has the terminal
open at this point, and this can be change whenever someone
opens the tty */
/* Read any data before handling hup */
if (has_input) {
read_stdio(fd, pipe, &read_eof);
}
if (has_hup && opt_terminal && pipe == STDOUT_PIPE) {
/* We got a HUP from the terminal master this means there
are no open slaves ptys atm, and we will get a lot
of wakeups until we have one, switch to polling
mode. */
/* If we read some data this cycle, wait one more, maybe there
is more in the buffer before we handle the hup */
if (has_input && !read_eof) {
return G_SOURCE_CONTINUE; return G_SOURCE_CONTINUE;
} }
if (!tty_hup_timeout_scheduled) {
g_timeout_add (100, tty_hup_timeout_cb, NULL);
}
tty_hup_timeout_scheduled = true;
return G_SOURCE_REMOVE;
} }
/* End of input */ if (read_eof || (has_hup && !has_input)) {
if (pipe == STDOUT_PIPE) /* End of input */
masterfd_stdout = -1; if (pipe == STDOUT_PIPE)
if (pipe == STDERR_PIPE) masterfd_stdout = -1;
masterfd_stderr = -1; if (pipe == STDERR_PIPE)
num_stdio_fds--; masterfd_stderr = -1;
if (num_stdio_fds == 0) {
ninfo ("No more stdio, killing main loop"); close (fd);
g_main_loop_quit (main_loop); return G_SOURCE_REMOVE;
} }
close (fd); return G_SOURCE_CONTINUE;
return G_SOURCE_REMOVE;
} }
static gboolean timeout_cb (G_GNUC_UNUSED gpointer user_data) static gboolean timeout_cb (G_GNUC_UNUSED gpointer user_data)
@ -755,6 +806,14 @@ runtime_exit_cb (G_GNUC_UNUSED GPid pid, int status, G_GNUC_UNUSED gpointer user
g_main_loop_quit (main_loop); g_main_loop_quit (main_loop);
} }
static void
container_exit_cb (G_GNUC_UNUSED GPid pid, int status, G_GNUC_UNUSED gpointer user_data)
{
ninfo("container %d exited with status %d\n", pid, status);
container_status = status;
g_main_loop_quit (main_loop);
}
static void write_sync_fd(int sync_pipe_fd, int res, const char *message) static void write_sync_fd(int sync_pipe_fd, int res, const char *message)
{ {
_cleanup_free_ char *escaped_message = NULL; _cleanup_free_ char *escaped_message = NULL;
@ -893,10 +952,10 @@ static void setup_terminal_control_fifo()
ninfo("terminal_ctrl_fd: %d", terminal_ctrl_fd); ninfo("terminal_ctrl_fd: %d", terminal_ctrl_fd);
} }
static void setup_oom_handling(int cpid) static void setup_oom_handling(int container_pid)
{ {
/* Setup OOM notification for container process */ /* Setup OOM notification for container process */
_cleanup_free_ char *memory_cgroup_path = process_cgroup_subsystem_path(cpid, "memory"); _cleanup_free_ char *memory_cgroup_path = process_cgroup_subsystem_path(container_pid, "memory");
_cleanup_close_ int cfd = -1; _cleanup_close_ int cfd = -1;
int ofd = -1; /* Not closed */ int ofd = -1; /* Not closed */
if (!memory_cgroup_path) { if (!memory_cgroup_path) {
@ -932,9 +991,8 @@ int main(int argc, char *argv[])
_cleanup_free_ char *csname = NULL; _cleanup_free_ char *csname = NULL;
GError *err = NULL; GError *err = NULL;
_cleanup_free_ char *contents = NULL; _cleanup_free_ char *contents = NULL;
int cpid = -1; int container_pid = -1;
int status; pid_t main_pid, create_pid;
pid_t pid, main_pid, create_pid;
/* Used for !terminal cases. */ /* Used for !terminal cases. */
int slavefd_stdin = -1; int slavefd_stdin = -1;
int slavefd_stdout = -1; int slavefd_stdout = -1;
@ -1205,8 +1263,8 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
cpid = atoi(contents); container_pid = atoi(contents);
ninfo("container PID: %d", cpid); ninfo("container PID: %d", container_pid);
/* Setup endpoint for attach */ /* Setup endpoint for attach */
_cleanup_free_ char *attach_symlink_dir_path = NULL; _cleanup_free_ char *attach_symlink_dir_path = NULL;
@ -1220,45 +1278,46 @@ int main(int argc, char *argv[])
/* Send the container pid back to parent */ /* Send the container pid back to parent */
if (!opt_exec) { if (!opt_exec) {
write_sync_fd(sync_pipe_fd, cpid, NULL); write_sync_fd(sync_pipe_fd, container_pid, NULL);
} }
setup_oom_handling(cpid); setup_oom_handling(container_pid);
if (masterfd_stdout >= 0) { if (masterfd_stdout >= 0) {
g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE)); g_unix_fd_add (masterfd_stdout, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDOUT_PIPE));
num_stdio_fds++;
} }
if (masterfd_stderr >= 0) { if (masterfd_stderr >= 0) {
g_unix_fd_add (masterfd_stderr, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDERR_PIPE)); g_unix_fd_add (masterfd_stderr, G_IO_IN, stdio_cb, GINT_TO_POINTER(STDERR_PIPE));
num_stdio_fds++;
} }
if (opt_timeout > 0) { if (opt_timeout > 0) {
g_timeout_add_seconds (opt_timeout, timeout_cb, NULL); g_timeout_add_seconds (opt_timeout, timeout_cb, NULL);
} }
g_child_watch_add (container_pid, container_exit_cb, NULL);
g_main_loop_run (main_loop); g_main_loop_run (main_loop);
/* Drain stdout and stderr */
if (masterfd_stdout != -1) {
g_unix_set_fd_nonblocking(masterfd_stdout, TRUE, NULL);
while (read_stdio(masterfd_stdout, STDOUT_PIPE, NULL))
;
}
if (masterfd_stderr != -1) {
g_unix_set_fd_nonblocking(masterfd_stderr, TRUE, NULL);
while (read_stdio(masterfd_stderr, STDERR_PIPE, NULL))
;
}
int exit_status = -1; int exit_status = -1;
const char *exit_message = NULL; const char *exit_message = NULL;
if (timed_out) { if (timed_out) {
kill(cpid, SIGKILL); kill(container_pid, SIGKILL);
exit_message = "command timed out"; exit_message = "command timed out";
} else { } else {
/* Wait for the container process and record its exit code */ exit_status = WEXITSTATUS(container_status);
while ((pid = waitpid(-1, &status, 0)) > 0) {
int child_exit_status = WEXITSTATUS(status);
printf("PID %d exited with status %d\n", pid, child_exit_status);
if (pid == cpid) {
exit_status = child_exit_status;
break;
}
}
if (pid == -1) {
exit_message = "runtime didn't create a child";
}
} }
if (!opt_exec) { if (!opt_exec) {