From 25f0b1e6bd096e9e8afde77747660d24883dd2ab Mon Sep 17 00:00:00 2001 From: Vacha Date: Tue, 27 Jul 2021 09:01:10 -0700 Subject: [PATCH] Validation for official plugins for upgrade tool (#973) Add validation to check for official plugins during the plugins installation task for the upgrade tool. Signed-off-by: Vacha Shah --- .../upgrade/InstallPluginsTask.java | 77 +++++++++++++++---- .../upgrade/InstallPluginsTaskTests.java | 77 +++++++++++++++++++ 2 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 distribution/tools/upgrade-cli/src/test/java/org/opensearch/upgrade/InstallPluginsTaskTests.java diff --git a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/InstallPluginsTask.java b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/InstallPluginsTask.java index b25877f212c..781a56e4b53 100644 --- a/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/InstallPluginsTask.java +++ b/distribution/tools/upgrade-cli/src/main/java/org/opensearch/upgrade/InstallPluginsTask.java @@ -11,15 +11,43 @@ package org.opensearch.upgrade; import org.opensearch.cli.Terminal; import org.opensearch.common.collect.Tuple; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Locale; +import java.util.Set; /** * Installs the list of plugins using the opensearch-plugin command. - */ +*/ class InstallPluginsTask implements UpgradeTask { private static final String ERROR_MSG = "Error installing plugin %s. Please install it manually."; + /** The list of official plugins that can be installed by the upgrade tool. */ + static final Set OFFICIAL_PLUGINS; + static { + try ( + InputStream stream = InstallPluginsTask.class.getResourceAsStream("/plugins.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)) + ) { + Set plugins = new HashSet<>(); + String line = reader.readLine(); + while (line != null) { + plugins.add(line.trim()); + line = reader.readLine(); + } + OFFICIAL_PLUGINS = Collections.unmodifiableSet(plugins); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override public void accept(final Tuple input) { final TaskInput taskInput = input.v1(); @@ -28,27 +56,46 @@ class InstallPluginsTask implements UpgradeTask { return; } terminal.println("Installing core plugins ..."); - final ProcessBuilder processBuilder = new ProcessBuilder(); + List manualPlugins = new ArrayList<>(); + for (String plugin : taskInput.getPlugins()) { - // TODO - validate if plugin is an official plugin for OpenSearch. - final String command = taskInput.getOpenSearchBin().resolve("opensearch-plugin") + " install " + plugin; - if (OS.WINDOWS == OS.current()) { - processBuilder.command("cmd.exe", "/c", command); + if (OFFICIAL_PLUGINS.contains(plugin)) { + executeInstallPluginCommand(plugin, taskInput, terminal); } else { - processBuilder.command("sh", "-c", command); - } - try { - final Process process = processBuilder.inheritIO().start(); - if (process.waitFor() != 0) { - terminal.errorPrint(Terminal.Verbosity.NORMAL, String.format(Locale.getDefault(), ERROR_MSG, plugin)); - } - } catch (IOException | InterruptedException e) { - terminal.errorPrint(Terminal.Verbosity.NORMAL, String.format(Locale.getDefault(), ERROR_MSG, plugin) + e.getMessage()); + manualPlugins.add(plugin); } } + if (!manualPlugins.isEmpty()) { + terminal.println("Please install the following custom plugins manually: " + manualPlugins); + } terminal.println("Success!" + System.lineSeparator()); } + // package private for unit testing + void executeInstallPluginCommand(String plugin, TaskInput taskInput, Terminal terminal) { + ProcessBuilder processBuilder = getProcessBuilderBasedOnOS(plugin, taskInput); + try { + final Process process = processBuilder.inheritIO().start(); + if (process.waitFor() != 0) { + terminal.errorPrint(Terminal.Verbosity.NORMAL, String.format(Locale.getDefault(), ERROR_MSG, plugin)); + } + } catch (IOException | InterruptedException e) { + terminal.errorPrint(Terminal.Verbosity.NORMAL, String.format(Locale.getDefault(), ERROR_MSG, plugin) + e.getMessage()); + } + } + + // package private for unit testing + ProcessBuilder getProcessBuilderBasedOnOS(String plugin, TaskInput taskInput) { + final String command = taskInput.getOpenSearchBin().resolve("opensearch-plugin") + " install " + plugin; + final ProcessBuilder processBuilder = new ProcessBuilder(); + if (OS.WINDOWS == OS.current()) { + processBuilder.command("cmd.exe", "/c", command); + } else { + processBuilder.command("sh", "-c", command); + } + return processBuilder; + } + private enum OS { WINDOWS, MAC, diff --git a/distribution/tools/upgrade-cli/src/test/java/org/opensearch/upgrade/InstallPluginsTaskTests.java b/distribution/tools/upgrade-cli/src/test/java/org/opensearch/upgrade/InstallPluginsTaskTests.java new file mode 100644 index 00000000000..f0aa85b4c82 --- /dev/null +++ b/distribution/tools/upgrade-cli/src/test/java/org/opensearch/upgrade/InstallPluginsTaskTests.java @@ -0,0 +1,77 @@ +/* + * 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 java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.elasticsearch.mock.orig.Mockito; +import org.junit.Before; +import org.opensearch.cli.MockTerminal; +import org.opensearch.common.collect.Tuple; +import org.opensearch.common.settings.Settings; +import org.opensearch.env.Environment; +import org.opensearch.env.TestEnvironment; +import org.opensearch.test.OpenSearchTestCase; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +public class InstallPluginsTaskTests extends OpenSearchTestCase { + + private final MockTerminal terminal = new MockTerminal(); + private InstallPluginsTask task; + private Environment env; + + private static final String OFFICIAL_PLUGIN = "analysis-icu"; + private static final String CUSTOM_PLUGIN = "job-scheduler"; + + @Before + public void setUpTask() throws IOException { + task = new InstallPluginsTask(); + env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", "").build()); + } + + public void testInstallPluginsTaskWithOfficialPlugin() throws IOException { + InstallPluginsTask spyTask = spy(task); + TaskInput taskInput = createTaskInputWithPlugin(OFFICIAL_PLUGIN); + spyTask.accept(new Tuple<>(taskInput, terminal)); + + verify(spyTask, Mockito.atLeast(1)).executeInstallPluginCommand(OFFICIAL_PLUGIN, taskInput, terminal); + } + + public void testInstallPluginsTaskWithCustomPlugin() throws IOException { + TaskInput taskInput = createTaskInputWithPlugin(CUSTOM_PLUGIN); + task.accept(new Tuple<>(taskInput, terminal)); + + assertThat(terminal.getOutput(), containsString("Please install the following custom plugins manually")); + } + + public void testGetCommandsBasedOnOS() { + TaskInput taskInput = createTaskInputWithPlugin(OFFICIAL_PLUGIN); + List commandsList = task.getProcessBuilderBasedOnOS(OFFICIAL_PLUGIN, taskInput).command(); + + final String os = System.getProperty("os.name", ""); + if (os.startsWith("Windows")) { + assertEquals("cmd.exe", commandsList.get(0)); + } else { + assertEquals("sh", commandsList.get(0)); + } + } + + private TaskInput createTaskInputWithPlugin(String plugin) { + TaskInput taskInput = new TaskInput(env); + List pluginsList = new ArrayList<>(); + pluginsList.add(plugin); + taskInput.setPlugins(pluginsList); + return taskInput; + } +}