add support of separate stderr output of container

this patch add a pipe besides the pty for container, and the stderr will be
sent from the stderr session if the session provided in spec.

this intend to support log the stdout and stderr separately.

Signed-off-by: Wang Xu <gnawux@gmail.com>
This commit is contained in:
Wang Xu
2015-10-04 19:28:49 +08:00
committed by Gao feng
parent fdc9364062
commit a5680759eb
4 changed files with 76 additions and 10 deletions
+1
View File
@@ -220,6 +220,7 @@ void hyper_event_hup(struct hyper_event *de, int efd)
if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0)
perror("epoll_ctl del epoll event failed");
close(de->fd);
de->fd = -1;
hyper_reset_event(de);
}
+68 -10
View File
@@ -36,18 +36,25 @@ static void pts_hup(struct hyper_event *de, int efd)
hyper_set_be32(buf->data + buf->get + 8, 12);
buf->get += 12;
if (buf->get + 12 > buf->size) {
fprintf(stdout, "%s: tty buf full (for stderr)\n", __func__);
} else {
/* no in event, no more data, send eof in stderr */
hyper_set_be64(buf->data + buf->get, exec->errseq);
hyper_set_be32(buf->data + buf->get + 8, 12);
buf->get += 12;
}
hyper_modify_event(ctl.efd, &ctl.tty, EPOLLIN | EPOLLOUT);
hyper_release_exec(exec, pod);
}
static int pts_loop(struct hyper_event *de)
static int pts_loop(struct hyper_event *de, uint64_t seq)
{
int size = -1;
struct hyper_buf *buf = &ctl.tty.wbuf;
struct hyper_exec *exec = container_of(de, struct hyper_exec, e);
fprintf(stdout, "%s\n", __func__);
while ((buf->get + 12 < buf->size) && size) {
size = read(de->fd, buf->data + buf->get + 12, buf->size - buf->get - 12);
fprintf(stdout, "%s: read %d data\n", __func__, size);
@@ -63,11 +70,9 @@ static int pts_loop(struct hyper_event *de)
break;
}
hyper_set_be64(buf->data + buf->get, exec->seq);
hyper_set_be64(buf->data + buf->get, seq);
hyper_set_be32(buf->data + buf->get + 8, size + 12);
buf->get += size + 12;
dprintf("%s: seq %" PRIu64" len %" PRIu32"\n", __func__, exec->seq, size);
}
if (hyper_modify_event(ctl.efd, &ctl.tty, EPOLLIN | EPOLLOUT) < 0) {
@@ -78,14 +83,37 @@ static int pts_loop(struct hyper_event *de)
return 0;
}
static int stdout_loop(struct hyper_event *de)
{
struct hyper_exec *exec = container_of(de, struct hyper_exec, e);
fprintf(stdout, "%s, seq %" PRIu64"\n", __func__, exec->seq);
return pts_loop(de, exec->seq);
}
struct hyper_event_ops pts_ops = {
.read = pts_loop,
.read = stdout_loop,
.hup = pts_hup,
.write = hyper_event_write,
.wbuf_size = 512,
/* don't need read buff, the pts data will store in tty buffer */
};
static int stderr_loop(struct hyper_event *de)
{
struct hyper_exec *exec = container_of(de, struct hyper_exec, errev);
fprintf(stdout, "%s, seq %" PRIu64"\n", __func__, exec->errseq);
return pts_loop(de, exec->errseq);
}
struct hyper_event_ops err_ops = {
/* don't need to deal with hup, the hup will be dealed by pts*/
.read = stderr_loop,
/* don't need read buff, the stderr data will store in tty buffer */
/* don't need write buff, the stderr data is one way */
};
int hyper_setup_exec_tty(struct hyper_exec *e)
{
int unlock = 0;
@@ -94,6 +122,16 @@ int hyper_setup_exec_tty(struct hyper_exec *e)
if (e->seq == 0)
return 0;
if (e->errseq > 0) {
int errpipe[2];
if (pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) < 0) {
fprintf(stderr, "creating stderr pipe failed\n");
return -1;
}
e->errev.fd = errpipe[0];
e->errfd = errpipe[1];
}
if (e->id) {
if (sprintf(path, "/tmp/hyper/%s/devpts/", e->id) < 0) {
fprintf(stderr, "get ptmx path failed\n");
@@ -179,9 +217,16 @@ int hyper_dup_exec_tty(int to, struct hyper_exec *e)
goto out;
}
if (dup2(fd, STDERR_FILENO) < 0) {
perror("dup tty device to stderr failed");
goto out;
if (e->errseq > 0) {
if (dup2(e->errfd, STDERR_FILENO) < 0) {
perror("dup err pipe to stderr failed");
goto out;
}
} else {
if (dup2(fd, STDERR_FILENO) < 0) {
perror("dup tty device to stderr failed");
goto out;
}
}
ret = 0;
@@ -205,6 +250,15 @@ int hyper_watch_exec_pty(struct hyper_exec *exec, struct hyper_pod *pod)
return -1;
}
if (exec->errseq == 0)
return 0;
if (hyper_init_event(&exec->errev, &err_ops, NULL) < 0 ||
hyper_add_event(ctl.efd, &exec->errev, EPOLLIN) < 0) {
fprintf(stderr, "add container stderr event failed\n");
return -1;
}
return 0;
}
@@ -447,8 +501,12 @@ int hyper_release_exec(struct hyper_exec *exec,
/* exec has no pty or the pty user already exited */
fprintf(stdout, "last user of exec exit, release\n");
close(exec->e.fd);
close(exec->errev.fd);
close(exec->ptyfd);
close(exec->errfd);
hyper_reset_event(&exec->e);
hyper_reset_event(&exec->errev);
list_del_init(&exec->list);
+3
View File
@@ -7,14 +7,17 @@
struct hyper_exec {
struct list_head list;
struct hyper_event e;
struct hyper_event errev;
char *id;
char **argv;
int argc;
uint64_t seq;
uint64_t errseq;
int pid;
int ptyno;
int init;
int ptyfd;
int errfd;
uint8_t code;
uint8_t exit;
};
+4
View File
@@ -228,6 +228,10 @@ static int hyper_parse_container(struct hyper_pod *pod, struct hyper_container *
i++;
c->exec.seq = json_token_ll(json, &toks[i]);
fprintf(stdout, "container seq %" PRIu64 "\n", c->exec.seq);
} else if (json_token_streq(json, t, "stderr") && t->size == 1) {
i++;
c->exec.errseq = json_token_ll(json, &toks[i]);
fprintf(stdout, "container stderr seq %" PRIu64 "\n", c->exec.errseq);
} else if (json_token_streq(json, t, "workdir") && t->size == 1) {
i++;
c->workdir = strdup(json_token_str(json, &toks[i]));