OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
instance_task.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Juniper Networks, Inc. All right reserved.
3  */
4 
5 #include <tbb/tbb.h>
6 #include "oper/instance_task.h"
7 #include "base/logging.h"
8 #include "io/event_manager.h"
9 
11 : is_running_(false), start_time_(0), reattempts_(0)
12 {}
13 
15  const std::string &cmd,
16  int cmd_type, EventManager *evm) :
17  name_(name), cmd_(cmd), input_(*(evm->io_service())),
18  setup_done_(false), pid_(0), cmd_type_(cmd_type), pipe_stdout_(false) {
19 }
20 
21 void InstanceTaskExecvp::ReadData(const boost::system::error_code &ec,
22  size_t read_bytes) {
23  if (read_bytes) {
24  std::string data(rx_buff_, read_bytes);
25  if (!on_data_cb_.empty()) {
26  on_data_cb_(this, data);
27  }
28  LOG(DEBUG, "Command output: " + data);
29  }
30 
31  if (ec) {
32  boost::system::error_code close_ec;
33  input_.close(close_ec);
34 
35  if (!on_exit_cb_.empty()) {
36  on_exit_cb_(this, ec);
37  }
38  LOG(DEBUG, "Command code: " + ec.message());
39  return;
40  }
41 
42  bzero(rx_buff_, sizeof(rx_buff_));
43  input_.async_read_some(boost::asio::buffer(rx_buff_, kBufLen),
44  boost::bind(&InstanceTaskExecvp::ReadData,
45  this, boost::asio::placeholders::error,
46  boost::asio::placeholders::bytes_transferred));
47 }
48 
50  assert(pid_);
51  kill(pid_, SIGTERM);
52 }
53 
55  assert(pid_);
56  kill(pid_, SIGKILL);
57 }
58 
60  return setup_done_;
61 }
62 
63 // If there is an error before the fork, task is set to "not running"
64 // and "false" is returned to caller so that caller can take appropriate
65 // action on task. If an error is encounted after fork, it is very
66 // likely that child process is running so we keep the task status as
67 // "running" and return "false" to caller, so that caller does not
68 // attempt to run the same task again. In this case, the child process
69 // exit notification can not be received by instance manager, hence
70 // instance manager has to rely on TaskTimeout delete the task.
72  std::vector<std::string> argv;
73 
74  is_running_ = true;
75 
76  boost::split(argv, cmd_, boost::is_any_of(" "), boost::token_compress_on);
77  std::vector<const char *> c_argv(argv.size() + 1);
78  for (std::size_t i = 0; i != argv.size(); ++i) {
79  c_argv[i] = argv[i].c_str();
80  }
81 
82  int err[2];
83  if (pipe(err) < 0) {
84  return is_running_ = false;
85  }
86 
87  pid_ = vfork();
88  if (pid_ == 0) {
89  close(err[0]);
90  if (pipe_stdout_) {
91  dup2(err[1], STDOUT_FILENO);
92  } else {
93  dup2(err[1], STDERR_FILENO);
94  }
95  close(err[1]);
96 
97  if (!pipe_stdout_) {
98  close(STDOUT_FILENO);
99  close(STDIN_FILENO);
100  }
101 
102  /* Close all the open fds before execvp */
103  CloseTaskFds();
104  execvp(c_argv[0], (char **) c_argv.data());
105  perror("execvp");
106 
107  _exit(127);
108  }
109 
110  close(err[1]);
111 
112  start_time_ = time(NULL);
113 
114  int fd = ::dup(err[0]);
115  close(err[0]);
116  if (fd == -1) {
117  //is_running_ is still true indicating the child process is
118  //running. Caller needs to verify the status before acting on
119  //the task again
120  return false;
121  }
122  boost::system::error_code ec;
123  input_.assign(fd, ec);
124  if (ec) {
125  close(fd);
126 
127  //is_running_ is still true indicating the child process is
128  //running. Caller needs to verify the status before acting on
129  //the task again
130  return false;
131  }
132  setup_done_ = true;
133 
134  bzero(rx_buff_, sizeof(rx_buff_));
135  input_.async_read_some(boost::asio::buffer(rx_buff_, kBufLen),
136  boost::bind(&InstanceTaskExecvp::ReadData,
137  this, boost::asio::placeholders::error,
138  boost::asio::placeholders::bytes_transferred));
139  return true;
140 
141 }
142 
144  timeout_timer_(TimerManager::CreateTimer(
145  *evm_->io_service(),
146  "Instance Manager Task Timeout",
147  TaskScheduler::GetInstance()->GetTaskId(
149 }
150 
153 }
154 
156  timeout_timer_->Start(time,
158  this),
160  this, _1, _2));
161 }
162 
165 }
166 
168  if (! on_timeout_cb_.empty()) {
169  on_timeout_cb_(this);
170  }
171 
172  return true;
173 }
174 
175 void InstanceTaskQueue::TimerErrorHandler(const std::string &name, std::string error) {
176  LOG(ERROR, "NetNS timeout error: " << error);
177 }
178 
181 
182  while(!task_queue_.empty()) {
183  InstanceTask *task = task_queue_.front();
184  task_queue_.pop();
185  delete task;
186  }
187 }
static const size_t kBufLen
Definition: instance_task.h:73
static void CloseTaskFds(void)
Definition: agent_cmn.h:80
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
Definition: task_int.h:10
void TimerErrorHandler(const std::string &name, std::string error)
OnDataCallback on_data_cb_
Definition: instance_task.h:67
boost::asio::posix::stream_descriptor input_
void StartTimer(int time)
OnTimeoutCallback on_timeout_cb_
std::queue< InstanceTask * > task_queue_
char rx_buff_[kBufLen]
bool Cancel()
Definition: timer.cc:150
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
time_t start_time_
Definition: instance_task.h:65
#define LOG(_Level, _Msg)
Definition: logging.h:33
void ReadData(const boost::system::error_code &ec, size_t read_bytes)
#define INSTANCE_MANAGER_TASK_NAME
Definition: agent.h:298
OnExitCallback on_exit_cb_
Definition: instance_task.h:68
struct task_ task
static EventManager evm
InstanceTaskExecvp(const std::string &name, const std::string &cmd, int cmd_type, EventManager *evm)
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222
InstanceTaskQueue(EventManager *evm)