LCOV - code coverage report
Current view: top level - vnsw/agent/uve - vm_stat_docker.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 142 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14