From 62eb1eeafdd4307a7df4a97f5aa1bff6c393e67e Mon Sep 17 00:00:00 2001 From: Kate Anderson Date: Tue, 26 Sep 2023 13:52:46 -0700 Subject: [PATCH 1/5] Add check for cgroups v2 in DockerData --- .../agent/utilization/DockerData.java | 70 +++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java index 54f86816c9..bb8bc87bf2 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java @@ -29,21 +29,78 @@ */ public class DockerData { - private static final String FILE_WITH_CONTAINER_ID = "/proc/self/cgroup"; + private static final String FILE_WITH_CONTAINER_ID_V1 = "/proc/self/cgroup"; + private static final String FILE_WITH_CONTAINER_ID_V2 = "/proc/self/mountinfo"; private static final String CPU = "cpu"; private static final Pattern VALID_CONTAINER_ID = Pattern.compile("^[0-9a-f]{64}$"); - private static final Pattern DOCKER_CONTAINER_STRING = Pattern.compile("^.*[^0-9a-f]+([0-9a-f]{64,}).*"); + private static final Pattern DOCKER_CONTAINER_STRING_V1 = Pattern.compile("^.*[^0-9a-f]+([0-9a-f]{64,}).*"); + private static final Pattern DOCKER_CONTAINER_STRING_V2 = Pattern.compile(".*/docker/containers/([0-9a-f]{64,}).*"); public String getDockerContainerId(boolean isLinux) { if (isLinux) { - File cpuInfoFile; - cpuInfoFile = new File(FILE_WITH_CONTAINER_ID); - return getDockerIdFromFile(cpuInfoFile); + //try to get the container id from the v2 location + File containerIdFileV2 = new File(FILE_WITH_CONTAINER_ID_V2); + String idResultV2 = cgroupV2GetDockerIdFromFile(containerIdFileV2); + if (idResultV2 != null) { + return idResultV2; + } + //try to get container id from the v1 location + File containerIdFileV1 = new File(FILE_WITH_CONTAINER_ID_V1); + return getDockerIdFromFile(containerIdFileV1); + } + return null; + } + + /* + THIS LOGIC IS NOT BEAUTIFUL. + IT SHOULD BE REFACTORED. + */ + + String cgroupV2GetDockerIdFromFile(File mountInfoFile) { + if (mountInfoFile.exists() && mountInfoFile.canRead()) { + try { + return cgroupV2ReadFile(new FileReader(mountInfoFile)); + } catch (FileNotFoundException e) { + } + } + return null; + } + + String cgroupV2ReadFile(Reader reader) { + try (BufferedReader bReader = new BufferedReader(reader)) { + String line; + StringBuilder resultGoesHere = new StringBuilder(); + while ((line = bReader.readLine()) != null) { + //check the first line with the docker/containers/ tag. + if (cgroupV2CheckLineAndGetResult(line, resultGoesHere)) { + String value = resultGoesHere.toString().trim(); + if (isInvalidDockerValue(value)) { + Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); + return null; + } + return value; + } + } + } catch (Throwable e) { + Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); } return null; } + boolean cgroupV2CheckLineAndGetResult(String line, StringBuilder resultGoesHere) { + String[] parts = line.split(" "); + if (parts.length >= 4 ) { + String mayContainId = parts[3]; + if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V2, resultGoesHere, mayContainId)) { + return true; + } + } + return false; + } + + //CGROUPS v1 logic + String getDockerIdFromFile(File cpuInfoFile) { if (cpuInfoFile.exists() && cpuInfoFile.canRead()) { try { @@ -94,7 +151,7 @@ boolean checkLineAndGetResult(String line, StringBuilder resultGoesHere) { String[] parts = line.split(":"); if (parts.length == 3 && validCpuLine(parts[1])) { String mayContainId = parts[2]; - if (checkAndGetMatch(DOCKER_CONTAINER_STRING, resultGoesHere, mayContainId)) { + if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V1, resultGoesHere, mayContainId)) { return true; } else if (!mayContainId.equals("/")) { Agent.LOG.log(Level.FINE, "Docker Data: Ignoring unrecognized cgroup ID format: {0}", mayContainId); @@ -115,6 +172,7 @@ private boolean validCpuLine(String segment) { return false; } + //Get the match for the capture group of a single-capture-group regex expression. private boolean checkAndGetMatch(Pattern p, StringBuilder result, String segment) { Matcher m = p.matcher(segment); if (m.matches() && m.groupCount() == 1) { From 561a8240880435b8e3530e6f5840c1ba4b98966d Mon Sep 17 00:00:00 2001 From: Kate Anderson Date: Tue, 26 Sep 2023 21:05:15 -0700 Subject: [PATCH 2/5] Refactor cgroups code --- .../newrelic/agent/utilization/CGroup.java | 6 + .../agent/utilization/DockerData.java | 161 +++++++++++------- .../agent/utilization/DockerDataTest.java | 62 +++---- 3 files changed, 134 insertions(+), 95 deletions(-) create mode 100644 newrelic-agent/src/main/java/com/newrelic/agent/utilization/CGroup.java diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/CGroup.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/CGroup.java new file mode 100644 index 0000000000..2532c43819 --- /dev/null +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/CGroup.java @@ -0,0 +1,6 @@ +package com.newrelic.agent.utilization; + +public enum CGroup { + V1, + V2 +} diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java index bb8bc87bf2..637b4303e1 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java @@ -41,39 +41,33 @@ public String getDockerContainerId(boolean isLinux) { if (isLinux) { //try to get the container id from the v2 location File containerIdFileV2 = new File(FILE_WITH_CONTAINER_ID_V2); - String idResultV2 = cgroupV2GetDockerIdFromFile(containerIdFileV2); + String idResultV2 = getDockerIdFromFile(containerIdFileV2, CGroup.V2); if (idResultV2 != null) { return idResultV2; } //try to get container id from the v1 location File containerIdFileV1 = new File(FILE_WITH_CONTAINER_ID_V1); - return getDockerIdFromFile(containerIdFileV1); + return getDockerIdFromFile(containerIdFileV1, CGroup.V1); } return null; } - /* - THIS LOGIC IS NOT BEAUTIFUL. - IT SHOULD BE REFACTORED. - */ - - String cgroupV2GetDockerIdFromFile(File mountInfoFile) { + String getDockerIdFromFile(File mountInfoFile, CGroup cgroup) { if (mountInfoFile.exists() && mountInfoFile.canRead()) { try { - return cgroupV2ReadFile(new FileReader(mountInfoFile)); + return readFile(new FileReader(mountInfoFile), cgroup); } catch (FileNotFoundException e) { } } return null; } - String cgroupV2ReadFile(Reader reader) { + String readFile(Reader reader, CGroup cgroup) { try (BufferedReader bReader = new BufferedReader(reader)) { String line; StringBuilder resultGoesHere = new StringBuilder(); while ((line = bReader.readLine()) != null) { - //check the first line with the docker/containers/ tag. - if (cgroupV2CheckLineAndGetResult(line, resultGoesHere)) { + if (checkLineAndGetResult(line, resultGoesHere, cgroup)) { String value = resultGoesHere.toString().trim(); if (isInvalidDockerValue(value)) { Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); @@ -88,53 +82,36 @@ String cgroupV2ReadFile(Reader reader) { return null; } - boolean cgroupV2CheckLineAndGetResult(String line, StringBuilder resultGoesHere) { - String[] parts = line.split(" "); - if (parts.length >= 4 ) { - String mayContainId = parts[3]; - if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V2, resultGoesHere, mayContainId)) { - return true; - } + boolean checkLineAndGetResult(String line, StringBuilder resultGoesHere, CGroup cgroup) { + if (cgroup == CGroup.V1) { + return checkLineAndGetResultV1(line, resultGoesHere); + } else if (cgroup == CGroup.V2) { + return checkLineAndGetResultV2(line, resultGoesHere); } return false; } - //CGROUPS v1 logic - - String getDockerIdFromFile(File cpuInfoFile) { - if (cpuInfoFile.exists() && cpuInfoFile.canRead()) { - try { - return readFile(new FileReader(cpuInfoFile)); - } catch (FileNotFoundException e) { + boolean checkLineAndGetResultV1(String line, StringBuilder resultGoesHere) { + String[] parts = line.split(":"); + if (parts.length == 3 && validCpuLine(parts[1])) { + String mayContainId = parts[2]; + if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V1, resultGoesHere, mayContainId)) { + return true; + } else if (!mayContainId.equals("/")) { + Agent.LOG.log(Level.FINE, "Docker Data: Ignoring unrecognized cgroup ID format: {0}", mayContainId); } } - return null; + return false; } - - /* - * protected for testing. - * - * Returns the docker id as a string, or null if this value could not be read, or failed validation. - */ - String readFile(Reader reader) { - try (BufferedReader bReader = new BufferedReader(reader)) { - - String line; - StringBuilder resultGoesHere = new StringBuilder(); - while ((line = bReader.readLine()) != null) { - if (checkLineAndGetResult(line, resultGoesHere)) { - String value = resultGoesHere.toString().trim(); - if (isInvalidDockerValue(value)) { - Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); - return null; - } - return value; - } + boolean checkLineAndGetResultV2(String line, StringBuilder resultGoesHere) { + String[] parts = line.split(" "); + if (parts.length >= 4 ) { + String mayContainId = parts[3]; + if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V2, resultGoesHere, mayContainId)) { + return true; } - } catch (Throwable e) { - Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); } - return null; + return false; } boolean isInvalidDockerValue(String value) { @@ -146,20 +123,6 @@ boolean isInvalidDockerValue(String value) { return (value == null) || (!VALID_CONTAINER_ID.matcher(value).matches()); } - // protected for testing - boolean checkLineAndGetResult(String line, StringBuilder resultGoesHere) { - String[] parts = line.split(":"); - if (parts.length == 3 && validCpuLine(parts[1])) { - String mayContainId = parts[2]; - if (checkAndGetMatch(DOCKER_CONTAINER_STRING_V1, resultGoesHere, mayContainId)) { - return true; - } else if (!mayContainId.equals("/")) { - Agent.LOG.log(Level.FINE, "Docker Data: Ignoring unrecognized cgroup ID format: {0}", mayContainId); - } - } - return false; - } - private boolean validCpuLine(String segment) { if (segment != null) { String[] parts = segment.split(","); @@ -181,4 +144,74 @@ private boolean checkAndGetMatch(Pattern p, StringBuilder result, String segment } return false; } + + //CGROUPS v1 logic + +// String getDockerIdFromFile(File cpuInfoFile) { +// if (cpuInfoFile.exists() && cpuInfoFile.canRead()) { +// try { +// return readFile(new FileReader(cpuInfoFile)); +// } catch (FileNotFoundException e) { +// } +// } +// return null; +// } + + /* + * protected for testing. + * + * Returns the docker id as a string, or null if this value could not be read, or failed validation. +// */ +// String readFile(Reader reader) { +// try (BufferedReader bReader = new BufferedReader(reader)) { +// +// String line; +// StringBuilder resultGoesHere = new StringBuilder(); +// while ((line = bReader.readLine()) != null) { +// if (checkLineAndGetResult(line, resultGoesHere)) { +// String value = resultGoesHere.toString().trim(); +// if (isInvalidDockerValue(value)) { +// Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); +// return null; +// } +// return value; +// } +// } +// } catch (Throwable e) { +// Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); +// } +// return null; +// } + // String cgroupV2GetDockerIdFromFile(File mountInfoFile) { +// if (mountInfoFile.exists() && mountInfoFile.canRead()) { +// try { +// return cgroupV2ReadFile(new FileReader(mountInfoFile)); +// } catch (FileNotFoundException e) { +// } +// } +// return null; +// } +// +// String cgroupV2ReadFile(Reader reader) { +// try (BufferedReader bReader = new BufferedReader(reader)) { +// String line; +// StringBuilder resultGoesHere = new StringBuilder(); +// while ((line = bReader.readLine()) != null) { +// //check the first line with the docker/containers/ tag. +// if (cgroupV2CheckLineAndGetResult(line, resultGoesHere)) { +// String value = resultGoesHere.toString().trim(); +// if (isInvalidDockerValue(value)) { +// Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); +// return null; +// } +// return value; +// } +// } +// } catch (Throwable e) { +// Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); +// } +// return null; +// } + + } diff --git a/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java b/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java index ee859632a7..4a900b38ef 100644 --- a/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java +++ b/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java @@ -41,59 +41,59 @@ public void testGetDockerIdNotLinux() { public void testCheckLineAndGetIdValid() { StringBuilder sb = new StringBuilder(); String line = "4:cpu:/docker/f37a7e4d17017e7bf774656b19ca4360c6cdc4951c86700a464101d0d9ce97ee"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("f37a7e4d17017e7bf774656b19ca4360c6cdc4951c86700a464101d0d9ce97ee", sb.toString()); sb = new StringBuilder(); line = "3:cpu:/lxc/cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159", sb.toString()); sb = new StringBuilder(); line = "3:cpu,memory:/lxc/cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159", sb.toString()); sb = new StringBuilder(); line = "3:cpuacct,cpu:/system.slice/docker-67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f.scope"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f", sb.toString()); sb = new StringBuilder(); line = "3:cpu:/system.slice/docker-67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f.scope"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f", sb.toString()); sb = new StringBuilder(); line = "2:cpu:/docker/47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2", sb.toString()); sb = new StringBuilder(); line = "2:cpu:/47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2", sb.toString()); sb = new StringBuilder(); line = "2:cpu:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod917d7891_0d63_11ea_873f_005056993b36.slice/docker-92b21022a0cecd0212c5097aa63ed8248ed832902dbdbb654e6df95e05573646.scope"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("92b21022a0cecd0212c5097aa63ed8248ed832902dbdbb654e6df95e05573646", sb.toString()); sb = new StringBuilder(); line = "1:cpu:/system.slice/crio-67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f.scope"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f", sb.toString()); //Azure docker container example sb = new StringBuilder(); line = "2:cpu:/containers/f142db3a4219409af324d5481e297545aa33425fb7dc837e68cee93c36062ca8"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("f142db3a4219409af324d5481e297545aa33425fb7dc837e68cee93c36062ca8", sb.toString()); //Azure docker container example sb = new StringBuilder(); line = "11:cpu,cpuacct:/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod4b42abd9_149e_4db2_82f9_d52edd985efe.slice/cri-containerd-d340a98bd7761414d6b3b8fabd2917c74d85155af1477b584bcc4adf4b94eaf1.scope"; - Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); Assert.assertEquals("d340a98bd7761414d6b3b8fabd2917c74d85155af1477b584bcc4adf4b94eaf1", sb.toString()); } @@ -105,64 +105,64 @@ public void testCheckLineAndGetIdInValid() { sb = new StringBuilder(); // it should be cpu not cpuacct line = "3:cpuacct:/lxc/cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); // it should be cpu not cpuacct line = "3:cpuacct:/cb8c113e5f3cf8332f5231f8154adc429ea910f7c29995372de4f571c55d3159"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "2:cpuset:/docker/47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "2:cpuset:/47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "1:hugetlb,perf_event,blkio,freezer,devices,memory,cpuacct,cpu,cpuset:/lxc/b6d196c1-50f2-4949-abdb-5d4909864487"; // id not grabbed becase of slashes (-) - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "1:hugetlb,perf_event,blkio,freezer,devices,memory,cpuacct,cpu,cpuset:/b6d196c1-50f2-4949-abdb-5d4909864487"; // id not grabbed becase of slashes (-) - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "4:cpu:/lxc/p1"; // id not grabbed because p not a valid id character - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); sb = new StringBuilder(); line = "4:cpu:/p1"; // id not grabbed because p not a valid id character - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "4:cpu:"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "4:cpu:"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "4:cpu:/"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "5:"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = ":"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "::"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "2:,:/"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); line = "2;,;/"; - Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb)); + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); } @Test @@ -224,7 +224,7 @@ public void testDockerError() throws Exception { // Invalid docker id. Missing characters. String invalidDockerId = "47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870"; StringReader reader = new StringReader("2:cpu:/docker/" + invalidDockerId); - Assert.assertNull(dockerData.readFile(reader)); + Assert.assertNull(dockerData.readFile(reader, CGroup.V1)); } @Test @@ -237,7 +237,7 @@ public void testDockerGCPError() throws Exception { // Invalid docker id. Missing characters. String invalidDockerId = "47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870"; StringReader reader = new StringReader("2:cpu:/" + invalidDockerId); - Assert.assertNull(dockerData.readFile(reader)); + Assert.assertNull(dockerData.readFile(reader, CGroup.V1)); } @Test @@ -249,7 +249,7 @@ public void testNoDockerError() throws Exception { ServiceFactory.setServiceManager(mockServiceManager); String validDockerID = "47cbd16b77c50cbf71401c069cd2189f0e659af17d5a2daca3bddf59d8a870b2"; StringReader reader = new StringReader("2:cpu:/docker/" + validDockerID); - Assert.assertEquals(validDockerID, dockerData.readFile(reader)); + Assert.assertEquals(validDockerID, dockerData.readFile(reader, CGroup.V1)); } @Test @@ -259,7 +259,7 @@ public void testInvalidDockerValueNull() { private void processFile(File file, String answer) { System.out.println("Current test file: " + file.getAbsolutePath()); - String actual = dockerData.getDockerIdFromFile(file); + String actual = dockerData.getDockerIdFromFile(file, CGroup.V1); Assert.assertEquals("The file " + file.getAbsolutePath() + " should have found " + answer + " but found " + actual, answer, actual); } From 5519c99d0849ea6a7d9bdaf5b93d38f87adc545e Mon Sep 17 00:00:00 2001 From: Kate Anderson Date: Thu, 28 Sep 2023 16:14:44 -0700 Subject: [PATCH 3/5] Write tests for cgroup V2 --- .../agent/utilization/DockerData.java | 4 +- .../agent/utilization/DockerDataTest.java | 86 +++++++++++++++++-- .../cgroup_v2_docker_container_id/README.md | 10 +++ .../cgroup_v2_docker_container_id/cases.json | 38 ++++++++ .../cgroup_v2_expected.txt | 20 +++++ .../docker_id_invalid_characters.txt | 20 +++++ .../docker_id_too_long.txt | 20 +++++ .../docker_id_too_short.txt | 20 +++++ .../docker_linux2.6.26_v1_enabled.txt | 34 ++++++++ .../cgroup_v2_docker_container_id/empty.txt | 0 .../linux_prefix.txt | 20 +++++ 11 files changed, 264 insertions(+), 8 deletions(-) create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/README.md create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cases.json create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cgroup_v2_expected.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_invalid_characters.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_long.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_short.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_linux2.6.26_v1_enabled.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/empty.txt create mode 100644 newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/linux_prefix.txt diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java index 637b4303e1..f074cdbc2d 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java @@ -91,7 +91,7 @@ boolean checkLineAndGetResult(String line, StringBuilder resultGoesHere, CGroup return false; } - boolean checkLineAndGetResultV1(String line, StringBuilder resultGoesHere) { + private boolean checkLineAndGetResultV1(String line, StringBuilder resultGoesHere) { String[] parts = line.split(":"); if (parts.length == 3 && validCpuLine(parts[1])) { String mayContainId = parts[2]; @@ -103,7 +103,7 @@ boolean checkLineAndGetResultV1(String line, StringBuilder resultGoesHere) { } return false; } - boolean checkLineAndGetResultV2(String line, StringBuilder resultGoesHere) { + private boolean checkLineAndGetResultV2(String line, StringBuilder resultGoesHere) { String[] parts = line.split(" "); if (parts.length >= 4 ) { String mayContainId = parts[3]; diff --git a/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java b/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java index 4a900b38ef..528b67c8a3 100644 --- a/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java +++ b/newrelic-agent/src/test/java/com/newrelic/agent/utilization/DockerDataTest.java @@ -36,9 +36,83 @@ public class DockerDataTest { public void testGetDockerIdNotLinux() { Assert.assertNull(dockerData.getDockerContainerId(false)); } + @Test + public void testCheckLineAndGetIdValidV2() { + StringBuilder sb = new StringBuilder(); + String line = "481 473 254:1 /docker/containers/f37a7e4d17017e7bf774656b19ca4360c6cdc4951c86700a464101d0d9ce97ee/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw"; + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + Assert.assertEquals("f37a7e4d17017e7bf774656b19ca4360c6cdc4951c86700a464101d0d9ce97ee", sb.toString()); + + sb = new StringBuilder(); + line = "886 322 5:997 /docker/containers/67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f/hosts /etc/hosts rw,relatime - opts ro"; + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + Assert.assertEquals("67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f", sb.toString()); + + sb = new StringBuilder(); + line = "886 322 5:997 /docker/containers/d340a98bd7761414d6b3b8fabd2917c74d85155af1477b584bcc4adf4b94eaf1 / rw - opts ro"; + Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + Assert.assertEquals("d340a98bd7761414d6b3b8fabd2917c74d85155af1477b584bcc4adf4b94eaf1", sb.toString()); + } + + @Test + public void testCheckLineAndGetIdInValidV2() { + StringBuilder sb = new StringBuilder(); + String line = "481 473 254:1 /fs /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + + //id-like string in the wrong place + sb = new StringBuilder(); + line = "211 921 5:646 / / rw master - opt opt rw,dontReadPath=/var/lib/67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + + //id too short + sb = new StringBuilder(); + line = "481 473 254:1 /docker/containers/12345/hosts ro - proc proc rw"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + + //missing prefix + sb = new StringBuilder(); + line = "213 888 9:000 a2ffe0eb7ac22657a2a023ad628e9df837c38a03b1ebc904d3f6d644eb1a1a81 / rw - sys sys ro"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + + //linux prefix + sb = new StringBuilder(); + line = "886 322 5:997 /lxc/67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fb3c2f84a2f9900/hosts / ro - opts"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + //id includes invalid character z + sb = new StringBuilder(); + line = "886 322 5:997 /docker/containers/67f98c9e6188f9c1818672a15dbe46237b6ee7e77f834d40d41c5fz3c2f84a2f/hosts /etc/hosts rw,relatime - opts ro"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + + //id includes dashes + sb = new StringBuilder(); + line = "886 322 5:997 /docker/containers/67f98-c9e6188f9c-1818672a15dbe46237b6ee-7e77f834d40d41c5fb3c2f84a2f/hosts /etc/hosts rw,relatime - opts ro"; + Assert.assertFalse(dockerData.checkLineAndGetResult(line, sb, CGroup.V2)); + } + + @Test + public void testGetDockerIdFromFilesV2() throws Exception { + Map tests = testToAnswers(AgentHelper.getFile("com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cases.json")); + List files = AgentHelper.getFiles("com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/"); + if (files == null || files.isEmpty()) { + Assert.fail("There were no files read in for testing."); + } + int testCount = 0; + for (File current : files) { + if (current.getName().toLowerCase().endsWith((".txt"))) { + String name = current.getName(); + Assert.assertTrue("The test file name " + name + " was not found in the list of tests", tests.containsKey(name)); + String answer = tests.get(name); + processFile(current, answer, CGroup.V2); + testCount++; + } + } + + Assert.assertEquals("The number of tests files does not match the number of tests", testCount, tests.size()); + } @Test - public void testCheckLineAndGetIdValid() { + public void testCheckLineAndGetIdValidV1() { StringBuilder sb = new StringBuilder(); String line = "4:cpu:/docker/f37a7e4d17017e7bf774656b19ca4360c6cdc4951c86700a464101d0d9ce97ee"; Assert.assertTrue(dockerData.checkLineAndGetResult(line, sb, CGroup.V1)); @@ -98,7 +172,7 @@ public void testCheckLineAndGetIdValid() { } @Test - public void testCheckLineAndGetIdInValid() { + public void testCheckLineAndGetIdInValidV1() { StringBuilder sb; String line; @@ -166,7 +240,7 @@ public void testCheckLineAndGetIdInValid() { } @Test - public void testGetDockerIdFromFiles() throws Exception { + public void testGetDockerIdFromFilesV1() throws Exception { Map tests = testToAnswers(AgentHelper.getFile("com/newrelic/agent/cross_agent_tests/docker_container_id/cases.json")); List files = AgentHelper.getFiles("com/newrelic/agent/cross_agent_tests/docker_container_id/"); if (files == null || files.isEmpty()) { @@ -178,7 +252,7 @@ public void testGetDockerIdFromFiles() throws Exception { String name = current.getName(); Assert.assertTrue("The test file name " + name + " was not found in the list of tests", tests.containsKey(name)); String answer = tests.get(name); - processFile(current, answer); + processFile(current, answer, CGroup.V1); testCount++; } } @@ -257,9 +331,9 @@ public void testInvalidDockerValueNull() { Assert.assertTrue(dockerData.isInvalidDockerValue(null)); } - private void processFile(File file, String answer) { + private void processFile(File file, String answer, CGroup cgroup) { System.out.println("Current test file: " + file.getAbsolutePath()); - String actual = dockerData.getDockerIdFromFile(file, CGroup.V1); + String actual = dockerData.getDockerIdFromFile(file, cgroup); Assert.assertEquals("The file " + file.getAbsolutePath() + " should have found " + answer + " but found " + actual, answer, actual); } diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/README.md b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/README.md new file mode 100644 index 0000000000..045361d87f --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/README.md @@ -0,0 +1,10 @@ +This directory contains tests for parsing a docker containerId from Linux containers with the cgroup V2 API. + +The id is grabbed from the `proc/self/mountinfo` file in the container's internal filesystem. This file is expected to +be missing for Linux distributions <2.6.26, which come with cgroup V1 OOTB. + +It is possible for users to manually enable cgroup V1 on newer Linux distributions, in which case the +`proc/self/mountinfo` file will exist, and the id will be grabbed in the same manner as for cgroup V2. +The expected contents of a manually set V1 system are shown in `docker_linux2.6.26_v1_enabled.txt`. + +There is not yet a cross-agent test spec for cgroup V2 implementation, which is why these tests are currently here. \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cases.json b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cases.json new file mode 100644 index 0000000000..1708052d89 --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cases.json @@ -0,0 +1,38 @@ +[ + { + "filename": "cgroup_v2_expected.txt", + "containerId": "f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef", + "expectedMetrics": null + }, + { + "filename": "docker_linux2.6.26_v1_enabled.txt", + "containerId": "47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2", + "expectedMetrics": null + }, + { + "filename": "linux_prefix.txt", + "containerId": null, + "expectedMetrics": null + }, + { + "filename": "empty.txt", + "containerId": null, + "expectedMetrics": null + }, + { + "filename": "docker_id_too_long.txt", + "containerId": null, + "expectedMetrics": null + }, + { + "filename": "docker_id_too_short.txt", + "containerId": null, + "expectedMetrics": null + }, + { + "filename": "docker_id_invalid_characters.txt", + "containerId": null, + "expectedMetrics": null + } + +] \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cgroup_v2_expected.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cgroup_v2_expected.txt new file mode 100644 index 0000000000..14730cdda1 --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/cgroup_v2_expected.txt @@ -0,0 +1,20 @@ +576 423 0:193 / / rw,relatime master:97 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/X2JRPUT7DMGYBTHANYD6GAECXV:/var/lib/docker/overlay2/l/PMA6UL53PD65QZ7GH3DYCSKPKR/work +577 576 0:196 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +578 576 0:197 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +587 578 0:198 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +588 576 0:199 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +589 588 0:33 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +590 578 0:195 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +591 578 0:200 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +592 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +593 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +594 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +424 577 0:196 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +425 577 0:196 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +426 577 0:196 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +434 577 0:196 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +435 577 0:196 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +436 577 0:197 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +437 577 0:197 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +438 577 0:197 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +439 588 0:201 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_invalid_characters.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_invalid_characters.txt new file mode 100644 index 0000000000..a8c12f9f7a --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_invalid_characters.txt @@ -0,0 +1,20 @@ +576 423 0:193 / / rw,relatime master:97 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/X2JRPUT7DMGYBTHANYD6GAECXV:/var/lib/docker/overlay2/l/PMA6UL53PD65QZ7GH3DYCSKPKR/work +577 576 0:196 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +578 576 0:197 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +587 578 0:198 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +588 576 0:199 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +589 588 0:33 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +590 578 0:195 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +591 578 0:200 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +592 576 254:1 /docker/containers/f37a7e4x17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +593 576 254:1 /docker/containers/f37a7e4x17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +594 576 254:1 /docker/containers/f37a7e4x17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +424 577 0:196 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +425 577 0:196 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +426 577 0:196 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +434 577 0:196 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +435 577 0:196 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +436 577 0:197 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +437 577 0:197 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +438 577 0:197 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +439 588 0:201 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_long.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_long.txt new file mode 100644 index 0000000000..bec57431e5 --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_long.txt @@ -0,0 +1,20 @@ +576 423 0:193 / / rw,relatime master:97 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/X2JRPUT7DMGYBTHANYD6GAECXV:/var/lib/docker/overlay2/l/PMA6UL53PD65QZ7GH3DYCSKPKR/work +577 576 0:196 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +578 576 0:197 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +587 578 0:198 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +588 576 0:199 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +589 588 0:33 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +590 578 0:195 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +591 578 0:200 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +592 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef6/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +593 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef6/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +594 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef6/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +424 577 0:196 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +425 577 0:196 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +426 577 0:196 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +434 577 0:196 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +435 577 0:196 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +436 577 0:197 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +437 577 0:197 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +438 577 0:197 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +439 588 0:201 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_short.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_short.txt new file mode 100644 index 0000000000..0be3365eeb --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_id_too_short.txt @@ -0,0 +1,20 @@ +576 423 0:193 / / rw,relatime master:97 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/X2JRPUT7DMGYBTHANYD6GAECXV:/var/lib/docker/overlay2/l/PMA6UL53PD65QZ7GH3DYCSKPKR/work +577 576 0:196 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +578 576 0:197 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +587 578 0:198 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +588 576 0:199 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +589 588 0:33 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +590 578 0:195 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +591 578 0:200 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +592 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97e/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +593 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97e/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +594 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97e/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +424 577 0:196 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +425 577 0:196 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +426 577 0:196 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +434 577 0:196 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +435 577 0:196 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +436 577 0:197 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +437 577 0:197 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +438 577 0:197 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +439 588 0:201 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_linux2.6.26_v1_enabled.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_linux2.6.26_v1_enabled.txt new file mode 100644 index 0000000000..8e66bad23c --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/docker_linux2.6.26_v1_enabled.txt @@ -0,0 +1,34 @@ +805 529 0:221 / / rw,relatime master:112 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/T7NO7IPGS5PEDEYSXQITHVHQGG +806 805 0:224 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +807 805 0:225 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +830 807 0:226 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +831 805 0:227 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +832 831 0:228 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755 +833 832 0:35 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime master:20 - cgroup cpuset rw,cpuset +834 832 0:36 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/cpu ro,nosuid,nodev,noexec,relatime master:21 - cgroup cpu rw,cpu +835 832 0:37 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/cpuacct ro,nosuid,nodev,noexec,relatime master:22 - cgroup cpuacct rw,cpuacct +836 832 0:38 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime master:23 - cgroup blkio rw,blkio +837 832 0:39 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:24 - cgroup memory rw,memory +838 832 0:40 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime master:25 - cgroup devices rw,devices +839 832 0:41 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime master:26 - cgroup freezer rw,freezer +840 832 0:42 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/net_cls ro,nosuid,nodev,noexec,relatime master:27 - cgroup net_cls rw,net_cls +841 832 0:43 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime master:28 - cgroup perf_event rw,perf_event +842 832 0:44 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/net_prio ro,nosuid,nodev,noexec,relatime master:29 - cgroup net_prio rw,net_prio +865 832 0:45 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime master:30 - cgroup hugetlb rw,hugetlb +866 832 0:46 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime master:31 - cgroup pids rw,pids +867 832 0:47 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/rdma ro,nosuid,nodev,noexec,relatime master:32 - cgroup rdma rw,rdma +868 832 0:48 /docker/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2 /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime master:33 - cgroup cgroup rw,name=systemd +869 807 0:223 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +870 807 0:229 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +871 805 254:1 /docker/containers/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +872 805 254:1 /docker/containers/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +873 805 254:1 /docker/containers/47cbb16b87c50dbf71201c069c32189f0e649af17d5a1daca3bddf59d8a870b2/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +530 806 0:224 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +531 806 0:224 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +532 806 0:224 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +533 806 0:224 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +534 806 0:224 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +559 806 0:225 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +560 806 0:225 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +561 806 0:225 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +562 831 0:230 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/empty.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/linux_prefix.txt b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/linux_prefix.txt new file mode 100644 index 0000000000..73c34c33c9 --- /dev/null +++ b/newrelic-agent/src/test/resources/com/newrelic/agent/uncross_agent_tests/cgroup_v2_docker_container_id/linux_prefix.txt @@ -0,0 +1,20 @@ +576 423 0:193 / / rw,relatime master:97 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/X2JRPUT7DMGYBTHANYD6GAECXV:/var/lib/docker/overlay2/l/PMA6UL53PD65QZ7GH3DYCSKPKR/work +577 576 0:196 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +578 576 0:197 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +587 578 0:198 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +588 576 0:199 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +589 588 0:33 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +590 578 0:195 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +591 578 0:200 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +592 576 254:1 /lxc/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +593 576 254:1 /lxc/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +594 576 254:1 /lxc/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +424 577 0:196 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +425 577 0:196 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +426 577 0:196 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +434 577 0:196 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +435 577 0:196 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +436 577 0:197 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +437 577 0:197 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +438 577 0:197 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +439 588 0:201 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file From f9688559d1f7be435a9a74d73103789ed2014761 Mon Sep 17 00:00:00 2001 From: Kate Anderson Date: Thu, 28 Sep 2023 16:58:44 -0700 Subject: [PATCH 4/5] Update comments in DockerData --- .../com/newrelic/agent/utilization/DockerData.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java index f074cdbc2d..f38d1c5239 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java @@ -20,12 +20,18 @@ import java.util.regex.Pattern; /* - * Grabs the docker container id from the file /proc/self/cgroup. The lines look something like below: + * Grabs the docker container id. + * For newer Linux systems running cgroup v2, this is taken from /proc/self/mountinfo. The line should look like: + * + * 594 576 254:1 /docker/containers/f37a7e4d17017e7bf994656b19ca4360c6cdc4951c86700a464101d0d9ce97ef/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard + * + * For older Linux systems running cgroup v1, this is taken from /proc/self/cgroup. The line should look like: * * +4:cpu:/docker/3ccfa00432798ff38f85839de1e396f771b4acbe9f4ddea0a761c39b9790a782 * * We should grab the "cpu" line. The long id number is the number we want. - * This is the full docker id, not the short id that appears when you run a "docker ps". + * + * In either case, this is the full docker id, not the short id that appears when you run a "docker ps". */ public class DockerData { From dc153dc9a3ad6ff4fa9e2911e7add244f676c1f2 Mon Sep 17 00:00:00 2001 From: Kate Anderson Date: Fri, 29 Sep 2023 09:57:21 -0700 Subject: [PATCH 5/5] Update/delete comments in DockerData --- .../agent/utilization/DockerData.java | 72 +------------------ 1 file changed, 3 insertions(+), 69 deletions(-) diff --git a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java index f38d1c5239..6e2334fcee 100644 --- a/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java +++ b/newrelic-agent/src/main/java/com/newrelic/agent/utilization/DockerData.java @@ -141,7 +141,9 @@ private boolean validCpuLine(String segment) { return false; } - //Get the match for the capture group of a single-capture-group regex expression. + /* + * Get the match for the capture group of a single-capture-group regex expression. + */ private boolean checkAndGetMatch(Pattern p, StringBuilder result, String segment) { Matcher m = p.matcher(segment); if (m.matches() && m.groupCount() == 1) { @@ -151,73 +153,5 @@ private boolean checkAndGetMatch(Pattern p, StringBuilder result, String segment return false; } - //CGROUPS v1 logic - -// String getDockerIdFromFile(File cpuInfoFile) { -// if (cpuInfoFile.exists() && cpuInfoFile.canRead()) { -// try { -// return readFile(new FileReader(cpuInfoFile)); -// } catch (FileNotFoundException e) { -// } -// } -// return null; -// } - - /* - * protected for testing. - * - * Returns the docker id as a string, or null if this value could not be read, or failed validation. -// */ -// String readFile(Reader reader) { -// try (BufferedReader bReader = new BufferedReader(reader)) { -// -// String line; -// StringBuilder resultGoesHere = new StringBuilder(); -// while ((line = bReader.readLine()) != null) { -// if (checkLineAndGetResult(line, resultGoesHere)) { -// String value = resultGoesHere.toString().trim(); -// if (isInvalidDockerValue(value)) { -// Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); -// return null; -// } -// return value; -// } -// } -// } catch (Throwable e) { -// Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); -// } -// return null; -// } - // String cgroupV2GetDockerIdFromFile(File mountInfoFile) { -// if (mountInfoFile.exists() && mountInfoFile.canRead()) { -// try { -// return cgroupV2ReadFile(new FileReader(mountInfoFile)); -// } catch (FileNotFoundException e) { -// } -// } -// return null; -// } -// -// String cgroupV2ReadFile(Reader reader) { -// try (BufferedReader bReader = new BufferedReader(reader)) { -// String line; -// StringBuilder resultGoesHere = new StringBuilder(); -// while ((line = bReader.readLine()) != null) { -// //check the first line with the docker/containers/ tag. -// if (cgroupV2CheckLineAndGetResult(line, resultGoesHere)) { -// String value = resultGoesHere.toString().trim(); -// if (isInvalidDockerValue(value)) { -// Agent.LOG.log(Level.WARNING, MessageFormat.format("Failed to validate Docker value {0}", value)); -// return null; -// } -// return value; -// } -// } -// } catch (Throwable e) { -// Agent.LOG.log(Level.FINEST, e, "Exception occurred when reading docker file."); -// } -// return null; -// } - }