diff --git a/distribution/build.gradle b/distribution/build.gradle
index 3e242aa1a2f..763e4cd189d 100644
--- a/distribution/build.gradle
+++ b/distribution/build.gradle
@@ -268,7 +268,7 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
* Properties to expand when copying packaging files *
*****************************************************************************/
configurations {
- ['libs', 'libsPluginCli', 'libsKeystoreCli', 'libsSecurityCli'].each {
+ ['libs', 'libsPluginCli', 'libsKeystoreCli', 'libsUpgradeCli'].each {
create(it) {
canBeConsumed = false
canBeResolved = true
@@ -289,6 +289,7 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
libsPluginCli project(':distribution:tools:plugin-cli')
libsKeystoreCli project(path: ':distribution:tools:keystore-cli')
+ libsUpgradeCli project(path: ':distribution:tools:upgrade-cli')
}
project.ext {
@@ -306,6 +307,9 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
into('tools/keystore-cli') {
from(configurations.libsKeystoreCli)
}
+ into('tools/upgrade-cli') {
+ from(configurations.libsUpgradeCli)
+ }
}
}
diff --git a/distribution/src/bin/opensearch-upgrade b/distribution/src/bin/opensearch-upgrade
new file mode 100755
index 00000000000..d271f9b5014
--- /dev/null
+++ b/distribution/src/bin/opensearch-upgrade
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+OPENSEARCH_MAIN_CLASS=org.opensearch.upgrade.UpgradeCli \
+ OPENSEARCH_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/upgrade-cli \
+ "`dirname "$0"`"/opensearch-cli \
+ "$@"
diff --git a/distribution/src/bin/opensearch-upgrade.bat b/distribution/src/bin/opensearch-upgrade.bat
new file mode 100644
index 00000000000..f44b3750eb9
--- /dev/null
+++ b/distribution/src/bin/opensearch-upgrade.bat
@@ -0,0 +1,16 @@
+@echo off
+
+setlocal enabledelayedexpansion
+setlocal enableextensions
+
+set OPENSEARCH_MAIN_CLASS=org.opensearch.upgrade.UpgradeCli
+set OPENSEARCH_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/upgrade-cli
+call "%~dp0opensearch-cli.bat" ^
+ %%* ^
+ || goto exit
+
+
+endlocal
+endlocal
+:exit
+exit /b %ERRORLEVEL%
diff --git a/distribution/tools/upgrade-cli/build.gradle b/distribution/tools/upgrade-cli/build.gradle
new file mode 100644
index 00000000000..5018a4bb870
--- /dev/null
+++ b/distribution/tools/upgrade-cli/build.gradle
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+ */
+
+apply plugin: 'opensearch.build'
+
+archivesBaseName = 'opensearch-upgrade-cli'
+
+dependencies {
+ compileOnly project(":server")
+ compileOnly project(":libs:opensearch-cli")
+ implementation "com.fasterxml.jackson.core:jackson-core:${versions.jackson}"
+ implementation "com.fasterxml.jackson.core:jackson-databind:${versions.jackson}"
+ implementation "com.fasterxml.jackson.core:jackson-annotations:${versions.jackson}"
+ testImplementation project(":test:framework")
+ testImplementation 'com.google.jimfs:jimfs:1.2'
+ testRuntimeOnly 'com.google.guava:guava:30.1.1-jre'
+}
+
+tasks.named("dependencyLicenses").configure {
+ mapping from: /jackson-.*/, to: 'jackson'
+}
+
+test {
+ systemProperty 'tests.security.manager', 'false'
+}
diff --git a/distribution/tools/upgrade-cli/licenses/jackson-LICENSE b/distribution/tools/upgrade-cli/licenses/jackson-LICENSE
new file mode 100644
index 00000000000..f5f45d26a49
--- /dev/null
+++ b/distribution/tools/upgrade-cli/licenses/jackson-LICENSE
@@ -0,0 +1,8 @@
+This copy of Jackson JSON processor streaming parser/generator is licensed under the
+Apache (Software) License, version 2.0 ("the License").
+See the License for details about distribution rights, and the
+specific rights regarding derivate works.
+
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
diff --git a/distribution/tools/upgrade-cli/licenses/jackson-NOTICE b/distribution/tools/upgrade-cli/licenses/jackson-NOTICE
new file mode 100644
index 00000000000..4c976b7b4cc
--- /dev/null
+++ b/distribution/tools/upgrade-cli/licenses/jackson-NOTICE
@@ -0,0 +1,20 @@
+# Jackson JSON processor
+
+Jackson is a high-performance, Free/Open Source JSON processing library.
+It was originally written by Tatu Saloranta (tatu.saloranta@iki.fi), and has
+been in development since 2007.
+It is currently developed by a community of developers, as well as supported
+commercially by FasterXML.com.
+
+## Licensing
+
+Jackson core and extension components may licensed under different licenses.
+To find the details that apply to this artifact see the accompanying LICENSE file.
+For more information, including possible other licensing options, contact
+FasterXML.com (http://fasterxml.com).
+
+## Credits
+
+A list of contributors may be found from CREDITS file, which is included
+in some artifacts (usually source distributions); but is always available
+from the source code management (SCM) system project uses.
diff --git a/distribution/tools/upgrade-cli/licenses/jackson-annotations-2.11.4.jar.sha1 b/distribution/tools/upgrade-cli/licenses/jackson-annotations-2.11.4.jar.sha1
new file mode 100644
index 00000000000..d1ddeaf8a61
--- /dev/null
+++ b/distribution/tools/upgrade-cli/licenses/jackson-annotations-2.11.4.jar.sha1
@@ -0,0 +1 @@
+2c3f5c079330f3a01726686a078979420f547ae4
\ No newline at end of file
diff --git a/distribution/tools/upgrade-cli/licenses/jackson-databind-2.11.4.jar.sha1 b/distribution/tools/upgrade-cli/licenses/jackson-databind-2.11.4.jar.sha1
new file mode 100644
index 00000000000..dd4ebcc7051
--- /dev/null
+++ b/distribution/tools/upgrade-cli/licenses/jackson-databind-2.11.4.jar.sha1
@@ -0,0 +1 @@
+5d9f3d441f99d721b957e3497f0a6465c764fad4
\ No newline at end of file
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/KeystoreWrapperUtil.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/KeystoreWrapperUtil.java
new file mode 100644
index 00000000000..f9300b65554
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/KeystoreWrapperUtil.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package org.opensearch.common.settings;
+
+/**
+ * Utility that has package level access to the {@link KeyStoreWrapper} for
+ * saving a setting.
+ */
+public final class KeystoreWrapperUtil {
+ /**
+ * No public constructor. Contains only static functions.
+ */
+ private KeystoreWrapperUtil() {}
+
+ /**
+ * Save a secure setting using the wrapper.
+ *
+ * @param keystore an instance of {@link KeyStoreWrapper}
+ * @param setting setting to save
+ * @param bytes value of the setting in bytes
+ */
+ public static void saveSetting(KeyStoreWrapper keystore, String setting, byte[] bytes) {
+ keystore.setFile(setting, bytes);
+ }
+}
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/package-info.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/package-info.java
new file mode 100644
index 00000000000..b3a4e951263
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/common/settings/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * 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.
+ */
+
+/**
+ * This exists to get access to the package level methods of KeyStoreWrapper.
+ */
+package org.opensearch.common.settings;
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/DetectEsInstallationTask.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/DetectEsInstallationTask.java
new file mode 100644
index 00000000000..24f4b79d125
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/DetectEsInstallationTask.java
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+package org.opensearch.upgrade;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.opensearch.Version;
+import org.opensearch.cli.Terminal;
+import org.opensearch.common.SuppressForbidden;
+import org.opensearch.common.collect.Tuple;
+import org.opensearch.common.settings.Settings;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+
+/**
+ * Looks for an existing elasticsearch installation. First it tries to identify automatically,
+ * and if unsuccessful, asks the user to input the missing details.
+ *
+ * If an elasticsearch installation can not be found, throws a runtime error which fails the
+ * upgrade task.
+ */
+class DetectEsInstallationTask implements UpgradeTask {
+ private static final int ES_DEFAULT_PORT = 9200;
+ private static final String ES_CONFIG_ENV = "ES_PATH_CONF";
+ private static final String ES_CONFIG_YML = "elasticsearch.yml";
+ private static final String ES_HOME = "ES_HOME";
+
+ @SuppressForbidden(reason = "We need to read external es config files")
+ @Override
+ public void accept(final Tuple input) {
+ final TaskInput taskInput = input.v1();
+ final Terminal terminal = input.v2();
+ try {
+ terminal.println("Looking for an elasticsearch installation ...");
+ String esHomeEnv = System.getenv(ES_HOME);
+ if (esHomeEnv == null) {
+ esHomeEnv = terminal.readText("Missing ES_HOME env variable, enter the path to elasticsearch home: ");
+ if (esHomeEnv == null || esHomeEnv.isEmpty()) {
+ throw new RuntimeException("Invalid input for path to elasticsearch home directory.");
+ }
+ }
+ taskInput.setEsHome(new File(esHomeEnv).toPath());
+
+ String esConfEnv = System.getenv(ES_CONFIG_ENV);
+ if (esConfEnv == null) {
+ esConfEnv = terminal.readText("Missing ES_PATH_CONF env variable, enter the path to elasticsearch config directory: ");
+ if (esConfEnv == null || esHomeEnv.isEmpty()) {
+ throw new RuntimeException("Invalid input for path to elasticsearch config directory.");
+ }
+ }
+ taskInput.setEsConfig(new File(esConfEnv).toPath());
+
+ final Settings esSettings = Settings.builder().loadFromPath(taskInput.getEsConfig().resolve(ES_CONFIG_YML)).build();
+ final String url = retrieveUrl(esSettings);
+ taskInput.setBaseUrl(url);
+ final boolean running = isRunning(url);
+ taskInput.setRunning(running);
+ if (running) {
+ terminal.println("Found a running instance of elasticsearch at " + url);
+ taskInput.setRunning(true);
+ try {
+ updateTaskInput(taskInput, fetchInfoFromUrl(taskInput.getBaseUrl()));
+ } catch (RuntimeException e) {
+ updateTaskInput(taskInput, fetchInfoFromEsSettings(esSettings));
+ }
+ try {
+ taskInput.setPlugins(fetchPluginsFromUrl(taskInput.getBaseUrl()));
+ } catch (RuntimeException e) {
+ taskInput.setPlugins(detectPluginsFromEsHome(taskInput.getEsHome()));
+ }
+ } else {
+ terminal.println("Did not find a running instance of elasticsearch at " + url);
+ updateTaskInput(taskInput, fetchInfoFromEsSettings(esSettings));
+ taskInput.setPlugins(detectPluginsFromEsHome(taskInput.getEsHome()));
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Error detecting existing elasticsearch installation. " + e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void updateTaskInput(TaskInput taskInput, Map, ?> response) {
+ final Map versionMap = (Map) response.get("version");
+ if (versionMap != null) {
+ final String vStr = versionMap.get("number");
+ if (vStr != null) {
+ taskInput.setVersion(Version.fromString(vStr));
+ }
+ }
+ taskInput.setNode((String) response.get("name"));
+ taskInput.setCluster((String) response.get("cluster_name"));
+ }
+
+ // package private for unit testing
+ String retrieveUrl(final Settings esSettings) {
+ final int port = Optional.ofNullable(esSettings.get("http.port")).map(this::extractPort).orElse(ES_DEFAULT_PORT);
+ return "http://localhost:" + port;
+ }
+
+ private Integer extractPort(final String port) {
+ try {
+ return Integer.parseInt(port.trim());
+ } catch (Exception ex) {
+ return ES_DEFAULT_PORT;
+ }
+ }
+
+ @SuppressForbidden(reason = "Need to connect to http endpoint for elasticsearch.")
+ private boolean isRunning(final String url) {
+ try {
+ final URL esUrl = new URL(url);
+ final HttpURLConnection conn = (HttpURLConnection) esUrl.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setConnectTimeout(1000);
+ conn.connect();
+ return conn.getResponseCode() == 200;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @SuppressForbidden(reason = "Retrieve information on the installation.")
+ private Map, ?> fetchInfoFromUrl(final String url) {
+ try {
+ final URL esUrl = new URL(url);
+ final HttpURLConnection conn = (HttpURLConnection) esUrl.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setConnectTimeout(1000);
+ conn.connect();
+
+ final StringBuilder json = new StringBuilder();
+ final Scanner scanner = new Scanner(esUrl.openStream());
+ while (scanner.hasNext()) {
+ json.append(scanner.nextLine());
+ }
+ scanner.close();
+ final ObjectMapper mapper = new ObjectMapper();
+ return mapper.readValue(json.toString(), Map.class);
+ } catch (IOException e) {
+ throw new RuntimeException("Error retrieving elasticsearch cluster info, " + e);
+ }
+ }
+
+ private Map, ?> fetchInfoFromEsSettings(final Settings esSettings) throws IOException {
+ final Map info = new HashMap<>();
+ final String node = esSettings.get("node.name") != null ? esSettings.get("node.name") : "unknown";
+ final String cluster = esSettings.get("cluster.name") != null ? esSettings.get("cluster.name") : "unknown";
+ info.put("name", node);
+ info.put("cluster_name", cluster);
+ return info;
+ }
+
+ @SuppressWarnings("unchecked")
+ @SuppressForbidden(reason = "Retrieve information on installed plugins.")
+ private List fetchPluginsFromUrl(final String url) {
+ final List plugins = new ArrayList<>();
+ try {
+ final URL esUrl = new URL(url + "/_cat/plugins?format=json&local=true");
+ final HttpURLConnection conn = (HttpURLConnection) esUrl.openConnection();
+ conn.setRequestMethod("GET");
+ conn.setConnectTimeout(1000);
+ conn.connect();
+ if (conn.getResponseCode() == 200) {
+ final StringBuilder json = new StringBuilder();
+ final Scanner scanner = new Scanner(esUrl.openStream());
+ while (scanner.hasNext()) {
+ json.append(scanner.nextLine());
+ }
+ scanner.close();
+ final ObjectMapper mapper = new ObjectMapper();
+ final Map[] response = mapper.readValue(json.toString(), Map[].class);
+ for (Map plugin : response) {
+ plugins.add(plugin.get("component"));
+ }
+ }
+ return plugins;
+ } catch (IOException e) {
+ throw new RuntimeException("Error retrieving elasticsearch plugin details, " + e);
+ }
+ }
+
+ private List detectPluginsFromEsHome(final Path esHome) {
+ // list out the contents of the plugins directory under esHome
+ return Collections.emptyList();
+ }
+}
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportJvmOptionsTask.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportJvmOptionsTask.java
new file mode 100644
index 00000000000..555c5535781
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportJvmOptionsTask.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package org.opensearch.upgrade;
+
+import org.opensearch.cli.Terminal;
+import org.opensearch.common.collect.Tuple;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Imports JVM options from an existing elasticsearch installation.
+ */
+class ImportJvmOptionsTask implements UpgradeTask {
+ private static final String JVM_OPTIONS_D = "jvm.options.d";
+
+ @Override
+ public void accept(final Tuple input) {
+ final TaskInput taskInput = input.v1();
+ final Terminal terminal = input.v2();
+ try {
+ terminal.println("Importing JVM options ...");
+ final Path jvmOptionsDir = taskInput.getOpenSearchConfig().resolve(JVM_OPTIONS_D);
+ if (!Files.exists(jvmOptionsDir)) {
+ Files.createDirectory(jvmOptionsDir);
+ }
+
+ final Path esJvmOptionsDir = taskInput.getEsConfig().resolve(JVM_OPTIONS_D);
+ if (Files.exists(esJvmOptionsDir) && Files.isDirectory(esJvmOptionsDir)) {
+ final List esJvmOptionsFiles = Files.list(esJvmOptionsDir).collect(Collectors.toList());
+ for (Path esJvmOptFile : esJvmOptionsFiles) {
+ final Path jvmOptFile = jvmOptionsDir.resolve(esJvmOptFile.getFileName().toString());
+ Files.copy(esJvmOptFile, jvmOptFile, StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ terminal.println("Success!" + System.lineSeparator());
+ } catch (Exception e) {
+ throw new RuntimeException("Error importing JVM options. " + e);
+ }
+ }
+}
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportKeystoreTask.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportKeystoreTask.java
new file mode 100644
index 00000000000..c5d578dfad4
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportKeystoreTask.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package org.opensearch.upgrade;
+
+import org.opensearch.cli.Terminal;
+import org.opensearch.common.collect.Tuple;
+import org.opensearch.common.settings.KeyStoreWrapper;
+import org.opensearch.common.settings.KeystoreWrapperUtil;
+import org.opensearch.common.settings.SecureString;
+
+import java.io.InputStream;
+
+/**
+ * Imports the secure Keystore settings from an existing elasticsearch installation.
+ */
+class ImportKeystoreTask implements UpgradeTask {
+ private static final String OPENSEARCH_KEYSTORE_FILENAME = "opensearch.keystore";
+ private static final String ES_KEYSTORE_FILENAME = "elasticsearch.keystore";
+
+ @Override
+ public void accept(final Tuple input) {
+ final TaskInput taskInput = input.v1();
+ final Terminal terminal = input.v2();
+ SecureString keyStorePassword = new SecureString(new char[0]);
+ try {
+ terminal.println("Importing keystore settings ...");
+ final KeyStoreWrapper esKeystore = KeyStoreWrapper.load(taskInput.getEsConfig(), ES_KEYSTORE_FILENAME);
+ if (esKeystore == null) {
+ terminal.println("No elasticsearch keystore settings to import.");
+ return;
+ }
+ KeyStoreWrapper openSearchKeystore = KeyStoreWrapper.load(
+ taskInput.getOpenSearchConfig().resolve(OPENSEARCH_KEYSTORE_FILENAME)
+ );
+ if (openSearchKeystore == null) {
+ openSearchKeystore = KeyStoreWrapper.create();
+ }
+ if (esKeystore.hasPassword()) {
+ final char[] passwordArray = terminal.readSecret("Enter password for the elasticsearch keystore : ");
+ keyStorePassword = new SecureString(passwordArray);
+ }
+ esKeystore.decrypt(keyStorePassword.getChars());
+ for (String setting : esKeystore.getSettingNames()) {
+ if (setting.equals("keystore.seed")) {
+ continue;
+ }
+ if (!openSearchKeystore.getSettingNames().contains(setting)) {
+ InputStream settingIS = esKeystore.getFile(setting);
+ byte[] bytes = new byte[settingIS.available()];
+ settingIS.read(bytes);
+ KeystoreWrapperUtil.saveSetting(openSearchKeystore, setting, bytes);
+ }
+ }
+ openSearchKeystore.save(taskInput.getOpenSearchConfig(), keyStorePassword.getChars());
+ terminal.println("Success!" + System.lineSeparator());
+ } catch (Exception e) {
+ throw new RuntimeException("Error importing keystore settings from elasticsearch, " + e);
+ } finally {
+ keyStorePassword.close();
+ }
+ }
+}
diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportLog4jPropertiesTask.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportLog4jPropertiesTask.java
new file mode 100644
index 00000000000..7934ba43ccf
--- /dev/null
+++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/ImportLog4jPropertiesTask.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package org.opensearch.upgrade;
+
+import org.opensearch.cli.Terminal;
+import org.opensearch.common.collect.Tuple;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Imports Log4j properties from an existing elasticsearch installation.
+ */
+class ImportLog4jPropertiesTask implements UpgradeTask {
+ static final String LOG4J_PROPERTIES = "log4j2.properties";
+
+ @Override
+ public void accept(final Tuple input) {
+ final TaskInput taskInput = input.v1();
+ final Terminal terminal = input.v2();
+ try {
+ terminal.println("Importing log4j.properties ...");
+ final Path log4jPropPath = taskInput.getOpenSearchConfig().resolve(LOG4J_PROPERTIES);
+ if (Files.exists(log4jPropPath)) {
+ Files.copy(
+ log4jPropPath,
+ taskInput.getOpenSearchConfig().resolve(LOG4J_PROPERTIES + ".bkp"),
+ StandardCopyOption.REPLACE_EXISTING
+ );
+ }
+ final Path esLog4jPropPath = taskInput.getEsConfig().resolve(LOG4J_PROPERTIES);
+ try (
+ InputStream esLog4jIs = Files.newInputStream(esLog4jPropPath);
+ OutputStream log4jOs = Files.newOutputStream(log4jPropPath, StandardOpenOption.TRUNCATE_EXISTING)
+ ) {
+ final Properties esLog4JProps = new Properties();
+ esLog4JProps.load(esLog4jIs);
+ final Properties log4jProps = renameValues(esLog4JProps);
+
+ log4jProps.store(log4jOs, "This is an auto-generated file imported from an existing elasticsearch installation.");
+ }
+ terminal.println("Success!" + System.lineSeparator());
+ } catch (IOException e) {
+ throw new RuntimeException("Error copying log4j properties. " + e);
+ }
+ }
+
+ /**
+ * Rename the values for OpenSearch log4j properties to reflect the changed names
+ * for java packages, class names and system variables.
+ *
+ * @param esLog4JProps existing elasticsearch log4j properties.
+ * @return updated properties for OpenSearch.
+ */
+ private Properties renameValues(Properties esLog4JProps) {
+ final Properties props = new Properties();
+ for (Map.Entry