OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vm_stat.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <sys/times.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <unistd.h>
9 #include <uve/vm_stat.h>
10 #include <uve/vm_stat_data.h>
11 #include <db/db.h>
12 #include <db/db_entry.h>
13 #include <db/db_table.h>
14 #include <base/address.h>
16 #include <cmn/agent.h>
17 #include <init/agent_param.h>
18 #include <uve/vrouter_uve_entry.h>
19 #include <sstream>
20 #include <fstream>
21 #include <uve/agent_uve.h>
22 #include <uve/vm_uve_table.h>
23 
24 using namespace boost::uuids;
25 using namespace boost::asio;
26 
27 VmStat::VmStat(Agent *agent, const uuid &vm_uuid):
28  agent_(agent), vm_uuid_(vm_uuid), mem_usage_(0),
29  virt_memory_(0), virt_memory_peak_(0), vm_memory_quota_(0),
30  prev_cpu_stat_(0), cpu_usage_(0),
31  prev_cpu_snapshot_time_(0), prev_vcpu_snapshot_time_(0),
32  input_(*(agent_->event_manager()->io_service())),
33  timer_(TimerManager::CreateTimer(*(agent_->event_manager())->io_service(),
34  "VmStatTimer")), marked_delete_(false), pid_(0), retry_(0), virtual_size_(0),
35  disk_size_(0), disk_name_(),
36  vm_state_(VrouterAgentVmState::VROUTER_AGENT_VM_UNKNOWN),
37  prev_vm_state_(VrouterAgentVmState::VROUTER_AGENT_VM_UNKNOWN),
38  vm_cpu_count_(kInvalidCpuCount), prev_vm_cpu_count_(kInvalidCpuCount) {
39 }
40 
43 }
44 
45 void VmStat::ReadData(const boost::system::error_code &ec,
46  size_t read_bytes, DoneCb &cb) {
47  if (read_bytes) {
48  data_<< rx_buff_;
49  }
50 
51  if (ec) {
52  boost::system::error_code close_ec;
53  input_.close(close_ec);
54  call_back_ = cb;
55  //Enqueue a request to process data
56  VmStatData *vm_stat_data = new VmStatData(this);
57 
58  VmUveTable *vmt = static_cast<VmUveTable *>
59  (agent_->uve()->vm_uve_table());
60  vmt->EnqueueVmStatData(vm_stat_data);
61  } else {
62  bzero(rx_buff_, sizeof(rx_buff_));
63  async_read(input_, boost::asio::buffer(rx_buff_, kBufLen),
64  boost::bind(&VmStat::ReadData, this, placeholders::error,
65  placeholders::bytes_transferred, cb));
66  }
67 }
68 
70  if (!call_back_.empty())
71  call_back_();
72 }
73 
74 void VmStat::ExecCmd(std::string cmd, DoneCb cb) {
75  char *argv[4];
76  char shell[80] = "/bin/sh";
77  char option[80] = "-c";
78  char ccmd[256];
79  memset(ccmd, 0, sizeof(ccmd));
80  strncpy(ccmd, cmd.c_str(), sizeof(ccmd)-1);
81 
82  argv[0] = shell;
83  argv[1] = option;
84  argv[2] = ccmd;
85  argv[3] = 0;
86 
87  int out[2];
88  if (pipe(out) < 0) {
89  return;
90  }
91 
92  if (vfork() == 0) {
93  //Close read end of pipe
94  close(out[0]);
95  dup2(out[1], STDOUT_FILENO);
96  //Close out[1] as stdout is a exact replica of out[1]
97  close(out[1]);
98 
99  /* Close all the open fds before execvp */
100  CloseTaskFds();
101  execvp(argv[0], argv);
102  perror("execvp");
103  exit(127);
104  }
105 
106  //Close write end of pipe
107  close(out[1]);
108 
109  boost::system::error_code ec;
110  int fd = ::dup(out[0]);
111  close(out[0]);
112  if (fd == -1) {
113  return;
114  }
115  input_.assign(fd, ec);
116  if (ec) {
117  close(fd);
118  return;
119  }
120 
121  bzero(rx_buff_, sizeof(rx_buff_));
122  async_read(input_, boost::asio::buffer(rx_buff_, kBufLen),
123  boost::bind(&VmStat::ReadData, this, placeholders::error,
124  placeholders::bytes_transferred, cb));
125 }
126 
127 bool VmStat::BuildVmStatsMsg(VirtualMachineStats *uve) {
128  uve->set_name(UuidToString(vm_uuid_));
129 
130  std::vector<VmCpuStats> cpu_stats_list;
131  VmCpuStats stats;
132  stats.set_cpu_one_min_avg(cpu_usage_);
133  stats.set_vm_memory_quota(vm_memory_quota_);
134  stats.set_rss(mem_usage_);
135  stats.set_virt_memory(virt_memory_);
136  stats.set_peak_virt_memory(virt_memory_peak_);
137  stats.set_disk_allocated_bytes(virtual_size_);
138  stats.set_disk_used_bytes(disk_size_);
139 
140 
141  cpu_stats_list.push_back(stats);
142  uve->set_cpu_stats(cpu_stats_list);
143 
144  return true;
145 }
146 
147 bool VmStat::BuildVmMsg(UveVirtualMachineAgent *uve) {
148  uve->set_name(UuidToString(vm_uuid_));
149 
150  VmCpuStats stats;
151  stats.set_cpu_one_min_avg(cpu_usage_);
152  stats.set_vm_memory_quota(vm_memory_quota_);
153  stats.set_rss(mem_usage_);
154  stats.set_virt_memory(virt_memory_);
155  stats.set_peak_virt_memory(virt_memory_peak_);
156  stats.set_disk_allocated_bytes(virtual_size_);
157  stats.set_disk_used_bytes(disk_size_);
158 
159  uve->set_cpu_info(stats);
160 
161  vnsConstants vns;
162  if (vm_state_ != VrouterAgentVmState::VROUTER_AGENT_VM_UNKNOWN) {
163  if (vm_state_ != prev_vm_state_) {
164  uve->set_vm_state(vns.VrouterAgentVmStateMap.at(vm_state_));
166  }
167  }
168 
171  uve->set_vm_cpu_count(vm_cpu_count_);
173  }
174  }
175 
176  return true;
177 }
178 
180  //We need to send same cpu info in two different UVEs
181  //(VirtualMachineStats and UveVirtualMachineAgent). One of them uses
182  //stats-oracle infra and other one does not use it. We need two because
183  //stats-oracle infra returns only SUM of cpu-info over a period of time
184  //and current value is returned using non-stats-oracle version. Using
185  //stats oracle infra we can still query the current value but for simpler
186  //interface we are sending current value in separate UVE.
187  //Also the non-stats oracle version has additional fields of vm_state and
188  //vm_cpu_count which are not sent in stats-oracle version.
189  VirtualMachineStats vm_agent;
190  if (BuildVmStatsMsg(&vm_agent)) {
191  VmUveTable *vmt = static_cast<VmUveTable *>
192  (agent_->uve()->vm_uve_table());
193  vmt->DispatchVmStatsMsg(vm_agent);
194  }
195  UveVirtualMachineAgent vm_msg;
196  if (BuildVmMsg(&vm_msg)) {
197  agent_->uve()->vm_uve_table()->DispatchVmMsg(vm_msg);
198  }
199 }
200 
202  return false;
203 }
204 
206  timer_->Cancel();
208  boost::bind(&VmStat::TimerExpiry, this));
209 }
210 
212 }
213 
214 void VmStat::Stop() {
215  marked_delete_ = true;
216  if (timer_->running() || retry_ == kRetryCount) {
217  //If timer is fired, then we are in middle of
218  //vm stat collection, in such case dont delete the vm stat
219  //entry as asio may be using it
220  delete this;
221  }
222 }
uint16_t vm_cpu_count_
Definition: vm_stat.h:68
static void CloseTaskFds(void)
Definition: agent_cmn.h:80
void ProcessData()
Definition: vm_stat.cc:69
double cpu_usage_
Definition: vm_stat.h:50
void ExecCmd(std::string cmd, DoneCb cb)
Definition: vm_stat.cc:74
virtual void DispatchVmStatsMsg(const VirtualMachineStats &uve)
Definition: vm_uve_table.cc:92
AgentUveBase * uve() const
Definition: agent.cc:909
virtual ~VmStat()
Definition: vm_stat.cc:41
bool BuildVmMsg(UveVirtualMachineAgent *uve)
Definition: vm_stat.cc:147
VrouterAgentVmState::type vm_state_
Definition: vm_stat.h:66
boost::uuids::uuid uuid
static const uint32_t kRetryCount
Definition: vm_stat.h:20
static std::string UuidToString(const boost::uuids::uuid &id)
Definition: string_util.h:138
uint32_t disk_size_
Definition: vm_stat.h:64
bool BuildVmStatsMsg(VirtualMachineStats *uve)
Definition: vm_stat.cc:127
void ReadData(const boost::system::error_code &ec, size_t read_bytes, DoneCb &cb)
Definition: vm_stat.cc:45
std::stringstream data_
Definition: vm_stat.h:56
DoneCb call_back_
Definition: vm_stat.h:62
void SendVmCpuStats()
Definition: vm_stat.cc:179
uint16_t prev_vm_cpu_count_
Definition: vm_stat.h:69
VmUveTableBase * vm_uve_table() const
VrouterAgentVmState::type prev_vm_state_
Definition: vm_stat.h:67
void Stop()
Definition: vm_stat.cc:214
Definition: agent.h:358
uint32_t virt_memory_
Definition: vm_stat.h:46
uint32_t mem_usage_
Definition: vm_stat.h:45
uint32_t virt_memory_peak_
Definition: vm_stat.h:47
uint32_t virtual_size_
Definition: vm_stat.h:63
VmStat(Agent *agent, const boost::uuids::uuid &vm_uuid)
Definition: vm_stat.cc:27
uint32_t vmi_vm_vn_uve_interval_msecs() const
Definition: agent_param.h:467
AgentParam * params() const
Definition: agent.h:1218
uint32_t vm_memory_quota_
Definition: vm_stat.h:48
bool marked_delete_
Definition: vm_stat.h:59
virtual void DispatchVmMsg(const UveVirtualMachineAgent &uve)
char rx_buff_[kBufLen]
Definition: vm_stat.h:55
virtual void Start()
Definition: vm_stat.cc:211
void StartTimer()
Definition: vm_stat.cc:205
bool Cancel()
Definition: timer.cc:150
void EnqueueVmStatData(VmStatData *data)
Definition: vm_uve_table.cc:78
Agent * agent_
Definition: vm_stat.h:43
virtual bool TimerExpiry()
Definition: vm_stat.cc:201
boost::asio::posix::stream_descriptor input_
Definition: vm_stat.h:57
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:108
static const uint16_t kInvalidCpuCount
Definition: vm_stat.h:21
Timer * timer_
Definition: vm_stat.h:58
boost::function< void(void)> DoneCb
Definition: vm_stat.h:22
bool running() const
Definition: timer.h:86
static const size_t kBufLen
Definition: vm_stat.h:19
uint32_t retry_
Definition: vm_stat.h:61
const boost::uuids::uuid vm_uuid_
Definition: vm_stat.h:44
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:222