Support running elasticsearch-oss distribution in test cluster for BWC (#764)

We need to install elasticsearch in the test cluster nodes to be able to run the BWC tests. This commit makes the following changes to enable that,
- updates DistributionDownloadPlugin to download elasticsearch-oss distributions.
- updates OpenSearchNode to be able to run both OpenSearch and Elasticsearch distributions.

Signed-off-by: Rabi Panda <adnapibar@gmail.com>
This commit is contained in:
Rabi Panda 2021-05-25 11:16:12 -07:00 committed by GitHub
parent 9c95cf424b
commit 59563fbf72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 199 additions and 60 deletions

View File

@ -31,6 +31,7 @@ package org.opensearch.gradle.fixtures
import org.opensearch.gradle.OpenSearchDistribution import org.opensearch.gradle.OpenSearchDistribution
import org.opensearch.gradle.Version
import org.opensearch.gradle.VersionProperties import org.opensearch.gradle.VersionProperties
import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.GradleRunner
@ -65,7 +66,11 @@ class DistributionDownloadFixture {
private static String urlPath(String version, OpenSearchDistribution.Platform platform) { private static String urlPath(String version, OpenSearchDistribution.Platform platform) {
String fileType = ((platform == OpenSearchDistribution.Platform.LINUX || String fileType = ((platform == OpenSearchDistribution.Platform.LINUX ||
platform == OpenSearchDistribution.Platform.DARWIN)) ? "tar.gz" : "zip" platform == OpenSearchDistribution.Platform.DARWIN)) ? "tar.gz" : "zip"
"/releases/core/opensearch/${version}/opensearch-${version}-${platform}-x64.$fileType" if (Version.fromString(version).onOrAfter(Version.fromString("1.0.0"))) {
return "/releases/core/opensearch/${version}/opensearch-${version}-${platform}-x64.$fileType"
} else {
return "/downloads/elasticsearch/elasticsearch-oss-${version}-${platform}-x86_64.$fileType"
}
} }
private static byte[] filebytes(String urlPath) throws IOException { private static byte[] filebytes(String urlPath) throws IOException {

View File

@ -55,7 +55,7 @@ import java.util.Comparator;
* A plugin to manage getting and extracting distributions of OpenSearch. * A plugin to manage getting and extracting distributions of OpenSearch.
* <p> * <p>
* The plugin provides hooks to register custom distribution resolutions. * The plugin provides hooks to register custom distribution resolutions.
* This plugin resolves distributions from the Elastic downloads service if * This plugin resolves distributions from the OpenSearch downloads service if
* no registered resolution strategy can resolve to a distribution. * no registered resolution strategy can resolve to a distribution.
*/ */
public class DistributionDownloadPlugin implements Plugin<Project> { public class DistributionDownloadPlugin implements Plugin<Project> {
@ -68,6 +68,12 @@ public class DistributionDownloadPlugin implements Plugin<Project> {
private static final String SNAPSHOT_REPO_NAME = "opensearch-snapshots"; private static final String SNAPSHOT_REPO_NAME = "opensearch-snapshots";
public static final String DISTRO_EXTRACTED_CONFIG_PREFIX = "opensearch_distro_extracted_"; public static final String DISTRO_EXTRACTED_CONFIG_PREFIX = "opensearch_distro_extracted_";
// for downloading Elasticsearch OSS distributions to run BWC
private static final String FAKE_IVY_GROUP_ES = "elasticsearch-distribution";
private static final String DOWNLOAD_REPO_NAME_ES = "elasticsearch-downloads";
private static final String SNAPSHOT_REPO_NAME_ES = "elasticsearch-snapshots";
private static final String FAKE_SNAPSHOT_IVY_GROUP_ES = "elasticsearch-distribution-snapshot";
private NamedDomainObjectContainer<OpenSearchDistribution> distributionsContainer; private NamedDomainObjectContainer<OpenSearchDistribution> distributionsContainer;
private NamedDomainObjectContainer<DistributionResolution> distributionsResolutionStrategiesContainer; private NamedDomainObjectContainer<DistributionResolution> distributionsResolutionStrategiesContainer;
@ -164,12 +170,27 @@ public class DistributionDownloadPlugin implements Plugin<Project> {
}); });
} }
private static void addIvyRepo2(Project project, String name, String url, String group) {
IvyArtifactRepository ivyRepo = project.getRepositories().ivy(repo -> {
repo.setName(name);
repo.setUrl(url);
repo.metadataSources(IvyArtifactRepository.MetadataSources::artifact);
repo.patternLayout(layout -> layout.artifact("/downloads/elasticsearch/elasticsearch-oss-[revision](-[classifier]).[ext]"));
});
project.getRepositories().exclusiveContent(exclusiveContentRepository -> {
exclusiveContentRepository.filter(config -> config.includeGroup(group));
exclusiveContentRepository.forRepositories(ivyRepo);
});
}
private static void setupDownloadServiceRepo(Project project) { private static void setupDownloadServiceRepo(Project project) {
if (project.getRepositories().findByName(DOWNLOAD_REPO_NAME) != null) { if (project.getRepositories().findByName(DOWNLOAD_REPO_NAME) != null) {
return; return;
} }
addIvyRepo(project, DOWNLOAD_REPO_NAME, "https://artifacts.opensearch.org", FAKE_IVY_GROUP); addIvyRepo(project, DOWNLOAD_REPO_NAME, "https://artifacts.opensearch.org", FAKE_IVY_GROUP);
addIvyRepo(project, SNAPSHOT_REPO_NAME, "https://snapshots-no-kpi.opensearch.org", FAKE_SNAPSHOT_IVY_GROUP); addIvyRepo(project, SNAPSHOT_REPO_NAME, "https://snapshots-no-kpi.opensearch.org", FAKE_SNAPSHOT_IVY_GROUP);
addIvyRepo2(project, DOWNLOAD_REPO_NAME_ES, "https://artifacts-no-kpi.elastic.co", FAKE_IVY_GROUP_ES);
addIvyRepo2(project, SNAPSHOT_REPO_NAME_ES, "https://snapshots-no-kpi.elastic.co", FAKE_SNAPSHOT_IVY_GROUP_ES);
} }
/** /**
@ -181,17 +202,24 @@ public class DistributionDownloadPlugin implements Plugin<Project> {
* coordinates that resolve to the Elastic download service through an ivy repository. * coordinates that resolve to the Elastic download service through an ivy repository.
*/ */
private String dependencyNotation(OpenSearchDistribution distribution) { private String dependencyNotation(OpenSearchDistribution distribution) {
Version distroVersion = Version.fromString(distribution.getVersion());
if (distribution.getType() == Type.INTEG_TEST_ZIP) { if (distribution.getType() == Type.INTEG_TEST_ZIP) {
return "org.opensearch.distribution.integ-test-zip:opensearch:" + distribution.getVersion() + "@zip"; if (distroVersion.onOrAfter("1.0.0")) {
return "org.opensearch.distribution.integ-test-zip:opensearch:" + distribution.getVersion() + "@zip";
} else {
return "org.elasticsearch.distribution.integ-test-zip:elasticsearch:" + distribution.getVersion() + "@zip";
}
} }
Version distroVersion = Version.fromString(distribution.getVersion());
String extension = distribution.getType().toString(); String extension = distribution.getType().toString();
String classifier = ":x64"; String classifier = distroVersion.onOrAfter("1.0.0") ? ":x64" : ":x86_64";
if (distribution.getType() == Type.ARCHIVE) { if (distribution.getType() == Type.ARCHIVE) {
extension = distribution.getPlatform() == Platform.WINDOWS ? "zip" : "tar.gz"; extension = distribution.getPlatform() == Platform.WINDOWS ? "zip" : "tar.gz";
if (distroVersion.onOrAfter("7.0.0")) {
if (distroVersion.onOrAfter("1.0.0")) {
classifier = ":" + distribution.getPlatform() + "-x64"; classifier = ":" + distribution.getPlatform() + "-x64";
} else if (distroVersion.onOrAfter("7.0.0")) {
classifier = ":" + distribution.getPlatform() + "-x86_64";
} else { } else {
classifier = ""; classifier = "";
} }
@ -205,7 +233,13 @@ public class DistributionDownloadPlugin implements Plugin<Project> {
classifier = ""; classifier = "";
} }
String group = distribution.getVersion().endsWith("-SNAPSHOT") ? FAKE_SNAPSHOT_IVY_GROUP : FAKE_IVY_GROUP; String group;
return group + ":opensearch" + ":" + distribution.getVersion() + classifier + "@" + extension; if (distroVersion.onOrAfter("1.0.0")) {
group = distribution.getVersion().endsWith("-SNAPSHOT") ? FAKE_SNAPSHOT_IVY_GROUP : FAKE_IVY_GROUP;
return group + ":opensearch" + ":" + distribution.getVersion() + classifier + "@" + extension;
} else {
group = distribution.getVersion().endsWith("-SNAPSHOT") ? FAKE_SNAPSHOT_IVY_GROUP_ES : FAKE_IVY_GROUP_ES;
return group + ":elasticsearch-oss" + ":" + distribution.getVersion() + classifier + "@" + extension;
}
} }
} }

View File

@ -159,13 +159,9 @@ public class OpenSearchNode implements TestClusterConfiguration {
final LinkedHashMap<String, String> defaultConfig = new LinkedHashMap<>(); final LinkedHashMap<String, String> defaultConfig = new LinkedHashMap<>();
private final Path confPathRepo; private final Path confPathRepo;
private final Path configFile;
private final Path confPathLogs; private final Path confPathLogs;
private final Path transportPortFile; private final Path transportPortFile;
private final Path httpPortsFile; private final Path httpPortsFile;
private final Path opensearchStdoutFile;
private final Path opensearchStderrFile;
private final Path opensearchStdinFile;
private final Path tmpDir; private final Path tmpDir;
private int currentDistro = 0; private int currentDistro = 0;
@ -179,6 +175,9 @@ public class OpenSearchNode implements TestClusterConfiguration {
private Path confPathData; private Path confPathData;
private String keystorePassword = ""; private String keystorePassword = "";
private boolean preserveDataDir = false; private boolean preserveDataDir = false;
private final Config opensearchConfig;
private final Config legacyESConfig;
private Config currentConfig;
OpenSearchNode( OpenSearchNode(
String path, String path,
@ -199,19 +198,109 @@ public class OpenSearchNode implements TestClusterConfiguration {
this.bwcJdk = bwcJdk; this.bwcJdk = bwcJdk;
workingDir = workingDirBase.toPath().resolve(safeName(name)).toAbsolutePath(); workingDir = workingDirBase.toPath().resolve(safeName(name)).toAbsolutePath();
confPathRepo = workingDir.resolve("repo"); confPathRepo = workingDir.resolve("repo");
configFile = workingDir.resolve("config/opensearch.yml");
confPathData = workingDir.resolve("data"); confPathData = workingDir.resolve("data");
confPathLogs = workingDir.resolve("logs"); confPathLogs = workingDir.resolve("logs");
transportPortFile = confPathLogs.resolve("transport.ports"); transportPortFile = confPathLogs.resolve("transport.ports");
httpPortsFile = confPathLogs.resolve("http.ports"); httpPortsFile = confPathLogs.resolve("http.ports");
opensearchStdoutFile = confPathLogs.resolve("opensearch.stdout.log");
opensearchStderrFile = confPathLogs.resolve("opensearch.stderr.log");
opensearchStdinFile = workingDir.resolve("opensearch.stdin");
tmpDir = workingDir.resolve("tmp"); tmpDir = workingDir.resolve("tmp");
waitConditions.put("ports files", this::checkPortsFilesExistWithDelay); waitConditions.put("ports files", this::checkPortsFilesExistWithDelay);
setTestDistribution(TestDistribution.INTEG_TEST); setTestDistribution(TestDistribution.INTEG_TEST);
setVersion(VersionProperties.getOpenSearch()); setVersion(VersionProperties.getOpenSearch());
opensearchConfig = Config.getOpenSearchConfig(workingDir);
legacyESConfig = Config.getLegacyESConfig(workingDir);
currentConfig = opensearchConfig;
}
/*
* An object to contain the configuration needed to install
* either an OpenSearch or an elasticsearch distribution on
* this test node.
*
* This is added to be able to run BWC testing against a
* cluster running elasticsearch.
*
* legacyESConfig will be removed in a future release.
*/
private static class Config {
final String distroName;
final String command;
final String keystoreTool;
final String pluginTool;
final String envTempDir;
final String envJavaOpts;
final String envPathConf;
final Path configFile;
final Path stdoutFile;
final Path stderrFile;
final Path stdinFile;
Config(
String distroName,
String command,
String keystoreTool,
String pluginTool,
String envTempDir,
String envJavaOpts,
String envPathConf,
Path configFile,
Path stdoutFile,
Path stderrFile,
Path stdinFile
) {
this.distroName = distroName;
this.command = command;
this.keystoreTool = keystoreTool;
this.pluginTool = pluginTool;
this.envTempDir = envTempDir;
this.envJavaOpts = envJavaOpts;
this.envPathConf = envPathConf;
this.configFile = configFile;
this.stdoutFile = stdoutFile;
this.stderrFile = stderrFile;
this.stdinFile = stdinFile;
}
static Config getOpenSearchConfig(Path workingDir) {
Path confPathLogs = workingDir.resolve("logs");
return new Config(
"OpenSearch",
"opensearch",
"opensearch-keystore",
"opensearch-plugin",
"OPENSEARCH_TMPDIR",
"OPENSEARCH_JAVA_OPTS",
"OPENSEARCH_PATH_CONF",
workingDir.resolve("config/opensearch.yml"),
confPathLogs.resolve("opensearch.stdout.log"),
confPathLogs.resolve("opensearch.stderr.log"),
workingDir.resolve("opensearch.stdin")
);
}
static Config getLegacyESConfig(Path workingDir) {
Path confPathLogs = workingDir.resolve("logs");
return new Config(
"Elasticsearch",
"elasticsearch",
"elasticsearch-keystore",
"elasticsearch-plugin",
"ES_TMPDIR",
"ES_JAVA_OPTS",
"ES_PATH_CONF",
workingDir.resolve("config/elasticsearch.yml"),
confPathLogs.resolve("es.stdout.log"),
confPathLogs.resolve("es.stderr.log"),
workingDir.resolve("es.stdin")
);
}
}
private void applyConfig() {
if (getVersion().onOrAfter("1.0.0")) {
currentConfig = opensearchConfig;
} else {
currentConfig = legacyESConfig;
}
} }
@Input @Input
@ -231,6 +320,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
checkFrozen(); checkFrozen();
distributions.clear(); distributions.clear();
doSetVersion(version); doSetVersion(version);
applyConfig();
} }
@Override @Override
@ -240,6 +330,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
for (String version : versions) { for (String version : versions) {
doSetVersion(version); doSetVersion(version);
} }
applyConfig();
} }
private void doSetVersion(String version) { private void doSetVersion(String version) {
@ -424,7 +515,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
@Internal @Internal
public Path getConfigDir() { public Path getConfigDir() {
return configFile.getParent(); return currentConfig.configFile.getParent();
} }
@Override @Override
@ -451,7 +542,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
* @return stream of log lines * @return stream of log lines
*/ */
public Stream<String> logLines() throws IOException { public Stream<String> logLines() throws IOException {
return Files.lines(opensearchStdoutFile, StandardCharsets.UTF_8); return Files.lines(currentConfig.stdoutFile, StandardCharsets.UTF_8);
} }
@Override @Override
@ -500,20 +591,20 @@ public class OpenSearchNode implements TestClusterConfiguration {
if (getVersion().onOrAfter("7.6.0")) { if (getVersion().onOrAfter("7.6.0")) {
logToProcessStdout("installing " + pluginsToInstall.size() + " plugins in a single transaction"); logToProcessStdout("installing " + pluginsToInstall.size() + " plugins in a single transaction");
final String[] arguments = Stream.concat(Stream.of("install", "--batch"), pluginsToInstall.stream()).toArray(String[]::new); final String[] arguments = Stream.concat(Stream.of("install", "--batch"), pluginsToInstall.stream()).toArray(String[]::new);
runOpenSearchBinScript("opensearch-plugin", arguments); runOpenSearchBinScript(currentConfig.pluginTool, arguments);
logToProcessStdout("installed plugins"); logToProcessStdout("installed plugins");
} else { } else {
logToProcessStdout("installing " + pluginsToInstall.size() + " plugins sequentially"); logToProcessStdout("installing " + pluginsToInstall.size() + " plugins sequentially");
pluginsToInstall.forEach(plugin -> runOpenSearchBinScript("opensearch-plugin", "install", "--batch", plugin)); pluginsToInstall.forEach(plugin -> runOpenSearchBinScript(currentConfig.pluginTool, "install", "--batch", plugin));
logToProcessStdout("installed plugins"); logToProcessStdout("installed plugins");
} }
} }
logToProcessStdout("Creating opensearch keystore with password set to [" + keystorePassword + "]"); logToProcessStdout("Creating " + currentConfig.command + " keystore with password set to [" + keystorePassword + "]");
if (keystorePassword.length() > 0) { if (keystorePassword.length() > 0) {
runOpenSearchBinScriptWithInput(keystorePassword + "\n" + keystorePassword, "opensearch-keystore", "create", "-p"); runOpenSearchBinScriptWithInput(keystorePassword + "\n" + keystorePassword, currentConfig.keystoreTool, "create", "-p");
} else { } else {
runOpenSearchBinScript("opensearch-keystore", "-v", "create"); runOpenSearchBinScript(currentConfig.keystoreTool, "-v", "create");
} }
if (keystoreSettings.isEmpty() == false || keystoreFiles.isEmpty() == false) { if (keystoreSettings.isEmpty() == false || keystoreFiles.isEmpty() == false) {
@ -541,7 +632,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
} }
} }
logToProcessStdout("Starting OpenSearch process"); logToProcessStdout("Starting " + currentConfig.distroName + " process");
startOpenSearchProcess(); startOpenSearchProcess();
} }
@ -553,11 +644,11 @@ public class OpenSearchNode implements TestClusterConfiguration {
private void logToProcessStdout(String message) { private void logToProcessStdout(String message) {
try { try {
if (Files.exists(opensearchStdoutFile.getParent()) == false) { if (Files.exists(currentConfig.stdoutFile.getParent()) == false) {
Files.createDirectories(opensearchStdoutFile.getParent()); Files.createDirectories(currentConfig.stdoutFile.getParent());
} }
Files.write( Files.write(
opensearchStdoutFile, currentConfig.stdoutFile,
("[" + Instant.now().toString() + "] [BUILD] " + message + "\n").getBytes(StandardCharsets.UTF_8), ("[" + Instant.now().toString() + "] [BUILD] " + message + "\n").getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE, StandardOpenOption.CREATE,
StandardOpenOption.APPEND StandardOpenOption.APPEND
@ -580,6 +671,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
} }
logToProcessStdout("Switch version from " + getVersion() + " to " + distributions.get(currentDistro + 1).getVersion()); logToProcessStdout("Switch version from " + getVersion() + " to " + distributions.get(currentDistro + 1).getVersion());
currentDistro += 1; currentDistro += 1;
applyConfig();
setting("node.attr.upgraded", "true"); setting("node.attr.upgraded", "true");
} }
@ -595,7 +687,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
if (Files.exists(from.toPath()) == false) { if (Files.exists(from.toPath()) == false) {
throw new TestClustersException("Can't create extra config file from " + from + " for " + this + " as it does not exist"); throw new TestClustersException("Can't create extra config file from " + from + " for " + this + " as it does not exist");
} }
Path dst = configFile.getParent().resolve(destination); Path dst = currentConfig.configFile.getParent().resolve(destination);
try { try {
Files.createDirectories(dst.getParent()); Files.createDirectories(dst.getParent());
Files.copy(from.toPath(), dst, StandardCopyOption.REPLACE_EXISTING); Files.copy(from.toPath(), dst, StandardCopyOption.REPLACE_EXISTING);
@ -686,7 +778,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
} }
try (InputStream byteArrayInputStream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) { try (InputStream byteArrayInputStream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8))) {
LoggedExec.exec(project, spec -> { LoggedExec.exec(project, spec -> {
spec.setEnvironment(getESEnvironment()); spec.setEnvironment(getOpenSearchEnvironment());
spec.workingDir(getDistroDir()); spec.workingDir(getDistroDir());
spec.executable(OS.conditionalString().onUnix(() -> "./bin/" + tool).onWindows(() -> "cmd").supply()); spec.executable(OS.conditionalString().onUnix(() -> "./bin/" + tool).onWindows(() -> "cmd").supply());
spec.args(OS.<List<CharSequence>>conditional().onWindows(() -> { spec.args(OS.<List<CharSequence>>conditional().onWindows(() -> {
@ -708,17 +800,17 @@ public class OpenSearchNode implements TestClusterConfiguration {
private void runKeystoreCommandWithPassword(String keystorePassword, String input, CharSequence... args) { private void runKeystoreCommandWithPassword(String keystorePassword, String input, CharSequence... args) {
final String actualInput = keystorePassword.length() > 0 ? keystorePassword + "\n" + input : input; final String actualInput = keystorePassword.length() > 0 ? keystorePassword + "\n" + input : input;
runOpenSearchBinScriptWithInput(actualInput, "opensearch-keystore", args); runOpenSearchBinScriptWithInput(actualInput, currentConfig.keystoreTool, args);
} }
private void runOpenSearchBinScript(String tool, CharSequence... args) { private void runOpenSearchBinScript(String tool, CharSequence... args) {
runOpenSearchBinScriptWithInput("", tool, args); runOpenSearchBinScriptWithInput("", tool, args);
} }
private Map<String, String> getESEnvironment() { private Map<String, String> getOpenSearchEnvironment() {
Map<String, String> defaultEnv = new HashMap<>(); Map<String, String> defaultEnv = new HashMap<>();
getRequiredJavaHome().ifPresent(javaHome -> defaultEnv.put("JAVA_HOME", javaHome)); getRequiredJavaHome().ifPresent(javaHome -> defaultEnv.put("JAVA_HOME", javaHome));
defaultEnv.put("OPENSEARCH_PATH_CONF", configFile.getParent().toString()); defaultEnv.put(currentConfig.envPathConf, currentConfig.configFile.getParent().toString());
String systemPropertiesString = ""; String systemPropertiesString = "";
if (systemProperties.isEmpty() == false) { if (systemProperties.isEmpty() == false) {
systemPropertiesString = " " systemPropertiesString = " "
@ -728,7 +820,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
// OPENSEARCH_PATH_CONF is also set as an environment variable and for a reference to ${OPENSEARCH_PATH_CONF} // OPENSEARCH_PATH_CONF is also set as an environment variable and for a reference to ${OPENSEARCH_PATH_CONF}
// to work OPENSEARCH_JAVA_OPTS, we need to make sure that OPENSEARCH_PATH_CONF before OPENSEARCH_JAVA_OPTS. Instead, // to work OPENSEARCH_JAVA_OPTS, we need to make sure that OPENSEARCH_PATH_CONF before OPENSEARCH_JAVA_OPTS. Instead,
// we replace the reference with the actual value in other environment variables // we replace the reference with the actual value in other environment variables
.map(p -> p.replace("${OPENSEARCH_PATH_CONF}", configFile.getParent().toString())) .map(p -> p.replace("${" + currentConfig.envPathConf + "}", currentConfig.configFile.getParent().toString()))
.collect(Collectors.joining(" ")); .collect(Collectors.joining(" "));
} }
String jvmArgsString = ""; String jvmArgsString = "";
@ -743,12 +835,12 @@ public class OpenSearchNode implements TestClusterConfiguration {
} }
String heapSize = System.getProperty("tests.heap.size", "512m"); String heapSize = System.getProperty("tests.heap.size", "512m");
defaultEnv.put( defaultEnv.put(
"OPENSEARCH_JAVA_OPTS", currentConfig.envJavaOpts,
"-Xms" + heapSize + " -Xmx" + heapSize + " -ea -esa " + systemPropertiesString + " " + jvmArgsString + " " + "-Xms" + heapSize + " -Xmx" + heapSize + " -ea -esa " + systemPropertiesString + " " + jvmArgsString + " " +
// Support passing in additional JVM arguments // Support passing in additional JVM arguments
System.getProperty("tests.jvm.argline", "") System.getProperty("tests.jvm.argline", "")
); );
defaultEnv.put("OPENSEARCH_TMPDIR", tmpDir.toString()); defaultEnv.put(currentConfig.envTempDir, tmpDir.toString());
// Windows requires this as it defaults to `c:\windows` despite OPENSEARCH_TMPDIR // Windows requires this as it defaults to `c:\windows` despite OPENSEARCH_TMPDIR
defaultEnv.put("TMP", tmpDir.toString()); defaultEnv.put("TMP", tmpDir.toString());
@ -786,24 +878,24 @@ public class OpenSearchNode implements TestClusterConfiguration {
final ProcessBuilder processBuilder = new ProcessBuilder(); final ProcessBuilder processBuilder = new ProcessBuilder();
Path effectiveDistroDir = getDistroDir(); Path effectiveDistroDir = getDistroDir();
List<String> command = OS.<List<String>>conditional() List<String> command = OS.<List<String>>conditional()
.onUnix(() -> Arrays.asList(effectiveDistroDir.resolve("./bin/opensearch").toString())) .onUnix(() -> Arrays.asList(effectiveDistroDir.resolve("./bin/" + currentConfig.command).toString()))
.onWindows(() -> Arrays.asList("cmd", "/c", effectiveDistroDir.resolve("bin\\opensearch.bat").toString())) .onWindows(() -> Arrays.asList("cmd", "/c", effectiveDistroDir.resolve("bin\\" + currentConfig.command + ".bat").toString()))
.supply(); .supply();
processBuilder.command(command); processBuilder.command(command);
processBuilder.directory(workingDir.toFile()); processBuilder.directory(workingDir.toFile());
Map<String, String> environment = processBuilder.environment(); Map<String, String> environment = processBuilder.environment();
// Don't inherit anything from the environment for as that would lack reproducibility // Don't inherit anything from the environment for as that would lack reproducibility
environment.clear(); environment.clear();
environment.putAll(getESEnvironment()); environment.putAll(getOpenSearchEnvironment());
// don't buffer all in memory, make sure we don't block on the default pipes // don't buffer all in memory, make sure we don't block on the default pipes
processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(opensearchStderrFile.toFile())); processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(currentConfig.stderrFile.toFile()));
processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(opensearchStdoutFile.toFile())); processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(currentConfig.stdoutFile.toFile()));
if (keystorePassword != null && keystorePassword.length() > 0) { if (keystorePassword != null && keystorePassword.length() > 0) {
try { try {
Files.write(opensearchStdinFile, (keystorePassword + "\n").getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE); Files.write(currentConfig.stdinFile, (keystorePassword + "\n").getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE);
processBuilder.redirectInput(opensearchStdinFile.toFile()); processBuilder.redirectInput(currentConfig.stdinFile.toFile());
} catch (IOException e) { } catch (IOException e) {
throw new TestClustersException("Failed to set the keystore password for " + this, e); throw new TestClustersException("Failed to set the keystore password for " + this, e);
} }
@ -812,7 +904,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
try { try {
opensearchProcess = processBuilder.start(); opensearchProcess = processBuilder.start();
} catch (IOException e) { } catch (IOException e) {
throw new TestClustersException("Failed to start ES process for " + this, e); throw new TestClustersException("Failed to start " + currentConfig.command + " process for " + this, e);
} }
reaper.registerPid(toString(), opensearchProcess.pid()); reaper.registerPid(toString(), opensearchProcess.pid());
} }
@ -884,8 +976,8 @@ public class OpenSearchNode implements TestClusterConfiguration {
stopHandle(opensearchProcess.toHandle(), true); stopHandle(opensearchProcess.toHandle(), true);
reaper.unregister(toString()); reaper.unregister(toString());
if (tailLogs) { if (tailLogs) {
logFileContents("Standard output of node", opensearchStdoutFile); logFileContents("Standard output of node", currentConfig.stdoutFile);
logFileContents("Standard error of node", opensearchStderrFile); logFileContents("Standard error of node", currentConfig.stderrFile);
} }
opensearchProcess = null; opensearchProcess = null;
// Clean up the ports file in case this is started again. // Clean up the ports file in case this is started again.
@ -919,7 +1011,10 @@ public class OpenSearchNode implements TestClusterConfiguration {
// and in that case the ML processes will be grandchildren of the wrapper. // and in that case the ML processes will be grandchildren of the wrapper.
List<ProcessHandle> children = processHandle.children().collect(Collectors.toList()); List<ProcessHandle> children = processHandle.children().collect(Collectors.toList());
try { try {
logProcessInfo("Terminating opensearch process" + (forcibly ? " forcibly " : "gracefully") + ":", processHandle.info()); logProcessInfo(
"Terminating " + currentConfig.command + " process" + (forcibly ? " forcibly " : "gracefully") + ":",
processHandle.info()
);
if (forcibly) { if (forcibly) {
processHandle.destroyForcibly(); processHandle.destroyForcibly();
@ -939,7 +1034,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
waitForProcessToExit(processHandle); waitForProcessToExit(processHandle);
if (processHandle.isAlive()) { if (processHandle.isAlive()) {
throw new TestClustersException("Was not able to terminate opensearch process for " + this); throw new TestClustersException("Was not able to terminate " + currentConfig.command + " process for " + this);
} }
} finally { } finally {
children.forEach(each -> stopHandle(each, forcibly)); children.forEach(each -> stopHandle(each, forcibly));
@ -1026,7 +1121,7 @@ public class OpenSearchNode implements TestClusterConfiguration {
try { try {
processHandle.onExit().get(OPENSEARCH_DESTROY_TIMEOUT, OPENSEARCH_DESTROY_TIMEOUT_UNIT); processHandle.onExit().get(OPENSEARCH_DESTROY_TIMEOUT, OPENSEARCH_DESTROY_TIMEOUT_UNIT);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOGGER.info("Interrupted while waiting for ES process", e); LOGGER.info("Interrupted while waiting for {} process", currentConfig.command, e);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (ExecutionException e) { } catch (ExecutionException e) {
LOGGER.info("Failure while waiting for process to exist", e); LOGGER.info("Failure while waiting for process to exist", e);
@ -1037,8 +1132,8 @@ public class OpenSearchNode implements TestClusterConfiguration {
private void createWorkingDir() throws IOException { private void createWorkingDir() throws IOException {
// Start configuration from scratch in case of a restart // Start configuration from scratch in case of a restart
fileSystemOperations.delete(d -> d.delete(configFile.getParent())); fileSystemOperations.delete(d -> d.delete(currentConfig.configFile.getParent()));
Files.createDirectories(configFile.getParent()); Files.createDirectories(currentConfig.configFile.getParent());
Files.createDirectories(confPathRepo); Files.createDirectories(confPathRepo);
Files.createDirectories(confPathData); Files.createDirectories(confPathData);
Files.createDirectories(confPathLogs); Files.createDirectories(confPathLogs);
@ -1164,8 +1259,13 @@ public class OpenSearchNode implements TestClusterConfiguration {
baseConfig.put("discovery.initial_state_timeout", "0s"); baseConfig.put("discovery.initial_state_timeout", "0s");
// TODO: Remove these once https://github.com/elastic/elasticsearch/issues/46091 is fixed // TODO: Remove these once https://github.com/elastic/elasticsearch/issues/46091 is fixed
baseConfig.put("logger.org.opensearch.action.support.master", "DEBUG"); if (getVersion().onOrAfter("1.0.0")) {
baseConfig.put("logger.org.opensearch.cluster.coordination", "DEBUG"); baseConfig.put("logger.org.opensearch.action.support.master", "DEBUG");
baseConfig.put("logger.org.opensearch.cluster.coordination", "DEBUG");
} else {
baseConfig.put("logger.org.elasticsearch.action.support.master", "DEBUG");
baseConfig.put("logger.org.elasticsearch.cluster.coordination", "DEBUG");
}
HashSet<String> overriden = new HashSet<>(baseConfig.keySet()); HashSet<String> overriden = new HashSet<>(baseConfig.keySet());
overriden.retainAll(settings.keySet()); overriden.retainAll(settings.keySet());
@ -1178,10 +1278,10 @@ public class OpenSearchNode implements TestClusterConfiguration {
// Make sure no duplicate config keys // Make sure no duplicate config keys
settings.keySet().stream().filter(OVERRIDABLE_SETTINGS::contains).forEach(baseConfig::remove); settings.keySet().stream().filter(OVERRIDABLE_SETTINGS::contains).forEach(baseConfig::remove);
final Path configFileRoot = configFile.getParent(); final Path configFileRoot = currentConfig.configFile.getParent();
try { try {
Files.write( Files.write(
configFile, currentConfig.configFile,
Stream.concat(settings.entrySet().stream(), baseConfig.entrySet().stream()) Stream.concat(settings.entrySet().stream(), baseConfig.entrySet().stream())
.map(entry -> entry.getKey() + ": " + entry.getValue()) .map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining("\n")) .collect(Collectors.joining("\n"))
@ -1196,17 +1296,17 @@ public class OpenSearchNode implements TestClusterConfiguration {
} }
logToProcessStdout("Copying additional config files from distro " + configFiles); logToProcessStdout("Copying additional config files from distro " + configFiles);
for (Path file : configFiles) { for (Path file : configFiles) {
Path dest = configFile.getParent().resolve(file.getFileName()); Path dest = currentConfig.configFile.getParent().resolve(file.getFileName());
if (Files.exists(dest) == false) { if (Files.exists(dest) == false) {
Files.copy(file, dest); Files.copy(file, dest);
} }
} }
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException("Could not write config file: " + configFile, e); throw new UncheckedIOException("Could not write config file: " + currentConfig.configFile, e);
} }
tweakJvmOptions(configFileRoot); tweakJvmOptions(configFileRoot);
LOGGER.info("Written config file:{} for {}", configFile, this); LOGGER.info("Written config file:{} for {}", currentConfig.configFile, this);
} }
private void tweakJvmOptions(Path configFileRoot) { private void tweakJvmOptions(Path configFileRoot) {
@ -1428,12 +1528,12 @@ public class OpenSearchNode implements TestClusterConfiguration {
@Internal @Internal
Path getOpensearchStdoutFile() { Path getOpensearchStdoutFile() {
return opensearchStdoutFile; return currentConfig.stdoutFile;
} }
@Internal @Internal
Path getOpensearchStderrFile() { Path getOpensearchStderrFile() {
return opensearchStderrFile; return currentConfig.stderrFile;
} }
private static class FileEntry implements Named { private static class FileEntry implements Named {