aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-core/src/main/java
diff options
context:
space:
mode:
authorAlain Kermis <alain.kermis@sonarsource.com>2023-06-08 16:37:41 +0200
committersonartech <sonartech@sonarsource.com>2023-06-13 20:03:39 +0000
commite1676e22d0f752fcc358aa630e3ce6651a404faa (patch)
tree17d19dbd33b5fec6c90fc44ecef926fbf0223549 /server/sonar-webserver-core/src/main/java
parent555abeb7d7c38477b11f7b3f18f35d7c668b5cff (diff)
downloadsonarqube-e1676e22d0f752fcc358aa630e3ce6651a404faa.tar.gz
sonarqube-e1676e22d0f752fcc358aa630e3ce6651a404faa.zip
SONAR-19425 Update logic for SQ container context
Diffstat (limited to 'server/sonar-webserver-core/src/main/java')
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java5
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java95
-rw-r--r--server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java9
3 files changed, 96 insertions, 13 deletions
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java
index 22a59f5207f..30c18a19b2b 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupport.java
@@ -19,10 +19,15 @@
*/
package org.sonar.server.platform;
+import javax.annotation.CheckForNull;
+
public interface ContainerSupport {
/**
* @return {@code true} if we can detect that SQ is running inside a docker container
*/
boolean isRunningInContainer();
+ @CheckForNull
+ String getContainerContext();
+
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java
index 38997c558f5..e6d81ac1a9b 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/platform/ContainerSupportImpl.java
@@ -19,27 +19,100 @@
*/
package org.sonar.server.platform;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.stream.Stream;
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Objects;
+import java.util.Scanner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.System2;
import org.sonar.server.util.Paths2;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
public class ContainerSupportImpl implements ContainerSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ContainerSupportImpl.class);
+ private static final String CONTAINER_FILE_PATH = "/run/.containerenv";
+ private static final String DOCKER = "docker";
+ private static final String PODMAN = "podman";
+ private static final String BUILDAH = "buildah";
+ private static final String CONTAINER_D = "containerd";
+ private static final String GENERAL_CONTAINER = "general_container";
+
+ private static final String[] MOUNT_GREP_COMMAND = {"bash", "-c", "mount | grep 'overlay on /'"};
+ private static final String[] CAT_COMMAND = {"bash", "-c", "cat /run/.containerenv"};
+
+ private final System2 system2;
private final Paths2 paths2;
+ private String containerContextCache;
- public ContainerSupportImpl(Paths2 paths2) {
+ public ContainerSupportImpl(Paths2 paths2, System2 system2) {
this.paths2 = paths2;
+ this.system2 = system2;
+
+ populateCache();
+ }
+
+ @VisibleForTesting
+ void populateCache() {
+ if (isDocker()) {
+ containerContextCache = DOCKER;
+ } else if (isPodman()) {
+ containerContextCache = PODMAN;
+ } else if (isBuildah()) {
+ containerContextCache = BUILDAH;
+ } else if (isContainerd()) {
+ containerContextCache = CONTAINER_D;
+ } else if (isGeneralContainer()) {
+ containerContextCache = GENERAL_CONTAINER;
+ } else {
+ containerContextCache = null;
+ }
}
@Override
public boolean isRunningInContainer() {
- if (paths2.exists("/run/.containerenv")) {
- return true;
- }
- try (Stream<String> stream = Files.lines(paths2.get("/proc/1/cgroup"))) {
- return stream.anyMatch(line -> line.contains("/docker") || line.contains("/kubepods") || line.contains("containerd.service") );
- } catch (IOException e) {
- return false;
+ return containerContextCache != null;
+ }
+
+ @Override
+ public String getContainerContext() {
+ return containerContextCache;
+ }
+
+ private boolean isDocker() {
+ return executeCommand(MOUNT_GREP_COMMAND).contains("/docker") && paths2.exists("/.dockerenv");
+ }
+
+ private boolean isPodman() {
+ return Objects.equals(system2.envVariable("container"), PODMAN) && paths2.exists(CONTAINER_FILE_PATH);
+ }
+
+ private boolean isBuildah() {
+ return paths2.exists(CONTAINER_FILE_PATH) && executeCommand(CAT_COMMAND).contains("engine=\"buildah-");
+ }
+
+ private boolean isContainerd() {
+ return executeCommand(MOUNT_GREP_COMMAND).contains("/containerd");
+ }
+
+ private boolean isGeneralContainer() {
+ return paths2.exists(CONTAINER_FILE_PATH);
+ }
+
+ @VisibleForTesting
+ String executeCommand(String[] command) {
+ try {
+ Process process = new ProcessBuilder().command(command).start();
+ try (Scanner scanner = new Scanner(process.getInputStream(), UTF_8)) {
+ scanner.useDelimiter("\n");
+ return scanner.next();
+ } finally {
+ process.destroy();
+ }
+ } catch (Exception e) {
+ LOG.debug("Failed to execute command", e);
+ return "";
}
}
}
diff --git a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java
index f35f1f026f2..dd10f981ab5 100644
--- a/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java
+++ b/server/sonar-webserver-core/src/main/java/org/sonar/server/telemetry/CloudUsageDataProvider.java
@@ -48,6 +48,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2;
+import org.sonar.server.platform.ContainerSupport;
import org.sonar.server.util.Paths2;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -64,13 +65,15 @@ public class CloudUsageDataProvider {
static final String SONAR_HELM_CHART_VERSION = "SONAR_HELM_CHART_VERSION";
static final String DOCKER_RUNNING = "DOCKER_RUNNING";
private static final String[] KUBERNETES_PROVIDER_COMMAND = {"bash", "-c", "uname -r"};
+ private final ContainerSupport containerSupport;
private final System2 system2;
private final Paths2 paths2;
private OkHttpClient httpClient;
private TelemetryData.CloudUsage cloudUsageData;
@Inject
- public CloudUsageDataProvider(System2 system2, Paths2 paths2) {
+ public CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2) {
+ this.containerSupport = containerSupport;
this.system2 = system2;
this.paths2 = paths2;
if (isOnKubernetes()) {
@@ -79,7 +82,8 @@ public class CloudUsageDataProvider {
}
@VisibleForTesting
- CloudUsageDataProvider(System2 system2, Paths2 paths2, OkHttpClient httpClient) {
+ CloudUsageDataProvider(ContainerSupport containerSupport, System2 system2, Paths2 paths2, OkHttpClient httpClient) {
+ this.containerSupport = containerSupport;
this.system2 = system2;
this.paths2 = paths2;
this.httpClient = httpClient;
@@ -107,6 +111,7 @@ public class CloudUsageDataProvider {
kubernetesPlatform,
getKubernetesProvider(),
getOfficialHelmChartVersion(),
+ containerSupport.getContainerContext(),
isOfficialImageUsed());
return cloudUsageData;