Skip to content

Commit

Permalink
Add support to export docker container statistics from agent.
Browse files Browse the repository at this point in the history
-Define a new hypervisor mode for docker in agent.
-Define different class types for collection of stats for KVM and Docker
-Based on hypervisor type create appropriate object for collection of stats

Change-Id: I81290adf9d10494d0dde21976f353a0c55064f21
Closes-Bug: #1454211
  • Loading branch information
ashoksr committed May 18, 2015
1 parent 6c7edcc commit 6829545
Show file tree
Hide file tree
Showing 12 changed files with 614 additions and 290 deletions.
8 changes: 8 additions & 0 deletions src/vnsw/agent/cmn/agent.cc
Expand Up @@ -70,6 +70,14 @@ bool Agent::isXenMode() {
return params_->isXenMode();
}

bool Agent::isKvmMode() {
return params_->isKvmMode();
}

bool Agent::isDockerMode() {
return params_->isDockerMode();
}

static void SetTaskPolicyOne(const char *task, const char *exclude_list[],
int count) {
TaskScheduler *scheduler = TaskScheduler::GetInstance();
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/cmn/agent.h
Expand Up @@ -792,6 +792,8 @@ class Agent {
AgentParam *params() const { return params_; }

bool isXenMode();
bool isKvmMode();
bool isDockerMode();
// Agent param accessor functions
bool isVmwareMode() const;
bool isVmwareVcenterMode() const;
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/init/agent_param.cc
Expand Up @@ -334,6 +334,8 @@ void AgentParam::ParseHypervisor() {
hypervisor_mode_ = AgentParam::MODE_VMWARE;
GetValueFromTree<string>(vmware_physical_port_,
"HYPERVISOR.vmware_physical_interface");
} else if (opt_str.get() == "docker") {
hypervisor_mode_ = AgentParam::MODE_DOCKER;
} else {
hypervisor_mode_ = AgentParam::MODE_KVM;
}
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/init/agent_param.h
Expand Up @@ -34,6 +34,7 @@ class AgentParam {
MODE_KVM,
MODE_XEN,
MODE_VMWARE,
MODE_DOCKER,
};

enum VmwareMode {
Expand Down Expand Up @@ -155,6 +156,7 @@ class AgentParam {
HypervisorMode mode() const { return hypervisor_mode_; }
bool isXenMode() const { return hypervisor_mode_ == MODE_XEN; }
bool isKvmMode() const { return hypervisor_mode_ == MODE_KVM; }
bool isDockerMode() const { return hypervisor_mode_ == MODE_DOCKER; }
bool isVmwareMode() const { return hypervisor_mode_ == MODE_VMWARE; }
bool isVmwareVcenterMode() const { return vmware_mode_ == VCENTER; }
VmwareMode vmware_mode() const { return vmware_mode_; }
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/uve/SConscript
Expand Up @@ -113,6 +113,8 @@ libstatsuve = env.Library('statsuve',
'interface_uve_stats_table.cc',
'stats_manager.cc',
'vm_stat.cc',
'vm_stat_kvm.cc',
'vm_stat_docker.cc',
'vm_uve_entry.cc',
'vm_uve_table.cc',
'vn_uve_entry.cc',
Expand Down
266 changes: 0 additions & 266 deletions src/vnsw/agent/uve/vm_stat.cc
Expand Up @@ -113,138 +113,6 @@ void VmStat::ExecCmd(std::string cmd, DoneCb cb) {
placeholders::bytes_transferred, cb));
}

void VmStat::ReadCpuStat() {
std::string tmp;
//Typical output from command
//Id: 1
//Name: instance-00000001
//UUID: 90cb7351-d2dc-4d8d-a216-2f460be183b6
//OS Type: hvm
//State: running
//CPU(s): 1
//CPU time: 13.4s
//Max memory: 2097152 KiB

//Get 'CPU time' from the output
double cpu_stat = 0;
std::string cpu_stat_str;
while (data_ >> tmp) {
if (tmp == "time:") {
data_ >> cpu_stat_str;
break;
}
}

//Remove the last character from 'cpu_stat_str'
if (cpu_stat_str.size() >= 2) {
cpu_stat_str.erase(cpu_stat_str.size() - 1);
//Convert string to double
stringstream ss(cpu_stat_str);
ss >> cpu_stat;
}

time_t now;
time(&now);
if (prev_cpu_snapshot_time_) {
cpu_usage_ = (cpu_stat - prev_cpu_stat_)/
difftime(now, prev_cpu_snapshot_time_);
cpu_usage_ *= 100;
}

prev_cpu_stat_ = cpu_stat;
prev_cpu_snapshot_time_ = now;

//Clear buffer
data_.str(" ");
data_.clear();

//Trigger a request to start vcpu stat collection
GetVcpuStat();
}

void VmStat::ReadVcpuStat() {
std::string tmp;
uint32_t index = 0;
std::vector<double> vcpu_usage;
//Read latest VCPU usage time
while(data_ >> tmp) {
if (tmp == "VCPU:") {
//Current VCPU index
data_ >> index;
}

if (tmp == "time:") {
double usage = 0;
data_ >> usage;
vcpu_usage.push_back(usage);
}
}

vcpu_usage_percent_.clear();
if (prev_vcpu_usage_.size() != vcpu_usage.size()) {
//In case a new VCPU get added
prev_vcpu_usage_ = vcpu_usage;
}

time_t now;
time(&now);
//Calculate VCPU usage
if (prev_vcpu_snapshot_time_) {
for (uint32_t i = 0; i < vcpu_usage.size(); i++) {
double cpu_usage = (vcpu_usage[i] - prev_vcpu_usage_[i])/
difftime(now, prev_vcpu_snapshot_time_);
cpu_usage *= 100;
vcpu_usage_percent_.push_back(cpu_usage);
}
}

prev_vcpu_usage_ = vcpu_usage;
prev_vcpu_snapshot_time_ = now;

data_.str(" ");
data_.clear();
//Trigger a request to start mem stat
GetMemStat();
}

void VmStat::ReadMemStat() {
if (pid_) {
std::ostringstream proc_file;
proc_file << "/proc/"<<pid_<<"/status";
std::ifstream file(proc_file.str().c_str());

bool vmsize = false;
bool peak = false;
bool rss = false;
std::string line;
while (std::getline(file, line)) {
if (line.find("VmSize") != std::string::npos) {
std::stringstream vm(line);
std::string tmp; vm >> tmp; vm >> virt_memory_;
vmsize = true;
}
if (line.find("VmRSS") != std::string::npos) {
std::stringstream vm(line);
std::string tmp;
vm >> tmp;
vm >> mem_usage_;
rss = true;
}
if (line.find("VmPeak") != std::string::npos) {
std::stringstream vm(line);
std::string tmp; vm >> tmp; vm >> virt_memory_peak_;
peak = true;
}
if (rss && vmsize && peak)
break;
}
}

data_.str(" ");
data_.clear();
GetDiskName();
}

bool VmStat::BuildVmStatsMsg(VirtualMachineStats *uve) {
uve->set_name(UuidToString(vm_uuid_));

Expand Down Expand Up @@ -282,30 +150,6 @@ bool VmStat::BuildVmMsg(UveVirtualMachineAgent *uve) {
return true;
}

void VmStat::GetCpuStat() {
std::ostringstream cmd;
cmd << "virsh dominfo " << agent_->GetUuidStr(vm_uuid_);
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadCpuStat, this));
}

void VmStat::GetVcpuStat() {
std::ostringstream cmd;
cmd << "virsh vcpuinfo " << agent_->GetUuidStr(vm_uuid_);
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadVcpuStat, this));
}

