Skip to content

Commit

Permalink
Add sample systemd integ tests to verify behavior
Browse files Browse the repository at this point in the history
Signed-off-by: Rajat Gupta <gptrajat@amazon.com>
  • Loading branch information
Rajat Gupta committed Feb 21, 2025
1 parent 64f1c96 commit beaa600
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 190 deletions.
18 changes: 0 additions & 18 deletions qa/systemd-test/build.gradle
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
import org.opensearch.gradle.Architecture
import org.opensearch.gradle.VersionProperties
import org.opensearch.gradle.testfixtures.TestFixturesPlugin

apply plugin: 'opensearch.standalone-rest-test'
apply plugin: 'opensearch.test.fixtures'

testFixtures.useFixture()

dockerCompose {
useComposeFiles = ['docker-compose.yml']
}


tasks.register("integTest", Test) {
outputs.doNotCacheIf('Build cache is disabled for Docker tests') { true }
maxParallelForks = '1'
include '**/*IT.class'
}

tasks.named("check").configure { dependsOn "integTest" }

tasks.named("integTest").configure {
dependsOn "composeUp"
finalizedBy "composeDown"
}
64 changes: 0 additions & 64 deletions qa/systemd-test/docker-compose.yml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -42,59 +42,47 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.HttpURLConnection;
import java.net.URL;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;


public class SystemdIT {
private static final String OPENSEARCH_URL = "http://localhost:9200"; // OpenSearch URL (port 9200)
private static String containerId;

private static String opensearchPid;
private static final String CONTAINER_NAME = "opensearch-systemd-test-container";

@BeforeClass
public static void setup() throws IOException, InterruptedException {
containerId = getContainerId();

String status = executeCommand("docker exec " + containerId + " systemctl status opensearch", "Failed to check OpenSearch status");

opensearchPid = getOpenSearchPid();

if (opensearchPid.isEmpty()) {
throw new RuntimeException("Failed to find OpenSearch process ID");
}
}

private static String getContainerId() throws IOException, InterruptedException {
return executeCommand("docker ps -qf name=" + CONTAINER_NAME, "OpenSearch container '" + CONTAINER_NAME + "' is not running");
}

private static String getOpenSearchPid() throws IOException, InterruptedException {
String command = "docker exec " + containerId + " systemctl show --property=MainPID opensearch";
String command = "systemctl show --property=MainPID opensearch";
String output = executeCommand(command, "Failed to get OpenSearch PID");
return output.replace("MainPID=", "").trim();
}

private boolean checkPathExists(String path) throws IOException, InterruptedException {
String command = String.format("docker exec %s test -e %s && echo true || echo false", containerId, path);
String command = String.format("test -e %s && echo true || echo false", path);
return Boolean.parseBoolean(executeCommand(command, "Failed to check path existence"));
}

private boolean checkPathReadable(String path) throws IOException, InterruptedException {
String command = String.format("docker exec %s su opensearch -s /bin/sh -c 'test -r %s && echo true || echo false'", containerId, path);
String command = String.format("su opensearch -s /bin/sh -c 'test -r %s && echo true || echo false'", path);
return Boolean.parseBoolean(executeCommand(command, "Failed to check read permission"));
}

private boolean checkPathWritable(String path) throws IOException, InterruptedException {
String command = String.format("docker exec %s su opensearch -s /bin/sh -c 'test -w %s && echo true || echo false'", containerId, path);
String command = String.format("su opensearch -s /bin/sh -c 'test -w %s && echo true || echo false'", path);
return Boolean.parseBoolean(executeCommand(command, "Failed to check write permission"));
}

private String getPathOwnership(String path) throws IOException, InterruptedException {
String command = String.format("docker exec %s stat -c '%%U:%%G' %s", containerId, path);
String command = String.format("stat -c '%%U:%%G' %s", path);
return executeCommand(command, "Failed to get path ownership");
}

Expand All @@ -113,44 +101,6 @@ private static String executeCommand(String command, String errorMessage) throws
}
}

