Line data Source code
1 : /* 2 : * Copyright (c) 2015 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_docker.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> 15 : #include <ifmap/ifmap_agent_parser.h> 16 : #include <cmn/agent.h> 17 : #include <uve/vrouter_uve_entry.h> 18 : #include <sstream> 19 : #include <fstream> 20 : #include <uve/agent_uve.h> 21 : #include <uve/vm_uve_table.h> 22 : 23 : using namespace boost::uuids; 24 : using namespace boost::asio; 25 : 26 0 : VmStatDocker::VmStatDocker(Agent *agent, const uuid &vm_uuid) 27 0 : : VmStat(agent, vm_uuid), container_id_() { 28 0 : } 29 : 30 0 : VmStatDocker::~VmStatDocker() { 31 0 : } 32 : 33 0 : void VmStatDocker::Start() { 34 0 : if (vm_uuid_ == nil_uuid()) { 35 0 : return; 36 : } 37 0 : GetContainerId(); 38 : } 39 : 40 0 : void VmStatDocker::ReadCpuStat() { 41 0 : double cpu_stat = 0; 42 0 : std::string cpu_stat_str; 43 0 : data_ >> cpu_stat_str; 44 : 45 0 : if (!cpu_stat_str.empty()) { 46 : //Convert string to double 47 0 : std::stringstream ss(cpu_stat_str); 48 0 : ss >> cpu_stat; 49 : //Convert from Nanoseconds to seconds 50 0 : cpu_stat = cpu_stat / kOneSecInNanoSecs; 51 0 : } 52 : 53 : time_t now; 54 0 : time(&now); 55 0 : if (prev_cpu_snapshot_time_) { 56 0 : cpu_usage_ = (cpu_stat - prev_cpu_stat_)/ 57 0 : difftime(now, prev_cpu_snapshot_time_); 58 0 : cpu_usage_ *= 100; 59 : } 60 : 61 0 : prev_cpu_stat_ = cpu_stat; 62 0 : prev_cpu_snapshot_time_ = now; 63 : 64 : //Clear buffer 65 0 : data_.str(" "); 66 0 : data_.clear(); 67 : 68 : //Trigger a request to start Memory stat collection 69 0 : GetMemoryQuota(); 70 0 : } 71 : 72 0 : void VmStatDocker::ReadMemStat() { 73 0 : if (pid_) { 74 0 : std::ostringstream proc_file; 75 0 : proc_file << "/proc/"<<pid_<<"/status"; 76 0 : std::ifstream file(proc_file.str().c_str()); 77 : 78 0 : bool vmsize = false; 79 0 : bool rss = false; 80 0 : bool peak = false; 81 0 : std::string line; 82 0 : while (std::getline(file, line)) { 83 0 : if (line.find("VmSize") != std::string::npos) { 84 0 : std::stringstream vm(line); 85 0 : std::string tmp; vm >> tmp; vm >> virt_memory_; 86 0 : vmsize = true; 87 0 : } 88 0 : if (line.find("VmRSS") != std::string::npos) { 89 0 : std::stringstream vm(line); 90 0 : std::string tmp; 91 0 : vm >> tmp; 92 0 : vm >> mem_usage_; 93 0 : rss = true; 94 0 : } 95 0 : if (line.find("VmPeak") != std::string::npos) { 96 0 : std::stringstream vm(line); 97 0 : std::string tmp; vm >> tmp; vm >> virt_memory_peak_; 98 0 : peak = true; 99 0 : } 100 0 : if (rss && vmsize && peak) 101 0 : break; 102 : } 103 0 : } 104 : 105 0 : data_.str(" "); 106 0 : data_.clear(); 107 : 108 0 : SendVmCpuStats(); 109 0 : StartTimer(); 110 0 : } 111 : 112 0 : void VmStatDocker::GetCpuStat() { 113 0 : std::ostringstream cmd; 114 0 : cmd << "cat /sys/fs/cgroup/cpuacct/docker/" << container_id_ 115 0 : << "/cpuacct.usage"; 116 0 : ExecCmd(cmd.str(), boost::bind(&VmStatDocker::ReadCpuStat, this)); 117 0 : } 118 : 119 0 : void VmStatDocker::GetMemoryQuota() { 120 0 : std::ostringstream cmd; 121 0 : cmd << "cat /sys/fs/cgroup/memory/docker/" << container_id_ 122 0 : << "/memory.stat"; 123 0 : ExecCmd(cmd.str(), boost::bind(&VmStatDocker::ReadMemoryQuota, this)); 124 0 : } 125 : 126 0 : void VmStatDocker::GetMemStat() { 127 0 : ReadMemStat(); 128 0 : } 129 : 130 0 : void VmStatDocker::GetPid() { 131 0 : std::ostringstream cmd; 132 0 : cmd << "docker inspect " << container_id_ << "| grep -A3 \\\"Paused\\\":"; 133 0 : ExecCmd(cmd.str(), boost::bind(&VmStatDocker::ReadPid, this)); 134 0 : } 135 : 136 0 : void VmStatDocker::ReadPid() { 137 : /* Expecting data_ to have the following content 138 : * "Paused": false, 139 : * "Pid": 24430, 140 : * "Restarting": false, 141 : * "Running": true, 142 : */ 143 0 : string tmp, paused_str, pid_str, running_str; 144 0 : while (data_ >> tmp) { 145 0 : if (tmp.find("Paused") != std::string::npos) { 146 0 : data_ >> paused_str; 147 : } 148 0 : if (tmp.find("Pid") != std::string::npos) { 149 0 : data_ >> pid_str; 150 : } 151 0 : if (tmp.find("Running") != std::string::npos) { 152 0 : data_ >> running_str; 153 0 : break; 154 : } 155 : } 156 : 157 : //Remove the last character from 'pid_str' 158 0 : if (pid_str.size() >= 2) { 159 0 : pid_str.erase(pid_str.size() - 1); 160 : //Convert string to uint32_t 161 0 : std::stringstream ss(pid_str); 162 0 : ss >> pid_; 163 0 : } 164 : 165 0 : vm_state_ = VrouterAgentVmState::VROUTER_AGENT_VM_UNKNOWN; 166 0 : if (paused_str == "true,") { 167 0 : vm_state_ = VrouterAgentVmState::VROUTER_AGENT_VM_PAUSED; 168 0 : } else if (running_str == "false,") { 169 0 : vm_state_ = VrouterAgentVmState::VROUTER_AGENT_VM_SHUTDOWN; 170 0 : } else if (running_str == "true,") { 171 0 : vm_state_ = VrouterAgentVmState::VROUTER_AGENT_VM_ACTIVE; 172 : } 173 0 : data_.str(" "); 174 0 : data_.clear(); 175 0 : GetMemStat(); 176 0 : } 177 : 178 0 : void VmStatDocker::ReadMemoryQuota() { 179 0 : std::string tmp; 180 0 : while (data_ >> tmp) { 181 0 : if (tmp == "hierarchical_memory_limit") { 182 0 : data_ >> vm_memory_quota_; 183 : /* Convert the 'vm_memory_quota_' to KiB to make it consistent with 184 : Kvm's 'vm_memory_quota_' */ 185 0 : vm_memory_quota_/= 1024; 186 0 : break; 187 : } 188 : } 189 : 190 0 : data_.str(" "); 191 0 : data_.clear(); 192 0 : GetPid(); 193 0 : } 194 : 195 0 : bool VmStatDocker::TimerExpiry() { 196 0 : if (container_id_.empty()) { 197 0 : GetContainerId(); 198 : } else { 199 : //Get CPU and memory stats 200 0 : GetCpuStat(); 201 : } 202 0 : return false; 203 : } 204 : 205 0 : void VmStatDocker::ReadContainerId() { 206 0 : data_ >> container_id_; 207 : //Clear buffer 208 0 : data_.str(" "); 209 0 : data_.clear(); 210 : 211 0 : if (!container_id_.empty()) { 212 : //Successfully read container-id, collect other data 213 0 : GetCpuStat(); 214 : } else { 215 0 : retry_++; 216 : //Retry after timeout 217 0 : if (retry_ < kRetryCount) { 218 0 : StartTimer(); 219 : } 220 : } 221 0 : } 222 : 223 0 : void VmStatDocker::GetContainerId() { 224 0 : std::ostringstream cmd; 225 0 : cmd << "docker ps --no-trunc | grep " << agent_->GetUuidStr(vm_uuid_) 226 0 : << " | awk '{ print $1 }'"; 227 0 : ExecCmd(cmd.str(), boost::bind(&VmStatDocker::ReadContainerId, this)); 228 0 : }