diff --git a/server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java b/server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java index 320bc15fda1..b33ab21e1dc 100644 --- a/server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java +++ b/server/src/main/java/org/elasticsearch/monitor/os/OsProbe.java @@ -511,17 +511,26 @@ public class OsProbe { assert !controllerMap.isEmpty(); final String cpuAcctControlGroup = controllerMap.get("cpuacct"); - assert cpuAcctControlGroup != null; + if (cpuAcctControlGroup == null) { + logger.debug("no [cpuacct] data found in cgroup stats"); + return null; + } final long cgroupCpuAcctUsageNanos = getCgroupCpuAcctUsageNanos(cpuAcctControlGroup); final String cpuControlGroup = controllerMap.get("cpu"); - assert cpuControlGroup != null; + if (cpuControlGroup == null) { + logger.debug("no [cpu] data found in cgroup stats"); + return null; + } final long cgroupCpuAcctCpuCfsPeriodMicros = getCgroupCpuAcctCpuCfsPeriodMicros(cpuControlGroup); final long cgroupCpuAcctCpuCfsQuotaMicros = getCgroupCpuAcctCpuCfsQuotaMicros(cpuControlGroup); final OsStats.Cgroup.CpuStat cpuStat = getCgroupCpuAcctCpuStat(cpuControlGroup); final String memoryControlGroup = controllerMap.get("memory"); - assert memoryControlGroup != null; + if (memoryControlGroup == null) { + logger.debug("no [memory] data found in cgroup stats"); + return null; + } final String cgroupMemoryLimitInBytes = getCgroupMemoryLimitInBytes(memoryControlGroup); final String cgroupMemoryUsageInBytes = getCgroupMemoryUsageInBytes(memoryControlGroup); diff --git a/server/src/test/java/org/elasticsearch/monitor/os/OsProbeTests.java b/server/src/test/java/org/elasticsearch/monitor/os/OsProbeTests.java index f76ac728948..c473e4155ae 100644 --- a/server/src/test/java/org/elasticsearch/monitor/os/OsProbeTests.java +++ b/server/src/test/java/org/elasticsearch/monitor/os/OsProbeTests.java @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anyOf; @@ -188,22 +189,121 @@ public class OsProbeTests extends ESTestCase { final boolean areCgroupStatsAvailable = randomBoolean(); final String hierarchy = randomAlphaOfLength(16); - final OsProbe probe = new OsProbe() { + final OsProbe probe = buildStubOsProbe(areCgroupStatsAvailable, hierarchy); + final OsStats.Cgroup cgroup = probe.osStats().getCgroup(); + + if (areCgroupStatsAvailable) { + assertNotNull(cgroup); + assertThat(cgroup.getCpuAcctControlGroup(), equalTo("/" + hierarchy)); + assertThat(cgroup.getCpuAcctUsageNanos(), equalTo(364869866063112L)); + assertThat(cgroup.getCpuControlGroup(), equalTo("/" + hierarchy)); + assertThat(cgroup.getCpuCfsPeriodMicros(), equalTo(100000L)); + assertThat(cgroup.getCpuCfsQuotaMicros(), equalTo(50000L)); + assertThat(cgroup.getCpuStat().getNumberOfElapsedPeriods(), equalTo(17992L)); + assertThat(cgroup.getCpuStat().getNumberOfTimesThrottled(), equalTo(1311L)); + assertThat(cgroup.getCpuStat().getTimeThrottledNanos(), equalTo(139298645489L)); + assertThat(cgroup.getMemoryLimitInBytes(), equalTo("18446744073709551615")); + assertThat(cgroup.getMemoryUsageInBytes(), equalTo("4796416")); + } else { + assertNull(cgroup); + } + } + + public void testCgroupProbeWithMissingCpuAcct() { + assumeTrue("test runs on Linux only", Constants.LINUX); + + final String hierarchy = randomAlphaOfLength(16); + + // This cgroup data is missing a line about cpuacct + List procSelfCgroupLines = getProcSelfGroupLines(hierarchy) + .stream() + .map(line -> line.replaceFirst(",cpuacct", "")) + .collect(Collectors.toList()); + + final OsProbe probe = buildStubOsProbe(true, hierarchy, procSelfCgroupLines); + + final OsStats.Cgroup cgroup = probe.osStats().getCgroup(); + + assertNull(cgroup); + } + + public void testCgroupProbeWithMissingCpu() { + assumeTrue("test runs on Linux only", Constants.LINUX); + + final String hierarchy = randomAlphaOfLength(16); + + // This cgroup data is missing a line about cpu + List procSelfCgroupLines = getProcSelfGroupLines(hierarchy) + .stream() + .map(line -> line.replaceFirst(":cpu,", ":")) + .collect(Collectors.toList()); + + + final OsProbe probe = buildStubOsProbe(true, hierarchy, procSelfCgroupLines); + + final OsStats.Cgroup cgroup = probe.osStats().getCgroup(); + + assertNull(cgroup); + } + + public void testCgroupProbeWithMissingMemory() { + assumeTrue("test runs on Linux only", Constants.LINUX); + + final String hierarchy = randomAlphaOfLength(16); + + // This cgroup data is missing a line about memory + List procSelfCgroupLines = getProcSelfGroupLines(hierarchy) + .stream() + .filter(line -> !line.contains(":memory:")) + .collect(Collectors.toList()); + + final OsProbe probe = buildStubOsProbe(true, hierarchy, procSelfCgroupLines); + + final OsStats.Cgroup cgroup = probe.osStats().getCgroup(); + + assertNull(cgroup); + } + + private static List getProcSelfGroupLines(String hierarchy) { + return Arrays.asList( + "10:freezer:/", + "9:net_cls,net_prio:/", + "8:pids:/", + "7:blkio:/", + "6:memory:/" + hierarchy, + "5:devices:/user.slice", + "4:hugetlb:/", + "3:perf_event:/", + "2:cpu,cpuacct,cpuset:/" + hierarchy, + "1:name=systemd:/user.slice/user-1000.slice/session-2359.scope", + "0::/cgroup2"); + } + + private static OsProbe buildStubOsProbe(final boolean areCgroupStatsAvailable, final String hierarchy) { + List procSelfCgroupLines = getProcSelfGroupLines(hierarchy); + + return buildStubOsProbe(areCgroupStatsAvailable, hierarchy, procSelfCgroupLines); + } + + /** + * Builds a test instance of OsProbe. Methods that ordinarily read from the filesystem are overridden to return values based upon + * the arguments to this method. + * + * @param areCgroupStatsAvailable whether or not cgroup data is available. Normally OsProbe establishes this for itself. + * @param hierarchy a mock value used to generate a cgroup hierarchy. + * @param procSelfCgroupLines the lines that will be used as the content of /proc/self/cgroup + * @return a test instance + */ + private static OsProbe buildStubOsProbe( + final boolean areCgroupStatsAvailable, + final String hierarchy, + List procSelfCgroupLines + ) { + return new OsProbe() { @Override List readProcSelfCgroup() { - return Arrays.asList( - "10:freezer:/", - "9:net_cls,net_prio:/", - "8:pids:/", - "7:blkio:/", - "6:memory:/" + hierarchy, - "5:devices:/user.slice", - "4:hugetlb:/", - "3:perf_event:/", - "2:cpu,cpuacct,cpuset:/" + hierarchy, - "1:name=systemd:/user.slice/user-1000.slice/session-2359.scope", - "0::/cgroup2"); + return procSelfCgroupLines; } @Override @@ -249,26 +349,6 @@ public class OsProbeTests extends ESTestCase { boolean areCgroupStatsAvailable() { return areCgroupStatsAvailable; } - }; - - final OsStats.Cgroup cgroup = probe.osStats().getCgroup(); - - if (areCgroupStatsAvailable) { - assertNotNull(cgroup); - assertThat(cgroup.getCpuAcctControlGroup(), equalTo("/" + hierarchy)); - assertThat(cgroup.getCpuAcctUsageNanos(), equalTo(364869866063112L)); - assertThat(cgroup.getCpuControlGroup(), equalTo("/" + hierarchy)); - assertThat(cgroup.getCpuCfsPeriodMicros(), equalTo(100000L)); - assertThat(cgroup.getCpuCfsQuotaMicros(), equalTo(50000L)); - assertThat(cgroup.getCpuStat().getNumberOfElapsedPeriods(), equalTo(17992L)); - assertThat(cgroup.getCpuStat().getNumberOfTimesThrottled(), equalTo(1311L)); - assertThat(cgroup.getCpuStat().getTimeThrottledNanos(), equalTo(139298645489L)); - assertThat(cgroup.getMemoryLimitInBytes(), equalTo("18446744073709551615")); - assertThat(cgroup.getMemoryUsageInBytes(), equalTo("4796416")); - } else { - assertNull(cgroup); - } } - }