@Test
public void testClusterHealth() throws IOException {
HttpURLConnection healthCheck = (HttpURLConnection) new URL(OPENSEARCH_URL + "/_cluster/health").openConnection();
healthCheck.setRequestMethod("GET");
int healthResponseCode = healthCheck.getResponseCode();
assertTrue(healthResponseCode == HttpURLConnection.HTTP_OK);
}

@Test
public void testMaxProcesses() throws IOException, InterruptedException {
String limits = executeCommand("docker exec " + containerId + " cat /proc/" + opensearchPid + "/limits", "Failed to read process limits");
assertTrue("Max processes limit should be 4096 or unlimited",
limits.contains("Max processes 4096 4096") ||
limits.contains("Max processes unlimited unlimited"));
}

@Test
public void testFileDescriptorLimit() throws IOException, InterruptedException {
String limits = executeCommand("docker exec " + containerId + " cat /proc/" + opensearchPid + "/limits", "Failed to read process limits");
assertTrue("File descriptor limit should be at least 65535",
limits.contains("Max open files 65535 65535") ||
limits.contains("Max open files unlimited unlimited"));
}

@Test
public void testSystemCallFilter() throws IOException, InterruptedException {
// Check if Seccomp is enabled
String seccomp = executeCommand("docker exec " + containerId + " grep Seccomp /proc/" + opensearchPid + "/status", "Failed to read Seccomp status");
assertFalse("Seccomp should be enabled", seccomp.contains("0"));

// Test specific system calls that should be blocked
String rebootResult = executeCommand("docker exec " + containerId + " su opensearch -c 'kill -s SIGHUP 1' 2>&1 || echo 'Operation not permitted'", "Failed to test reboot system call");
assertTrue("Reboot system call should be blocked", rebootResult.contains("Operation not permitted"));

String swapResult = executeCommand("docker exec " + containerId + " su opensearch -c 'swapon -a' 2>&1 || echo 'Operation not permitted'", "Failed to test swap system call");
assertTrue("Swap system call should be blocked", swapResult.contains("Operation not permitted"));
}

@Test
public void testReadOnlyPaths() throws IOException, InterruptedException {
String[] readOnlyPaths = {
Expand Down Expand Up @@ -180,56 +130,4 @@ public void testReadWritePaths() throws IOException, InterruptedException {
}
}

@Test
public void testOpensearchProcessCannotExit() throws IOException, InterruptedException {

String scriptContent = "#!/bin/sh\n" +
"if [ $# -ne 1 ]; then\n" +
" echo \"Usage: $0 <PID>\"\n" +
" exit 1\n" +
"fi\n" +
"if kill -15 $1 2>/dev/null; then\n" +
" echo \"SIGTERM signal sent to process $1\"\n" +
"else\n" +
" echo \"Failed to send SIGTERM to process $1\"\n" +
"fi\n" +
"sleep 2\n" +
"if kill -0 $1 2>/dev/null; then\n" +
" echo \"Process $1 is still running\"\n" +
"else\n" +
" echo \"Process $1 has terminated\"\n" +
"fi";

String[] command = {
"docker",
"exec",
"-u", "testuser",
containerId,
"sh",
"-c",
"echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid
};

ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();

// Wait a moment for any potential termination to take effect
Thread.sleep(2000);

// Check if the OpenSearch process is still running
String processCheck = executeCommand(
"docker exec " + containerId + " kill -0 " + opensearchPid + " 2>/dev/null && echo 'Running' || echo 'Not running'",
"Failed to check process status"
);

// Verify the OpenSearch service status
String serviceStatus = executeCommand(
"docker exec " + containerId + " systemctl is-active opensearch",
"Failed to check OpenSearch service status"
);

assertTrue("OpenSearch process should still be running", processCheck.contains("Running"));
assertEquals("OpenSearch service should be active", "active", serviceStatus.trim());
}

}

0 comments on commit beaa600

Please sign in to comment.