Skip to content

Commit ff83032

Browse files
authored
Update cgroup resolver to try all possible base paths (#1981)
Summary: Update cgroup resolver to try all possible base paths For certain environments, like OVH cloud's managed kubernetes service, the auto discovery mechanism fails due to a confusion between cgroup v1 and v2. This is fixed by attempting all cgroup base paths rather than trying the first to match and failing if it doesn't work. This is the second iteration of this change (#1978 was the earlier attempt). Relevant Issues: N/A Type of change: /kind bug Test Plan: Community user deployed this change and verified their OVH MKS cluster is working now --------- Signed-off-by: Dom Del Nano <ddelnano@gmail.com>
1 parent 555c888 commit ff83032

File tree

3 files changed

+96
-61
lines changed

3 files changed

+96
-61
lines changed

src/shared/metadata/cgroup_path_resolver.cc

Lines changed: 82 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
#include "src/common/fs/fs_wrapper.h"
2828
#include "src/shared/metadata/cgroup_path_resolver.h"
2929

30-
DEFINE_bool(force_cgroup2_mode, true, "Flag to force assume cgroup2 fs for testing purposes");
30+
DEFINE_bool(test_only_force_cgroup2_mode, false,
31+
"Flag to force assume cgroup2 fs for testing purposes");
3132

3233
namespace px {
3334
namespace md {
3435

35-
StatusOr<std::string> CGroupBasePath(std::string_view sysfs_path) {
36+
StatusOr<std::vector<std::string>> CGroupBasePaths(std::string_view sysfs_path) {
37+
std::vector<std::string> base_paths;
3638
// Different hosts may mount different cgroup dirs. Try a couple for robustness.
3739
const std::vector<std::string> cgroup_dirs = {"cpu,cpuacct", "cpu", "pids"};
3840

@@ -43,7 +45,7 @@ StatusOr<std::string> CGroupBasePath(std::string_view sysfs_path) {
4345
std::string base_path = absl::StrCat(sysfs_path, "/cgroup/", cgroup_dir);
4446

4547
if (fs::Exists(base_path)) {
46-
return base_path;
48+
base_paths.push_back(base_path);
4749
}
4850
}
4951

@@ -52,12 +54,18 @@ StatusOr<std::string> CGroupBasePath(std::string_view sysfs_path) {
5254
auto fs_status = statfs(cgv2_base_path.c_str(), &info);
5355
bool cgroupv2 = (fs_status == 0) && (info.f_type == CGROUP2_SUPER_MAGIC);
5456

55-
if (cgroupv2 || FLAGS_force_cgroup2_mode) {
56-
return cgv2_base_path;
57+
if (cgroupv2 || FLAGS_test_only_force_cgroup2_mode) {
58+
if (FLAGS_test_only_force_cgroup2_mode) {
59+
return std::vector{cgv2_base_path};
60+
}
61+
base_paths.push_back(cgv2_base_path);
5762
}
5863
// (TODO): This check for cgroup2FS is eventually to be moved above the cgroupv1 check.
5964

60-
return error::NotFound("Could not find CGroup base path");
65+
if (base_paths.empty()) {
66+
return error::NotFound("Could not find CGroup base path");
67+
}
68+
return base_paths;
6169
}
6270

6371
StatusOr<std::string> FindSelfCGroupProcs(std::string_view base_path) {
@@ -137,17 +145,32 @@ StatusOr<CGroupTemplateSpec> CreateCGroupTemplateSpecFromPath(std::string_view p
137145
}
138146

139147
StatusOr<CGroupTemplateSpec> AutoDiscoverCGroupTemplate(std::string_view sysfs_path) {
140-
PX_ASSIGN_OR_RETURN(std::string base_path, CGroupBasePath(sysfs_path));
141-
LOG(INFO) << "Auto-discovered CGroup base path: " << base_path;
142-
143-
PX_ASSIGN_OR_RETURN(std::string self_cgroup_procs, FindSelfCGroupProcs(base_path));
144-
LOG(INFO) << "Auto-discovered example path: " << self_cgroup_procs;
145-
146-
PX_ASSIGN_OR_RETURN(CGroupTemplateSpec cgroup_path_template,
147-
CreateCGroupTemplateSpecFromPath(self_cgroup_procs));
148-
LOG(INFO) << "Auto-discovered template: " << cgroup_path_template.templated_path;
148+
PX_ASSIGN_OR_RETURN(std::vector<std::string> base_paths, CGroupBasePaths(sysfs_path));
149+
for (const auto& base_path : base_paths) {
150+
LOG(INFO) << "Auto-discovered CGroup base path: " << base_path;
151+
152+
auto self_cgroup_procs_status = FindSelfCGroupProcs(base_path);
153+
if (!self_cgroup_procs_status.ok()) {
154+
LOG(WARNING) << "Could not find self in cgroup procs. Trying next base path.";
155+
continue;
156+
}
157+
auto self_cgroup_procs = self_cgroup_procs_status.ConsumeValueOrDie();
158+
LOG(INFO) << "Auto-discovered example path: " << self_cgroup_procs;
159+
160+
auto cgroup_path_template_status = CreateCGroupTemplateSpecFromPath(self_cgroup_procs);
161+
if (!cgroup_path_template_status.ok()) {
162+
LOG(WARNING) << absl::Substitute(
163+
"Failed to create cgroup template spec from path $0. Trying next base path.",
164+
self_cgroup_procs);
165+
continue;
166+
}
167+
auto cgroup_path_template = cgroup_path_template_status.ConsumeValueOrDie();
168+
LOG(INFO) << "Auto-discovered template: " << cgroup_path_template.templated_path;
149169

150-
return cgroup_path_template;
170+
return cgroup_path_template;
171+
}
172+
return error::NotFound("Unable to auto discover cgroup template from $0",
173+
absl::StrJoin(base_paths, ", "));
151174
}
152175

153176
StatusOr<std::unique_ptr<CGroupPathResolver>> CGroupPathResolver::Create(
@@ -222,51 +245,52 @@ Status LegacyCGroupPathResolver::Init(std::string_view sysfs_path) {
222245
// $2 = container runtime
223246
// These template parameters are resolved by calls to PodPath.
224247
// Different hosts may mount different cgroup dirs. Try a couple for robustness.
225-
PX_ASSIGN_OR_RETURN(std::string cgroup_dir, CGroupBasePath(sysfs_path));
226-
227-
// Attempt assuming naming scheme #1.
228-
std::string cgroup_kubepods_base_path = absl::Substitute("$0/kubepods", cgroup_dir);
229-
if (fs::Exists(cgroup_kubepods_base_path)) {
230-
cgroup_kubepod_guaranteed_path_template_ =
231-
absl::StrCat(cgroup_kubepods_base_path, "/pod$0/$1/cgroup.procs");
232-
cgroup_kubepod_besteffort_path_template_ =
233-
absl::StrCat(cgroup_kubepods_base_path, "/besteffort/pod$0/$1/cgroup.procs");
234-
cgroup_kubepod_burstable_path_template_ =
235-
absl::StrCat(cgroup_kubepods_base_path, "/burstable/pod$0/$1/cgroup.procs");
236-
cgroup_kubepod_convert_dashes_ = false;
237-
return Status::OK();
238-
}
248+
PX_ASSIGN_OR_RETURN(std::vector<std::string> cgroup_dirs, CGroupBasePaths(sysfs_path));
239249

240-
// Attempt assuming naming scheme #3.
241-
// Must be before the scheme below, since there have been systems that have both paths,
242-
// but this must take priority.
243-
cgroup_kubepods_base_path = absl::Substitute("$0/system.slice/containerd.service", cgroup_dir);
244-
if (fs::Exists(cgroup_kubepods_base_path)) {
245-
cgroup_kubepod_guaranteed_path_template_ =
246-
absl::StrCat(cgroup_kubepods_base_path, "/kubepods-pod$0.slice:$2:$1/cgroup.procs");
247-
cgroup_kubepod_besteffort_path_template_ = absl::StrCat(
248-
cgroup_kubepods_base_path, "/kubepods-besteffort-pod$0.slice:$2:$1/cgroup.procs");
249-
cgroup_kubepod_burstable_path_template_ = absl::StrCat(
250-
cgroup_kubepods_base_path, "/kubepods-burstable-pod$0.slice:$2:$1/cgroup.procs");
251-
cgroup_kubepod_convert_dashes_ = true;
252-
return Status::OK();
253-
}
250+
for (const auto& cgroup_dir : cgroup_dirs) {
251+
// Attempt assuming naming scheme #1.
252+
std::string cgroup_kubepods_base_path = absl::Substitute("$0/kubepods", cgroup_dir);
253+
if (fs::Exists(cgroup_kubepods_base_path)) {
254+
cgroup_kubepod_guaranteed_path_template_ =
255+
absl::StrCat(cgroup_kubepods_base_path, "/pod$0/$1/cgroup.procs");
256+
cgroup_kubepod_besteffort_path_template_ =
257+
absl::StrCat(cgroup_kubepods_base_path, "/besteffort/pod$0/$1/cgroup.procs");
258+
cgroup_kubepod_burstable_path_template_ =
259+
absl::StrCat(cgroup_kubepods_base_path, "/burstable/pod$0/$1/cgroup.procs");
260+
cgroup_kubepod_convert_dashes_ = false;
261+
return Status::OK();
262+
}
254263

255-
// Attempt assuming naming scheme #2.
256-
cgroup_kubepods_base_path = absl::Substitute("$0/kubepods.slice", cgroup_dir);
257-
if (fs::Exists(cgroup_kubepods_base_path)) {
258-
cgroup_kubepod_guaranteed_path_template_ =
259-
absl::StrCat(cgroup_kubepods_base_path, "/kubepods-pod$0.slice/$2-$1.scope/cgroup.procs");
260-
cgroup_kubepod_besteffort_path_template_ = absl::StrCat(
261-
cgroup_kubepods_base_path,
262-
"/kubepods-besteffort.slice/kubepods-besteffort-pod$0.slice/$2-$1.scope/cgroup.procs");
263-
cgroup_kubepod_burstable_path_template_ = absl::StrCat(
264-
cgroup_kubepods_base_path,
265-
"/kubepods-burstable.slice/kubepods-burstable-pod$0.slice/$2-$1.scope/cgroup.procs");
266-
cgroup_kubepod_convert_dashes_ = true;
267-
return Status::OK();
268-
}
264+
// Attempt assuming naming scheme #3.
265+
// Must be before the scheme below, since there have been systems that have both paths,
266+
// but this must take priority.
267+
cgroup_kubepods_base_path = absl::Substitute("$0/system.slice/containerd.service", cgroup_dir);
268+
if (fs::Exists(cgroup_kubepods_base_path)) {
269+
cgroup_kubepod_guaranteed_path_template_ =
270+
absl::StrCat(cgroup_kubepods_base_path, "/kubepods-pod$0.slice:$2:$1/cgroup.procs");
271+
cgroup_kubepod_besteffort_path_template_ = absl::StrCat(
272+
cgroup_kubepods_base_path, "/kubepods-besteffort-pod$0.slice:$2:$1/cgroup.procs");
273+
cgroup_kubepod_burstable_path_template_ = absl::StrCat(
274+
cgroup_kubepods_base_path, "/kubepods-burstable-pod$0.slice:$2:$1/cgroup.procs");
275+
cgroup_kubepod_convert_dashes_ = true;
276+
return Status::OK();
277+
}
269278

279+
// Attempt assuming naming scheme #2.
280+
cgroup_kubepods_base_path = absl::Substitute("$0/kubepods.slice", cgroup_dir);
281+
if (fs::Exists(cgroup_kubepods_base_path)) {
282+
cgroup_kubepod_guaranteed_path_template_ =
283+
absl::StrCat(cgroup_kubepods_base_path, "/kubepods-pod$0.slice/$2-$1.scope/cgroup.procs");
284+
cgroup_kubepod_besteffort_path_template_ = absl::StrCat(
285+
cgroup_kubepods_base_path,
286+
"/kubepods-besteffort.slice/kubepods-besteffort-pod$0.slice/$2-$1.scope/cgroup.procs");
287+
cgroup_kubepod_burstable_path_template_ = absl::StrCat(
288+
cgroup_kubepods_base_path,
289+
"/kubepods-burstable.slice/kubepods-burstable-pod$0.slice/$2-$1.scope/cgroup.procs");
290+
cgroup_kubepod_convert_dashes_ = true;
291+
return Status::OK();
292+
}
293+
}
270294
return error::NotFound("Could not find kubepods slice under sysfs ($0)", sysfs_path);
271295
}
272296

src/shared/metadata/cgroup_path_resolver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "src/common/system/system.h"
2828
#include "src/shared/metadata/k8s_objects.h"
2929

30-
DECLARE_bool(force_cgroup2_mode);
30+
DECLARE_bool(test_only_force_cgroup2_mode);
3131

3232
namespace px {
3333
namespace md {

src/shared/metadata/cgroup_path_resolver_test.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ TEST(LegacyCGroupPathResolverTest, StandardFormat) {
316316
ContainerType::kContainerd));
317317
}
318318

319-
TEST(LeagcyCGroupPathResolverTest, Cgroup2Format) {
319+
TEST(LegacyCGroupPathResolverTest, Cgroup2Format) {
320+
PX_SET_FOR_SCOPE(FLAGS_test_only_force_cgroup2_mode, true);
320321
ASSERT_OK_AND_ASSIGN(
321322
auto path_resolver,
322323
LegacyCGroupPathResolver::Create(GetSysFsPathFromTestDataFile(
@@ -326,7 +327,6 @@ TEST(LeagcyCGroupPathResolverTest, Cgroup2Format) {
326327
"cgroup.procs",
327328
"testdata/sysfs3")));
328329

329-
FLAGS_force_cgroup2_mode = true;
330330
EXPECT_EQ(
331331
GetPathToTestDataFile(
332332
"testdata/sysfs3/cgroup/kubepods.slice/kubepods-besteffort.slice/"
@@ -379,5 +379,16 @@ TEST(CGroupPathResolver, Cgroup2Format) {
379379
"docker-a7638fe3934b37419cc56bca73465a02b354ba6e98e10272542d84eb2014dd62.scope/cgroup.procs");
380380
}
381381

382+
/**
383+
* TODO(ddelnano): Refactor the cgroup resolver code so that logic within AutoDiscoverCGroupPath
384+
* and CGroupBasePaths can be tested. OVH's managed k8s failed to work with our logic because
385+
* it enables cgroup v1 and v2 while the PEM existed in a v2 cgroup. Ideally our tests would
386+
* cover the following scenarios for both LegacyCGroupPathResolver and CGroupPathResolver:
387+
* 1. cgroup1 only
388+
* 2. cgroup2 only
389+
* 3. cgroup1+cgroup2 w/ cgroup1 failing (gh#XXX bug)
390+
* 4. cgroup1+cgroup2 w/ cgroup1 succeeding
391+
*/
392+
382393
} // namespace md
383394
} // namespace px

0 commit comments

Comments
 (0)