Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 78 additions & 31 deletions conmon/conmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ static char *runtime_path = NULL;
static char *bundle_path = NULL;
static char *pid_file = NULL;
static bool systemd_cgroup = false;
static bool exec = false;
static GOptionEntry entries[] =
{
{ "terminal", 't', 0, G_OPTION_ARG_NONE, &terminal, "Terminal", NULL },
Expand All @@ -84,12 +85,13 @@ static GOptionEntry entries[] =
{ "bundle", 'b', 0, G_OPTION_ARG_STRING, &bundle_path, "Bundle path", NULL },
{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &pid_file, "PID file", NULL },
{ "systemd-cgroup", 's', 0, G_OPTION_ARG_NONE, &systemd_cgroup, "Enable systemd cgroup manager", NULL },
{ "exec", 'e', 0, G_OPTION_ARG_NONE, &exec, "Exec a command in a running container", NULL },
{ NULL }
};

int main(int argc, char *argv[])
{
int ret;
int ret, runtime_status;
char cwd[PATH_MAX];
char default_pid_file[PATH_MAX];
GError *err = NULL;
Expand All @@ -105,7 +107,7 @@ int main(int argc, char *argv[])
struct termios t;
struct epoll_event ev;
struct epoll_event evlist[MAX_EVENTS];
int child_pipe = -1;
int sync_pipe_fd = -1;
char *sync_pipe, *endptr;
int len;
GError *error = NULL;
Expand All @@ -126,7 +128,7 @@ int main(int argc, char *argv[])
if (runtime_path == NULL)
nexit("Runtime path not provided. Use --runtime");

if (bundle_path == NULL) {
if (bundle_path == NULL && !exec) {
if (getcwd(cwd, sizeof(cwd)) == NULL) {
nexit("Failed to get working directory");
}
Expand All @@ -147,7 +149,7 @@ int main(int argc, char *argv[])
sync_pipe = getenv("_OCI_SYNCPIPE");
if (sync_pipe) {
errno = 0;
child_pipe = strtol(sync_pipe, &endptr, 10);
sync_pipe_fd = strtol(sync_pipe, &endptr, 10);
if (errno != 0 || *endptr != '\0')
pexit("unable to parse _OCI_SYNCPIPE");
}
Expand Down Expand Up @@ -184,23 +186,41 @@ int main(int argc, char *argv[])

}

/* Create the container */
cmd = g_string_new(runtime_path);
if (systemd_cgroup) {
g_string_append_printf(cmd, " --systemd-cgroup");
}
g_string_append_printf(cmd, " create %s --bundle %s --pid-file %s",
cid, bundle_path, pid_file);
if (terminal) {
g_string_append_printf(cmd, " --console %s", slname);
if (!exec) {
/* Create the container */
if (systemd_cgroup) {
g_string_append_printf(cmd, " --systemd-cgroup");
}
g_string_append_printf(cmd, " create %s --bundle %s --pid-file %s",
cid, bundle_path, pid_file);
if (terminal) {
g_string_append_printf(cmd, " --console %s", slname);
}
} else {
int i;

/* Exec the command */
if (terminal) {
g_string_append_printf(cmd, " exec -d --pid-file %s --console %s %s",
pid_file, slname, cid);
} else {
g_string_append_printf(cmd, " exec -d --pid-file %s %s",
pid_file, cid);
}

for (i = 1; i < argc; i++) {
g_string_append_printf(cmd, " %s", argv[i]);
}
}
ret = system(cmd->str);
if (ret != 0) {

runtime_status = system(cmd->str);
if (runtime_status != 0) {
nexit("Failed to create container");
}

/* Read the pid so we can wait for the process to exit */
g_file_get_contents("pidfile", &contents, NULL, &err);
g_file_get_contents(pid_file, &contents, NULL, &err);
if (err) {
fprintf(stderr, "Failed to read pidfile: %s\n", err->message);
g_error_free(err);
Expand All @@ -211,9 +231,9 @@ int main(int argc, char *argv[])
printf("container PID: %d\n", cpid);

/* Send the container pid back to parent */
if (child_pipe > 0) {
if (sync_pipe_fd > 0 && !exec) {
len = snprintf(buf, BUF_SIZE, "{\"pid\": %d}\n", cpid);
if (len < 0 || write(child_pipe, buf, len) != len) {
if (len < 0 || write(sync_pipe_fd, buf, len) != len) {
pexit("unable to send container pid to parent");
}
}
Expand Down Expand Up @@ -303,25 +323,52 @@ int main(int argc, char *argv[])

/* Wait for the container process and record its exit code */
while ((pid = waitpid(-1, &status, 0)) > 0) {
printf("PID %d exited\n", pid);
int exit_status = WEXITSTATUS(status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were doing this conversion up in the go code so need to remove the conversion from https://github.com/kubernetes-incubator/cri-o/blob/master/oci/oci.go#L338

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks for spotting that one.


printf("PID %d exited with status %d\n", pid, exit_status);
if (pid == cpid) {
_cleanup_free_ char *status_str = NULL;
ret = asprintf(&status_str, "%d", status);
if (ret < 0) {
pexit("Failed to allocate memory for status");
}
g_file_set_contents("exit", status_str,
strlen(status_str), &err);
if (err) {
fprintf(stderr,
"Failed to write %s to exit file: %s\n",
status_str, err->message);
g_error_free(err);
exit(1);
if (!exec) {
_cleanup_free_ char *status_str = NULL;
ret = asprintf(&status_str, "%d", exit_status);
if (ret < 0) {
pexit("Failed to allocate memory for status");
}
g_file_set_contents("exit", status_str,
strlen(status_str), &err);
if (err) {
fprintf(stderr,
"Failed to write %s to exit file: %s\n",
status_str, err->message);
g_error_free(err);
exit(1);
}
} else {
/* Send the command exec exit code back to the parent */
if (sync_pipe_fd > 0) {
len = snprintf(buf, BUF_SIZE, "{\"exit_code\": %d}\n", exit_status);
if (len < 0 || write(sync_pipe_fd, buf, len) != len) {
pexit("unable to send exit status");
exit(1);
}
}
}
break;
}
}

if (exec && pid < 0 && errno == ECHILD && sync_pipe_fd > 0) {
/*
* waitpid failed and set errno to ECHILD:
* The runtime exec call did not create any child
* process and we can send the system() exit code
* to the parent.
*/
len = snprintf(buf, BUF_SIZE, "{\"exit_code\": %d}\n", WEXITSTATUS(runtime_status));
if (len < 0 || write(sync_pipe_fd, buf, len) != len) {
pexit("unable to send exit status");
exit(1);
}
}

return EXIT_SUCCESS;
}
79 changes: 76 additions & 3 deletions oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ type syncInfo struct {
Pid int `json:"pid"`
}

// exitCodeInfo is used to return the monitored process exit code to the daemon
type exitCodeInfo struct {
ExitCode int32 `json:"exit_code"`
}

// Name returns the name of the OCI Runtime
func (r *Runtime) Name() string {
return r.name
Expand Down Expand Up @@ -177,16 +182,61 @@ func (e ExecSyncError) Error() string {
return fmt.Sprintf("command error: %+v, stdout: %s, stderr: %s, exit code %d", e.Err, e.Stdout.Bytes(), e.Stderr.Bytes(), e.ExitCode)
}

func prepareExec() (pidFile, parentPipe, childPipe *os.File, err error) {
parentPipe, childPipe, err = os.Pipe()
if err != nil {
return nil, nil, nil, err
}

pidFile, err = ioutil.TempFile("", "pidfile")
if err != nil {
parentPipe.Close()
childPipe.Close()
return nil, nil, nil, err
}

return
}

// ExecSync execs a command in a container and returns it's stdout, stderr and return code.
func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp *ExecSyncResponse, err error) {
args := []string{"exec", c.name}
pidFile, parentPipe, childPipe, err := prepareExec()
if err != nil {
return nil, ExecSyncError{
ExitCode: -1,
Err: err,
}
}
defer parentPipe.Close()
defer func() {
if e := os.Remove(pidFile.Name()); e != nil {
logrus.Warnf("could not remove temporary PID file %s", pidFile.Name())
}
}()

var args []string
args = append(args, "-c", c.name)
args = append(args, "-r", r.path)
args = append(args, "-p", pidFile.Name())
args = append(args, "-e")
if c.terminal {
args = append(args, "-t")
}

args = append(args, command...)
cmd := exec.Command(r.Path(), args...)

cmd := exec.Command(r.conmonPath, args...)

var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf
cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe)
// 0, 1 and 2 are stdin, stdout and stderr
cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))

err = cmd.Start()
if err != nil {
childPipe.Close()
return nil, ExecSyncError{
Stdout: stdoutBuf,
Stderr: stderrBuf,
Expand All @@ -195,6 +245,9 @@ func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp
}
}

// We don't need childPipe on the parent side
childPipe.Close()

if timeout > 0 {
done := make(chan error, 1)
go func() {
Expand Down Expand Up @@ -260,7 +313,27 @@ func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp
Err: err,
}
}
}
}

var ec *exitCodeInfo
if err := json.NewDecoder(parentPipe).Decode(&ec); err != nil {
return nil, ExecSyncError{
Stdout: stdoutBuf,
Stderr: stderrBuf,
ExitCode: -1,
Err: err,
}
}

logrus.Infof("Received container exit code: %v", ec.ExitCode)

if ec.ExitCode != 0 {
return nil, ExecSyncError{
Stdout: stdoutBuf,
Stderr: stderrBuf,
ExitCode: ec.ExitCode,
Err: fmt.Errorf("container workload exited with error %v", ec.ExitCode),
}
}

Expand Down Expand Up @@ -335,7 +408,7 @@ func (r *Runtime) UpdateStatus(c *Container) error {
if err != nil {
return fmt.Errorf("status code conversion failed: %v", err)
}
c.state.ExitCode = int32(utils.StatusToExitCode(statusCode))
c.state.ExitCode = int32(statusCode)
}

return nil
Expand Down
1 change: 0 additions & 1 deletion test/ctr.bats
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ function teardown() {
run ocic ctr execsync --id "$ctr_id" doesnotexist
echo "$output"
[ "$status" -ne 0 ]
[[ "$output" =~ "executable file not found in" ]]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where has this gone?

Copy link
Author

@sameo sameo Jan 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This string was returned by runC itself. Other runtimes may not decide to return the same string.
To be runtime agnostic, I think the only thing we can safely check here is that this execsync call really failed.

cleanup_ctrs
cleanup_pods
Expand Down
5 changes: 0 additions & 5 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,3 @@ func dockerRemove(container string) error {
_, err := ExecCmd("docker", "rm", container)
return err
}

// StatusToExitCode converts wait status code to an exit code
func StatusToExitCode(status int) int {
return ((status) & 0xff00) >> 8
}