From ed1b22c277b9af488d273f5826fcfdab02ed3d6c Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Thu, 6 Feb 2025 00:05:12 -0800 Subject: [PATCH 01/29] Add integration tests for systemd Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 26 ++ qa/systemd-test/docker-compose.yml | 62 +++++ .../opensearch/systemdinteg/SystemdIT.java | 237 ++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 qa/systemd-test/build.gradle create mode 100644 qa/systemd-test/docker-compose.yml create mode 100644 qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle new file mode 100644 index 0000000000000..8a29941b094d1 --- /dev/null +++ b/qa/systemd-test/build.gradle @@ -0,0 +1,26 @@ +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" +} diff --git a/qa/systemd-test/docker-compose.yml b/qa/systemd-test/docker-compose.yml new file mode 100644 index 0000000000000..b5cea89d23f20 --- /dev/null +++ b/qa/systemd-test/docker-compose.yml @@ -0,0 +1,62 @@ +services: + # self-contained systemd example: run 'docker-compose up' to see it + amazonlinux: + image: opensearch-systemd-test + container_name: opensearch-systemd-test-container + build: + dockerfile_inline: | + FROM amazonlinux:2023 + # install systemd + RUN dnf -y install systemd && dnf clean all + # in practice, you'd COPY in the RPM you want to test right here + RUN dnf -y install https://artifacts.opensearch.org/releases/bundle/opensearch/2.18.0/opensearch-2.18.0-linux-x64.rpm && dnf clean all + # add a test-user + RUN useradd -ms /bin/bash testuser + # no colors + ENV SYSTEMD_COLORS=0 + # no escapes + ENV SYSTEMD_URLIFY=0 + # explicitly specify docker virtualization + ENV container=docker + # for debugging systemd issues in container, you want this, but it is very loud! + # ENV SYSTEMD_LOG_LEVEL=debug + # plumb journald logs to stdout + COPY <> /etc/opensearch/opensearch.yml + RUN echo "network.host: 0.0.0.0" >> /etc/opensearch/opensearch.yml + RUN echo "discovery.type: single-node" >> /etc/opensearch/opensearch.yml + # provide /dev/console for journal logs to go to stdout + tty: true + # capabilities to allow systemd to sandbox + cap_add: + # https://systemd.io/CONTAINER_INTERFACE/#what-you-shouldnt-do bullet 1 + - SYS_ADMIN + # https://systemd.io/CONTAINER_INTERFACE/#what-you-shouldnt-do bullet 2 + - MKNOD + # evil, but best you can do on docker? podman is better here. + cgroup: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + - ../../distribution/packages/src/common/systemd/opensearch.service:/etc/systemd/system/opensearch.service + # tmpfs mounts for systemd + tmpfs: + - /run + - /run/lock + # health check for opensearch + ports: + - "9200:9200" + - "9300:9300" + privileged: true + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"] + start_period: 15s \ No newline at end of file diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java new file mode 100644 index 0000000000000..395737d6bee31 --- /dev/null +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -0,0 +1,237 @@ +/* +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +/* +* Licensed to Elasticsearch under one or more contributor +* license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright +* ownership. Elasticsearch licenses this file to you under +* the Apache License, Version 2.0 (the "License"); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +/* +* Modifications Copyright OpenSearch Contributors. See +* GitHub history for details. +*/ + +package org.opensearch.systemdinteg; + +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import java.io.IOException; +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.*; +import static org.junit.Assert.assertTrue; +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 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); + 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); + 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); + 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); + return executeCommand(command, "Failed to get path ownership"); + } + + private static String executeCommand(String command, String errorMessage) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command}); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + StringBuilder output = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + } + if (process.waitFor() != 0) { + throw new RuntimeException(errorMessage); + } + return output.toString().trim(); + } + } + + @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 = { + "/etc/os-release", "/usr/lib/os-release", "/etc/system-release", + "/proc/self/mountinfo", "/proc/diskstats", + "/proc/self/cgroup", "/sys/fs/cgroup/cpu", "/sys/fs/cgroup/cpu/-", + "/sys/fs/cgroup/cpuacct", "/sys/fs/cgroup/cpuacct/-", + "/sys/fs/cgroup/memory", "/sys/fs/cgroup/memory/-" + }; + + for (String path : readOnlyPaths) { + if (checkPathExists(path)) { + assertTrue("Path should be readable: " + path, checkPathReadable(path)); + assertFalse("Path should not be writable: " + path, checkPathWritable(path)); + } + } + } + + @Test + public void testReadWritePaths() throws IOException, InterruptedException { + String[] readWritePaths = {"/var/log/opensearch", "/var/lib/opensearch"}; + for (String path : readWritePaths) { + assertTrue("Path should exist: " + path, checkPathExists(path)); + assertTrue("Path should be readable: " + path, checkPathReadable(path)); + assertTrue("Path should be writable: " + path, checkPathWritable(path)); + assertEquals("Path should be owned by opensearch:opensearch", "opensearch:opensearch", getPathOwnership(path)); + } + } + + @Test + public void testProcessExit() throws IOException, InterruptedException { + + String scriptContent = "#!/bin/sh\n" + + "if [ $# -ne 1 ]; then\n" + + " echo \"Usage: $0 \"\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()); + } + +} From 6ff5a71b1988fcc8f0b1ddabc76966ef394af93e Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Thu, 6 Feb 2025 03:06:30 -0800 Subject: [PATCH 02/29] Fix indentation Signed-off-by: Rajat Gupta --- .../test/java/org/opensearch/systemdinteg/SystemdIT.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 395737d6bee31..03cb24d255329 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -44,8 +44,8 @@ import java.io.BufferedReader; import java.net.HttpURLConnection; import java.net.URL; -import static org.junit.Assert.*; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -72,7 +72,7 @@ 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 { + private static String getOpenSearchPid() throws IOException, InterruptedException { String command = "docker exec " + containerId + " systemctl show --property=MainPID opensearch"; String output = executeCommand(command, "Failed to get OpenSearch PID"); return output.replace("MainPID=", "").trim(); @@ -137,7 +137,6 @@ public void testFileDescriptorLimit() throws IOException, InterruptedException { limits.contains("Max open files unlimited unlimited")); } - @Test public void testSystemCallFilter() throws IOException, InterruptedException { // Check if Seccomp is enabled @@ -152,7 +151,6 @@ public void testSystemCallFilter() throws IOException, InterruptedException { assertTrue("Swap system call should be blocked", swapResult.contains("Operation not permitted")); } - @Test public void testReadOnlyPaths() throws IOException, InterruptedException { String[] readOnlyPaths = { From 9eae65a19976c56d3e166bfb978ca67a5ecf9001 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 10 Feb 2025 02:29:49 -0800 Subject: [PATCH 03/29] Remove unit file mount Signed-off-by: Rajat Gupta --- qa/systemd-test/docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/qa/systemd-test/docker-compose.yml b/qa/systemd-test/docker-compose.yml index b5cea89d23f20..fe38376f33081 100644 --- a/qa/systemd-test/docker-compose.yml +++ b/qa/systemd-test/docker-compose.yml @@ -47,7 +47,6 @@ services: cgroup: host volumes: - /sys/fs/cgroup:/sys/fs/cgroup - - ../../distribution/packages/src/common/systemd/opensearch.service:/etc/systemd/system/opensearch.service # tmpfs mounts for systemd tmpfs: - /run From 03de0180e7e538e0c4945b87d65a03ecb8881a9e Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 11 Feb 2025 07:19:57 -0800 Subject: [PATCH 04/29] Use centos image Signed-off-by: Rajat Gupta --- qa/systemd-test/docker-compose.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qa/systemd-test/docker-compose.yml b/qa/systemd-test/docker-compose.yml index fe38376f33081..2300e647485cb 100644 --- a/qa/systemd-test/docker-compose.yml +++ b/qa/systemd-test/docker-compose.yml @@ -1,11 +1,14 @@ services: # self-contained systemd example: run 'docker-compose up' to see it - amazonlinux: + centos: image: opensearch-systemd-test container_name: opensearch-systemd-test-container build: dockerfile_inline: | - FROM amazonlinux:2023 + FROM centos:8 + RUN sed -i 's|mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/*.repo && \ + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/*.repo + # install systemd RUN dnf -y install systemd && dnf clean all # in practice, you'd COPY in the RPM you want to test right here @@ -26,7 +29,7 @@ services: ForwardToConsole=yes EOF # start systemd as PID 1 - CMD ["/sbin/init"] + CMD ["usr/sbin/init"] # enable opensearch service RUN systemctl enable opensearch # shutdown systemd properly From 0de299c43ebf627319c44cbad81fbda9bf13d9fe Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Thu, 20 Feb 2025 10:24:19 -0800 Subject: [PATCH 05/29] Change method name Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 03cb24d255329..d766f7ce79a7f 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -181,7 +181,7 @@ public void testReadWritePaths() throws IOException, InterruptedException { } @Test - public void testProcessExit() throws IOException, InterruptedException { + public void testOpensearchProcessCannotExit() throws IOException, InterruptedException { String scriptContent = "#!/bin/sh\n" + "if [ $# -ne 1 ]; then\n" + From 0cd3d8b0b2d814cbfc16695d654d5ea4cd75ae15 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Thu, 20 Feb 2025 23:25:22 -0800 Subject: [PATCH 06/29] Add sample systemd integ tests to verify behavior Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 18 --- qa/systemd-test/docker-compose.yml | 64 ---------- .../opensearch/systemdinteg/SystemdIT.java | 114 +----------------- 3 files changed, 6 insertions(+), 190 deletions(-) delete mode 100644 qa/systemd-test/docker-compose.yml diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index 8a29941b094d1..52f5407613593 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -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" -} diff --git a/qa/systemd-test/docker-compose.yml b/qa/systemd-test/docker-compose.yml deleted file mode 100644 index 2300e647485cb..0000000000000 --- a/qa/systemd-test/docker-compose.yml +++ /dev/null @@ -1,64 +0,0 @@ -services: - # self-contained systemd example: run 'docker-compose up' to see it - centos: - image: opensearch-systemd-test - container_name: opensearch-systemd-test-container - build: - dockerfile_inline: | - FROM centos:8 - RUN sed -i 's|mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/*.repo && \ - sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/*.repo - - # install systemd - RUN dnf -y install systemd && dnf clean all - # in practice, you'd COPY in the RPM you want to test right here - RUN dnf -y install https://artifacts.opensearch.org/releases/bundle/opensearch/2.18.0/opensearch-2.18.0-linux-x64.rpm && dnf clean all - # add a test-user - RUN useradd -ms /bin/bash testuser - # no colors - ENV SYSTEMD_COLORS=0 - # no escapes - ENV SYSTEMD_URLIFY=0 - # explicitly specify docker virtualization - ENV container=docker - # for debugging systemd issues in container, you want this, but it is very loud! - # ENV SYSTEMD_LOG_LEVEL=debug - # plumb journald logs to stdout - COPY <> /etc/opensearch/opensearch.yml - RUN echo "network.host: 0.0.0.0" >> /etc/opensearch/opensearch.yml - RUN echo "discovery.type: single-node" >> /etc/opensearch/opensearch.yml - # provide /dev/console for journal logs to go to stdout - tty: true - # capabilities to allow systemd to sandbox - cap_add: - # https://systemd.io/CONTAINER_INTERFACE/#what-you-shouldnt-do bullet 1 - - SYS_ADMIN - # https://systemd.io/CONTAINER_INTERFACE/#what-you-shouldnt-do bullet 2 - - MKNOD - # evil, but best you can do on docker? podman is better here. - cgroup: host - volumes: - - /sys/fs/cgroup:/sys/fs/cgroup - # tmpfs mounts for systemd - tmpfs: - - /run - - /run/lock - # health check for opensearch - ports: - - "9200:9200" - - "9300:9300" - privileged: true - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"] - start_period: 15s \ No newline at end of file diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index d766f7ce79a7f..17fb33fcd0d9c 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -42,25 +42,17 @@ 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()) { @@ -68,33 +60,29 @@ public static void setup() throws IOException, InterruptedException { } } - 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"); } @@ -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 = { @@ -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 \"\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()); - } - } From 426e2627135a7a869e5d5643d909462b22f474d2 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 24 Feb 2025 22:05:43 +0000 Subject: [PATCH 07/29] Update su with sudo probably need to have a privileged mode Signed-off-by: Peter Zhu --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 17fb33fcd0d9c..db39d1f0e34a0 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -72,12 +72,12 @@ private boolean checkPathExists(String path) throws IOException, InterruptedExce } private boolean checkPathReadable(String path) throws IOException, InterruptedException { - String command = String.format("su opensearch -s /bin/sh -c 'test -r %s && echo true || echo false'", path); + String command = String.format("sudo 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("su opensearch -s /bin/sh -c 'test -w %s && echo true || echo false'", path); + String command = String.format("sudo su opensearch -s /bin/sh -c 'test -w %s && echo true || echo false'", path); return Boolean.parseBoolean(executeCommand(command, "Failed to check write permission")); } From 2228b658be2be41583a6011b1f9810e10c1b7179 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 25 Feb 2025 00:41:06 -0800 Subject: [PATCH 08/29] Additional tests Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 1 - .../opensearch/systemdinteg/SystemdIT.java | 80 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index 52f5407613593..d8df7b1b0b144 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -1,7 +1,6 @@ apply plugin: 'opensearch.standalone-rest-test' tasks.register("integTest", Test) { - maxParallelForks = '1' include '**/*IT.class' } diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index db39d1f0e34a0..4619c583e04af 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -130,4 +130,84 @@ public void testReadWritePaths() throws IOException, InterruptedException { } } + @Test + public void testMaxProcesses() throws IOException, InterruptedException { + String limits = executeCommand("sudo 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("sudo 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("sudo 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("sudo 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("sudo 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 testOpenSearchProcessCannotExit() throws IOException, InterruptedException { + + String scriptContent = "#!/bin/sh\n" + + "if [ $# -ne 1 ]; then\n" + + " echo \"Usage: $0 \"\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 = { + "sudo", + "-u", "nobody", + "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( + "kill -0 " + opensearchPid + " 2>/dev/null && echo 'Running' || echo 'Not running'", + "Failed to check process status" + ); + + // Verify the OpenSearch service status + String serviceStatus = executeCommand( + "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()); + } + } From d52d8aeedb7b76cc5894ba4fa8e052acad5186ce Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 25 Feb 2025 09:23:47 -0800 Subject: [PATCH 09/29] Wrap commands with su -c Signed-off-by: Rajat Gupta --- .../java/org/opensearch/systemdinteg/SystemdIT.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 4619c583e04af..47cdab8e4a93f 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -132,7 +132,7 @@ public void testReadWritePaths() throws IOException, InterruptedException { @Test public void testMaxProcesses() throws IOException, InterruptedException { - String limits = executeCommand("sudo cat /proc/" + opensearchPid + "/limits", "Failed to read process limits"); + String limits = executeCommand("sudo su -c '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")); @@ -140,7 +140,7 @@ public void testMaxProcesses() throws IOException, InterruptedException { @Test public void testFileDescriptorLimit() throws IOException, InterruptedException { - String limits = executeCommand("sudo cat /proc/" + opensearchPid + "/limits", "Failed to read process limits"); + String limits = executeCommand("sudo su -c '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")); @@ -149,7 +149,7 @@ public void testFileDescriptorLimit() throws IOException, InterruptedException { @Test public void testSystemCallFilter() throws IOException, InterruptedException { // Check if Seccomp is enabled - String seccomp = executeCommand("sudo grep Seccomp /proc/" + opensearchPid + "/status", "Failed to read Seccomp status"); + String seccomp = executeCommand("sudo su -c '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 @@ -181,9 +181,8 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc "fi"; String[] command = { - "sudo", - "-u", "nobody", - "sh", + "su", + "nobody", "-c", "echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid }; From 6c905055099b38fb892e5fb81e9dfb8d094f964a Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 25 Feb 2025 09:28:01 -0800 Subject: [PATCH 10/29] Add sudo Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 1 + 1 file changed, 1 insertion(+) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 47cdab8e4a93f..824b65a62bf83 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -181,6 +181,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc "fi"; String[] command = { + "sudo", "su", "nobody", "-c", From c2eafe1335c318d5e25f89cc12b0fd0952f1c7de Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 09:14:00 -0800 Subject: [PATCH 11/29] Remove sudo for test process exit Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 824b65a62bf83..e9de7e6466a26 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -181,10 +181,6 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc "fi"; String[] command = { - "sudo", - "su", - "nobody", - "-c", "echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid }; From 8c0e2979f237271eb0b5d784ff1f9014f0852d4c Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 09:23:14 -0800 Subject: [PATCH 12/29] Minor fixes Signed-off-by: Rajat Gupta --- .../org/opensearch/systemdinteg/SystemdIT.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index e9de7e6466a26..9af9a89d088bb 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -172,13 +172,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc " 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"; + "fi\n" String[] command = { "echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid @@ -190,12 +184,6 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc // Wait a moment for any potential termination to take effect Thread.sleep(2000); - // Check if the OpenSearch process is still running - String processCheck = executeCommand( - "kill -0 " + opensearchPid + " 2>/dev/null && echo 'Running' || echo 'Not running'", - "Failed to check process status" - ); - // Verify the OpenSearch service status String serviceStatus = executeCommand( "systemctl is-active opensearch", From 5bd58b65935b7cccf5455c2fd07dd574b06ccd05 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 09:30:04 -0800 Subject: [PATCH 13/29] Fixed script string Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 9af9a89d088bb..c85ad838b0b63 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -172,7 +172,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc " echo \"SIGTERM signal sent to process $1\"\n" + "else\n" + " echo \"Failed to send SIGTERM to process $1\"\n" + - "fi\n" + "fi\n"; String[] command = { "echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid From 04863d826042b5a77da9fa997d57453c1d4b8d1c Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 09:38:22 -0800 Subject: [PATCH 14/29] Remove redundant code Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 1 - 1 file changed, 1 deletion(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index c85ad838b0b63..1fe58bedcaf60 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -190,7 +190,6 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc "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()); } From 0a70f06cae5adec0edb21b89a90265d5d4b66be5 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 09:59:41 -0800 Subject: [PATCH 15/29] Add terminate script Signed-off-by: Rajat Gupta --- .../opensearch/systemdinteg/SystemdIT.java | 25 ++++++++----------- .../src/test/resources/scripts/terminate.sh | 20 +++++++++++++++ 2 files changed, 30 insertions(+), 15 deletions(-) create mode 100755 qa/systemd-test/src/test/resources/scripts/terminate.sh diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 1fe58bedcaf60..580c122d405e6 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -42,6 +42,11 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.PosixFilePermissions; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -163,22 +168,12 @@ public void testSystemCallFilter() throws IOException, InterruptedException { @Test public void testOpenSearchProcessCannotExit() throws IOException, InterruptedException { - String scriptContent = "#!/bin/sh\n" + - "if [ $# -ne 1 ]; then\n" + - " echo \"Usage: $0 \"\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"; - - String[] command = { - "echo '" + scriptContent.replace("'", "'\"'\"'") + "' > /tmp/terminate.sh && chmod +x /tmp/terminate.sh && /tmp/terminate.sh " + opensearchPid - }; + String scriptPath = getClass().getResource("/scripts/terminate.sh").getPath(); - ProcessBuilder processBuilder = new ProcessBuilder(command); + if (scriptPath == null) { + throw new IllegalStateException("Could not find terminate.sh script in resources"); + } + ProcessBuilder processBuilder = new ProcessBuilder(scriptPath, opensearchPid); Process process = processBuilder.start(); // Wait a moment for any potential termination to take effect diff --git a/qa/systemd-test/src/test/resources/scripts/terminate.sh b/qa/systemd-test/src/test/resources/scripts/terminate.sh new file mode 100755 index 0000000000000..73c43a91dce51 --- /dev/null +++ b/qa/systemd-test/src/test/resources/scripts/terminate.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +if kill -15 $1 2>/dev/null; then + echo "SIGTERM signal sent to process $1" +else + echo "Failed to send SIGTERM to process $1" +fi + +sleep 2 + +if kill -0 $1 2>/dev/null; then + echo "Process $1 is still running" +else + echo "Process $1 has terminated" +fi \ No newline at end of file From 6c5206d84b8571093283bdc628c05ab4b193c44e Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 10:02:29 -0800 Subject: [PATCH 16/29] Modified terminate script Signed-off-by: Rajat Gupta --- qa/systemd-test/src/test/resources/scripts/terminate.sh | 8 -------- 1 file changed, 8 deletions(-) diff --git a/qa/systemd-test/src/test/resources/scripts/terminate.sh b/qa/systemd-test/src/test/resources/scripts/terminate.sh index 73c43a91dce51..21ea62a475e70 100755 --- a/qa/systemd-test/src/test/resources/scripts/terminate.sh +++ b/qa/systemd-test/src/test/resources/scripts/terminate.sh @@ -9,12 +9,4 @@ if kill -15 $1 2>/dev/null; then echo "SIGTERM signal sent to process $1" else echo "Failed to send SIGTERM to process $1" -fi - -sleep 2 - -if kill -0 $1 2>/dev/null; then - echo "Process $1 is still running" -else - echo "Process $1 has terminated" fi \ No newline at end of file From 17f99495adb531c8878b5528eff1c153b6d6ed8b Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 26 Feb 2025 10:18:13 -0800 Subject: [PATCH 17/29] Add Changelog-3.0 entry Signed-off-by: Rajat Gupta --- CHANGELOG-3.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-3.0.md b/CHANGELOG-3.0.md index 4c366d0c7714f..4e33bfa5a259c 100644 --- a/CHANGELOG-3.0.md +++ b/CHANGELOG-3.0.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add execution_hint to cardinality aggregator request (#[17312](https://github.com/opensearch-project/OpenSearch/pull/17312)) - Arrow Flight RPC plugin with Flight server bootstrap logic and client for internode communication ([#16962](https://github.com/opensearch-project/OpenSearch/pull/16962)) - Added offset management for the pull-based Ingestion ([#17354](https://github.com/opensearch-project/OpenSearch/pull/17354)) +- Added integ tests for systemd configs ([#17410](https://github.com/opensearch-project/OpenSearch/pull/17410)) ### Dependencies - Update Apache Lucene to 10.1.0 ([#16366](https://github.com/opensearch-project/OpenSearch/pull/16366)) From 3ef18a412a77c8c2569e78461b1f66471435b555 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Fri, 28 Feb 2025 10:09:03 -0800 Subject: [PATCH 18/29] Fix for gradle precommit workflow Signed-off-by: Rajat Gupta --- .../opensearch/systemdinteg/SystemdIT.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 580c122d405e6..ac54e0417cd1d 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -41,12 +41,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.io.BufferedReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.PosixFilePermissions; +import java.util.Locale; + import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -72,28 +76,28 @@ private static String getOpenSearchPid() throws IOException, InterruptedExceptio } private boolean checkPathExists(String path) throws IOException, InterruptedException { - String command = String.format("test -e %s && echo true || echo false", path); + String command = String.format(Locale.ROOT, "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("sudo su opensearch -s /bin/sh -c 'test -r %s && echo true || echo false'", path); + String command = String.format(Locale.ROOT, "sudo 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("sudo su opensearch -s /bin/sh -c 'test -w %s && echo true || echo false'", path); + String command = String.format(Locale.ROOT, "sudo 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("stat -c '%%U:%%G' %s", path); + String command = String.format(Locale.ROOT, "stat -c '%%U:%%G' %s", path); return executeCommand(command, "Failed to get path ownership"); } private static String executeCommand(String command, String errorMessage) throws IOException, InterruptedException { Process process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command}); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder output = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { @@ -106,7 +110,6 @@ private static String executeCommand(String command, String errorMessage) throws } } - @Test public void testReadOnlyPaths() throws IOException, InterruptedException { String[] readOnlyPaths = { "/etc/os-release", "/usr/lib/os-release", "/etc/system-release", @@ -124,7 +127,6 @@ public void testReadOnlyPaths() throws IOException, InterruptedException { } } - @Test public void testReadWritePaths() throws IOException, InterruptedException { String[] readWritePaths = {"/var/log/opensearch", "/var/lib/opensearch"}; for (String path : readWritePaths) { @@ -135,7 +137,6 @@ public void testReadWritePaths() throws IOException, InterruptedException { } } - @Test public void testMaxProcesses() throws IOException, InterruptedException { String limits = executeCommand("sudo su -c 'cat /proc/" + opensearchPid + "/limits'", "Failed to read process limits"); assertTrue("Max processes limit should be 4096 or unlimited", @@ -143,7 +144,6 @@ public void testMaxProcesses() throws IOException, InterruptedException { limits.contains("Max processes unlimited unlimited")); } - @Test public void testFileDescriptorLimit() throws IOException, InterruptedException { String limits = executeCommand("sudo su -c 'cat /proc/" + opensearchPid + "/limits'", "Failed to read process limits"); assertTrue("File descriptor limit should be at least 65535", @@ -151,7 +151,6 @@ public void testFileDescriptorLimit() throws IOException, InterruptedException { limits.contains("Max open files unlimited unlimited")); } - @Test public void testSystemCallFilter() throws IOException, InterruptedException { // Check if Seccomp is enabled String seccomp = executeCommand("sudo su -c 'grep Seccomp /proc/" + opensearchPid + "/status'", "Failed to read Seccomp status"); @@ -165,10 +164,14 @@ public void testSystemCallFilter() throws IOException, InterruptedException { assertTrue("Swap system call should be blocked", swapResult.contains("Operation not permitted")); } - @Test public void testOpenSearchProcessCannotExit() throws IOException, InterruptedException { - String scriptPath = getClass().getResource("/scripts/terminate.sh").getPath(); + String scriptPath; + try { + scriptPath = getClass().getResource("/scripts/terminate.sh").toURI().getPath(); + } catch (URISyntaxException e) { + throw new RuntimeException("Failed to convert URL to URI", e); + } if (scriptPath == null) { throw new IllegalStateException("Could not find terminate.sh script in resources"); From 596c012b7b11ab7a1345dcd381e0c4aafc2a25bc Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Fri, 28 Feb 2025 10:26:46 -0800 Subject: [PATCH 19/29] Fix testing conventions gradle precommit check Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index ac54e0417cd1d..56b8d39fecce6 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -55,8 +55,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; - -public class SystemdIT { +public class SystemdIT extends OpenSearchIntegTestCase { private static String opensearchPid; From 27c26b907a3a6cc4a05261619bdd96b9ca9a8fdf Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Fri, 28 Feb 2025 10:47:08 -0800 Subject: [PATCH 20/29] Fix imports Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 56b8d39fecce6..3d3433416fe18 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -50,11 +50,11 @@ import java.nio.file.StandardOpenOption; import java.nio.file.attribute.PosixFilePermissions; import java.util.Locale; +import org.opensearch.test.OpenSearchIntegTestCase; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; - public class SystemdIT extends OpenSearchIntegTestCase { private static String opensearchPid; @@ -167,7 +167,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc String scriptPath; try { - scriptPath = getClass().getResource("/scripts/terminate.sh").toURI().getPath(); + scriptPath = SystemdIT.class.getResource("/scripts/terminate.sh").toURI().getPath(); } catch (URISyntaxException e) { throw new RuntimeException("Failed to convert URL to URI", e); } From 726a1b686f2481ffacd3be373a7e57ba92624378 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Fri, 28 Feb 2025 23:16:18 -0800 Subject: [PATCH 21/29] Only run as part of build integTest, remove gradle check Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 2 -- .../opensearch/systemdinteg/SystemdIT.java | 20 +------------------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index d8df7b1b0b144..154651fbb71e7 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -3,5 +3,3 @@ apply plugin: 'opensearch.standalone-rest-test' tasks.register("integTest", Test) { include '**/*IT.class' } - -tasks.named("check").configure { dependsOn "integTest" } diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 3d3433416fe18..1768143e61f34 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -5,25 +5,6 @@ * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ - -/* -* Licensed to Elasticsearch under one or more contributor -* license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright -* ownership. Elasticsearch licenses this file to you under -* the Apache License, Version 2.0 (the "License"); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. @@ -55,6 +36,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; + public class SystemdIT extends OpenSearchIntegTestCase { private static String opensearchPid; From 86cb531027f4222b11d978f0108eaa010616ff4c Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 3 Mar 2025 11:45:59 -0800 Subject: [PATCH 22/29] Remove bash Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 1768143e61f34..4678394bba797 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -77,7 +77,7 @@ private String getPathOwnership(String path) throws IOException, InterruptedExce } private static String executeCommand(String command, String errorMessage) throws IOException, InterruptedException { - Process process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command}); + Process process = Runtime.getRuntime().exec(new String[]{command}); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder output = new StringBuilder(); String line; From cdef0835a12c6e15c3d27c05aafdab3f13e8dc2f Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 3 Mar 2025 12:30:40 -0800 Subject: [PATCH 23/29] add sudo for systemctl command Signed-off-by: Rajat Gupta --- .../src/test/java/org/opensearch/systemdinteg/SystemdIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 4678394bba797..d508a1e74935b 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -51,7 +51,7 @@ public static void setup() throws IOException, InterruptedException { } private static String getOpenSearchPid() throws IOException, InterruptedException { - String command = "systemctl show --property=MainPID opensearch"; + String command = "sudo systemctl show --property=MainPID opensearch"; String output = executeCommand(command, "Failed to get OpenSearch PID"); return output.replace("MainPID=", "").trim(); } From 8d880e8bd7862e66a5f81150a93031e0f5312fdc Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 3 Mar 2025 12:52:02 -0800 Subject: [PATCH 24/29] Remove OpenSearchIntegTest class Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 3 ++- .../systemdinteg/{SystemdIT.java => SystemdInteg.java} | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) rename qa/systemd-test/src/test/java/org/opensearch/systemdinteg/{SystemdIT.java => SystemdInteg.java} (98%) diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index 154651fbb71e7..299306ce6e768 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'opensearch.standalone-rest-test' tasks.register("integTest", Test) { - include '**/*IT.class' + include '**/*IT.class', + include '**/*Integ.class' } diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java similarity index 98% rename from qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java rename to qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java index d508a1e74935b..68446974d1664 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java @@ -31,13 +31,12 @@ import java.nio.file.StandardOpenOption; import java.nio.file.attribute.PosixFilePermissions; import java.util.Locale; -import org.opensearch.test.OpenSearchIntegTestCase; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -public class SystemdIT extends OpenSearchIntegTestCase { +public class SystemdInteg { private static String opensearchPid; From e0e7c613d37c111264958a9e9081b65f3cda676b Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 3 Mar 2025 13:00:12 -0800 Subject: [PATCH 25/29] Rename test file Signed-off-by: Rajat Gupta --- .../systemdinteg/{SystemdInteg.java => SystemdTestInteg.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename qa/systemd-test/src/test/java/org/opensearch/systemdinteg/{SystemdInteg.java => SystemdTestInteg.java} (98%) diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java similarity index 98% rename from qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java rename to qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java index 68446974d1664..2b33d1b5f0ae0 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdInteg.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java @@ -36,7 +36,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -public class SystemdInteg { +public class SystemdTestInteg { private static String opensearchPid; @@ -148,7 +148,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc String scriptPath; try { - scriptPath = SystemdIT.class.getResource("/scripts/terminate.sh").toURI().getPath(); + scriptPath = SystemdTestInteg.class.getResource("/scripts/terminate.sh").toURI().getPath(); } catch (URISyntaxException e) { throw new RuntimeException("Failed to convert URL to URI", e); } From c1f26771570a72dbc748af7699a7ad20995ecbed Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Mon, 3 Mar 2025 13:17:42 -0800 Subject: [PATCH 26/29] Add test script Signed-off-by: Rajat Gupta --- .../{SystemdTestInteg.java => SystemdIT.java} | 6 ++- .../scripts/test_opensearch_process.sh | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) rename qa/systemd-test/src/test/java/org/opensearch/systemdinteg/{SystemdTestInteg.java => SystemdIT.java} (97%) create mode 100755 qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java similarity index 97% rename from qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java rename to qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java index 2b33d1b5f0ae0..0a74da1bd8ef9 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdTestInteg.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java @@ -19,6 +19,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -35,8 +36,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import org.opensearch.test.OpenSearchIntegTestCase; -public class SystemdTestInteg { +public class SystemdIT extends OpenSearchIntegTestCase { private static String opensearchPid; @@ -148,7 +150,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc String scriptPath; try { - scriptPath = SystemdTestInteg.class.getResource("/scripts/terminate.sh").toURI().getPath(); + scriptPath = SystemdIT.class.getResource("/scripts/terminate.sh").toURI().getPath(); } catch (URISyntaxException e) { throw new RuntimeException("Failed to convert URL to URI", e); } diff --git a/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh b/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh new file mode 100755 index 0000000000000..ba3ed2794a907 --- /dev/null +++ b/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Function to get OpenSearch PID +get_opensearch_pid() { + pid=$(systemctl show -p MainPID opensearch | cut -d'=' -f2) + if [ "$pid" -eq 0 ]; then + echo "OpenSearch is not running" >&2 + exit 1 + fi + echo "$pid" +} + +# Function to check service status +check_service_status() { + status=$(systemctl is-active opensearch) + if [ "$status" != "active" ]; then + echo "Service status check failed. Expected 'active', got '$status'" >&2 + exit 1 + fi +} + +# Main test +main() { + # Get OpenSearch PID + opensearch_pid=$(get_opensearch_pid) + + # Run terminate script + ./terminate.sh "$opensearch_pid" + + # Wait for potential termination + sleep 2 + + # Check service status + check_service_status + + echo "Test passed: OpenSearch process cannot be terminated" +} + +main "$@" \ No newline at end of file From ccc1b7ba894c9d960640486cf867e1f10338cbb0 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 4 Mar 2025 00:09:58 -0800 Subject: [PATCH 27/29] Extend LuceneTestCase class Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 7 +------ .../{SystemdIT.java => SystemdIntegTests.java} | 11 ++++++----- 2 files changed, 7 insertions(+), 11 deletions(-) rename qa/systemd-test/src/test/java/org/opensearch/systemdinteg/{SystemdIT.java => SystemdIntegTests.java} (96%) diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index 299306ce6e768..ca79f7a837102 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -1,6 +1 @@ -apply plugin: 'opensearch.standalone-rest-test' - -tasks.register("integTest", Test) { - include '**/*IT.class', - include '**/*Integ.class' -} +apply plugin: 'opensearch.standalone-test' diff --git a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIntegTests.java similarity index 96% rename from qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java rename to qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIntegTests.java index 0a74da1bd8ef9..2beadd9445412 100644 --- a/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIT.java +++ b/qa/systemd-test/src/test/java/org/opensearch/systemdinteg/SystemdIntegTests.java @@ -11,6 +11,7 @@ */ package org.opensearch.systemdinteg; +import org.apache.lucene.tests.util.LuceneTestCase; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; @@ -36,9 +37,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import org.opensearch.test.OpenSearchIntegTestCase; -public class SystemdIT extends OpenSearchIntegTestCase { + +public class SystemdIntegTests extends LuceneTestCase { private static String opensearchPid; @@ -52,7 +53,7 @@ public static void setup() throws IOException, InterruptedException { } private static String getOpenSearchPid() throws IOException, InterruptedException { - String command = "sudo 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(); } @@ -78,7 +79,7 @@ private String getPathOwnership(String path) throws IOException, InterruptedExce } private static String executeCommand(String command, String errorMessage) throws IOException, InterruptedException { - Process process = Runtime.getRuntime().exec(new String[]{command}); + Process process = Runtime.getRuntime().exec(new String[]{"bash", "-c", command}); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder output = new StringBuilder(); String line; @@ -150,7 +151,7 @@ public void testOpenSearchProcessCannotExit() throws IOException, InterruptedExc String scriptPath; try { - scriptPath = SystemdIT.class.getResource("/scripts/terminate.sh").toURI().getPath(); + scriptPath = SystemdIntegTests.class.getResource("/scripts/terminate.sh").toURI().getPath(); } catch (URISyntaxException e) { throw new RuntimeException("Failed to convert URL to URI", e); } From 8d5e2fc47e5b57c1c054f70fc42babc58d6e09c5 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Tue, 4 Mar 2025 09:08:02 -0800 Subject: [PATCH 28/29] Remove test bash script Signed-off-by: Rajat Gupta --- .../scripts/test_opensearch_process.sh | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100755 qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh diff --git a/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh b/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh deleted file mode 100755 index ba3ed2794a907..0000000000000 --- a/qa/systemd-test/src/test/resources/scripts/test_opensearch_process.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -# Function to get OpenSearch PID -get_opensearch_pid() { - pid=$(systemctl show -p MainPID opensearch | cut -d'=' -f2) - if [ "$pid" -eq 0 ]; then - echo "OpenSearch is not running" >&2 - exit 1 - fi - echo "$pid" -} - -# Function to check service status -check_service_status() { - status=$(systemctl is-active opensearch) - if [ "$status" != "active" ]; then - echo "Service status check failed. Expected 'active', got '$status'" >&2 - exit 1 - fi -} - -# Main test -main() { - # Get OpenSearch PID - opensearch_pid=$(get_opensearch_pid) - - # Run terminate script - ./terminate.sh "$opensearch_pid" - - # Wait for potential termination - sleep 2 - - # Check service status - check_service_status - - echo "Test passed: OpenSearch process cannot be terminated" -} - -main "$@" \ No newline at end of file From d3b1c0aad12b4efa5259dddb55d72125b01abcb8 Mon Sep 17 00:00:00 2001 From: Rajat Gupta Date: Wed, 5 Mar 2025 12:54:14 -0800 Subject: [PATCH 29/29] Modify build.gradle Signed-off-by: Rajat Gupta --- qa/systemd-test/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qa/systemd-test/build.gradle b/qa/systemd-test/build.gradle index ca79f7a837102..7db5ddbf9ff12 100644 --- a/qa/systemd-test/build.gradle +++ b/qa/systemd-test/build.gradle @@ -1 +1,5 @@ -apply plugin: 'opensearch.standalone-test' +apply plugin: 'opensearch.standalone-rest-test' + +tasks.register("integTest", Test){ + include "**/*IntegTests.class" +}