Skip to content

Commit

Permalink
Merge pull request #1529 from newrelic/cgroupsv2-containerID
Browse files Browse the repository at this point in the history
Cgroupsv2 container
  • Loading branch information
kanderson250 authored Sep 29, 2023
2 parents 52e4151 + dc153dc commit 510c9c9
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.newrelic.agent.utilization;

public enum CGroup {
V1,
V2
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,60 @@
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 {

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 = 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, CGroup.V1);
}
return null;
}

String getDockerIdFromFile(File cpuInfoFile) {
if (cpuInfoFile.exists() && cpuInfoFile.canRead()) {
String getDockerIdFromFile(File mountInfoFile, CGroup cgroup) {
if (mountInfoFile.exists() && mountInfoFile.canRead()) {
try {
return readFile(new FileReader(cpuInfoFile));
return readFile(new FileReader(mountInfoFile), cgroup);
} 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) {
String readFile(Reader reader, CGroup cgroup) {
try (BufferedReader bReader = new BufferedReader(reader)) {

String line;
StringBuilder resultGoesHere = new StringBuilder();
while ((line = bReader.readLine()) != null) {
if (checkLineAndGetResult(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));
Expand All @@ -80,28 +88,46 @@ String readFile(Reader reader) {
return null;
}

boolean isInvalidDockerValue(String value) {
/*
* Value should be exactly 64 characters.
*
* Value is expected to include only [0-9a-f]
*/
return (value == null) || (!VALID_CONTAINER_ID.matcher(value).matches());
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;
}

// protected for testing
boolean checkLineAndGetResult(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];
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);
}
}
return false;
}
private 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;
}
}
return false;
}

boolean isInvalidDockerValue(String value) {
/*
* Value should be exactly 64 characters.
*
* Value is expected to include only [0-9a-f]
*/
return (value == null) || (!VALID_CONTAINER_ID.matcher(value).matches());
}

private boolean validCpuLine(String segment) {
if (segment != null) {
Expand All @@ -115,6 +141,9 @@ 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) {
Expand All @@ -123,4 +152,6 @@ private boolean checkAndGetMatch(Pattern p, StringBuilder result, String segment
}
return false;
}


}
Loading

0 comments on commit 510c9c9

Please sign in to comment.