void VmStat::GetMemStat() {
ReadMemStat();
}

void VmStat::GetDiskName() {
std::ostringstream cmd;
cmd << "virsh domblklist " << agent_->GetUuidStr(vm_uuid_) << " | grep "
<< agent_->GetUuidStr(vm_uuid_);
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadDiskName, this));
}


void VmStat::SendVmCpuStats() {
//We need to send same cpu info in two different UVEs
//(VirtualMachineStats and UveVirtualMachineAgent). One of them uses
Expand All @@ -326,78 +170,7 @@ void VmStat::SendVmCpuStats() {
}
}

void VmStat::ReadDiskName() {
data_ >> disk_name_;
if (!disk_name_.empty()) {
GetDiskStat();
} else {
SendVmCpuStats();
StartTimer();
}
}

void VmStat::GetDiskStat() {
std::ostringstream cmd;
cmd << "virsh domblkinfo " << agent_->GetUuidStr(vm_uuid_) << " "
<< disk_name_;
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadDiskStat, this));
}

void VmStat::ReadDiskStat() {
bool disk_size_found = false, virtual_size_found = false;
std::string tmp;
std::string virtual_size_str, disk_size_str;
while (data_ >> tmp) {
if (tmp == "Capacity:") {
data_ >> virtual_size_str;
virtual_size_found = true;
} else if (tmp == "Allocation:") {
data_ >> disk_size_str;
disk_size_found = true;
}
if (virtual_size_found && disk_size_found) {
break;
}
}
if (virtual_size_str.size() >= 2) {
//Convert string to uint32_t
stringstream ss(virtual_size_str);
ss >> virtual_size_;
}

if (disk_size_str.size() >= 2) {
//Convert string to uint32_t
stringstream ss(disk_size_str);
ss >> disk_size_;
}

SendVmCpuStats();
StartTimer();
}

