Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
edb4f89
Update docker container ID test to use a UUID that's 64 hex-chars lon…
zacharycmontoya Jun 30, 2025
bb3d458
Rename container::find_docker_container_id to container::find_contain…
zacharycmontoya Jun 30, 2025
2174c80
Add other cgroup file examples from the .NET Tracer
zacharycmontoya Jun 30, 2025
136d4cc
Fix formatting
zacharycmontoya Jun 30, 2025
43f214a
Add temporary logging to stdout and stderr for the container-id parsing
zacharycmontoya Jul 14, 2025
d6e9297
This doesn't pass unit tests, but now I am writing some more helpful …
zacharycmontoya Jul 14, 2025
6251ac4
Remove the host namespace check since it stops us from working on Doc…
zacharycmontoya Jul 14, 2025
7fb67c9
Also remove the eager cgroup lookup because that's stopping us from c…
zacharycmontoya Jul 14, 2025
70d6db4
Refactor to better align with Java implementation
zacharycmontoya Jul 14, 2025
f0abaad
Remove all uses of logger now that we're done debugging system-tests …
zacharycmontoya Jul 15, 2025
565c4e0
Put back the get_cgroup_version and add temporary logging to confirm …
zacharycmontoya Jul 15, 2025
587405f
Restore the cgroup logic, but also include TMPFS_MAGIC as a valid val…
zacharycmontoya Jul 16, 2025
08909b1
Remove logging (again) and reduce the diff
zacharycmontoya Jul 16, 2025
376793e
Restore the previous substring approach and execute this first before…
zacharycmontoya Jul 16, 2025
039883a
Apply suggestions from code review
zacharycmontoya Jul 16, 2025
d8576b9
Move the regex string literals closer to their usage
zacharycmontoya Jul 16, 2025
9d1946b
Fix formatting
zacharycmontoya Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions src/datadog/platform_util.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "platform_util.h"

#include <cassert>
#include <cstdint>
#include <fstream>
#include <regex>

// clang-format off
#if defined(__x86_64__) || defined(_M_X64)
Expand Down Expand Up @@ -291,6 +293,7 @@ namespace {
#if defined(__linux__) || defined(__unix__)
/// Magic numbers from linux/magic.h:
/// <https://github.com/torvalds/linux/blob/ca91b9500108d4cf083a635c2e11c884d5dd20ea/include/uapi/linux/magic.h#L71>
constexpr uint64_t TMPFS_MAGIC = 0x01021994;
constexpr uint64_t CGROUP_SUPER_MAGIC = 0x27e0eb;
constexpr uint64_t CGROUP2_SUPER_MAGIC = 0x63677270;

Expand Down Expand Up @@ -330,27 +333,29 @@ Optional<Cgroup> get_cgroup_version() {
return nullopt;
}

if (buf.f_type == CGROUP_SUPER_MAGIC)
if (buf.f_type == CGROUP_SUPER_MAGIC || buf.f_type == TMPFS_MAGIC)
return Cgroup::v1;
else if (buf.f_type == CGROUP2_SUPER_MAGIC)
return Cgroup::v2;

return nullopt;
}

Optional<std::string> find_docker_container_id_from_cgroup() {
Optional<std::string> find_container_id_from_cgroup() {
auto cgroup_fd = std::ifstream("/proc/self/cgroup", std::ios::in);
if (!cgroup_fd.is_open()) return nullopt;

return find_docker_container_id(cgroup_fd);
return find_container_id(cgroup_fd);
}
#endif
} // namespace

