Skip to content

Commit 017a25e

Browse files
authored
[SMAGENT-1855] Docker engine support for cpuset usage (#1473)
Parses the CpusetCpus value from the docker socket, parses it to count the number of cpus and stores the value with the other container data.
1 parent 3a39ac9 commit 017a25e

File tree

5 files changed

+153
-1
lines changed

5 files changed

+153
-1
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#pragma once
2+
3+
#include <stdexcept>
4+
#include "logger.h"
5+
6+
namespace libsinsp
7+
{
8+
9+
/**
10+
* Simple helper to read a comma-separated list that includes ranges and
11+
* determine the total count of the values within.
12+
* Examples: 1,4-5 = 3; 0-15 = 16; 3,7,11 = 3
13+
*
14+
* See the "List Format" section of
15+
* http://man7.org/linux/man-pages/man7/cpuset.7.html
16+
*
17+
* Returns -1 if string is invalid.
18+
*/
19+
class cgroup_list_counter
20+
{
21+
public:
22+
const int INVALID_CPU_COUNT = -1;
23+
24+
/**
25+
* Return the number of elements given by the buffer. If needed, log at the
26+
* given log-level.
27+
*/
28+
int operator ()(const char *buffer, sinsp_logger::severity log_level)
29+
{
30+
reset();
31+
32+
int cpu_count = 0;
33+
34+
try
35+
{
36+
const char *position = buffer;
37+
for(; '\0' != *position; ++position)
38+
{
39+
if ('-' == *position)
40+
{
41+
if (nullptr == m_section_start)
42+
{
43+
throw std::runtime_error("duplicate range indicator before start");
44+
}
45+
if (nullptr != m_range_indicator)
46+
{
47+
throw std::runtime_error("duplicate range indicators");
48+
}
49+
50+
m_range_indicator = position;
51+
}
52+
else if (',' == *position)
53+
{
54+
cpu_count += process_section(m_section_start, position, m_range_indicator);
55+
reset();
56+
}
57+
else if (nullptr == m_section_start)
58+
{
59+
m_section_start = position;
60+
}
61+
62+
}
63+
64+
// There is never a trailing comma so always process the
65+
// final section
66+
cpu_count += process_section(m_section_start, position, m_range_indicator);
67+
68+
}
69+
catch (const std::exception& ex)
70+
{
71+
g_logger.format(log_level,
72+
"Invalid List Format: %s. Detail: %s",
73+
buffer,
74+
ex.what());
75+
return INVALID_CPU_COUNT;
76+
}
77+
78+
return cpu_count;
79+
}
80+
81+
private:
82+
83+
static int process_number(const char *section_start, const char *section_end)
84+
{
85+
std::string section(section_start, section_end - section_start);
86+
return std::stoi(section.c_str());
87+
88+
}
89+
90+
static int process_section(const char *section_start, const char *section_end, const char *range_indicator)
91+
{
92+
if (nullptr == section_start)
93+
{
94+
throw std::runtime_error("invalid end of section before start of section");
95+
}
96+
97+
if (nullptr == section_end)
98+
{
99+
throw std::runtime_error("invalid end of section");
100+
}
101+
102+
if (section_end <= section_start)
103+
{
104+
throw std::runtime_error("invalid section");
105+
}
106+
107+
if (range_indicator)
108+
{
109+
// Split into two sections
110+
int first = process_number(section_start, range_indicator);
111+
int second = process_number(range_indicator + 1, section_end);
112+
113+
if (second <= first)
114+
{
115+
throw std::runtime_error("invalid range");
116+
}
117+
118+
return second - first + 1;
119+
}
120+
121+
// We don't care what the value is, we just want to know that it is a number
122+
(void)process_number(section_start, section_end);
123+
return 1;
124+
}
125+
126+
void reset()
127+
{
128+
m_section_start = nullptr;
129+
m_range_indicator = nullptr;
130+
}
131+
132+
const char *m_section_start = nullptr;
133+
const char *m_range_indicator = nullptr;
134+
};
135+
136+
}

userspace/libsinsp/container.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ string sinsp_container_manager::container_to_json(const sinsp_container_info& co
219219
container["cpu_shares"] = (Json::Value::Int64) container_info.m_cpu_shares;
220220
container["cpu_quota"] = (Json::Value::Int64) container_info.m_cpu_quota;
221221
container["cpu_period"] = (Json::Value::Int64) container_info.m_cpu_period;
222+
container["cpuset_cpu_count"] = (Json::Value::Int) container_info.m_cpuset_cpu_count;
222223

223224
if(!container_info.m_mesos_task_id.empty())
224225
{

userspace/libsinsp/container_engine/docker_common.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ limitations under the License.
1818
*/
1919

2020
#include "container_engine/docker.h"
21+
#include "cgroup_list_counter.h"
2122
#include "sinsp.h"
2223
#include "sinsp_int.h"
2324
#include "container.h"
@@ -739,7 +740,13 @@ bool docker_async_source::parse_docker(std::string &container_id, sinsp_containe
739740
{
740741
container->m_cpu_period = cpu_period;
741742
}
742-
const Json::Value &privileged = host_config_obj["Privileged"];
743+
const auto cpuset_cpus = host_config_obj["CpusetCpus"].asString();
744+
if (!cpuset_cpus.empty())
745+
{
746+
libsinsp::cgroup_list_counter counter;
747+
container->m_cpuset_cpu_count = counter(cpuset_cpus.c_str(), sinsp_logger::SEV_DEBUG);
748+
}
749+
const Json::Value& privileged = host_config_obj["Privileged"];
743750
if(!privileged.isNull() && privileged.isBool())
744751
{
745752
container->m_privileged = privileged.asBool();

userspace/libsinsp/container_info.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class sinsp_container_info
182182
m_cpu_shares(1024),
183183
m_cpu_quota(0),
184184
m_cpu_period(100000),
185+
m_cpuset_cpu_count(0),
185186
m_is_pod_sandbox(false),
186187
m_metadata_complete(true),
187188
m_metadata_deadline(0)
@@ -223,6 +224,7 @@ class sinsp_container_info
223224
int64_t m_cpu_shares;
224225
int64_t m_cpu_quota;
225226
int64_t m_cpu_period;
227+
int32_t m_cpuset_cpu_count;
226228
std::list<container_health_probe> m_health_probes;
227229

228230
bool m_is_pod_sandbox;

userspace/libsinsp/parsers.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4708,6 +4708,12 @@ void sinsp_parser::parse_container_json_evt(sinsp_evt *evt)
47084708
container_info.m_cpu_period = cpu_period.asInt64();
47094709
}
47104710

4711+
const Json::Value& cpuset_cpu_count = container["cpuset_cpu_count"];
4712+
if(check_json_val_is_convertible(cpuset_cpu_count, Json::intValue, "cpuset_cpu_count"))
4713+
{
4714+
container_info.m_cpuset_cpu_count = cpuset_cpu_count.asInt();
4715+
}
4716+
47114717
const Json::Value& mesos_task_id = container["mesos_task_id"];
47124718
if(check_json_val_is_convertible(mesos_task_id, Json::stringValue, "mesos_task_id"))
47134719
{

0 commit comments

Comments
 (0)