static void exec_runc()

in storm-core/src/native/worker-launcher/impl/oci/oci.c [700:798]


static void exec_runc(const char* container_id, const char* runc_config_path,
    const char* pid_file_path, const char* worker_artifacts_dir) {
  char* runc_path = get_value(OCI_RUNC_CONFIG_KEY);
  if (runc_path == NULL) {
    runc_path = strdup(DEFAULT_OCI_RUNC);
    if (runc_path == NULL) {
      fputs("ERROR: Unable to allocate memory in exec_runc\n", ERRORFILE);
      exit(1);
    }
  }

  char* dir_end = strrchr(runc_config_path, '/');
  if (dir_end == NULL) {
    fprintf(ERRORFILE, "ERROR: Error getting bundle path from config path %s\n",
        runc_config_path);
    exit(1);
  }
  char* bundle_path = strndup(runc_config_path, dir_end - runc_config_path);

  //We must use runc detached mode so that 
  //the worker process can stay alive when the supervisor dies
  const char* const runc_args[] = {
      runc_path, "run",
      "-d",
      "--pid-file", pid_file_path,
      "-b", bundle_path,
      container_id,
      NULL
  };
  const char* const runc_env[] = { NULL };

  int i;
  fprintf(LOGFILE, "command: ");
  for (i = 0; runc_args[i] != NULL; i++) {
    fprintf(LOGFILE, "%s ", runc_args[i]);
  }
  fputs("\n", LOGFILE);
  fflush(LOGFILE);

  //runc detached mode gives up the control of stdio to the calling process
  //The calling process will hang until the runc container terminates if it reads runc container's stdout
  //We redirect the stdout and stderr to files as a workaround.
  //There maybe a better way to solve this problem.
  char* runc_out_file = concatenate("%s/runc-%s.out", "runc out file", 2, worker_artifacts_dir, container_id);
  char* runc_err_file = concatenate("%s/runc-%s.err", "runc err file", 2, worker_artifacts_dir, container_id);

  int fd_out = open(runc_out_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  if (fd_out == -1) {
    fprintf(ERRORFILE, "ERROR: Failed to open %s\n", runc_out_file);
    exit(ERROR_OPENING_FILE);
  }

  int fd_err = open(runc_err_file, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  if (fd_err == -1) {
    fprintf(ERRORFILE, "ERROR: Failed to open %s\n", runc_err_file);
    exit(ERROR_OPENING_FILE);
  }

  fprintf(LOGFILE, "Redirecting STDOUT and STDERR to %s and %s\n", runc_out_file, runc_err_file);
  //Flush everything before redirection
  fflush(LOGFILE);
  fflush(ERRORFILE);

  int save_out = dup(fileno(stdout));
  int save_err = dup(fileno(stderr));

  if (dup2(fd_out, fileno(stdout)) == -1) {
    fprintf(ERRORFILE, "ERROR: Failed to redirect STDOUT to %s\n", runc_out_file);
    exit(1);
  }
  if (dup2(fd_err, fileno(stderr)) == -1) {
    fprintf(ERRORFILE, "ERROR: Failed to redirect STDERR to %s\n", runc_err_file);
    exit(1);
  }

  if (execve(runc_path, (char* const*)runc_args, (char* const*)runc_env) == -1) {
    char* errstr = strerror(errno);

    //restore STDOUT and STDERR redirection
    fflush(stdout); 
    fflush(stderr); 
    close(fd_out);
    close(fd_err);
    dup2(save_out, fileno(stdout));
    dup2(save_err, fileno(stderr));
    close(save_out);
    close(save_err);

    fputs("ERROR: Failed to exec:", ERRORFILE);
    const char* const* argp;
    for (argp = runc_args; *argp != NULL; ++argp) {
      fprintf(ERRORFILE, " %s", *argp);
    }
    fprintf(ERRORFILE, " : %s\n", errstr);
    free(runc_path);
  }

  exit(ERROR_OCI_RUN_FAILED);
}