Optional<std::string> find_docker_container_id(std::istream& source) {
Optional<std::string> find_container_id(std::istream& source) {
std::string line;

// Look for Docker container IDs in the basic format: `docker-<uuid>.scope`.
constexpr std::string_view docker_str = "docker-";

std::string line;
while (std::getline(source, line)) {
// Example:
// `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope`
Expand All @@ -366,23 +371,46 @@ Optional<std::string> find_docker_container_id(std::istream& source) {
}
}

// Reset the stream to the beginning.
source.clear();
source.seekg(0);

// Perform a second pass using a regular expression for matching container IDs
// in a Fargate environment. This two-step approach is used because STL
// `regex` is relatively slow, so we avoid using it unless necessary.
static const std::string uuid_regex_str =
"[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}"
"|(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$)";
static const std::string container_regex_str = "[0-9a-f]{64}";
static const std::string task_regex_str = "[0-9a-f]{32}-\\d+";
static const std::regex path_reg("(?:.+)?(" + uuid_regex_str + "|" +
container_regex_str + "|" + task_regex_str +
")(?:\\.scope)?$");

while (std::getline(source, line)) {
// Example:
// `0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope`
std::smatch match;
if (std::regex_match(line, match, path_reg) && match.size() == 2) {
assert(match.ready());
assert(match.size() == 2);

return match.str(1);
}
}

return nullopt;
}

Optional<ContainerID> get_id() {
#if defined(__linux__) || defined(__unix__)
if (is_running_in_host_namespace()) {
// Not in a container, no need to continue.
return nullopt;
}

auto maybe_cgroup = get_cgroup_version();
if (!maybe_cgroup) return nullopt;

ContainerID id;
switch (*maybe_cgroup) {
case Cgroup::v1: {
if (auto maybe_id = find_docker_container_id_from_cgroup()) {
if (auto maybe_id = find_container_id_from_cgroup()) {
id.value = *maybe_id;
id.type = ContainerID::Type::container_id;
break;
Expand All @@ -392,9 +420,12 @@ Optional<ContainerID> get_id() {
// inode.
[[fallthrough]];
case Cgroup::v2: {
if (auto maybe_inode = get_inode("/sys/fs/cgroup")) {
id.type = ContainerID::Type::cgroup_inode;
id.value = std::to_string(*maybe_inode);
if (!is_running_in_host_namespace()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not quite sure I understand the reasoning behind moving this here, could you explain the reasoning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's two reasons why I did this:

  • In our Java and C# implementations, we only perform this host cgroup namespace check when we try to get the inode, so this aligns with those implementations.
  • I'm not sure if this is a WSL/WSL2 issue, but when I run the system-tests against the nginx weblog container we're DEFINITELY running in a container, but the check fails. Perhaps this is the same Docker in Docker issue referenced in the code comments, but anyways this shouldn't fail and return early when we can definitely extract the container-id in the cgroupv1 scenario

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't investigated too much, however, IIRC this function can fails in docker in docker setup.

// Host namespace inode number are hardcoded, which allows for dectection of
// whether the binary is running in host or not. However, it does not work when
// running in a Docker in Docker environment.
bool is_running_in_host_namespace() {

auto maybe_inode = get_inode("/sys/fs/cgroup");
if (maybe_inode) {
id.type = ContainerID::Type::cgroup_inode;
id.value = std::to_string(*maybe_inode);
}
}
}; break;
}
Expand Down
8 changes: 4 additions & 4 deletions src/datadog/platform_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ struct ContainerID final {
std::string value;
};

/// Find the docker container ID from a given source.
/// Find the container ID from a given source.
/// This function is exposed mainly for testing purposes.
///
/// @param source The input from which to read the Docker container ID.
/// @return An Optional containing the Docker container ID if found, otherwise
/// @param source The input from which to read the container ID.
/// @return An Optional containing the container ID if found, otherwise
/// nothing.
Optional<std::string> find_docker_container_id(std::istream& source);
Optional<std::string> find_container_id(std::istream& source);

/// Function to retrieve the container metadata.
///
Expand Down
140 changes: 135 additions & 5 deletions test/test_platform_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ PLATFORM_UTIL_TEST("find docker container ID") {
{__LINE__, "empty inputs", "", nullopt},
{__LINE__, "no docker container ID", "coucou", nullopt},
{__LINE__, "one line with docker container ID",
"0::/system.slice/docker-abcdef0123456789abcdef0123456789.scope",
"abcdef0123456789abcdef0123456789"},
"0::/system.slice/"
"docker-"
"cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope",
"cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411"},
{__LINE__, "multiline wihtout docker container ID", R"(
0::/
10:memory:/user.slice/user-0.slice/session-14.scope
Expand All @@ -41,22 +43,150 @@ PLATFORM_UTIL_TEST("find docker container ID") {
9:hugetlb:/
8:cpuset:/
7:pids:/user.slice/user-0.slice/session-14.scope
3:cpu:/system.slice/docker-abcdef0123456789abcdef0123456789.scope
3:cpu:/system.slice/docker-cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411.scope
6:freezer:/
5:net_cls,net_prio:/
4:perf_event:/
3:cpu,cpuacct:/user.slice/user-0.slice/session-14.scope
2:devices:/user.slice/user-0.slice/session-14.scope
1:name=systemd:/user.slice/user-0.slice/session-14.scope
)",
"abcdef0123456789abcdef0123456789"},
"cde7c2bab394630a42d73dc610b9c57415dced996106665d427f6d0566594411"},
}));

CAPTURE(test_case.name);

std::istringstream is(test_case.input);

auto maybe_container_id = container::find_docker_container_id(is);
auto maybe_container_id = container::find_container_id(is);
if (test_case.expected_container_id.has_value()) {
REQUIRE(maybe_container_id.has_value());
CHECK(*maybe_container_id == *test_case.expected_container_id);
} else {
CHECK(!maybe_container_id.has_value());
}
}

PLATFORM_UTIL_TEST("find multiline container IDs") {
struct TestCase {
size_t line;
std::string_view name;
std::string input;
Optional<std::string> expected_container_id;
};

auto test_case = GENERATE(values<TestCase>({
{__LINE__, "Docker", R"(
13:name=systemd:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
12:pids:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
11:hugetlb:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
10:net_prio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
9:perf_event:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
8:net_cls:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
7:freezer:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
6:devices:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
5:memory:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
4:blkio:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
3:cpuacct:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
2:cpu:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
1:cpuset:/docker/3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860
)",
"3726184226f5d3147c25fdeab5b60097e378e8a720503a5e19ecfdf29f869860"},
{__LINE__, "Kubernetes", R"(
11:perf_event:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
10:pids:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
9:memory:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
8:cpu,cpuacct:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
7:blkio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
6:cpuset:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
5:devices:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
4:freezer:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
3:net_cls,net_prio:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
2:hugetlb:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
1:name=systemd:/kubepods/besteffort/pod3d274242-8ee0-11e9-a8a6-1e68d864ef1a/3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1
1:name=systemd:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod2d3da189_6407_48e3_9ab6_78188d75e609.slice/docker-3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1.scope
)",
"3e74d3fd9db4c9dd921ae05c2502fb984d0cde1b36e581b13f79c639da4518a1"},
{__LINE__, "Ecs", R"(
9:perf_event:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
8:memory:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
7:hugetlb:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
6:freezer:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
5:devices:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
4:cpuset:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
3:cpuacct:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
2:cpu:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
1:blkio:/ecs/haissam-ecs-classic/5a0d5ceddf6c44c1928d367a815d890f/38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce
)",
"38fac3e99302b3622be089dd41e7ccf38aff368a86cc339972075136ee2710ce"},
{__LINE__, "Fargate1Dot3", R"(
11:hugetlb:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
10:pids:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
9:cpuset:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
8:net_cls,net_prio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
7:cpu,cpuacct:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
6:perf_event:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
5:freezer:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
4:devices:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
3:blkio:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
2:memory:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
1:name=systemd:/ecs/55091c13-b8cf-4801-b527-f4601742204d/432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da
)",
"432624d2150b349fe35ba397284dea788c2bf66b885d14dfc1569b01890ca7da"},
{__LINE__, "Fargate1Dot4", R"(
11:hugetlb:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
10:pids:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
9:cpuset:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
8:net_cls,net_prio:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
7:cpu,cpuacct:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
6:perf_event:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
5:freezer:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
4:devices:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
3:blkio:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
2:memory:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
1:name=systemd:/ecs/34dc0b5e626f2c5c4c5170e34b10e765-1234567890
)",
"34dc0b5e626f2c5c4c5170e34b10e765-1234567890"},
{__LINE__, "EksNodegroup", R"(
11:blkio:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
10:cpuset:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
9:perf_event:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
8:memory:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
7:pids:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
6:cpu,cpuacct:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
5:net_cls,net_prio:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
4:devices:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
3:freezer:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
2:hugetlb:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
1:name=systemd:/kubepods.slice/kubepods-pod9508fe66_7675_4003_b7c9_d83e9f8f85e5.slice/cri-containerd-26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4.scope
)",
"26cfbe35e08b24f053011af4ada23d8fcbf81f27f8331a94f56de5b677c903e4"},
{__LINE__, "PcfContainer1", R"(
12:memory:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
11:rdma:/
10:freezer:/garden/6f265890-5165-7fab-6b52-18d1
9:hugetlb:/garden/6f265890-5165-7fab-6b52-18d1
8:pids:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
7:perf_event:/garden/6f265890-5165-7fab-6b52-18d1
6:cpu,cpuacct:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
5:net_cls,net_prio:/garden/6f265890-5165-7fab-6b52-18d1
4:cpuset:/garden/6f265890-5165-7fab-6b52-18d1
3:blkio:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
2:devices:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
)",
"6f265890-5165-7fab-6b52-18d1"},
{__LINE__, "PcfContainer2", R"(
1:name=systemd:/system.slice/garden.service/garden/6f265890-5165-7fab-6b52-18d1
)",
"6f265890-5165-7fab-6b52-18d1"},
}));

CAPTURE(test_case.name);

std::istringstream is(test_case.input);

auto maybe_container_id = container::find_container_id(is);
if (test_case.expected_container_id.has_value()) {
REQUIRE(maybe_container_id.has_value());
CHECK(*maybe_container_id == *test_case.expected_container_id);
Expand Down