void VmStat::ReadMemoryQuota() {
std::string tmp;
while (data_ >> tmp) {
if (tmp == "actual") {
data_ >> vm_memory_quota_;
}
}
GetCpuStat();
}

void VmStat::GetMemoryQuota() {
std::ostringstream cmd;
cmd << "virsh dommemstat " << agent_->GetUuidStr(vm_uuid_);
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadMemoryQuota, this));
}

bool VmStat::TimerExpiry() {
if (pid_ == 0) {
GetPid();
} else {
//Get CPU and memory stats
GetCpuStat();
}
return false;
}

Expand All @@ -406,46 +179,7 @@ void VmStat::StartTimer() {
timer_->Start(kTimeout, boost::bind(&VmStat::TimerExpiry, this));
}

void VmStat::ReadPid() {
std::string tmp;
uint32_t pid;

while (data_) {
data_ >> pid;
data_ >> tmp;
if (tmp.find("qemu") != std::string::npos ||
tmp.find("kvm") != std::string::npos) {
//Copy PID
pid_ = pid;
break;
}
//Flush out this line
data_.ignore(512, '\n');
}

data_.str(" ");
data_.clear();
if (pid_) {
//Successfully read pid of process, collect other data
GetMemoryQuota();
} else {
retry_++;
//Retry after timeout
if (retry_ < kRetryCount) {
StartTimer();
}
}
}

void VmStat::GetPid() {
std::ostringstream cmd;
cmd << "ps -eo pid,cmd | grep " << agent_->GetUuidStr(vm_uuid_)
<< " | grep instance-";
ExecCmd(cmd.str(), boost::bind(&VmStat::ReadPid, this));
}

void VmStat::Start() {
GetPid();
}

void VmStat::Stop() {
Expand Down
25 changes: 6 additions & 19 deletions src/vnsw/agent/uve/vm_stat.h
Expand Up @@ -24,35 +24,22 @@ class VmStat {
typedef boost::function<void(void)> DoneCb;

VmStat(Agent *agent, const boost::uuids::uuid &vm_uuid);
~VmStat();
virtual ~VmStat();
bool marked_delete() const { return marked_delete_; }

void Start();
virtual void Start();
void Stop();
void HandleSigChild(const boost::system::error_code& error, int sig);
void ProcessData();
private:
bool BuildVmStatsMsg(VirtualMachineStats *uve);
bool BuildVmMsg(UveVirtualMachineAgent *uve);
void ReadCpuStat();
void ReadVcpuStat();
void ReadMemStat();
void ReadDiskStat();
void ReadDiskName();
void GetCpuStat();
void GetVcpuStat();
void GetMemStat();
void GetDiskName();
void GetDiskStat();
void ReadData(const boost::system::error_code &ec, size_t read_bytes,
DoneCb &cb);
void ExecCmd(std::string cmd, DoneCb cb);
virtual bool TimerExpiry();

protected:
void StartTimer();
bool TimerExpiry();
void GetPid();
void ReadPid();
void ReadMemoryQuota();
void GetMemoryQuota();
void ExecCmd(std::string cmd, DoneCb cb);
void SendVmCpuStats();

Agent *agent_;
Expand Down

0 comments on commit 6829545

Please sign in to comment.